Folien ab 26.9.16 (Version 2)

Werbung
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
Herunterladen