Software Engineering II Bachelor-/Diplomstudiengang Medieninformatik Sommersemester 2015 ► 2 SWS Vorlesung + 2 SWS Praktikum ► APL (BGA) Alternative Prüfungsleistung (Belegarbeit) → Anfertigung, Dokumentation und Verteidigung des Gruppenbelegs Prof. Dr. Hartmut Fritzsche Fakultät Informatik/Mathematik Büro: Z 342 Sprechzeit: Mittwoch 12.00 -13.00 Uhr Tel. (0351) 462 2606 [email protected] www.informatik.htw-dresden.de/~fritzsch Aufbau der Lehrveranstaltung ► umfasst die Module „SE I“ und „SE II“ (zwei Semester) ► orientiert sich an den Phasen des Softwareentwicklungsprozesses (SEP) ► Nutzung einer Softwareentwicklungsumgebung (SEU) im Praktikum Eclipse + TOPCASED + Mercurial + ... ► Beginn mit thematischen Praktikumsveranstaltungen ► Gruppenprojekt (2 – 4 Studierende) >> Dez. 2013 – Juli 2014 mit dem Ziel, eine lauffähige Anwendung zu entwickeln, zu dokumentieren und zu verteidigen. Inhalt 1. Einführung: Ziele und Arbeitsmethoden der Softwaretechnik 2. Der Softwareentwicklungsprozess (Überblick) 3. Anforderungsanalyse / -definition 4. Objektorientierte Modellierung Unified Modeling Language (UML 2) 5. von UML nach Java ... 6. Entwurf und Implementation 7. Konfigurationsmanagement 8. Wiederverwendung und Evolution 9. Musterarchitekturen SE II Literatur H. Balzert: Lehrbuch der Objektmodellierung. Analyse und Entwurf mit der UML 2. Spektrum Akademischer Verlag, 2004 M. Fowler, K. Scott UML konzentriert. Eine Einführung in die Standard Objektmodellierungssprache. Addison-Wesley, 2. Aufl., 2000 C. Rupp, S. Queins, B. Zengler UML 2 glasklar, Praxiswissen für die UML-Modellierung Carl Hanser Verlag, 3. Aufl., 2007 W. Pree Komponentenbasierte Softwareentwicklung mit Frameworks. dpunkt.verlag, 1997 I. Sommerville Software Engineering. Addison-Wesley, 8. Aufl. 2007 G. Popp Konfigurationsmanagement mit Subversion, Ant und Maven dpunkt.verlag, 2. Aufl. 2008 7 Konfigurationsmanagement ► Ziele des KM: ● Im SEP entstehende Ergebnisse (Artefakte: Dokumente, Modelle, Code, ...) sicher verwalten ● Zugriffskontrolle für verteilt arbeitende Entwickler ● Kontrolle über Veränderungen an Artefakten im Laufe der Entwicklung ► Das KM umfasst Aufgaben wie ● die Kontrolle der entwickelten Quellprogramme ● die Bereitstellung von „Build“-Funktionalität ● das Release-Engineering ► KM = Regelwerk, mit dem KM-Prozess beschrieben wird Der KM-Prozess (Kernprozess) ► Auswahl der Konfigurationselemente • Betrachten von Typen von Konfigurationselementen (z.B. Quelltext) • Alle Instanzen der Konfigurationselemente zusammen bilden das Softwareprodukt Beispiel: Build-Skripte sind Konfigurationselemente, JavaDoc-Dokumentationen (API) sind eher keine, können aus kommentierten Quelltexten erstellt werden. • Typische Konfigurationselemente: Quelltext UseCases Architektur-/Designdokumente Schnittstellenverträge Testspezifikationen und Testdaten Build-Skripte Installationsanleitung, Benutzerdokumentation ... ► Festlegung der Projektstruktur • Ist gleichbedeutend mit der Hierarchie der Verzeichnisse im Projekt • Empfehlung: separaten Ast für jedes Konfigurationselement im Verzeichnisbaum • Verzeichnisse, die keine Konfigurationselemente enthalten, sollen nur temporäre Dateien enthalten, die neu generiert werden können Beispiel: enthält temporäre Dateien ► Verwaltung der Konfigurationselemente • Instanzen der Konfigurationselemente werden im Repository gespeichert ( ≈ spezialisierte Datenbank) • Aufbau eines Repository entspricht der Projektstruktur, aber ohne temporäre Ordner • Eine effektive Arbeit mit Werkzeugen ist nur möglich, wenn herstellerspezifische Formate im Repository verwaltet werden können. Repositories werden über eine Schnittstelle direkt in die Entwicklungswerkzeuge integriert. • Repositories setzen intern die Versionierung ein: - nach jeder Änderung an einer Datei wird eine neue Version im Repository gespeichert - nach und nach entsteht eine Versionshistorie, alle jemals vorgenommenen Änderungen werden dokumentiert (Löschen als Spezialfall einer Änderung) - der Prozess heisst Versionskontrolle - Versionen einer Datei werden vom Repository durchnummeriert • Deltabildung: - Werkzeuge ermitteln nur ein Delta zwischen zwei Versionen und legen ein Delta im Repository ab (zur Erinnerung: diff-Befehl!) - als „Anker“ dient eine komplette Dateiversion (erste oder letzte) - es wird zwischen Vorwärtsdeltas und Rückwärtsdeltas unterschieden - moderne Systeme wie Subversion beherrschen auch eine Deltabildung auf Byte-Ebene (alternativ werden Komplettversionen gespeichert, was sehr speicherintensiv ist) • Check-out / check-in: - im Projekt arbeitet man nicht mit Dateien im Repository, sondern mit Arbeitskopien in einem lokalen Arbeitsbereich (ebenfalls vom Versionsverwaltungssystem verwaltet) - Repository liefert auf Anforderung eine Arbeitskopie (Check-out), aktualisiert die Arbeitskopie bei Bedarf (Update) liest Änderungen in das Repository ein (Check-in, Commit) • Parallele Änderungen an Dateien: - das Repository kontrolliert, ob mehrere Teammitglieder parallel an derselben Datei arbeiten wollen oder gearbeitet haben - Überprüfung vor Änderung: Lock-Modify-Unlock Die Sperre erfolgt beim Check-out oder (wie bei Subversion) durch separaten Lock-Befehl Die Freigabe erfolgt beim Check-in oder durch separaten Unlock-Befehl - Überprüfung nach Änderung: Copy-Modify-Merge Beim Check-in überprüft das Repository, ob eine Datei zwischenzeitlich von einem anderen Nutzer verändert wurde. Wenn ja → Konflikt Der Nutzer entscheidet bei Konflikten, ob seine Änderungen mit der Version im Repository zusammenpassen. Wenn Ja → Merge + Check-in Merges funktionieren nur für zeilenbasierte Textdateien ! • Tags und Baselines: - „Schnappschüsse“: Versionsnummern schlecht zu merken - ein Tag markiert die zu einem Zeitpunkt gültige Version aller Dateien im Repository mit frei wählbarem Bezeichner Der Zustand des Repositories kann durch Angabe des Tags abgerufen werden. - eine Baseline (Bezugskonfiguration) bezeichnet einen hervorgehobenen Tag. (= freigegebenes Zwischenergebnis des Systems, es muss ein gesicherter Status vorliegen) Die Vorbereitungsphase einer Baseline wird mit einem Code Freeze begonnen. - als Release wird der Zustand des Systems bezeichnet, in dem es in den produktiven Einsatz geht. Anwender arbeiten mit einem Release. Für jedes Release wird eine Baseline erstellt. • Branches: - Projekte mit überschaubarem Zeitraum können lineare Entwicklungspfade haben. → Schwierige Ressourcenplanung bei größeren Projekten - größere Projekte sollten mit verzweigten oder parallelen Entwicklungspfaden (Branches) arbeiten. - Releases werden in einem separaten Relese-Branch vorbereitet, ein Teil des Teams arbeitet im Hauptentwicklungspfad (Trunk ) weiter. Relese-Branch und Trunk werden nach dem Release wieder zusammengeführt. Abbildung nach G. Popp ► Aufbau eines Build-Prozesses Automatisierung der Schritte zur Erstellung eines Produkts: 1. Quellelemente ermitteln 2. Produkt aus den Quellelementen erstellen → Aufrufe Compiler, Linker, Generatoren 3. Produkt prüfen → automatisierte Modultests (noch kein Integrationstest möglich) 4. Produkt ausliefern → Erstellen eines Auslieferungspakets (ear-/war-Dateien) 5. Ergebnisse dokumentieren → Schritte des Build in Log-Datei dokumentieren Unterscheidung: Entwickler-Build, Integrations-Build, Release-Build Umsetzung des Build-Prozesses: • Basis der Automatisierung bilden Skripte, die interpretativ verarbeitet werden (Ant, Maven) • Es werden Shell-Skripte zum Starten/Stoppen von Web- oder Applikationsservern verwendet (Nachteil: Plattformabhängigkeit) • Integrierte Umgebungen bieten Build & Run-Funktionalität: → Die Funktionalität ist komfortabel, aber kein Ersatz für Projektautomatisierung mit Skripten! Versionsverwaltungssysteme (KM-Werkzeuge) ► Versionsverwaltungssysteme stellen dem KM-Prozess ein Repository zur Verfügung ► ermöglichen die Aufzeichnung der Entwicklungsgeschichte von Programmdokumenten in Projekten und unterstützen die Gruppenarbeit (check-out – check-in). ► Das Concurrent Versions System (CVS) ist ein System, das das VersionsManagement auf der Ebene von Quellprogrammen unterstützt (Open Source). → → → keine Deltas auf der Ebene von Binaries! nur Dateien versionierbar, keine Verzeichnisse keine Unterstützung von Transaktionen ► Subversion (Open Source) ist ein seit 2004 verfügbares Nachfolgesystem zu CVS. Client-Server-Architektur von Subversion: Abbildung nach G. Popp Beispiel: Windows-Explorer als svn-Client (mit tortoisesvn) Eclipse mit subclipse als svn-Client ► Mercurial (Open Source) ist als Plug-in zu Eclipse verfügbar. ● Dezentrale Verwaltung eines Repositorys: → Das Repository liegt als Clone auf dem lokalen Rechner → Jedes Repository (.hg) verwaltet die gesamte Historie → Arbeitsverzeichnis enthält aktuelle Verzeichnisse/Dateien + .hg → Clone überträgt Repositorien komplett → Änderungen an Dateien werden zu Changeset zusammengefasst, ein Changeset wird bei Commit zu neuer Revision → Das Anpassen unterschiedlicher Repositorien erfolgt mittels Push/Pull und Merge ● Ein Topcased- oder Java-Projekt kann zusätzlich unter Mercurial gestellt werden. → HgEclipse Quelle: http://mercurial.selenic.com/wiki/GermanUnderstandingMercurial Wenn Alice jetzt ein Pull ausführt, sind beide Repositorien synchron. EclipseMercurial - Installation mittels Update-Manager Projekt unter Mercurial stellen: Projekt unter Mercurial gestellt: Im X-Verzeichnis wurde ein .hg angelegt (nicht sichtbar) Commit: erzeugt neues changeset Historie nach dem „Befüllen“: Ändern im Arbeitsverzeichnis + Historie: Neuer Branch: Ant http://ant.apache.org ► dient zur Umsetzung eines Build-Prozesses ► Nachfolger von make, Open Source ► als plattformunabhängiges Werkzeug konzipiert ► basiert als Werkzeug auf Java, benötigt zur Ausführung ein JDK ► Ant-Skripte werden als XML-Dateien geschrieben ► passt plattformspezifische Angaben im Skript an (z.B. Dateipfade) ► beherrscht inkrementelle Builds Architektur von Ant: Abbildung nach G. Popp Aufbau eines Ant-Build-Skriptes ● Oberstes Element beschreibt ein Projekt ● Es folgen Schritte in Form von Zielen (Targets) ● Name des auszuführenden Zieles wird Ant als Parameter übergeben ● Jedes Ziel besteht aus einer oder mehreren Funktionen (Tasks) ● Die Funktionen werden von Ant oder externen Bibliotheken bereitgestellt. ● Datentypen (Types) stellen Variablen dar, mit denen Ziele und Variablen parametrisiert werden ● Datentypen sind einfache Name – Wert – Paare … bis ... komplexe Typen Beispiel: Properties definieren ● Fest kodierte Werte vermeiden ● Konstanten in Form von Properties definieren ● Name – Wert – Paare, Werte können nicht mehr geändert werden ● Properties gelten global im gesamten Skript ● Es gibt sechs verschiedene Arten, Properties zu definieren, hier Beschränkung, z.B. <property file= «dateiname» /> ● Werte werden mittels ${ ... ● Es gibt vordefinierte Properties } zugegriffen lädt Properties aus Datei Vordefinierte Properties: ${basedir} Wert des basedir-Attributs aus project-Element ${ant.file} Pfad des Build-Skriptes ${ant.version} Version von Ant ${ant.project.name} Name des Projekts im project-Element ${ant.java.version} Version der JVM, die Ant ausführt Alle Java-System-Properties, z.B ${user.home} Init-Ziel aus dem Jamus-Build-Script: Die Auswahl von Dateien erfolgt über Filesets. Fielesets enthalten Patternsets und/oder Selektoren Ein Patternset-Element selektiert Dateien mittels Einschluss- oder Ausschlussbedingungen <patternset> <include name = «suchmuster» /> <exclude name = «suchmuster» /> </patternset> Kein javac, zuvor schon übersetzt ! Maven ► Produkt der Apache Software Foundation (Jakarta-Projekt) ► Werkzeug zur Durchführung des Build-Prozesses ► Modellbasierter deklarativer Ansatz: Metadaten des Projekts werden in einem Modell beschrieben → Projektmodell (POM), Datei pom.xml im Projektverzeichnis ► legt automatisch den Build-Prozess fest, trifft Annahmen über dessen Ablauf, nur auf oberster Stufe anstoßen (hoher Automatisierungsgrad!) ► Verwaltung der Abhängigkeiten zu externen Bibliotheken → Maven-Repositorien (keine Versionierung) ► unterstützt die Erstellung der Projektdokumentation Architektur von Maven: Abbildung nach G. Popp Benutzung von der Kommandozeile: ► Download zip-Archiv von http://maven.apache.org/download und in Verzeichnis entpacken ► Version Maven 3.0.3 ► Umgebungsvariable MAVEN_HOME definieren → Ref. auf Maven-Verzeichnis ► Umgebungsvariable PATH um $MAVEN_HOME/bin ergänzen ► Umgebungsvariable JAVA_HOME setzen ► Funktionsfähigkeit mit mvn -version prüfen Benutzung in Eclipse: ► Plug-in bereitstellen von http://m2eclipse.sonatype.org/sites/m2e Umsetzung eines Build-Prozesses mit Maven ► Erfassung des Projektmodells in pom.xml <!-- Projektmodell für MyProject --> <project> <!-- allgemeine Angaben zum Projekt --> <groupID> HTWD </groupID> <artifactID>myproject</artifactID> <packaging>jar</packaging> <name> MyProject</name> <url>http://xyz </url> <!-- Properties --> <!-- Anpassung des Standard- Build-Prozesses --> <!-- Einbindung externer Bibliotheken --> < dependencies> </dependencies> </project> ► Das POM enthält keine aufrufbaren Ziele ► Ein Maven Build-Prozess besteht aus einer Reihe von standardisierten Build-Phasen ► Namen der Phasen und Bedeutung → Build Lebenszyklus ► Die Abarbeitung der Pasen erfolgt immer von oben nach unten → meistens nur Teil der Phasen ausgeführt ► Den einzelnen Phasen müssen Build-Ziele zugeordnet werden (Lifecycle-Mapping) ► Ausgangspunkt ist der Artefakt aus <packaging>--Element ► Es gibt eine vollständige Referenz der Lifecycle-Mappings ► Aufruf des Compilers: mvn compile ► Maven führt alle übergeordneten Phasen des Lebenszyklus aus. → Process Resources → laden des Plug-ins maven-compiler-plugin und Ausführen des zugeordneten Build-Zieles compile ► Plug-ins werden im Maven-Repository verwaltet und von dort in den Build-Prozess eingebunden Zustandsbasiertes Testen mit Junit und JUnitDoclet Blackboxtest → Unit-Test → Klassentest → Spezifikationsbasierter (funktioale)r Test → Äquivalenzklassen-Bildung Testziel: Jede Operation (Methode) in jedem Zustand wenigstens einmal Ausführen. → Generalisierung von Zuständen notwendig r Integrationstest [ ] Javadoc – Generieren von Dokumentationen ► Homepage: http://www.oracle.com/technetwork/java/javase/ documentation/javadoc-137458.html ► Software-Dokumentationswerkzeug, kommt mit JDK (Kommandozeile) ► javadoc generiert aus Java-Quelltexten standardmäßig HTML-Dateien (API) ► erhält beim Aufruf Angaben über die zu dokumentierenden Quelltexte ► parst Quelltexte und erkennt Javadoc-Kommentare /** * * */ ► Javadoc-Kommentare können Javadoc-Tags enthalten /** * @author max moritz * @version 1.0 * */ ► mittels Taglets kann der Tag-Wortschatz von Javadoc erweitert werden ► ein Doclet erzeugt die Ausgabe, es existieren Doclets für die Ausgabe in HTML, RTF, XML, PDF, ... Tag & Parameter Ausgabe Verwendung in @author name beschreibt Autor Klasse, Interface @version version erzeugt einen Versionseintrag, max. 1 x pro Klasse/Interface Klasse, Interface @see reference erzeugt link auf anderes Element der Dokumentation Klasse, Interface, Instanzvariable, Methode @param name description Parameterbeschreibung Methode @return description Returnwert Methode @exception classname description Beschreibung einer Exception Methode @throws classname description Beschreibung einer Exception Methode @depricated description veraltete Methode Methode {@inheritDoc} Kopiert Beschreibung aus überschriebener Überschreibende Methode Methode {@link reference} Link zu einem anderen Symbol Klasse, Interface, Instanzvariable, Methode {@value … } Gibt den Wert eines konstanten Feldes zurück Statisches Feld {@code … } formatiert Text buchstabengetreu mit dem Quelltextzeichensatz entsprechend <code> Klasse, Interface, Instanzvariable, Methode … } unterdrückt die Interpretation von HTMLoder Javadoc-Tags Klasse, Interface, Instanzvariable, Methode {@literal Beispiel: Generieren der Dokumentation: javadoc [options] [packagenames] [sourcefiles] [@files] Beispiel: Zusätzlich: -version -author Erzeugte Dateien: Doclets ► sind in Java geschriebene Programme ► nutzen die Doclet-API (lib/tools.jar des SDK in den classpath aufnehmen, enthält Implementierungen der Doclet-API-Interfaces) http://docs.oracle.com/javase/1.4.2/docs/tooldocs/javadoc/doclet/index.html ► spezifizieren Inhalt und Format der Ausgaben des Javadoc-Tools (Standard: Generierung der API-Dokumentation in HTML ► Schritte, um ein eigenes Doclet zu erzeugen: - Java-Programm MyDoclet erstellen (Interfaces der Doclet-API bereitstellen: import com.sun.javadoc.*, Eintrittspunkt in MyDoclet ist eine Methode public static boolean start(RootDoc root) { … } ) - Doclet-Programm MyDoclet übersetzen mit javac - javadoc -doclet MyDoclet ... Beispiel: import com.sun.javadoc.*; public class ListClass { public static boolean start(RootDoc root) { ClassDoc[] classes = root.classes(); for (int i = 0; i < classes.length; ++i) { System.out.println(classes[i]); } return true; } } aus: http://download.oracle.com/javase/1.4.2/docs/tooldocs/javadoc/overview.html 8 Wiederverwendung und Evolution 8.1 Individuelle Komponenten: Module und Klassen 8.2 Komponentenbasierte Softwareentwicklung: Frameworks 8.3 Entwurfsmuster 8.1 Individuelle Komponenten: Module und Klassen ► Module repräsentieren Abstrakte Datenstrukturen (ADS) ► Klassen repräsentieren Abstrakte Datentypen (ADT) ► ADT erweitern ADS um Mittel zur Objekterzeugung (Objektfabriken) ► Module werden bei der Wiederverwendung leicht modifiziert ► Klassen können abgeleitet werden (Vererbung – keine Änderung des bestehenden Quelltextes) ► ► Objektbasierte ObjektbasierteSprachen Sprachen (z.B. (z.B.Java) Java) verbessern verbesserndas dasModulkonzept Modulkonzept (z.B. (z.B.MODULA MODULA2)2) ► W. individueller Komponenten ist nicht kostenlos (Ausfindigmachen, Schnittstellen verstehen, Wartung der Bibliotheken) ► Objekt-basierte Sprachen allein garantieren keine Verbesserung der W. Studie zu NASA-Projekten: 12 % Änderung verursachen 55 % der Kosten relativ zu Neuentwicklung Bibliotheken: 1) B. mit Top-down-Routinen bzw. Klassen Anwendungsarchitektur ... 2) Anwendungsprogramm Bibliotheksroutinen B. mit Routinen im Callback-Verfahren ... Anwendungsarchitektur Anwendungsprogramm Bibliotheksroutinen 8.2 Komponentenbasierte Softwareentwicklung: Frameworks Framework: Sammlung individueller Komponenten mit definiertem Kooperationsverhalten zur Lösung einer Aufgabe Whitebox-Framework: Anpassung durch Subklassenbildung + Compilation Blackbox-Framework: Anpassung zur Laufzeit durch unterschiedliche Instanziierung Whitebox-Framework Einschubmethode in der Klasse A, „abstract“ Der Programmierer muss die Implementation des Frameworks bis zu einem gewissen Grade kennen Blackbox-Framework Es existiert eine Anzahl fertiger Komponenten Änderungen durch Komposition der Komponenten (nicht durch Programmierung) Beispiel: Beispiel: Framework Frameworkvor vorund undnach nachder derSpezialisierung Spezialisierung Instanzen einsetzen ► ► Aus Auseinem einemWhitebox-Framework Whitebox-Frameworkentwickelt entwickeltsich sich mit mitzunehmendem zunehmendemReifegrad Reifegradein einBlackbox-Framework Blackbox-Framework ► ► Gängige GängigeFrameworks Frameworkssind sind weder wederreine reineWhiteboxWhitebox-noch nochreine reineBlackbox-Frameworks Blackbox-Frameworks Wie konstruiert man Frameworks ? → am Beispiel (nach Wolfgang Pree): - Framework „Diskrete Simulation“ entwerfen - Anwendung zur Simulation einer Kasse in einem Supermarkt - Anwendung zur Simulation eines Parkhauses Beispiel: Diskrete Simulation von Ereignissen ● ● ● Zentrale Elemente: Ereignisse mit zugeordneter Zeit (Beispiel Supermarkt: Eintreffen eines Kunden) Ereignisse werden durch Zufallsgenerator erzeugt Die Simulation entwickelt sich in Richtung der Zeitachse und sammelt statistische Informationen Actor: Paar Ereignis – Aktion Aktoren wissen, wie sie auf erhaltene Nachrichten zu reagieren haben. In time ist der Zeitpunkt des Ereignisses gespeichert commit() kapselt die Funktionalität des Actors. Die Simulation ruft commit() auf, wenn die Eintrittszeit des Ereignisses erreicht ist. simulate iteriert über actors - der aktuelle Zeitpunkt wird auf Zeitpunkt des Actors eingestellt - commit() des Actors wird aufgerufen Simulation endet, wenn Simulationszeit duration verbraucht ist. schedule fügt einen Actor entsprechend Eintrittszeitpunkt seines Ereignisses in SortedQueue ein. reset SortedQUeue wird gelöscht, Simulationszeit zurückgesetzt (time=0). ... ... Die DieKlasse Klasse Simulation Simulation realisiert realisierteine eineabstrakte abstrakteSimulation Simulation auf der Basis des Protokolls der Klasse Actor auf der Basis des Protokolls der Klasse Actor Beispiel: Whitebox-Framework → Blackbox-Framework Registrierkasse im Supermarkt (convenience store) Kunden Customer Kundengenerator CustomerGenerator Kasse SimpleServiceStation public class SimpleServiceStation { public class SimpleServiceStation { ... ... public void requestService(Customer c){ public void requestService(Customer c){ if (Warteschlange ist leer ) if (Warteschlange ist leer ) c.activate() c.activate() // Bediener verarbeitet die Kundenanfrage // Bediener verarbeitet die Kundenanfrage else else waitingLine.enqueue(c); waitingLine.enqueue(c); // Erstellen von Statistiken über die Warteschlange // Erstellen von Statistiken über die Warteschlange ... ... } } public void free(){ public void free(){ Actor actor; Actor actor; // Erstellen von Statistiken über die Warteschlange // Erstellen von Statistiken über die Warteschlange ... ... if (Warteschlange enthält Kunden ) if (Warteschlange enthält Kunden ) actor = waitingLine.dequeue(); actor = waitingLine.dequeue(); if (actor instanceof Customer) if (actor instanceof Customer) ((Customer)actor).activate(); ((Customer)actor).activate(); } } } } ... ... } } ... ... ... ... ... ... schedule public class ConvenienceStoreSim { public class ConvenienceStoreSim { ... ... public void simulate(int avrgServiceDuration, public void simulate(int avrgServiceDuration, int arrivalRate, int duration){ int arrivalRate, int duration){ SimpleServiceStation station; SimpleServiceStation station; Simulation simulation; Simulation simulation; CustomerGenerator generator; CustomerGenerator generator; simulation = new Simulation(); simulation = new Simulation(); station = new SimpleServiceStation(simulation, station = new SimpleServiceStation(simulation, arrivalRate, arrivalRate, AvrgServiceDuration, …) AvrgServiceDuration, …) generator = new generator = new CustomerGenerator(0,station,simulation); CustomerGenerator(0,station,simulation); simulation.schedule(generator,0); simulation.schedule(generator,0); // mit Erzeugung von Kunden beginnen // mit Erzeugung von Kunden beginnen simulation.simulate(duration); simulation.simulate(duration); } } } ... ... } station.provideStatistics(); station.provideStatistics(); Entwurfsüberlegungen ► Schwachstelle: enge Kopplung zwischen CustomerGenerator, Customer und SimpleServiceStation. → → ► Service-Station mit zwei Bedienern ? Ausfall eines Bedieners? Mittel, um Frameworks flexibler gestalten zu können → → → → Schablonenmethoden und Einschubmethoden Entkoppeln CustomerGenerator – Customer Flexibilität durch Komposition Skalierbarkeit von Einschubmethoden ► Platzierung von Einschubmethoden → Schablonenmethoden rufen Einschubmethoden auf. Schablonenmethode Einschubmethode Klasse MySimulation in der Anwendung DiskSim2 ► Entkopplung der Klassen CustomerGenerator und Customer → Das Verhalten kann durch die Definition von Unterklassen verändert werden. → CustomerGenerator wird durch ActorGenerator ersetzt Originalentwurf: Originalentwurf: public class CustomerGenerator extends Actor { public class CustomerGenerator extends Actor { ... ... public void commit(){ public void commit(){ Customer c= new Customer( … ); Customer c= new Customer( … ); station.requestService(c); station.requestService(c); ... ... } } ... ... } } Entwurf mit Einschubmethode: Entwurf mit Einschubmethode: public class ActorGenerator extends Actor { public class ActorGenerator extends Actor { ... ... public void commit(){ public void commit(){ Actor a= makeActor(); Actor a= makeActor(); station.requestService(a); station.requestService(a); ... ... } } public void makeActor(){ public void makeActor(){ Return new Customer( … ); Return new Customer( … ); } } ... ... } } ► Wenn Schablonen- und Einschubmethoden sich in einer Klasse befinden, kann Verhalten nur durch die Definition weiterer Unterklassen verändert werden. → Damit sind Anpassungen zur Laufzeit nicht möglich. Lösung: Flexibilität durch Komposition Einschubmethoden Einschubmethodenerlauben erlaubenflexible flexibleAnpassungen Anpassungenzur zurLaufzeit, Laufzeit, wenn ihre Klasse mit der Klasse abstrakt gekoppelt ist, wenn ihre Klasse mit der Klasse abstrakt gekoppelt ist, die diedie diezur zurEinschubmethode Einschubmethodegehörende gehörendeSchablonenmethode Schablonenmethodeenthält enthält Beispiel: Beispiel:Im ImOriginalansatz Originalansatzwurde wurdedie dieabstrakte abstrakteMethode Methode enqueue() der Klasse Queue in Unterklassen enqueue() der Klasse Queue in Unterklassenüberschrieben, überschrieben, die auf diese Weise verschiedene Warteschlangen die auf diese Weise verschiedene Warteschlangenrealisieren. realisieren. → Schablonenmethode enqueue() in Queue, → Schablonenmethode enqueue() in Queue, die dieAuswahl Auswahlwird wirdQPolicy-Objekt QPolicy-Objektübertragen übertragen → Beim Umschalten der QPolicy-Instanz muss explizit für Konsistenz gesorgt werden! Wird z.B. von FIFOQueue auf SortedQueue umgeschaltet, müssen Objekte entsprechend Zeitattribut neu geordnet werden, die ursprüngliche Ordnung muss gespeichert werden, um sie ggf. wieder herzustellen. Einfachste Art der Konsistenzhaltung: Schlange leer! ► Skalierbarkeit von Einschub-Methoden → was Schablonenmethode und was Einschub-Methode ist, ist relativ Schablonenmethode Einschubmethode commit() von ActorGenerator → makeActor() simulate() von Simulation → commit() → Im Idealfall nur elementarste Einschubmethoden überschreiben, um Verhalten der alles umfassenden Schablonenmethode zu beeinflussen Muster für Kombinationen von Einschubmethoden: H - Hook-Klasse = Klasse, die Einschubmethode enthält T - Template-Klasse = Klasse die Schablonenmethode enthält TH Vereinigungsmuster = Schablonenklasse u. Einschubklasse in einer Klasse vereinigt T–H Trennungsmuster = abstrakte Kopplung der Klassen → Das Verhalten von T-Objekten kann durch das Einsetzen unterschiedlicher H-Objekte geändert werden → Ein T-Objekt verweist auf ein H-Objekt (Nachrichtensenden ist notwendig) 8.3 Entwurfsmuster • Entwurfsmuster sind typischerweise in Anwendungen vorkommende Kombinationen von Klassen/Objekten zu größeren Einheiten • aus Erfahrungen abstrahiert • zur Nachnutzung bestimmt • unabhängig von der Programmiersprache • Gamma et al. haben einen Katalog von 23 Entwurfsmustern beschrieben. → ● Alphabetische Auflistung /Klassifikation Anwendungsbeispiel: MVC-Architektur → verstehen, welche Muster eingesetzt werden Grundlegende Elemente von Mustern • Muster-Name 1-2 Wörter, erweitert das Entwurfsvokabular Zweck. Zweck. • Problembeschreibung Problem und Anwendungskontext werden erklärt • Lösungsbeschreibung abstrakte Beschreibung eines Entwurfsproblems, kein konkreter Entwurf, keine konkrete Implementierung • Konsequenzen Kosten-Nutzen-Verhältnis von Mustern abwägen Auswirkungen auf Flexibilität, Erweiterbarkeit, Portabilität Erzeugungsmuster Strukturmuster Verhaltensmuster Fabrikmethode Adapter Interpreter Klassen-basiert Abstrakte Fabrik Brücke Schablonenmethode Instanzen-basiert Erbauer Kompositum Zuständigkeitskette Prototyp Dekorierer Kommando Singleton Fassade Iterator Fliegengewicht Vermittler Stellvertreter Memento Beobachter Zustand Strategie Besucher Beobachter (Observer) [ Verhaltensmuster, objektbasiert ] Definiere eine 1-zu-n-Abhängigkeit zwischen Objekten, so dass die Änderung Definiere eine 1-zu-n-Abhängigkeit zwischen Objekten, so dass die Änderung des Zustandes eines Objektes dazu führt, dass alle abhängigen Objekte des Zustandes eines Objektes dazu führt, dass alle abhängigen Objekte benachrichtigt und automatisch aktualisiert werden. benachrichtigt und automatisch aktualisiert werden. Beispiel: Zeitgeber - konkrete Subjektklasse - benachrichtigt Beobachter jede Sekunde public class Zeitgeber extends Subject { public class Zeitgeber extends Subject { int gibStunde(){ }; int gibStunde(){ }; int gibMinute(){ }; int gibMinute(){ }; int gibSekunde(){ }; int gibSekunde(){ }; void tick(){ void tick(){ // aktualisiert internen Zustand des Zeitgebers // aktualisiert internen Zustand des Zeitgebers benachrichtige(); benachrichtige(); } } } } public class Digitaluhr extends Beobachter { public class Digitaluhr extends Beobachter { Public void aktualisiere(){ Public void aktualisiere(){ // überschreibt Operation der Beobachterklasse // überschreibt Operation der Beobachterklasse } } } } - das Beobachter-Muster ermöglicht es, Beobachter und Subjekte unabhängig voneinander zu modifizieren - Subjekte und Beobachter können einzeln wiederverwendet werden - neue Beobachter können ohne Änderung des Subjekts hinzugefügt werden Kompositum (Composite) [ Strukturmuster, objektbasiert ] Füge Objekte zu Baumstrukturen zusammen, um Teil-Ganzes-Hierarchien zu Füge Objekte zu Baumstrukturen zusammen, um Teil-Ganzes-Hierarchien zu modellieren. Das Muster ermöglicht es Klienten, einzelne Objekte sowie modellieren. Das Muster ermöglicht es Klienten, einzelne Objekte sowie Kompositionen von Objekten einheitlich zu behandeln. Kompositionen von Objekten einheitlich zu behandeln. Implementierung: - explizite Referenzen auf Elternobjekte (um sich in der Hierarchie nach oben zu bewegen) - Blatt- und Kompositionsklassen vor Klienten verstecken Beispiel: Grafik-Objekte in Bibliotheken - alle Klienten verwenden nur die Schnittstelle von Component - der Klient wird einfacher, er kann zusammengesetzte und elementare Objekte gleich behandeln - es ist einfach, neue Arten von Komponenten einzufügen Proxy / Stellvertreter (Proxy) [ Strukturmuster, objektbasiert ] Kontrolliere den Zugriff auf ein Objekt mit Hilfe eines vorgelagerten StellvertreterKontrolliere den Zugriff auf ein Objekt mit Hilfe eines vorgelagerten StellvertreterObjekts. Objekts. create - der Proxy leitet Befehle an das echte Objekt weiter - ein Remote-Proxy verbirgt die Tatsache, dass sich ein Objekt in einem anderen Adressraum befindet - ein virtuelles Proxy dient der Optimierung - Schutz-Proxies ermöglichen die Durchführung zusätzlicher Verwaltungsaufgaben beim Zugriff auf das Objekt Fassade (Facade) [ Strukturmuster, objektbasiert ] Bietet eine einheitliche, einfache Schnittstelle zu einer Menge von Schnittstellen Bietet eine einheitliche, einfache Schnittstelle zu einer Menge von Schnittstellen bzw. Klassen (Paket). bzw. Klassen (Paket). Die Fassadenklasse definiert eine abstrakte Schnittstelle, um die Benutzung des Die Fassadenklasse definiert eine abstrakte Schnittstelle, um die Benutzung des Pakets zu vereinfachen. Pakets zu vereinfachen. Die Facade weiß, welche Klassen des Pakets für die Bearbeitung einer Botschaft zuständig sind und delegiert Botschaften an die zuständige Klasse. Keine neue Funktionalität! - die Klienten kommunizieren mit dem Paket, indem sie Botschaften an die Fassade schicken, welche diese dann an das zuständige Objekt innerhalb des Pakets weiterleitet - das Fassaden-Muster reduziert die Anzahl der Klassen, welche den Klienten bekannt sein müssen und vereinfacht die Benutzung des Systems - die lose Kopplung erleichtert es, Pakete auszutauschen und erleichtert deren unabhängige Implementierung - bei Bedarf können Klienten die Fassade umgehen und direkt auf Klassen des Pakets zugreifen. Adapter (Adapter, Wrapper) [ Strukturmuster, objektbasiert ] Passe die Schnittstelle einer Klasse an eine andere, von Kunden erwartete Passe die Schnittstelle einer Klasse an eine andere, von Kunden erwartete Schnittstelle an. Zur Anpassung eines Interfaces an ein anderes wird ein Schnittstelle an. Zur Anpassung eines Interfaces an ein anderes wird ein Adapterobjekt verwendet. Adapterobjekt verwendet. Delegation realize Beispiel: „Hüllenklassen“: Klasse Integer für Datentyp int usw. in Java Singleton (Singleton) [ Erzeugungsmuster, objektbasiert ] Sichere ab, dass eine Klasse genau ein Exemplar besitzt, und stelle einen globalen Sichere ab, dass eine Klasse genau ein Exemplar besitzt, und stelle einen globalen Zugriffspunkt darauf bereit. Zugriffspunkt darauf bereit. - Bei manchen Klassen ist es notwendig, dass es genau 1 Objekt gibt - Zugriff von mehreren anderen Objekten erforderlich Klassenvariable Klassenmethode public final class Singleton { public final class Singleton { private static Singleton uniqueInstance = null; private static Singleton uniqueInstance = null; } private Singleton(){ private Singleton(){ } } public static Singleton instance(){ public static Singleton instance(){ if (uniqueInstance == null) { if (uniqueInstance == null) { uniqueInstance = new Singleton(); uniqueInstance = new Singleton(); } } return uniqueInstance; return uniqueInstance; } } } - der Konstruktor ist private, nur mittels instance() können Objekte erzeugt werden - das Singleton-Muster ist eine Verbesserung gegenüber globalen Variablen - die Singleton-Klasse kann durch Unterklassen spezialisiert werden - Vorsicht vor „Singletonitis“ Fabrik-Methode (Factory Method) [ Erzeugungsmuster, klassenbasiert ] Definiere eine Klassenschnittstelle mit Operationen zum Erzeugen eines Definiere eine Klassenschnittstelle mit Operationen zum Erzeugen eines Objekts, aber lasse Unterklassen entscheiden, von welcher Klasse das zu Objekts, aber lasse Unterklassen entscheiden, von welcher Klasse das zu erzeugnde Objekt ist. erzeugnde Objekt ist. Das Muster wird auch als „virtueller Konstruktor“ bezeichnet. Das Muster wird auch als „virtueller Konstruktor“ bezeichnet. createProduct() ist abstrakt und heißt Fabrikmethode, sie ist für die Fabrikation von Objekten verantwortlich. Strategie (Strategy) [ Verhaltensmuster ] Definiere eine Familie von Algorithmen, kapsele jeden einzelnen und mache sie Definiere eine Familie von Algorithmen, kapsele jeden einzelnen und mache sie austauschbar. Das Strategie-Muster ermöglicht es, den Algorithmus unabhängig austauschbar. Das Strategie-Muster ermöglicht es, den Algorithmus unabhängig von ihn nutzenden Klienten zu variieren. von ihn nutzenden Klienten zu variieren. Schablonenmethode (Strategy) [ Verhaltensmuster, objektbasiert ] Definiere das Skelett eines Algorithmus in einer Operation und delegiere Definiere das Skelett eines Algorithmus in einer Operation und delegiere einzelne Schritte an Unterklassen. Die Verwendung einer Schablonenmethode einzelne Schritte an Unterklassen. Die Verwendung einer Schablonenmethode ermöglicht es Unterklassen, bestimmte Schritte eines Algorithmus zu überermöglicht es Unterklassen, bestimmte Schritte eines Algorithmus zu überschreiben, ohne seine Struktur zu verändern. schreiben, ohne seine Struktur zu verändern. Beispiel Schablonenmethode-Muster: - Schablonenmethoden bilden die grundlegende Technik zur Wiederverwendung von Code - sie realisieren das Prinzip „Don't call us, we'll call you“ 9 Musterarchitekturen 9.1 Die MVC-Architektur 9.2 Grafische Benutzeroberflächen 9.3 Client-Server-Systeme mittels http und Servlets 9.4 Datenbankanbindungen an Java-Applikationen Die Model-View-Controller-Architektur (MVC) View Model Controller • Modell-Objekt stellt das Anwendungsobjekt dar • View-Objekt stellt die Bildschirmrepräsentation dar • Controller-Objekt bestimmt die Reaktion auf Benutzereingaben → Veränderung des Modells Einsatz von Entwurfsmustern in der MVC-Architektur: • Beobachter-Muster zur Entkopplung von Modell-Objekt und View-Objekt • Strategie-Muster zur Realisierung unterschiedlicher Reaktionen auf Benutzereingaben ● Kompositum-Muster zur Realisierung der Views 9.2 Grafische Benutzeroberflächen ► Entwicklung: - Oberflächenprogrammierung - Grafikprogrammierung ► AWT Swing SWT - schwergewichtig, plattformunabhängig (portabel) - leichtgewichtig, plattformunabhängig - schwergewichtig, plattformabhängig ► Peers schaffen einheitliche Schnittstelle zwischen AWT und Plattform-API, sind in Java geschriebene Interfaces, Paket java.awt.peer ► Aufbau einer GUI in 2 Schritten: - Struktur erstellen - Aktionen implementieren, die über die GUI ausgelöst werden Darstellung aus Mittendorf, Singer,Strobel: Java Programmierhandbuch u. Referenz AWT (Abstract Window Toolkit) ► Alle Komponenten von abstrakter Klasse Component abgeleitet ► Container (abstrakt) können andere Komponenten enthalten ● ● wird nicht direkt instanziiert verwaltet einen Vektor von Komponenten Klasse Container ▶ Container werden nicht direkt instantiiert. ▶ Windows und Panel sind spezielle Container ▶ Window ohne Rahmen und Menüleiste ▶ Panel als Zeichenelement nutzen ▶ Frame ist Window mit Rahmen ( sicherheitsrelevant bei Applets!) ▶ Jeder Container verwaltet einen Layoutmanager zur Positionierung von Komponenten Auslösen von Aktionen (Event Handling) public class ConvenienceStoreSim extends Applet implements ActionListener{ ... Button quitButton; ... quitButton.addActionListener(this); ... public void actionPerformed(ActionEvent evt) { if(evt.getActionCommand().equals("Simulate")){ simulate((int)(serviceDurationPanel.getValue()), (int)(arrivalRatePanel.getValue()), (int)(durationPanel.getValue())); } if (evt.getActionCommand().equals("Quit")){ System.exit(0); window.dispose(); } } Swing = 100 % pure Java → Java Versionen existierender AWT-Komponenten + „higher level“-Komponenten (trees, tabbed panes, … ) Abb.: de.wikipedia.org/wiki/Swing_(Java) ▶ GUI-Komponenten mit „pluggable“ Look & Feel → Windows-, Sun Solaris-, Macintosh-, Java (Metal)-Oberfläche → kann zur Laufzeit geändert werden Beispiele: Motif-, Metal-, Ocean-, Synth-, Nimbus-L&F ▶ Swing-Komponenten sind „leichtgewichtig“ (bauen nicht auf User-Interface-Code auf, der BS-abhängig ist) ▶ Swing ist nicht thread-sicher (Wechselwirkungen zwischen Threads) ▶ Swing-Komponenten sind JavaBeans (nutzen Event Model) ▶ Packages javax.swing javax.accessibility ... ▶ Swing hat eigene Klassen für Event-Handling → MVC-Prinzip für jede JComponent Klassifizierung von Komponenten ► Jedes Programm, das ein Swing-GUI repräsentiert, enthält wenigstens 1 Toplevel-Swing-Container, d.i. eine Instanz von - JFrame oder - JDialog oder - JApplet ► Panels (Pane) sind Zwischencontainer → JPanel, JScrollPane, JTabbedPane ► Jeder Toplevel-Container enthält indirekt einen Zwischen-Container ContentPane. Dieser Container enthält direkt oder indirekt alle sichtbaren Komponenten (Ausnahme MenuBar). ► Atomare Komponenten: JComboBox, JTextField, JTable, ... MVC-Architektur für Komponenten ► Nutzer können steuern - wie Widgets aussehen, - wie sie auf Eingaben reagieren, - wie Daten repräsentiert werden ► View und Controller sind in einem Objekt vereinigt, das delegate heißt. delegates - stellen das Modell dar (View-Aspekt) - übertragen Nutzereingaben zum Modell (Controller-Aspekt) ► Eine JComponent hat - ein simple model - ein simple delegate ► Mögliche Models für eine spezielle JComponent sind Klassen, die ein für die Komponente spezifisches Model Interface implementieren. ► Mögliche Delegates für eine spezielle JComponent sind Klassen, die ein für die Komponente spezifisches Delegate Interface implementieren. Beispiel: Eine Klasse, die ein Model für JButton darstellt, muss Beispiel: Eine Klasse, die ein Model für JButton darstellt, muss das Interface ButtonModel implementieren. das Interface ButtonModel implementieren. Das Interface ButtonUI definiert das Delegate eines JButton. Das Interface ButtonUI definiert das Delegate eines JButton. ► Alle Delegates sind von ComponentUI abgeleitet. ► ComponentUI enthält Funktionalität, um zu definieren, wie eine Delegate-Klasse eine JComponent rendert. Primäre Methode: paint() ► Spezielle Subinterfaces von ComponentUI definieren die ControllerAspekte ► DefaultButtonModel ist das Default-Model von JButton ► BasicButtonUI ist das Default-Delegate für JButton. Andere Klassen sind WindowsButtonUI, MetalButtonUI, MacButtonUI und MotifButtonUI MVC-Architektur und GUI-Event Handling Beispiel: Eine Liste fungiert als Modell für zwei Views Motivation: Der Mittelwert kann nicht von der View-Liste berechnet werden. Problem: Falls View-Liste abgeschaltet wird, kann kein Mittelwert mehr berechnet werden - Die Views (avgField und textList) fungieren als ChangeListener zum Modell (implementieren ein ChangeListener-Interface). Sie benutzen eine Methode stateChanged. - Der Controller (textField) benutzt einen ActionListener, der dafür sorgt, dass die Daten im Modell geändert werden (Methode actionPerformed). - Problem: In der Methode stateChanged können keine Daten übergeben werden. - Lösung: Adapter vermitteln, sie besitzen erforderliche Informationen Swing-Beispiele: Beispiel: JTree In der Klasse Gui.Gui : zuvor muss Syntaxbaum aufgebaut sein ! Konstruktor der Klasse TTree : liefert DefaultMutableTreeNode SWT (Standard Widget Toolkit) ▶ Ursprung: - Rational Devision of IBM → Object Technology International, Inc. (OTI) - für Visual Age/Smalltalk Projekt → Portabilität - Java-basiert: IBM VisualAge/Micro Edition → Perfrmance-Probleme mit AWT/Swing - Neues Toolkit: Smaltalk-Code → Java Code OpenWidget Layer als Basis für SWT ▶ weiterentwickelt im Eclipse-Projekt, um Zugriff auf die „nativen“ User Interface-Unterstützungen des Betriebssystems zu erhalten ▶ Auch für Standalone-Java-Applikationen einsetzbar ▶ Komponente der Eclipse-Workbench → org.eclipse.swt.widgets u.a. ▶ Package org.eclipse.swt.custom speziell für Eclipse entwickelt → ohne neue native Routinen Beispiel: 1) HelloWorld-Programm mit SWT Beschaffen eines Quellprogramms http://my.safaribooksonline.com/book/web-development/widgets/0321256638/ 2) In Eclipse Java-Projekt kreieren Einstellungen, um das Programm auszuführen: Vorlesungsbsp > Kontextmenü > Properties Aus dem Verzeichnis 'plugins' Mit 'OK' bestätigen, die im Quelltexteditor gezeigten Fehler sollten verschwinden Vorlesungsbsp > Kontextmenü > Run As > Run Configurations Zur Vermeidung des Fehlers Das Fenster wird geöffnet: Einbettung von Swing-Komponenten in SWT: Problem: - Jamus (Testwerkzeug) basiert auf AWT/Swing - soll Eclipse-Nutzern als Werkzeug zur Verfügung gestellt werden - Eclipse basiert auf SWT, kann mit Swing nicht arbeiten - Integration von Jamus in Eclipse-IDE: → PDE-Projekt anlegen (Struktur schaffen) → Jamus-Perspektive schaffen → Integration von Views/Editoren in IDE → Integration Menüs → Frames bleiben Frames ► Über die Eclipse-Homepage ist ein Package swingintegration.example_0.0.2.jar erreichbar. Adresse: http://www.eclipse.org/articles/Article-Swing-SWTIntegration/files/swingintegration.example_0.0.2.jar ► Alle Klassen des Packages wurden in die eigene Anwendung in das Paket de.htw.dresden.jamus.embeddedSwing übernommen und individuell angepasst. ► Die Klasse EmbeddedSwingComposite ist die Basis für die Einbettung von AWT/Swing-Komponenten. neu ermöglicht die Integration von AWT/Swing Jamus-Perspektive schaffen Ausschnitt aus plugin.xml → Die Perspektive wird der Workbench über den Extension Point org.eclipse.ui.perspectives bekannt gegeben → Die Klasse Perspective muss org.eclipse.ui.IPerspectiveFactory implementieren → mit der Methode createInitialLayout können der Perspektive Ansichten (z.B. Projekt-Explorer, Editor) hinzugefügt und das Layout konfiguriert werden. Jamus-Menü Jamus-Perspektive Verwenden eines Templates für Einbettung der Swing-Komponenten: Erläuterung zum Programmtext: - EmbeddedSwingComponent ist eine abstrakte Klasse, die Methode createSwingComponent ist abstrakt. - es wird eine lokale, anonyme Klasse gebildet, die von EmbeddedSwingComposite abgeleitet ist - in der lokalen Klasse wird die Methode createSwingComponent() überschrieben - die innere Klasse kann auf Attribute und Methoden der umgebenden Klasse zugreifen - in der umgebenden Klasse wird keine Instanz der inneren Klasse benötigt → Eine Instanz der Klasse EmbeddedSwingComposite wird erzeugt (Singleton-Muster!) → der erste Parameter muss vom Typ org.eclipse.swt.Composite sein → Composite gruppiert grafische Elemente in einem Container → Swing-Komponenten können in einem Composite-Container eingebettet werden → die Swing-Komponente muss von javax.Swing.JComponent abgeleitet sein → mittels Integrationstechnik werden realisiert: JProjectTree - Darstellung Projekt-Explorer DocumentTextEditor - Anzeigen Quelltext im Editor Gui - Darstellung des openFile-Dialogs Einbetten des Projekt-Explorers (TreeViewpart - View-Reiter): Einbetten des Quelltext-Editors (EditorViewpart): Einbetten des OpenFile-Dialogs: showDialog wird von openFileOpenDialog und openProjectOpenDialog aufgerufen Pulldown-Menü → die Klasse Gui.Gui wird als Command in Eclipse realisiert → das Element commandParameter dient zur Unterscheidung der Menüeinträge → das Jamus-Menü-Command wird abhängig von der Jamus-Perspektive eingeblendet → das Verhalten von Commands wird durch Handler definiert → Über en Extension Point org.eclipse.ui.handlers kann zu einem Command eine Handlerklasse registriert werden → das Pulldown-Menü kann über den Extension Point org.eclipse.ui.handlers registriert werden. → Hinzufügen von Commands/Untermenüs → Menüaktionen werden in der Methode execute der Handlerklasse Gui imlementiert Frames bleiben Frames Technologie (1) Projekt → → → → → Plug-in-Development-Projekt erzeugen Kopieren der (alten) Jamus-Dateien in das Projekt Abhängigkeiten prüfen Quellprogramme anpassen Testen mit: „Launch an Eclipse Application“ (2) Projekt → → → → etc. installieren: Projekt exportieren (jar-File) Projekt installieren (Help‐> Install New Software) (3) Projekt → entwickeln: nutzen (Eclipse mit Jamus-Plug-In): Erstellen/Öffnen eines Jamus-Projektes Bereistellen/Editieren eines Quelltextes Parsen, Instrumentieren, Darstellen des gerichteten Graphen JFace ► JFace ist ein „higher level” UI-Toolkit, in Eclipse bereitgestellt ► aus den von SWT zur Verfügung gestellten Basiskomponenten werden komplexere Widgets zusammengesetzt Es wird eine Abstraktionsschicht für den Zugriff auf die Komponenten bereitgestellt. ► JFace besitzt Abhängigkeiten zu einigen Eclipse-Bibliotheken ► stellt Viewer ListViewer, TableViewer, TreeViewer etc. bereit ► die Viewer besitzen Adapter-Interfaces 9.3 Client-Server-Systeme mittels http und Servlets ► Servlets sind spezielle Java-Klassen ► Verteilte Anwendungen: ► Servlets benötigen spezielle Laufzeitumgebung: → Servlet-Runner, Web-Container (analog „Sandbox“ für Applets) ► Servlets unterliegen Lebenszyklus ► Servlets zur dynamischen Erzeugung von Web-Inhalten ► Beschränkung auf Web-Anwendungen: → Apache Web-Server + Tomcat als Web-Container Client-seitig: Applets Server-seitig: Servlets Der Servlet-Lebenszyklus ● Laden und Initialisieren durch Laufzeitumgebung (Container) ● Zyklisch: ● Servlet entfernen - Daten empfangen (Request) - verarbeiten - Daten zurückliefern (Response) Servlet-Programmierung ► API: Package javax.servlet http://download.oracle.com/javaee/6/api/javax/servlet/package-summary.html http://download.oracle.com/javaee/6/api/javax/servlet/http/package-summary.html ► Implementierung der Schnittstelle javax.servlet.Servlet ► Nutzung des http-Protokolls: Servlet als Spezialisierung der Klasse javax.servlet.http.HttpServlet + Überschreiben der Methoden zur Behandlung von http-Interaktionen ► alle Methoden erwarten 2 Parameter: HttpServletRequest (Daten vom Client) HttpServletResponse (Daten an Client) ► Die Behandlung von Client-Requests erfolgt mit Methode service des Servlets. Die Methode service leitet Requests an eine in der Servlet-Klasse überdefinierte Methode doXXX weiter. ► Methoden zur Behandlung von Requests: • doGet - Behandlung von GET-Requests, HEAD-Requests • doPost - Behandlung von POST-Requests • doPut - Behandlung von PUT-Requests • doDelete - Behandlung von DELETE-Requests ► HTTP-Request • für alle HTTP-Methoden: getParameterValues liefert den Wert eines Parameters getParameterNames liefert die Namen der Parameter • speziell für GET (HTTP): getQueryString liefert einen String, der ggf. zu parsen ist. • für POST, PUT, DELETE: getReader liefert einen BufferedReader, der zum Lesen von Text-Daten verwendet werden kann, getInputStream liefert einen ServletInputStream, der zum Lesen von binär-Daten verwendet werdeen kann. ► HTTP-Response Für die Rückgabe von Antworten bietet ein HttpServletResponse-Objekt folgende Möglichkeiten: • getWriter liefert einen Writer für die Ausgabe von Textdaten • getOutputStream liefert einen Output Stream für die Ausgabe von Binaries ► Servlet-Metadaten Metadaten über ein Servlet werden in einer XML-Datei web.xml gespeichert (sog. Deployment-Deskriptor) Beispiel Das in der Server2Go-Applikation verwendete Servlet MyServlet Die Ausgabe am Browser: hier vordefinierte Beispiele auswählen Beispiel Servlet-Anwendung RequestInfoExample In: htdocs\webapps\examples\Web-INF\classes\ RequestInfoExample RequestInfoExample /Users/fritzsch/workstation/SE/Demos-Beispiele/ServletExamples/classes/RequestInfoExample.java Beispiel Servlet-Anwendung RequestHeaderExample In: htdocs\webapps\examples\Web-INF\classes\ RequestHeaderExample RequestHeaderExample /Users/fritzsch/Downloads/server2go/htdocs/webapps/examples/WEB-INF/classes/RequestHeaderExample.java Beispiel Servlet-Anwendung RequestParamExample In: htdocs\webapps\examples\Web-INF\classes\ RequestParamExample RequestParamExample /Users/fritzsch/Downloads/server2go/htdocs/webapps/examples/WEB-INF/classes/RequestParamExample.java <form <form action="RequestParamExample" action="RequestParamExample" method=POST> method=POST> First First Name: Name: <input <input type=text type=text size=20 size=20 name=firstname> name=firstname> <br> <br> Last Last Name: Name: <input <input type=text type=text size=20 size=20 name=lastname> name=lastname> <br> <br> <input <input type=submit> type=submit> </form> </form> web.xml /Users/fritzsch/Downloads/server2go/htdocs/webapps/examples/WEB-INF/web.xml /Users/fritzsch/workstation/SE/Demos-Beispiele/ServletExamples/classes/RequestParamExample.java /Users/fritzsch/Downloads/server2go/htdocs/webapps/examples/WEB-INF/classes/RequestParamExample.java Aufrufe von Servlets: ● über die URL des Browsers ● mittels eines Formulars ● mittels eines Applets Im Applet – in init bzw. start: URL url = new URL(...); URLConnection connection = url.openConnection(); OutputStream out = connection.getOutputStream; PrintStream pout = new Printstream(out); InputStream in = connection.getInputStream(); 9.4 Datenbankanbindungen an Java-Applikationen ► Ein Java-Client-Programm, das auf eine Datenbank zugreifen soll, enthält folgende Funktionen: 1. Laden eines JDBC-Treibers 2. Öffnen einer Datenbank (Verbindung aufbauen) 3. Senden von SQL-Anweisungen an die Datenbank 4. Auslesen und Bearbeiten der Ergebnisse ► Die Schritte 1. und 2. sind einmal in einer Anwendung auszuführen, die Schritte 3 und 4 werden wiederholt ausgeführt. ► Voraussetzungen 1. Installieren eines JDK → Bereitstellen JDBC API (Java DataBase Connectivity) DB-Zugriff unabhängig vom verwendeten DBMS Setzen der Umgebungsvariablen JAVA_HOME 2. Installation eines Treibers auf der Maschine → siehe Anleitung Server2Go 3. Installation eines DBMS → MySQL kommt mit dem Server2Go → MS ACCESS im Beispiel Biolexikon 4. Vorbereitung einer Datenbank → mittels phpMyAdmin erstellen Items – für MyServlet-Beispiel biolexikon – für Biolexikon ► JDBC-Treiber laden u. DB-Verbindung aufbauen: 1) Bereitstellen eines Treibers (für MySQL) zur Laufzeit: Class.forName("com.mysql.jdbc.Driver").newInstance(); Class.forName("com.mysql.jdbc.Driver").newInstance(); 2) DB-Verbindung aufbauen: Connection Connection con con == DriverManager.getConnection(a,b,c) DriverManager.getConnection(a,b,c) a: url-String der Form jdbc : subprotocol : subname String String url url == "jdbc:mysql://localhost:7188/server2go"; "jdbc:mysql://localhost:7188/server2go"; b: Benutzername als String c: Passwort als String Festlegung des Treiber-Herstellers ► SQL-Anweisung an die DB senden: 1) Erzeugen eines Statement-Objektes, um SQL-Statements an die Datenbank zu senden: Statement stmt = con.createStatement(); Statement Statement stmt stmt == con.createStatement(); con.createStatement(); 2) Übermitteln des SFW-Blockes: String String query query == "SELECT "SELECT *" *" ++ "FROM String query = "SELECT *" + "FROM items"; items"; ResultSet stmt.executeQuery(query); items"; ResultSet rs rs =="FROM stmt.executeQuery(query); ResultSet rs = stmt.executeQuery(query); 3) Automatische Übermittlung des Statements an das DBMS mittels JDBC-Treiber. ► Auslesen und Bearbeiten der Ergebnisse: ● ● ● ● SFW-Anweisung liefert Tabelle als Instanz von ResultSet Methoden von ResultSet dienen dem Durchlaufen der Tabelle und dem Zugriff auf Ergebnisse: Zeilenweise von links nach rechts. Ausgabe der Tabelle als HTML-Datei Vorteil: Web-Browser kümmert sich um die Formatierung Auflistung der Spaltennamen: dynamisch ermitteln ResultSetMetaData rsmd == rs.getMetadata(); ResultSetMetaData rsmd = rs.getMetadata(); ResultSetMetaData rsmd rs.getMetadata(); int colums = rsmd.getColumnCount(); int colums = rsmd.getColumnCount(); int colums = rsmd.getColumnCount(); for (int i=1;i<=colums;i++) for (int fori=1;i<=colums;i++) (int i=1;i<=colums;i++) System.out.println("<TH>" System.out.println("<TH>" ++ ● ++ System.out.println("<TH>"rsmd.getColumnName(i) + rsmd.getColumnName(i) "</TH>"); rsmd.getColumnName(i) + "</TH>"); "</TH>"); → Das Feld ist 1-basiert! ● Ausgabe des Tabelleninhaltes: while (rs.next()) while (rs.next()) { {{ while (rs.next()) System.out.println("<TR>");; System.out.println("<TR>");; System.out.println("<TR>");; for (int for (int fori=1;i<=colums;i++) (int i=1;i<=colums;i++) i=1;i<=colums;i++) System.out.println("<TD>" ++ System.out.println("<TD>" + System.out.println("<TD>" rs.getObject(i) ++ rs.getObject(i) + rs.getObject(i) "</TD>"); "</TD>"); "</TD>"); System.out.println("</TR>");; System.out.println("</TR>");; System.out.println("</TR>");; }} } ● Schließen geöffneter Objekte: Ressourcenfreigabe rs.close(); rs.close(); rs.close(); stmt.close(); stmt.close(); stmt.close(); con.close(); con.close(); con.close(); rs.next() positioniert zum nächsten Datensatz muss bereits vor dem Lesen des ersten Datensatzes aufgerufen werden Die innere Schleife generiert die <TD>-Elemente rs.getObject(int columnindex) liefert den Wert der durch den Parameter bestimmten Spalte der aktuellen Zeile als String. Der Wert ist immer von der Klasse Object, unabhängig vom Datentyp des Attributs in der DB-Tabelle. Die Ausgabemethode konvertiert den Wert in String. Falls der Datentyp der Elemente bekannt ist, können auch die Zugriffsmethoden getInt() getString() usw. verwendet werden. zeilenweise Ausgabe rs.getString(int columnIndex) rs.getString(String columnLabel) liefert den Wert der durch den Parameter bestimmten Spalte in der aktuellen Zeile als String zurück Beispiel 1. Erstellen der Datenbank Änderungen in der DB persistent machen: → Anleitung von Herrn Roeper 2. JDBC-Treiber bereitstellen Datei: mysql-connector-java-5.1.15.zip Quelle: http://www.mysql.com/downloads/connector/j mysql-connector-java-5.1.15.zip → entpacken mysql-connector-java-5.1.15-bin.jar nach webapps/mywebapp/WEB-INF/lib speichern 9.5 Analysieren der Applikation BioLex (Historisches biografisches Lexikon) → Architektur / HTML-Seite: ClientF.html → Applet: DBApplet.java → Kommunikation mit Servlet: ServletCom.java → Kommunikation mit Applet: COMApplet.java → Servlet: DBServlet.java → Kommunikation mit DB: DBConnect.java http://www2.htw-dresden.de/~fritzsch/ISGV/BioLex/ClientApplet/ClientF.html