Grundlagen der Komponentenbasierten Softwareentwicklung Prof. Dr. Stephan Kleuker Hochschule Osnabrück Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker 1 Ich • Prof. Dr. Stephan Kleuker, geboren 1967, verheiratet, 2 Kinder • seit 1.9.09 an der FH, Professur für Software-Entwicklung • vorher 4 Jahre FH Wiesbaden • davor 3 Jahre an der privaten FH Nordakademie in Elmshorn • davor 4 ½ Jahre tätig als Systemanalytiker und Systemberater in Wilhelmshaven • [email protected], Raum SI 0109 Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker 2 Ablauf • 2h Vorlesung + 2h Praktikum = 5 CP • Praktikum: – 11-12 Übungsblätter mit jeweils 8-10 Punkten ( 100) – Praktikum mit 80 oder mehr Punkten bestanden – Aufgaben in Dreier-Gruppen • Prüfung: Projektaufgabe (Kenntnisse aus der Vorlesung anwenden + eigene Untersuchungen, 3 Studis) • Folienveranstaltungen sind schnell, bremsen Sie mit Fragen • Foliensammlung größer als besprochene Folien • von Studierenden wird hoher Anteil an Eigenarbeit erwartet Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker 3 Verhaltenscodex • • • • Rechner sind zu Beginn der Veranstaltung aus Handys sind aus Wir sind pünktlich Es redet nur eine Person zur Zeit • Sie haben die Folien zur Kommentierung in der Vorlesung vorliegen (Ihre Aufgabe), Folien zweite Tage vor VL abends mit Aufgaben im Netz http://www.edvsz.hs-osnabrueck.de/kleuker/index.html • Probleme sofort melden • Wer aussteigt, teilt mit, warum Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker 4 Minimale Grundvoraussetzungen • Gute Programmierkenntnisse in Java (z. B. Polymorphie) • Gute Kenntnisse in objektorientiertem Design (z. B. einfache Pattern, wie Observer-Observable bzw. Model-ViewController) • Ordentliche Kenntnisse in der Datenbankmodellierung (ERModelle und deren Übersetzung in Tabellen) • Ordentliche Kenntnisse des Transaktionsbegriffs • Ordentliche Kenntnisse der Problematiken verteilter Systeme (z. B. Deadlock, Livelock) • Grundkenntnisse HTML/HTTP, JavaScript • Grundkenntnisse verteilte Systeme Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker 5 Konzept der Lehrveranstaltung • Zentrale, sich immer wiederholende, Ideen des Komponentenansatzes verstehen • Zentrales Beispiel: Teile der Java Enterprise Edition (JEE) Technologien; ein zentraler Jobmotor im Enterprise-/WebBereich • Ergänzung um Darstellungs- und Verknüpfungsschichten (z. B. JavaServer Faces (JSF)) • Vorlesung: Vermittlung grundlegender Konzepte (20% mit denen 80% erledigt werden) • Praktikum: konkrete Umsetzung der Vorlesungsinhalte; Selbststudium weiterer Teilbereiche Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker 6 Komponenten und SW-Architektur View View-Repräsentation JavaFX JSF POJO Scoped Beans Fachlogik Controller Zugriffskoordination Validierung Zugriff Fachklassen EJB JPA DB Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker 7 Themengebiete (Planung) 0 Grundlagen 1 Historie und Ziele der Softwareentwicklung 2 Reflexion und Annotationen 3 Komponentenbeispiel: JavaFX 4 Bean Validation 5 Java Persistence API (JPA) 6 JavaServer Faces (JSF) / JEE / EJB /CDI 7 Contexts and Dependcy Injection 8 (RESTful) Web Services 9 WebSockets Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker 8 Literatur • DAS Buch gibt es nicht, aber viele passende Bücher / Internetquellen für Teilthemen • Sun, The Java EE 7 Tutorial https://docs.oracle.com/javaee/7/tutorial/ • Martin Marinschek, Michael Kurz, Gerald Müllan, JavaServer Faces 2.0, 2. Auflage , dpunkt.verlag , 2010 • Ed Burns, Chris Schalk, JavaServer Faces 2.0, The Complete Reference, Mc Graw Hill, 2010 • Marcus Schießer, Martin Schmollinger, Workshop Java EE7, dpunkt.verlag , 2013 • Antonio Goncalves, Beginning Java EE 7, Apress, NY, USA, 2013 • Weitere: wird konkret zum jeweiligen Kapitel angegeben Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker 9 0. Grundlagen • XML-Erinnerung • Datenbanken – ER-Modellierung – Tabellenableitung – SQL – JDBC – Transaktionen • Functional Interfaces, Lambda-Ausdrücke • Design-Pattern Observer-Observable, MQTT • Testen • Reflexion • Annotationen Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker 10 Erinnerung: XML (1/2) • eXtensible Markup Language • strukturierte maschinen- und ansatzweise menschenlesbare Informationsbeschreibung • Processing Instruction am Anfang (evtl. mit encoding-Info) <?xml version="1.0"?> • Aufbau eines Elements mit Start- und End-Tags als Klammer <Elementname> Inhalt </Elementname> • Inhalt kann wieder aus Elementen bestehen, es ergibt sich Baumstruktur • Elemente können Attribute enthalten <Elementname att1="bla" att2="blubb" > Inhalt </Elementname> Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker 11 Erinnerung: XML (2/2) • Elemente, die maximal Attribute, aber keinen Inhalt haben, können verkürzt geschrieben werden <Elementname att1="bla" att2="blubb" /> • Kommentar <!-- Isch bin ähn Gommenta --> • weitere Möglichkeiten, wie Querverweise • Neben reiner Syntax kann auch die erlaubte inhaltliche Struktur spezifiziert werden (DTD: Document Type Definition), XML-Schema • Viele spannende Werkzeuge zur XML-Verarbeitung Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker 12 Erinnerung: Relationale Datenbanken • Relationen (Tabellen) beschreiben einfache Entitäten (Stammdaten) • Relationen beschreiben Verknüpfungen zwischen Entitäten (-> Fremdschlüssel) • • • • • Modellierung mit ER-Diagramm Einfache Übersetzung in Tabellen Effizienter Zugriff mit SQL ACID-Transaktionen Zugriff von Java mit JDBC • Wir nutzen JavaDB (Apache Derby) http://www.oracle.com/technetwork/java/javadb/overview /index.html Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker 13 Studenten besuchen Vorlesungen (1/5) Student Hoert Vorlesung matnr name semester matnr modulnr modulnr titel 42 Ute WiSe09 42 6942 6942 OOAD 3 43 Uwe WiSe09 42 6943 6943 DB 2 44 Urs SoSe10 43 6942 6944 Java 1 Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker semester 14 Studenten besuchen Vorlesungen (2/5) CREATE TABLE Student( matnr INTEGER, name VARCHAR(16), semester VARCHAR(6), CONSTRAINT PK_Student PRIMARY KEY(matnr) ); INSERT INTO Student VALUES(42,'Ute','WiSe09'); INSERT INTO Student VALUES(43,'Uwe','WiSe09'); INSERT INTO Student VALUES(44,'Urs','SoSe10'); Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker 15 Studenten besuchen Vorlesungen (3/5) CREATE TABLE Vorlesung( modulnr INTEGER, titel VARCHAR(10), semester INTEGER, CONSTRAINT PK_Vorlesung PRIMARY KEY(modulNr) ); INSERT INTO VORLESUNG VALUES(6942,'OOAD',3); INSERT INTO VORLESUNG VALUES(6943,'DB',2); INSERT INTO VORLESUNG VALUES(6944,'Java',1); Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker 16 Studenten besuchen Vorlesungen (4/5) CREATE TABLE Hoert( Matnr INTEGER, Modulnr INTEGER, CONSTRAINT PK_Hoert PRIMARY KEY (MatNr,Modulnr), CONSTRAINT FK_Hoert1 FOREIGN KEY (Matnr) REFERENCES Student(Matnr), CONSTRAINT FK_Hoert2 FOREIGN KEY (Modulnr) REFERENCES Vorlesung(Modulnr) ); INSERT INTO Hoert VALUES(42,6942); INSERT INTO Hoert VALUES(42,6943); INSERT INTO Hoert VALUES(43,6943); Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker 17 Studenten besuchen Vorlesungen (5/5) public static void main(String[] s) throws Exception { Class.forName("org.apache.derby.jdbc.ClientDriver").newInstance(); try (Connection con = DriverManager .getConnection("jdbc:derby://localhost:1527/Hochschule", "kleuker", "kleuker")) { Statement stmt = con.createStatement(); ResultSet rs = stmt.executeQuery("SELECT * FROM Student"); while (rs.next()) { System.out.print(rs.getInt(1) + ": " + rs.getString(2) + " Start:"); System.out.println(rs.getString(3)); } 42: Ute Start:WiSe09 } 43: Uwe Start:WiSe09 } 44: Urs Start:SoSe10 • Benötigt derbyclient.jar als JDBC-Treiber (im Installationsverzeichnis von JavaDB unter /lib) • Connection realisiert ab Java 7 Interface AutoCloseable Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker 18 AutoCloseable - Beispiel bis Java 6 ab Java 7 Connection con =…; try { … } catch (XYExcep e){ … } catch (YZExcep e){ … } finally { … con.close() } try (Connection con =…) { … } catch (XYExcep | YZExcep e){ … } finally { … } • con muss außerhalb des tryBlocks deklariert werden • gerne vergessen (schleichender Fehler) Komponentenbasierte SoftwareEntwicklung • con wird garantiert geschlossen (mehrere Zuweisungen mit „;“ möglich) • finally optional • nicht sinnvoll, wenn Verbindung länger genutzt Prof. Dr. Stephan Kleuker 19 Erinnerung: ACID-Transaktionen Atomicity Transaktionen werden entweder ganz oder gar nicht ausgeführt (Atomarität) Consistency (Konsistenz) Isolation Nebenläufige (gleichzeitige) Transaktionen laufen jede für sich so ab, als ob sie alleine ablaufen würden (Isolation) Durability (Dauerhaftigkeit) Transaktionen überführen die Datenbank von einem konsistenten Zustand in einen anderen konsistenten Zustand Die Wirkung einer abgeschlossenen Transaktion bleibt (auch nach einem Systemausfall) erhalten Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker 20 Transaktionen Zustände einer Transaktion Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker 21 Java 8 – Functional Interfaces (1/3) @FunctionalInterface // bel. Interface mit genau einer Methode public interface Ausgabe { public void ausgeben(String s); } public class AusgabeNutzer { private Ausgabe ausgabe; public AusgabeNutzer(Ausgabe a){ this.ausgabe = a; } public void nutzen(String s){ this.ausgabe.ausgeben("Nutzer: " +s); } } public class AusgabeImpl implements Ausgabe { @Override public void ausgeben(String s) { System.out.println("Impl: " + s); } Komponentenbasierte SoftwareProf. Dr. } Entwicklung Stephan Kleuker 22 Java 8 – Functional Interfaces (2/3) public class Main { public static void main(String[] args) { Ausgabe impl = new AusgabeImpl(); // klassisch AusgabeNutzer an1 = new AusgabeNutzer(impl); String text = "Text"; an1.nutzen(text); // Impl: Nutzer: Text AusgabeNutzer an2 = new AusgabeNutzer( new Ausgabe(){ // klassisch anonym @Override public void ausgeben(String s) { System.out.println("Ano: "+s); } } ); an2.nutzen(text); // Ano: Nutzer: Text Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker 23 Java 8 – Functional Interfaces (3/3) AusgabeNutzer an3 = new AusgabeNutzer( s -> System.out.println("Lambda: "+s) ); an3.nutzen(text); // Lambda: Nutzer: Text AusgabeNutzer an4 = new AusgabeNutzer( System.out::println ); an4.nutzen(text); // Nutzer: Text } } Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker 24 Einschub: Testen mit JUnit • Framework, um den Unit-Test eines Java-Programms zu automatisieren • einfacher Aufbau • leicht erlernbar • geht auf SUnit (Smalltalk) zurück • mittlerweile für viele Sprachen verfügbar (NUnit, CPPUnit) Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker 25 Testfall • Vor dem Testen müssen Testfälle spezifiziert werden • Vorbedingungen – Zu testende Software in klar definierte Ausgangslage bringen (z. B. Objekte mit zu testenden Methoden erzeugen) – Angeschlossene Systeme in definierten Zustand bringen – Weitere Rahmenbedingungen sichern (z. B. HW) • Ausführung – Was muss wann gemacht werden (einfachster Fall: Methodenaufruf) • Nachbedingungen – Welche Ergebnisse sollen vorliegen (einfachster Fall: Rückgabewerte) – Zustände anderer Objekte / angeschlossener Systeme Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker 26 Aufbau einer Testklasse (1/8) import import import import import import junit.framework.Assert; org.junit.After; org.junit.AfterClass; org.junit.Before; org.junit.BeforeClass; org.junit.Test; public class AnschauungTest { private int wert; private static int klasse; Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker Beliebiger Klassenname, Endung „Test“ üblich Nutzung von normalen Exemplarvariablen Klassenvariablen, außer als Konstanten, unüblich (und meist sinnlos) 27 Aufbau einer Testklasse (2/8) Verhaltensbeschreibung mit Annotationen Methode wird einmal vor vor allen Tests ausgeführt, z.B. Aufbau DB-Verbindung @BeforeClass public static void setUpBeforeClass() throws Exception { System.out.println("setUpBeforeClass"); klasse = 99; } einmal nach allen Tests (aufräumen) @AfterClass public static void tearDownAfterClass() throws Exception { System.out.println("tearDownAfterClass"); } Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker 28 Aufbau einer Testklasse (3/8) Methode wird vor jedem Test ausgeführt, Idee: einheitliche Ausgangssituation schaffen @Before public void setUp() throws Exception { System.out.println("setUp"); wert = 42; klasse = klasse + 1; System.out.println("klasse ist "+klasse); } einmal nach jeden Tests (lokal aufräumen) @After public void tearDown() throws Exception { System.out.println("tearDown"); } Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker 29 Aufbau einer Testklasse (4/8) Test ist beliebige mit @Test annotierte Methode Methodenname ist beliebig, beginnt typischerweise mit „test“ und beinhaltet Name der @Test Methode oder Sinn des Tests public void test1() { System.out.println("test1"); Experimente wert = wert + 1; Assert.assertTrue("Erwartet 43 gefunden: "+wert , wert == 43); } Prüfmethode, Parameter Text und Boolesche Bedingung; ist Bedingung „false“ wird Test als gescheitert festgehalten und Text ausgegeben Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker 30 Aufbau einer Testklasse (5/8) @Test public void test2() { System.out.println("test2"); wert = wert + 2; Assert.assertTrue(wert == 44); } Kurzform ohne Text (gibt assert-Varianten) wenn Testfall scheitert ist entweder das Programm oder der Test fehlerhaft @Test public void test3() { System.out.println("test3"); wert = wert + 3; Assert.assertTrue("Erwartet 44 gefunden: "+wert , wert == 44); } Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker 31 Aufbau einer Testklasse (6/8) @Test Test scheitert, wenn ausgeführt; public void test4() { markiert Stellen, die nicht System.out.println("test4"); erreicht werden sollen try{ if(42/0 == 0){ gewünschte Exception } Assert.fail(); } catch(ArithmeticException e){ } catch(Exception e){ ungewünschte Exception Assert.fail(); } } } @Test public void test5() { System.out.println("test5"); throw new IllegalArgumentException(); } Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker 32 Aufbau einer Testklasse (7/8) setUpBeforeClass setUp klasse ist 100 test4 tearDown setUp klasse ist 101 test5 tearDown setUp klasse ist 102 test1 tearDown setUp klasse ist 103 test2 tearDown setUp klasse ist 104 test3 tearDown tearDownAfterClass Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker 33 Aufbau einer Testklasse (8/8) • Error: Fehler durch Assert • Failure: Fehler durch Abbruch Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker 34 Tests in NetBeans erstellen (1/2) • JUnit einbinden (eine Variante) Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker 35 Tests in NetBeans erstellen (2/2) • Location: Test Packages, Start mit Rechtsklick auf Test Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker 36 Mini-Testbeispiel (1/5) • Spezifikation: Ein Tarif wird über das Alter und die Eigenschaft „Raucher“ bestimmt. Für unter 30-jährige Nichtraucher ist der Tarif „A“. Für alle sonstigen Nichtraucher „X“. Ansonsten darf die Tarifberechnung nicht durchgeführt werden. • Design: Klasse Tarif hat Methode public char gruppierungBerechnen(int alter , boolean istRaucher) throws UnversicherbarException • die den Tarif als Buchstaben zurück liefert und bei unerwünschten Daten eine spezielle Exception wirft Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker 37 Mini-Testbeispiel (2/5) • Erstellung der Testfälle mit Äquivalenzklassen und Grenzwertanalyse – „alter“ hat zwei Bereiche: „< 30“ und „>= 30“ – „istRaucher“ hat zwei Bereiche „true“, „false“ • Testfälle – alter = 29, istRaucher = false Ergebnis: ‚A‘ – alter = 30, istRaucher = false Ergebnis: ‚X‘ – alter = 30, istRaucher = true Ergebnis: Exception • Hinweis: Exceptions werden immer einzeln getestet Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker 38 Mini-Testbeispiel (3/5) package test; import import import import import business.Tarif; exceptions.UnversicherbarException; org.junit.Assert; org.junit.Before; org.junit.Test; public class TarifTest { private Tarif tarif; • Hinweis: Tests können auch vor der Programmierung nach dem Klassendesign entstehen („test first“) Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker 39 Mini-Testbeispiel (4/5) @Before public void setUp(){ tarif = new Tarif(); } @Test public void testGruppierungBerechnenA(){ try { char ergebnis = tarif.gruppierungBerechnen(29, false); Assert.assertTrue(ergebnis == 'A'); } catch (UnversicherbarException ex) { Assert.fail(); } } Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker 40 Mini-Testbeispiel (5/5) @Test public void testGruppierungBerechnenX(){ try { char ergebnis = tarif.gruppierungBerechnen(30, false); Assert.assertTrue(ergebnis == 'X'); } catch (UnversicherbarException ex) { Assert.fail(); } } @Test public void testGruppierungBerechnenException(){ try { char ergebnis = tarif.gruppierungBerechnen(30, true); Assert.fail(); } catch (UnversicherbarException ex) { } } }Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker 41 viele weitere Möglichkeiten • typisch eine Testklasse pro entwickelter Klasse • Tests zusammenfassbar in Test-Suites • Tests mit Parameterlisten aus Datei • viele Test-Frameworks basieren auf JUnit • Web-Tests mit Selenium • DB-Tests mit DBUnit • Ansatz zur Testfallerstellung mit Äquivalenzklassen (welche unterschiedlichen Eingaben führen zu unterschiedlichen Arten von Ergebnissen) Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker 42 Design-Pattern Observer-Observable • Es gibt Subjekte, für deren Zustand sich viele interessieren, (z. B. Nachrichtenkanäle) • Die Subjekte bieten die Möglichkeit, dass sich Interessenten anmelden (z. B. Kanal abonnieren) • Bei jeder Subjektzustandsänderung werden Interessenten informiert (neue Nachrichten) • Interessent muss sich bei Subjekt anmelden • Damit obiges Objekt weiß, wie Interessent angesprochen werden soll, muss Interessent Schnittstelle realisieren • Hinweis: Enge Verwandtschaft zu Model-View-Controller, wovon es einige Varianten gibt Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker 43 Beobachter (Observer – Observable) Anmerkung: Gibt Varianten; auch Publish-Subcribe genannt Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker 44 Beispiel MQTT • • • • • • Message Queue Telemetry Transport – Protokoll Seit 1999 entwickelt, OASIS Standard, http://mqtt.org/ Genutzt für M2M (Machine to Machine)-Kommunikation Broker bietet Topics an Nutzer können Topics abonnieren Nutzer können für Topics Nachrichten formulieren, die an alle Abonnenten gehen • Gibt viele unterschiedliche Broker-Anbieter (z. B. Apache Apollo), auch direkt Testen (http://www.mqttdashboard.com) • Gibt für viele Sprachen viele Umsetzungen von Clients zur Erstellung von Publishern und Subscribern • Beispiel Eclipse Paho https://eclipse.org/paho/ Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker 45 Fallstudie MQTT (1/10): • Realisiere einen Chat • Nutzer einigen sich auf einen Topic, auf dem sie schreiben und aus dem sie lesen können Anmerkung (wichtig für MQTT, hier nicht betrachtet) • Unterstützt verschiedene Quality of Service (0 = höchstens einmal liefern, 1= wenigstens einmal, 2= genau einmal) • Angemeldete Clients, die Kontakt verlieren, können bei neuem Kontakt zwischenzeitliche Nachrichten nachgereicht bekommen Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker 46 Fallstudie MQTT (2/10): Beispielumsetzung public class Konstanten { //public final static String VERBINDUNG ="tcp://0.0.0.0:61613"; public final static String VERBINDUNG ="tcp://broker.mqttdashboard.com:1883"; public final static String TOPIC = "wichtig/text"; } Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker 47 Fallstudie MQTT (3/10): Oberfläche 1/3 public class Fenster extends Application { private private private private TextField eingabe = new TextField(); TextArea ausgabe = new TextArea(""); Publisher publisher; Subscriber subscriber; @Override public void init(){ this.publisher = new Publisher(); this.subscriber = new Subscriber(this); } @Override public void start(Stage primaryStage) { primaryStage.setTitle("Chatt mit MQTT"); BorderPane borderPane = new BorderPane(); borderPane.setCenter(this.ausgabe); this.ausgabe.setEditable(false); Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker 48 Fallstudie MQTT (4/10): Oberfläche 2/3 borderPane.setTop(this.eingabe); this.eingabe.setOnAction(e -> { this.publisher.senden(this.eingabe.getText()); eingabe.setText(""); }); primaryStage.setOnCloseRequest(e -> { this.subscriber.trennen(); this.publisher.trennen(); System.out.println("ENDE"); }); Scene scene = new Scene(borderPane); } primaryStage.setScene(scene); primaryStage.show(); Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker 49 Fallstudie MQTT (5/10): Oberfläche 3/3 public void ausgeben(String text){ // Aktion muss auf JavaFX-Thread laufen, // wird so dort angehaengt Platform.runLater(new Runnable() { @Override public void run() { ausgabe.appendText(text+"\n"); } }); } // start von JavaFX muss so aussehen public static void main(String[] args) { launch(args); } Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker 50 Fallstudie MQTT (6/10): Publisher 1/2 public class Publisher { private MqttClient client; public Publisher(){ this.verbinden(); } public void verbinden() { try { this.client = new MqttClient(Konstanten.VERBINDUNG , MqttClient.generateClientId()); // muss eindeutig sein MqttConnectOptions options = new MqttConnectOptions(); // benoetigt, wenn nicht <authentication enabled="false"/> options.setPassword("password".toCharArray()); options.setUserName("admin"); this.client.connect(options); } catch (MqttException e) { System.out.println("Problem beim Verbinden:\n" + e); } } Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker 51 Fallstudie MQTT (7/10): Publisher 2/2 public void trennen() { try { if (this.client != null && this.client.isConnected()) this.client.disconnect(); } catch (MqttException e) { System.out.println("Problem beim Trennen:\n" + e); } } } public void senden(String text) { try { // generell können nur Byte-Arrays gesendet werden this.client.publish(Konstanten.TOPIC ,(this.client.getClientId() + ": " + text).getBytes() ,0,false); } catch (MqttException e) { System.out.println("Problem beim Senden:\n" + e); } } Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker 52 Fallstudie MQTT (8/10): Subscriber 1/3 import import import import import import import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken; org.eclipse.paho.client.mqttv3.MqttCallback; org.eclipse.paho.client.mqttv3.MqttClient; org.eclipse.paho.client.mqttv3.MqttConnectOptions; org.eclipse.paho.client.mqttv3.MqttException; org.eclipse.paho.client.mqttv3.MqttMessage; javafx.application.Platform; public class Subscriber { private MqttClient client; private Fenster fenster; public Subscriber(Fenster fenster){ this.fenster = fenster; lesen(); } Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker 53 Fallstudie MQTT (9/10): Subscriber 2/3 public void lesen(){ try { this.client = new MqttClient(Konstanten.VERBINDUNG , MqttClient.generateClientId()); this.client.setCallback(new MqttCallback() { @Override public void messageArrived(String topic , MqttMessage nachricht) throws Exception { fenster.ausgeben(nachricht.toString()); } @Override public void deliveryComplete(IMqttDeliveryToken arg0) { fenster.ausgeben("Token: "+ arg0); } @Override public void connectionLost(Throwable arg0) { fenster.ausgeben("Verbindung weg: " + arg0); } Komponentenbasierte SoftwareProf. Dr. }); Entwicklung Stephan Kleuker 54 Fallstudie MQTT (10/10): Subscriber 3/3 } MqttConnectOptions options = new MqttConnectOptions(); options.setWill(Konstanten.TOPIC ,"Isch bin wech".getBytes(), 0, false); client.connect(options); client.subscribe(Konstanten.TOPIC); } catch (MqttException e) { e.printStackTrace(); } public void trennen() { try { if (this.client != null && this.client.isConnected()){ this.client.disconnect(); } } catch (MqttException e) { System.out.println("Problem beim Trennen:\n" + e); } } } Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker 55 1. Historie und Ziele der Softwareentwicklung • • • • • • Entwicklung der Programmierung Bedeutung von Abstraktion Domain Specific Languages Model Driven Architecture Komponenten-Ansatz Komponenten-Architekturen Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker 56 Entwicklung der Programmierung (1/2) • Erste Rechner: Programmierung extrem HW-nah (Maschinenbefehle eng verwandt mit Stromschaltern) • Assembler: Befehle wie – Lege Wert der Speicherzelle X in Register R1 – Wenn Wert in R1 gleich Null springe zu Zeile 4242 Ein Assemblerbefehl ersetzt mehre Maschinenbefehle • Einfache Programmiersprachen, Fortran, Algol 60, z. B. – n:=n+1 – for q:=1 step s until n do A[q]:=B[q] – Sprünge (goto), Unterprogramme und Funktionen Programmiersprachenbefehl umgesetzt als mehrere Assemblerbefehle Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker 57 Entwicklung der Programmierung (2/2) • Modularisierung von Programmen / Bibliothekennutzung – z. B. Trennung von Header-Dateien und Implementierung – stdio.h, math.h • Objektorientierung – Weitere logische Strukturierung mit Klassen – Information Hiding – Statische und dynamische Polymorphie • Frameworks – Programmierte Teillösungen für Standardaufgaben (z. B. Datenverwaltung, Transaktionsmanagement) – Entwickler muss zur Nutzung Interfaces erfüllen Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker 58 Abstraktion Framework Bibliothek Programmiersprache Assembler Maschinensprache • Entwicklung auf/mit abstrakterer Ebene immer wesentlich schneller als auf unterer Ebene • Jeder Abstraktionsschritt kann Performance kosten Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker 59 Generelle Ziele der Softwareentwicklung • Schnelle Entwicklung – Keine fachliches Ergebnis doppelt – Einfache Nutzung existierender Ergebnisse (ohne Detailkenntnisse) • Qualitativ hochwertige Ergebnisse – Nutzung validierter und verifizierter Verfahren – Korrektheit und Performance • Übertragbarkeit der Ergebnisse – Schnelle Wiederverwendung bei ähnlichen Aufgaben – Unabhängigkeit von konkreten Sprachen und Betriebssystemen – Integrierbar in andere Software-Architekturen Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker 60 Aktuelle Themen der Softwareentwicklung (1/4) Domain Specific Languages • Problem: General Purpose Sprachen sind sehr mächtig, aber für spezifische Entwicklungsbereiche geht sehr viel Energie in für den Bereich gleichartige Programmierung • Spezielle Entwicklungssprache für individuellen Bereich, spezielle komplexe Hochsprachelemente anbietet • Neue Sprache z. B. mit XML (Syntax mit XML-Schema) darstellbar; Umwandlung in Programm mit Übersetzung (z. B. XSLT) ; hilfreich ist Visualisierungsmöglichkeit der DSL Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker 61 Aktuelle Themen der Softwareentwicklung (2/4) Model Driven Architecture • Ansatz: Häufig benötigt man die gleichen Ideen (z. B. Sortierverfahren) in sehr unterschiedlichen Sprachen; warum nicht in einer Sprache modellieren und dann in andere Sprachen transformieren? • Zur Modellbeschreibung wird eigene Sprache mit eigener Semantik benötigt (Metamodell und Metametamodell) • Ansatz: Umwandlung des CIM mit Transformationsregeln in ein PIM und dann ein PSM CIM: Computer Independent Model PIM: Platform Independent Model PSM: Platform Specific Model Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker 62 Aktuelle Themen der Softwareentwicklung (3/4) Metamodell Codegenerator Verwaltung liname:String * element Element name:String typ:String public class {Verwaltung.liname} { <foreach Element e:Verwaltung.element> private List<{e.typ}> {e.name}; } Verwaltung generierter Code Modell liname=„Hauptliste“ Element public class Hauptliste { name=„kunden“ private List<Kunde> kunden; typ=„Kunde“ private List<Produkt> produkte; Element } name=„produkte“ typ=„Produkt“ http://www.eclipse.org/modeling/ Eclipse Modelling Project (Xtext, Xpand/Xtend/Check) Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker 63 Aktuelle Themen der Softwareentwicklung (4/4) Komponentenbasierte Entwicklung • Idee: Software besteht aus Bausteinen • Komplexe Software wird aus einfachen Bausteinen zusammengebaut • Beispiel 1: GUI aus Buttons, ListBox, Slider, Panel, .... • Beispiel 2: Kundenverwaltung, Lagerhaltung, Bestellabwicklung, Finanzabwicklung • Bausteine können getrennt genutzt werden; sind konfigurierbar • Bausteine müssen zusammenarbeiten können • Konkretes Beispiel: Eclipse mit Plugins • Hinweis: Trotz üblichem Methodenkrieg können Teilideen aller Ansätze integriert werden Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker 64 Komponentenidee genauer (1/2) • Funktionalität nutzbar für andere (Schnittstelle) – Benötigt klare Schnittstellendefinition – Welche Methoden/Dienste werden angeboten (Parameter, Ergebnisse, Ausnahmen) – Welche Objekte (die Schnittstellenspezifikationen erfüllen) werden benötigt • Einstellungsmöglichkeiten – z. B. spezielle Methoden – z. B. Einstellungsdatei (XML) Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker 65 Komponentenidee genauer (2/2) • Funktionsgarantie – Genannte Dienste werden immer (auch bei neuen Versionen) angeboten – Dienstqualität (Korrektheit, Performance) ist garantiert • direkt nutzbar – Möglichst Installation durch Kopieren – Möglichst plattformunabhängig – Möglichst leicht in andere Systeme integrierbar Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker 66 Komponentenframework • Komponente muss bestimmte Schnittstellen befriedigen, damit Framework nutzbar wird • Typische Aufgaben eines Frameworks: – Framework kennt aktive Komponenten, kann so Konflikte lösen – Framework ermöglicht es, dass Komponenten Informationen austauschen – Framework bietet Standarddienste: Persistenz, Transaktionssicherheit, Anmeldung, Suche Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker 67 Zentrale Aspekte der Komponentenorientierung Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker 68 Komponentendiagramm • Bilder zeigen zwei alternative Darstellungen • Komponenten bieten Schnittstellen(realisierungen) (Kreis) und benötigen Schnittstellen(realisierungen) (Halbkreis) • Komponenten können über Schnittstellen in Diagrammen verknüpft werden • in Komponenten können zugehörige Klassen eingezeichnet werden Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker 69 Zusammenspiel von Komponenten (1/3) • Variante 1: Direkte Kommunikation • Komponenten bieten Schnittstellen zur Nutzung und benötigen Objekte zur Ausführung • Direktes Netzwerk von Komponenten • Vorteil: wenig Restriktionen in Entwicklung (Individualentwicklung) • Nachteil: keine Standardisierung; gleichartige Aufgaben evtl. mehrfach realisiert Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker 70 Beispiel: direkt verbundene Komponenten Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker 71 Zusammenspiel von Komponenten (2/3) • Variante 2: Nutzung einer Kommunikationsplattform mit zentralen Diensten Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker 72 Beispiele zentraler Dienste • Plattform bietet Kommunikationsdienste – Komponente abonniert sie interessierende Daten – Komponente bietet neue Daten zum abonnieren an • Lokalisationsdienst : Finden von Daten /Komponenten • Darstellungsdienst: Visualisierung der Daten • Transportdienst : transparenter und sicherer Datentransport der Komponenten untereinander • Speicherungsdienst : Daten persistieren, Konsistenz, Replikation und Backup • Sicherungsdienst : Sicherung der Integrität , Kontrolle von Nutzerauthentifizierung und –autorisierung • Vorteil: klar strukturiertes Kommunikationsverhalten; modularer Aufbau • Nachteil: Plattform muss hoch performant sein; kein direkter Informationsaustausch Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker 73 Beispiel mit Kommunikationsplattform Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker 74 Zusammenspiel von Komponenten (3/3) • Variante 3: Komponentenframework • Komponente selbst läuft in einem Container • Container stellt Dienste zur Verfügung (s. vorher) • Plattform regelt Zusammenspiel der Container • Vorteil: Konzentration auf Container Geschäftsprozess • Nachteil: Abhängigkeit vom Framework; Performance (?) • Hinweis: gibt weitere Varianten; Varianten nicht disjunkt Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker 75 Beispiel: Komponenten in Containern Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker 76 Entwicklung von Komponenten • Zentrales Ziel der Komponentenentwicklung durchzieht gesamten Entwicklungsprozess • Anforderungsanalyse: nicht-triviale unabhängige Teilaufgaben • Generell typisch: zentrale Informationsverwaltung (z. B. Stammdaten) • Komponentensysteme wachsen schrittweise – Klärung zentraler Prozesse (Stammdatenverwaltung) – Anschluss weiterer Prozesse • Migration erfolgt ebenfalls schrittweise; häufig aber Beginn mit einzelnen Komponenten, die sich an Altsystem anschließen • Komponentenentwicklung hat (einmaligen) Mehraufwand Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker 77 Beispiele Komponentenarchitekturen • Microsoft: Component Object Model (COM, bzw. COM+, DCOM, ActiveX) • OMG: Common Object Request Broker Architecture (CORBA) • Sun: Java Beans und Enterprise Java Beans • OSGi Alliance: OSGi (früher „Open Services Gateway initiative“) – Basis Java Virtual Machine – Ziel ist Gerätevernetzung (Handy, Gebäudeautomatisierung, Automotive) – Grundlage für Eclipse-Plugins (Equinox) Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker 78 2. Reflexion und Annotationen • • • • • Reflexion Annotationskonzept Erstellung eigener Annotationen Annotationen mit Reflexion nutzen Annotation Processing Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker 79 Reflexion • auch Introspektion, engl. reflection • Reflexion erlaubt in Java Meta-Programmierung; Klassen selbst als Objekte nutzen • Paket java.lang.reflect • Zu jeder Klasse gibt es ein Klassenobjekt der Klasse Class Class cl1 = String.class; try { // oder Class cl2 = Class.forName("java.lang.String"); } catch (ClassNotFoundException e) { System.out.println("gibs nich") } Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker 80 Nutzung von Class • Klassenobjekt erlaubt – Abfrage von Variablen, Konstruktoren, Methoden (mit Sichtbarkeiten, Typen, Parametern, Exceptions,…) – Abfrage und Änderung von Objektwerten – Nutzung von Konstruktoren und Methoden – Abfrage von Oberklassen • Insgesamt können damit zur Laufzeit beliebige Klassen analysiert und genutzt werden • Zentrale Reflection-Klassen: Field, Constructor, Method, Modifier Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker 81 Exemplarische Methoden der Klasse Class Annotation[] getDeclaredAnnotations() present on this element. Returns all annotations that are directly Constructor[] getDeclaredConstructors() Returns an array of Constructor objects reflecting all the constructors declared by the class represented by this Class object. Field[] getDeclaredFields() Returns an array of Field objects reflecting all fields declared by the class or interface represented by this Class object. Method[] getDeclaredMethods() Returns an array of Method objects reflecting all the methods declared by the class or interface represented by this Class object. Class[] getInterfaces() Determines the interfaces implemented by the class or interface represented by this object. int getModifiers() Returns the Java language modifiers for this class or interface, encoded in an integer. boolean isArray() Determines if this Class object represents an array class. T newInstance() this Class object. Komponentenbasierte SoftwareEntwicklung Creates a new instance of the class represented by http://docs.oracle.com/javase/7/docs/api/java/lang/Class.html Prof. Dr. Stephan Kleuker 82 Einsatzbereiche von Reflexion • Eingesetzt zur Entwicklung von Entwicklungswerkzeugen – Debugger – Class Browser, UML-Diagrammableitung – GUI Builder – IDEs wie z.B. Eclipse und Netbeans • Eingesetzt in Frameworks – Einheitliche Klassenbehandlung ohne Interfaces – Finden bestimmter Methoden (z. B. getXXX) und Eigenschaften – Meist Verwaltung unterschiedlicher Klassen – Tests privater Methoden • Oft verknüpft mit anderen fortgeschrittenen Ansätzen (ClassLoader, Annotationen, Bytecode-Manipulation) Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker 83 Ungewöhnliches Beispiel (1/2) • Praktisch nicht nutzbare Klasse package model; public class Heimlich { private int x; private Heimlich(){ } private void ausgeben(){ System.out.println("x ist "+x); } } • Hinweis: Folgender Ansatz geht nicht immer, hängt von Security-Einstellungen ab Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker 84 Ungewöhnliches Beispiel (2/2) public static void main(String[] s) throws Exception{ Class cl = Class.forName("model.Heimlich"); Constructor[] cons = cl.getDeclaredConstructors(); Constructor con = cons[0]; System.out.println(con); if(!con.isAccessible()) // evtl. SecurityManager-Exception con.setAccessible(true); Object[] parameter = {}; Heimlich h = (Heimlich) con.newInstance(parameter); System.out.println("" + h); private model.Heimlich() Field f=cl.getDeclaredFields()[0]; model.Heimlich@19821f f.setAccessible(true); x ist 42 f.set(h, 42); Method m=cl.getDeclaredMethods()[0]; m.setAccessible(true); m.invoke(h, parameter); } Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker 85 Anwendung von Reflexion • Gegeben Klasse Interaktionsbrett, die nicht verändert werden darf • Interaktionsbett bietet Knopf zum Schließen des Programms über einen JFrame an, der nur in einer privaten Exemplarvariablen rahmen steht • Schließen erfolgt mit System.exit(0) • Generell ok, aber haben Nutzer von Interaktionsbrett offene Ressourcen, werden diese ggfls. nicht geschlossen • Ansatz: Nutze Reflexion, um auf JFrame zuzugreifen und ergänze Methode, die zusätzlich beim Schließen aufgerufen wird • Bekannt: JFrame führt bei Fenster-Events in Sammlung zugeordneter WindowListener-Objekte passende Methoden aus Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker 86 Ausgangssituation (Skizze) Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker 87 Umsetzung in Klasse Subscriber public Subscriber(MainGui gui){ // gui über Ende informieren this.ia = new Interaktionsbrett(); try { Field feld = ia.getClass().getDeclaredField("rahmen"); feld.setAccessible(true); JFrame frame = (JFrame) feld.get(this.ia); frame.addWindowListener(new WindowAdapter() { @Override public void windowClosing(WindowEvent e) { gui.beenden(); } }); } catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e1) { e1.printStackTrace(); } Komponentenbasierte SoftwareProf. Dr. 88 } Entwicklung Stephan Kleuker Ergebnis (Skizze, Grenze der UML-Darstellung) Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker 89 Skizze: Reflexionsnutzung public class MainGui { private Subscriber sub; public MainGui(){ this.sub = new Subscriber(this); // ... } public void beenden(){ System.out.println("mach Schicht"); } public static void main(String[] s){ new MainGui(); } } Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker 90 Einsatz von Annotationen: Weiterverarbeitung // HelloWorldService.java import javax.jws.WebMethod; import javax.jws.WebService; @WebService public class HelloWorldService { @WebMethod public String helloWorld() { return "Hello World!"; } } • Annotationen beginnen mit einem @ und können, z. B. von anderen Programmen zur Weiterverarbeitung genutzt werden • hier z. B. soll die Erzeugung eines Web-Services durch die Kennzeichnung relevanter Teile durch Annotationen erfolgen • Java besitzt seit Version 5 Annotationen, man kann selbst weitere definieren Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker 91 Syntax von Annotationen • Annotationen können Parameter haben • ohne Parameter: @EinfacheAnnotation • mit einem Parameter @EinAnno(par="Hallo") oder @EinAnno("Hallo") (bei nur einem Parameter kann der Parameternamen weggelassen werden, woher par kommt, sehen wir später) • mit mehreren Parametern werden Wertepaare (Parametername, Wert) angegeben @KomplexAnno(par1="Hi", par2=42, par3={41,43}) • Annotationen können bei/vor anderen Modifiern (z.B. public, abstract) bei folgenden Elementen stehen: – package − Exemplar- und Klassenvariable – class, interface, enum − lokale Variablen – Methode − Parameter • Man kann einschränken, wo welche Annotation erlaubt ist Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker 92 Beispiel: Nutzung vordefinierter Annotation public class Oben { public void supertolleSpezialmethode(){ System.out.println("Ich bin oben"); } } public class Unten extends Oben{ @Override public void superTolleSpezialmethode(){ System.out.println("Ich bin unten"); } public static void main(String[] s){ Unten u = new Unten(); u.supertolleSpezialmethode(); } ohne Annotation in Java 1.4: } Ich bin oben Compilermeldung: ..\..\netbeans\Annotationen\src\Unten.java:2: method does not override a method from its superclass @Override public void superTolleSpezialmethode(){ 1 error Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker 93 Annotationen selbst schreiben public @interface Name { in @interface erlaubte Typen: String vor(); -Basisdatentypen String nach(); -String } -Aufzählungen (hier oder public @interface Problem { woanders definiert) int id(); - (weitere) @interface String text(); -Arrays der obigen Elemente Name verantwortlich(); enum Paket{ GUI, BUIS, INFRA, OLD; @Override public String toString() { return "das " + name() + " Paket"; } }; Paket[] betroffen() default {Paket.GUI,Paket.BUIS, Paket.INFRA, Paket.OLD}; } • Jede Annotation steht in ihrer eigenen Klassen-Datei • Erben automatisch von java.lang.annotation.Annotation • Ihre Methoden haben keine Parameter (ein Feld des Methodennamens wird für die Annotation festgelegt) Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker 94 Mit eigenen Annotationen annotieren @Problem( id=1, verantwortlich= @Name(vor="Heinz", nach="Meier"), text="Koordination offen", betroffen={Problem.Paket.GUI,Problem.Paket.BUIS} ) public class KlasseInBearbeitung { String eineExemplarvariable; @Problem( id=2, verantwortlich= @Name(vor="Horst", nach="Meier"), text="Test in main schreiben" ) public static void main(String[] s){ System.out.println("Noch viel zu tun"); } } Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker 95 Annotation von Annotationen • Grundsätzlich kann es sinnvoll sein, Annotationen selbst mit Zusatzinformationen zu annotieren (Meta-Information) • nicht gemeint ist folgendes: @Override @Deprecated public void xyz(){ dies ist nur eine Menge von Annotationen für ein Element • Meta-Informationen stehen in der „Klassendefinition“ der Annotationen Es gibt folgende Standard-Meta-Annotationen: • @Target (wo darf die Annotation stehen) • @Target({ElementType.TYPE, ElementType.METHOD}) @Retention („Beibehaltung“, wo soll Annotation sichtbar sein, z. B. auch noch zur Laufzeit?) @Retention(RetentionPolicy.RUNTIME) • @Documented (keine Parameter, Annotation in Doku sichtbar?) • @Inherited (keine Parameter, Annotation soll vererbt werden) Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker 96 Wertebereiche der Meta-Annotationen (aus Doku) import java.lang.annotation.*; @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.FIELD, ElementType.METHOD}) CLASS Annotations are to be recorded in the class file by the compiler but need not be retained by the VM at run time. RUNTIME Annotations are to be recorded in the class file by the compiler and retained by the VM at run time, so they may be read reflectively. SOURCE Annotations are to be discarded by the compiler. ANNOTATION_TYPE Annotation type declaration CONSTRUCTOR Constructor declaration FIELD Field declaration (inlcudes enum constants) LOCAL_VARIABLE Local variable declaration METHOD Method declaration PACKAGE Package declaration PARAMETER Parameter declaration TYPE Class, interface (including annotation type), or enum declaration Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker 97 Beispiel für zur Laufzeit lesbare Annotation import import import import import java.lang.annotation.Documented; java.lang.annotation.ElementType; java.lang.annotation.Retention; java.lang.annotation.RetentionPolicy; java.lang.annotation.Target; @Target({ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented // auch hier wichtig public @interface Name { String vor(); String nach(); } Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker 98 Annotationen über Reflexion auslesen (1/2) • Typischerweise werden Annotationen von speziellen Werkzeugen für Transformationen verwendet • SUN hat ab Java 5 ein zusätzliches Werkzeug apt (annotation processing tool) für Bearbeitungen und Transformationen hinzugefügt, ab Java 6 in javac integriert • Damit wir was sehen, nutzen wir Reflexion (Klassen werden als Objekte betrachtet) import java.lang.annotation.Annotation; import java.lang.reflect.Field; import java.lang.reflect.Method; public class Reflexionstest { public static void main(String[] s){ Class c = KlasseInBearbeitung.class; System.out.println(c); Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker 99 Annotationen über Reflexion auslesen (2/2) } } Field[] attribute = c.getDeclaredFields(); for(Field f:attribute) System.out.println(f); Method[] methoden = c.getDeclaredMethods(); for(Method m:methoden){ System.out.println(m); Annotation[] annos = m.getAnnotations(); for(Annotation an:annos){ System.out.println(an); Problem p = (Problem)an; // kritisch System.out.println(p.verantwortlich()); } } class KlasseInBearbeitung java.lang.String KlasseInBearbeitung.eineExemplarvariable public static void KlasseInBearbeitung.main(java.lang.String[]) @Problem(betroffen=[das GUI Paket, das BUIS Paket, das INFRA Paket, das OLD Paket], id=2, verantwortlich=@Name(vor=Horst, nach=Meier), text=Test in main schreiben) @Name(vor=Horst, nach=Meier) Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker 100 Konzept: Annotation-Processing • oft reicht Annotationsauswertung zur Laufzeit aus • manchmal wird zusätzlicher Programmcode benötigt, der auf Grundlage der Annotation und des annotierten Elements erzeugt werden soll • Annotation-Processing wertet Annotationen vor der eigentlichen Übersetzung aus (eigener JVM-Prozess) • ermöglicht u. a. Prüfung von Randbedingungen, ob Constraints für Annotationen erfüllt sind (z. B. annotierter Typ muss zusätzlich auch bestimmtes Interface realisieren) • ermöglicht die Erzeugung neuen Codes, der dann in einem folgenden Durchlauf übersetzt wird (mehre Läufe möglich) • Entwicklungsumgebungen können Annotationsverarbeitung einschalten und Prüfergebnisse anzeigen • verwandt zu Pre-Processing in C und C++ Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker 101 Annotations-Prozessor (1/6) - Annotation • benötigt Annotation, die nicht zut gleichen späteren Jar gehören muss (oft aber sinnvoll) package annotation; import import import import import java.lang.annotation.Documented; java.lang.annotation.ElementType; java.lang.annotation.Retention; java.lang.annotation.RetentionPolicy; java.lang.annotation.Target; @Documented @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) public @interface MeineAnnotation { String name() default "nix"; } Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker 102 Annotations-Prozessor (2/6) - AbstractProcessor Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker 103 Annotations-Prozessor (3/6) – Beispiel (nur Idee) @SupportedAnnotationTypes({"annotation.MeineAnnotation"}) @SupportedSourceVersion(SourceVersion.RELEASE_8) public class MeinProzessor extends AbstractProcessor { private ProcessingEnvironment env; private static int schritt = 1; @Override public void init(ProcessingEnvironment env) { super.init(env); this.env = env; env.getMessager().printMessage( Diagnostic.Kind.MANDATORY_WARNING, "init: " + this.env.getFiler()); } Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker 104 Annotations-Prozessor (4/6) @Override public boolean process(Set<? extends TypeElement> annotations , RoundEnvironment roundEnv) { env.getMessager().printMessage( Diagnostic.Kind.MANDATORY_WARNING,"process " + (schritt++)); for (Element e : roundEnv .getElementsAnnotatedWith(MeineAnnotation.class)) { System.out.println("t: " + e.asType()); // unueblich String name = e.getSimpleName().toString(); ermöglicht Schreiben TypeElement cl = (TypeElement) e; zusätzlichen Codes try { JavaFileObject f = processingEnv.getFiler(). createSourceFile(cl.getQualifiedName() + "Extras"); this.env.getMessager().printMessage(Diagnostic.Kind.NOTE , „Erzeugt " + f.toUri()); Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker 105 Annotations-Prozessor (5/6) try (Writer w = f.openWriter();){ PrintWriter pw = new PrintWriter(w); pw.println("package " + cl.getEnclosingElement().getSimpleName() + ";"); pw.println("public class „ + cl.getSimpleName() + "Extras {\n public " + cl.getSimpleName() + "Extras() {}"); annotierte Klasse TypeMirror type = e.asType(); nicht direkt nutzbar pw.println(" public void zeige" + name + "(" + type + " value) {\n" + " System.out.println(\"zeige:\" + value);\n" + " } \n" + "}"); pw.flush(); bricht Kompilierung ab } } catch (IOException x) { this.env.getMessager().printMessage(Diagnostic.Kind.ERROR, x.toString()); ermöglicht weiteren Annotations} Komponentenbasierte SoftwareProf. Dr. 106 Prozessoten die Bearbeitung } Entwicklung Stephan Kleuker return false; } Annotations-Prozessor (6/6) • Auslieferung als Jar-Datei • Anmeldung bei javac durch Info-Datei Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker 107 Annotationsnutzung (1/5) - Integration • einbinden der Jar-Datei • Einschalten der Annotationsnutzung (optional direkte Nutzung in der Entwicklungsumgebung) Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker 108 Annotationsnutzung (2/5) - Beispielklasse package example; import annotation.MeineAnnotation; @MeineAnnotation(name="Heinz") public class Beispiel { @Override public String toString() { return "Beispiel{" + '}'; } } Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker 109 Annotationsnutzung (3/5) – Ausgabe Clean & Build • Ausschnitt: Created dir: F:\workspaces\NetbeansWork_WS16\kbseAnnotationsprozessorNutzung\ build\generated-sources\ap-source-output Compiling 2 source files to F:\workspaces\NetbeansWork_WS16\kbseAnnotationsprozessorNutzung\ build\classes t: example.Beispiel warning: init: javac Filer warning: process 1 Note: Erzeugt file:/F:/workspaces/NetbeansWork_WS16/kbseAnnotationsprozessorNu tzung/build/generated-sources/ap-sourceoutput/example/BeispielExtras.java warning: process 2 warning: process 3 4 warnings compile: Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker 110 Annotationsnutzung (4/5) – Generierter Code Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker 111 Annotationsnutzung (5/5) – Nutzung generierten Codes public class Main { public static void main(String[] args) throws ClassNotFoundException, InstantiationException , IllegalAccessException, IllegalArgumentException , InvocationTargetException { Class cl = Class.forName("example.BeispielExtras"); Object[] parameter = {}; Object o = cl.getConstructors()[0].newInstance(parameter); System.out.println("o: " + o); Method m=cl.getDeclaredMethods()[0]; m.setAccessible(true); m.invoke(o, new Object[]{new Beispiel()}); } o: example.BeispielExtras@1db9742 } zeige:Beispiel{} Komponentenbasierte SoftwareEntwicklung Prof. Dr. Stephan Kleuker 112