Prof. Dr. A. Poetzsch-Heffter Dipl.-Inform. N. Rauch Technische Universität Kaiserslautern Fachbereich Informatik AG Softwaretechnik Lösungsvorschläge zum Übungsblatt 5: Fortgeschrittene Aspekte objektorientierter Programmierung (SS 2007) Aufgabe 1 Spezifikation mit JML II a) Man kann eine model variable verwenden. b) Dies lässt sich mit Hilfe von assignable-Klauseln regulieren. import java.util.ArrayList; class Behaelter { /* * Aufgabe 1 a): Verwendung von Model-Variablen zum Verbergen der Implementation. * Zur Demonstration wurde die Implementierung gegen eine ArrayList ausgetauscht. */ /*@ @ public model instance non_null int[] elements; @ public model instance int length; @ private represents length <- n; @ private represents elements <- downcast(a.toArray()); @ @ public static model pure int[] downcast( Object[] o ){ @ int[] t = new int[o.length]; @ for( int i = 0; i < o.length; i++ ) @ t[i] = ((Integer)o[i]).intValue(); @ return t; @ } @ @ public invariant 0 <= length && length <= elements.length; @*/ // Zur Demonstration der Unabhaengigkeit der Modellierung von der Implementierung // wurde die // interne Repraesentation durch eine ArrayList vorgenommen. Der urspruengliche // Code ist noch in Kommentaren vorhanden. // private /*@ non_null */ int[] a; // verlagert die Aussage "a != null" aus der Invar private /*@ non_null */ ArrayList a; // verlagert die Aussage "a != null" aus der Inv private int n; /*@ @ requires input != null; @ assignable elements, length; @ ensures elements.length == \old(input.length) && length == elements.length @ && (\forall int i; 0 <= i && i < length; elements[i] == \old(input[i]) ) @ && elements != \old(input); @*/ Behaelter( int[] input ){ n = input.length; a = // new int[n]; new ArrayList(); // System.arraycopy(input, 0, a, 0, n); for( int i = 0; i < input.length; i++ ) a.add(new Integer(input[i])); System.out.println("Laenge: " + a.size() + " " + a.toArray().length ); } /*@ @ requires length >= 1; @ assignable elements, length; @ ensures length + 1 == \old(length) && (\forall int i; 0 <= i && i < length; \result <= elements[i]); @*/ int extractMin() { int m = ((Integer)a.get(0)).intValue(); int mindex = 0; /*@ @ loop_invariant (\forall int j; 0 <= j && j < i; elements[mindex] <= elements[j]) @ && elements[mindex] == m; @*/ for (int i = 1; i < n; i++) { if (/*a[i]*/ ((Integer)a.get(i)).intValue() < m) { mindex = i; m = ((Integer)a.get(i)).intValue(); // a[i]; } } n--; // a[mindex] = a[n]; a.set(mindex, a.get(n)); return m; } /*@ @ constraint length <= \old(length); @*/ /* * Ein Test */ public static void main(String[] s){ int[] input = new int[]{1,2,3,4,5}; Behaelter b = new Behaelter(input); for( int i = 1; i <= 6; i++ ) System.out.println(i + "-ter Versuch: " + b.extractMin() ); } } Aufgabe 2 Spezifikation mit JML III a) Spezifikation des Interfaces: import java.io.FileReader; import java.io.FileWriter; class FileNotFoundException extends Exception {} class FileNotOpenException extends Exception {} class ReadOnlyViolation extends Exception {} public interface FileAnnotated { 2 //@ model instance boolean isOpen; //@ model instance boolean isWriteable; /*@ public normal_behavior requires name != null && (writeable || new java.io.File(name).exists()); assignable \everything; ensures isOpen && isWriteable == writeable; also public exceptional_behavior requires name == null || (! writeable && ! new java.io.File(name).exists()); assignable \nothing; signals(FileNotFoundException) true; / * public void open( String name, boolean writeable ) throws FileNotFoundException; /*@ public normal_behavior requires isOpen; assignable isOpen; ensures ! isOpen; also public exceptional_behavior requires ! isOpen; assignable \everything; signals(FileNotOpenException) true; / * public void close() throws FileNotOpenException; /*@ public normal_behavior requires isOpen && ! isWriteable; assignable \everything; ensures -1 <= \result && \result <= 65535; also public exceptional_behavior requires ! isOpen || isWriteable; assignable \everything; signals(FileNotOpenException) true; / * public int read() throws FileNotOpenException; /*@ public normal_behavior requires isOpen && isWriteable && ch >= 0; assignable \everything; ensures true; also public exceptional_behavior requires ! isOpen || ! isWriteable; assignable \everything; signals (FileNotOpenException) ! isOpen; signals (ReadOnlyViolation) isOpen && ! isWriteable; */ public void write( char ch ) throws FileNotOpenException, ReadOnlyViolation; } b) Implementierung: 3 import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; public class FileImpl implements FileAnnotated { private /*@ nullable */ FileReader reader; private /*@ nullable */ FileWriter writer; //@ private represents isOpen <- reader != null || writer != null; //@ private represents isWriteable <- writer != null; public void open( String name, boolean writeable ) throws FileNotFoundException { // close any files that are currently open for reading or writing try { close(); } catch (FileNotOpenException e1) { // ignore this exception, regard closing as service } if( name == null ) throw new FileNotFoundException(); java.io.File theFile = new java.io.File(name); if( ! writeable && ! theFile.exists() ) throw new FileNotFoundException(); try { if( writeable ){ writer = new FileWriter(theFile); } else { reader = new FileReader(theFile); } } catch (IOException e) { throw new FileNotFoundException(); } } public void close() throws FileNotOpenException { if( reader == null && writer == null ) throw new FileNotOpenException(); try { if( reader != null ){ reader.close(); } if( writer != null ){ writer.close(); } } catch( IOException e ){ // ignore this exception } reader = null; writer = null; } public int read() throws FileNotOpenException { if( reader == null ) throw new FileNotOpenException(); 4 try { return reader.read(); } catch (IOException e) { return -1; // problem } } public void write( char ch ) throws FileNotOpenException, ReadOnlyViolation { if( writer == null ){ if( reader == null ){ throw new FileNotOpenException(); } else { throw new ReadOnlyViolation(); } } try { writer.write(ch); } catch (IOException e) { // ignore exception } } public static void testZyklus(String name, boolean writeable ) { // File lesen: FileImpl f1 = new FileImpl(); System.out.println("Oeffnen des Files " + name); try { f1.open(name, writeable); } catch(FileNotFoundException e){ System.out.println("Oeffnen fehlgeschlagen."); } System.out.println("Lesen aus dem File:"); try { int i = f1.read(); while( i != -1 ){ System.out.print((char)i); i = f1.read(); } } catch(FileNotOpenException e){ System.out.println("Lesen des Files fehlgeschlagen."); } System.out.println("Schreiben in das File:"); try { f1.write(’a’); } catch (FileNotOpenException e) { System.out.println("File nicht geoeffnet."); } catch (ReadOnlyViolation e) { System.out.println("File nur zum Lesen geoeffnet."); } System.out.println("Schlie§en des Files:"); try { f1.close(); System.out.println("File geschlossen."); } catch (FileNotOpenException e) { System.out.println("File nicht geoeffnet."); } } 5 public static void main(String[] s) { if( s.length != 2 ){ System.out.println("Usage: Ein File zum Lesen und ein File zum " + "Schreiben angeben!"); return; } ////////////////////////////////////////////////// FileImpl.testZyklus(s[0], false); FileImpl.testZyklus(s[1], true); FileImpl.testZyklus("blabla1", false); FileImpl.testZyklus("blabla2", true); } } 6