pdf-1

Werbung
Der EMF-generierte Code
7. November 2012
Überblick
 Wie sieht der aus einem EMF-Modell generierte
Code aus? Wie ist die Beziehung zwischen Modell
und Code?
 Wie kann generierter Code durch
handgeschriebenen erweitert bzw. ersetzt werden?
 Wie kann ein Instanzmodell erstellt werden?
 Durch einen Instanzeditor
 Anwendung der generierten Klassen
 Durch Anwendung von reflektiven Methoden auf dem EMFModell
 Welcher Test-Code wird erstellt?
Taentzer
Modellgetriebene Softwareentwicklung
132
Eclipse Modeling Framework (EMF)
Java
Klassen zur
Manipulation
des Modells
EMF
Klassendiagramm
EMF Generator
benutzt
einfacher
baumbasierter
Editor
basierend auf
JET
Taentzer
Modellgetriebene Softwareentwicklung
133
Struktur des generierten Codes
 Struktur des Modellcodes:
 Schnittstellenklassen
 Implementierungsklassen
 weitere nützliche Klassen
 weitere Dateien, um den
Code als Eclipse-Plugin zu
benutzen
 META-INF/MANIFEST.MF:
alle wichtigen Einstellung
zum Plugin
 plugin.xml: Identifizierung
des Plugins und
Beziehungen zu anderen
Taentzer
Modellgetriebene Softwareentwicklung
134
Modellierte Klassen
 für eine modellierte Klasse wird
erzeugt:
Dozent.java:
 eine Schnittstellenklasse
 eine Implementierungsklasse
 create-Methode in der FactoryKlasse
public interface Dozent extends EObject {
…
}
DozentImpl.java:
public class DozentImpl extends EObjectImpl implements Dozent {
…
}
Taentzer
Modellgetriebene Softwareentwicklung
135
Abstrakte Klassen
 Für eine abstrakte Klasse wird
erzeugt:
 eine Schnittstellenklasse
 eine abstrakte Impl-Klasse
 keine create-Methode in der
Factory-Klasse
Lehrveranstaltung.java:
public interface Lehrveranstaltung extends EObject {
…
}
LehrveranstaltungImpl.java:
public abstract class LehrveranstaltungImpl extends EObjectImpl
implements Lehrveranstaltung {
…
}
Taentzer
Modellgetriebene Softwareentwicklung
136
Abstrakte und Schnittstellenklassen
Abstrakte Klasse:
 in EClass:

Schnittstellenklasse:
 in EClass:
Attribut abstract = true
 im generierten Code:
 abstrakte
Implementierungsklasse
 keine create-Methode in der
Factory
Taentzer
 Attribut interface = true
 Attribut instanceClass nicht
gesetzt
 im generierten Code:
 keine
Implementierungsklasse,
aber Schnittstellenklasse
 keine create-Methode in der
Factory
Modellgetriebene Softwareentwicklung
137
Vererbung
 Vererbung von EObject und
EObjectImpl
 Mehrfachvererbung im
Modell - Mehrfachvererbung
der entsprechenden
Schnittenstellen, Impl.Klasse erbt von nur einer
Impl.-Klasse
Uebung.java:
public interface Uebung extends Lehrveranstaltung
UebungImpl.java:
public class UebungImpl extends LehrveranstaltungImpl implements Uebung
Taentzer
Modellgetriebene Softwareentwicklung
138
Structural Features: Zugriffsmethoden
Dozent.name
 Für jedes Attribut und jede
Referenz:
 eine getter-Methode
 falls changeable = true:
 eine setter-Methode
Dozent.java:
public interface Dozent extends EObject {
...
String getName();
void setName(String value);
...
}
Taentzer
Modellgetriebene Softwareentwicklung
139
Einfache Attribute
DozentImpl.java:
protected static final String
NAME_EDEFAULT = null;
protected String name = NAME_EDEFAULT;
public String getName() {
return name;
}
public void setName(String newName) {
String oldName = name;
name = newName;
if (eNotificationRequired())
eNotify(new ENotificationImpl(this,Notification.SET,
VorlesungsverzeichnisPackage.DOZENT_NAME,
oldName, name));
}
Taentzer
Modellgetriebene Softwareentwicklung
140
Subject-Observer-Prinzip
 Subject: Objekt aus dem
EMF-Modell
 Observer: andere Objekte,
die das EMF-Objekt
benutzen
Subject
Observer
Observer
Observer
Observer
 Observer müssen sich als
Listener anmelden.
 bei Änderung des Subjects:
 Benachrichtungung an alle
Observer
 Observer in EMF: Adapter
Taentzer
Modellgetriebene Softwareentwicklung
141
Unidirektionale Referenzen
Falls resolveProxies = true:
 Zusätzlicher Code zur Behandlung
von Proxy-Objekten
VorlesungImpl.java:
protected EList<Uebung> uebung = null;
public EList<Uebung> getUebung() {
if (uebung == null) {
uebung = new EObjectEList(Uebung.class, this,
VorlesungsverzeichnisPackage.VORLESUNG__UEBUNG);
}
return uebung;
}
Taentzer
Modellgetriebene Softwareentwicklung
142
Bidirektionale Referenzen
LehrveranstaltungImpl.java:
public void setDozent(Dozent newDozent) {
if (newDozent != dozent) {
NotificationChain msgs = null;
if (dozent != null)
msgs = ((InternalEObject)dozent).eInverseRemove(this,
VorlesungsverzeichnisPackage.DOZENT__LV, Dozent.class, msgs);
if (newDozent != null)
msgs = ((InternalEObject)newDozent).eInverseAdd(this,
VorlesungsverzeichnisPackage.DOZENT__LV, Dozent.class, msgs);
msgs = basicSetDozent(newDozent, msgs);
if (msgs != null) msgs.dispatch();
}
else if (eNotificationRequired())
eNotify(new ENotificationImpl(this, Notification.SET,
VorlesungsverzeichnisPackage.LEHRVERANSTALTUNG__DOZENT,
newDozent, newDozent));
}
Taentzer
Modellgetriebene Softwareentwicklung
143
Factories
Eine Factory ist die zentrale Klasse, in der neue Objekte angelegt werden.
VorlesungsverzeichnisFactory.java:
public interface VorlesungsverzeichnisFactory
extends EFactory {
Vorlesungen createVorlesungen();
Dozent createDozent();
Raum createRaum();
Vorlesung createVorlesung();
Seminar createSeminar();
Übung createÜbung();
Raumverzeichnis createRaumverzeichnis();
Hörsaal createHörsaal();
Seminarraum createSeminarraum();
VorlesungsverzeichnisPackage
getVorlesungsverzeichnisPackage();
Taentzer
Modellgetriebene Softwareentwicklung
144
Factories
• Es kann mehrere Implementierungen für eine Factory geben.
• Es gibt eine DefaultFactory.
public class VorlesungsverzeichnisFactoryImpl extends
EFactoryImpl implements VorlesungsverzeichnisFactory {
public static VorlesungsverzeichnisFactory init() {
try {
VorlesungsverzeichnisFactory theVorlesungsverzeichnisFactory =
(VorlesungsverzeichnisFactory)EPackage.Registry.INSTANCE.
getEFactory("http://vorlesungsverzeichnis");
if (theVorlesungsverzeichnisFactory != null) {
return theVorlesungsverzeichnisFactory;
}
}
catch (Exception exception) {
EcorePlugin.INSTANCE.log(exception);
}
return new VorlesungsverzeichnisFactoryImpl();
}
}
Taentzer
Modellgetriebene Softwareentwicklung
145
Codeerweiterung
 An verschiedensten Stellen
sind Codeerweiterungen
wünschenswert.
 Mit EMF kann kein Verhalten
modelliert werden -> Codeerweiterung
 Nach der Codeerweiterung
muss eine erneute Codegenerierung möglich sein.
 Generierte Methoden haben
ein @generated Tag.
Taentzer
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
public boolean checkKonsistenz() {
// TODO: implement this method
// Ensure that you remove @generated or
mark it @generated NOT
throw new
UnsupportedOperationException();
}
 Nach manueller Codeerweiterung muss das Tag
@generated NOT gesetzt
werden.
Modellgetriebene Softwareentwicklung
146
Beispiel: Codeerweiterung
RaumImpl.java:
public boolean checkKonsistenz() {
EList<Lehrveranstaltung> lvList = this.getVeranstaltung();
for (Lehrveranstaltung lv1 : lvList) {
for (Lehrveranstaltung lv2 : lvList) {
if (lv1 != null && lv2 != null) {
if (lv1 != lv2) {
if ((lv1.getZeit() == lv2.getZeit())
&& (lv1.getTag() == lv2.getTag()))
return false;
}// if
}// if
}// for
}// for
return true;
}// checkKonsistenz
Taentzer
Modellgetriebene Softwareentwicklung
147
Erstellung eines Instanzmodells
Beispiel: Erstellung eines Vorlesungsverzeichnisses
VorlesungsverzeichnisBeispiel.java:
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
import org.eclipse.emf.ecore.xmi.impl.XMIResourceFactoryImpl;
import vorlesungsverzeichnis.*;
import vorlesungsverzeichnis.impl.*;
//...
// Create a resource set to hold the resources.
ResourceSet resourceSet = new ResourceSetImpl();
// Register the appropriate resource factory to handle all file extensions.
resourceSet.getResourceFactoryRegistry().getExtensionToFactoryMap().put
(Resource.Factory.Registry.DEFAULT_EXTENSION,
new XMIResourceFactoryImpl());
// Register the package to ensure it is available during loading.
resourceSet.getPackageRegistry().put
(VorlesungsverzeichnisPackage.eNS_URI,
VorlesungsverzeichnisPackage.eINSTANCE);
//...
Taentzer
Modellgetriebene Softwareentwicklung
148
Erstellung eines Instanzmodells
Beispiel: Erstellung eines Vorlesungsverzeichnisses
VorlesungsverzeichnisBeispiel.java:
//...
// If there are no arguments, emit an appropriate usage message.
if (args.length == 0) {
System.out.println("Enter a list of file paths or URIs that have content
like this:");
try {
Resource resource =
resourceSet.createResource(URI.createURI("http://My.vorlesungsverzeichnis"));
Verzeichnis root =
VorlesungsverzeichnisFactory.eINSTANCE.createVerzeichnis();
resource.getContents().add(root);
resource.save(System.out, null);
//Ab hier eigener Code
}
Taentzer
Modellgetriebene Softwareentwicklung
149
Erstellung eines eignen Modells
Beispiel: Erstellung eines Vorlesungsverzeichnisses
VorlesungsverzeichnisBeispiel.java:
//...
VorlesungsverzeichnisFactory vFactory =
VorlesungsverzeichnisFactory.eINSTANCE;
Verzeichnis vorlesungen = vFactory.createVerzeichnis();
//erstelle ein Raumverzeichnis
Raumverzeichnis verzeichnis = vFactory.createRaumverzeichnis();
vorlesungen.setRaumverzeichnis(verzeichnis);
//erstelle einen Raum
Raum r = vFactory.createHoersaal();
verzeichnis.getRaum().add(r);
//erstelle eine Vorlesung
Vorlesung vl1 = vFactory.createVorlesung();
vl1.setTag(Tag.DI);
vl1.setZeit(Zeit.ZWEI);
vorlesungen.getLv().add(vl1);
//...
Taentzer
Modellgetriebene Softwareentwicklung
150
Aufruf einer eignen Methode
Beispiel: Erstellung eines Vorlesungsverzeichnisses
VorlesungsverzeichnisBeispiel.java:
//...
Boolean c = true;
List<Raum> raeume = verzeichnis.getRaum();
for (Raum raum : raeume) {
c = c && raum.checkKonsistenz();
}
if (c)
System.out.println("Alle Räume sind konsistent belegt.");
else
System.out.println("Es gibt min. einen Raum mit inkonsistenter
Belegung.");
//...
Taentzer
Modellgetriebene Softwareentwicklung
151
Einlesen eines Instanzmodells
public static void main(String[] args) {
VorlesungsverzeichnisPackageImpl.init();
Resource.Factory.Registry.INSTANCE.getExtensionToFactoryMap().
put("vorlesungsverzeichnis", new XMIResourceFactoryImpl());
ResourceSet resourceSet = new ResourceSetImpl();
URI fileURI = URI.createURI("src/Test.vorlesungsverzeichnis");
Resource resource = resourceSet.getResource(fileURI, true);
Vorlesungsverzeichnis vz = (Vorlesungsverzeichnis)
resource.getContents().get(0);
}//main
Taentzer
Modellgetriebene Softwareentwicklung
152
JUnit
 Prinzipien:
 Zu jeder verfassten Klasse eine Testklasse entwerfen.
 Testcode und Anwendungscode sind strikt getrennt.
 Zum Schreiben von Tests werden lediglich benötigt:
 (TestSuite), TestCase, Assert
 Testsuiten dienen dazu, verschiedene Tests in einer
bestimmten Reihenfolge aufzurufen.
 Suiten können dazu verwendet werden,
verschiedene Klassen eines Paketes bzw. Projektes
auf einmal zu testen.
 Pakettests, Klassentests, Methodentests
public class VorlesungsverzeichnisTests extends
TestSuite { …
Taentzer
Modellgetriebene Softwareentwicklung
153
Definition von Testfällen
 Testfälle werden in einer normalen Klasse erstellt.
 Framework führt die definierten Testfälle aus.
 Jeder Test wird gekapselt:
 Es kann ein Fixture definiert werden. Damit wird ein
wiederverwendbares Testobjekt festgehalten.
 Verschiedene Tests nutzen keine gemeinsamen Daten im
Fixture. Jeder Test hat sein eigenes Fixture.
 Assert für den Vergleich von Soll- mit Istwerten
 Wir prüfen, ob das Ergebnis eines Tests ein bestimmtes
Ergebnis zurückliefert.
 Typische Assert-Methoden: assertTrue, assertEqual,
assertNull
Taentzer
Modellgetriebene Softwareentwicklung
154
Beispiel für einen Testfall
abstract class RaumTest
extends TestCase
public class SeminarraumTest extends RaumTest {
protected VorlesungsverzeichnisFactory vFactory =
VorlesungsverzeichnisFactory.eINSTANCE;
...
public static void main(String[] args) {
TestRunner.run(SeminarraumTest.class);
}
@Override
protected void setUp() throws Exception {
setFixture(vFactory.createSeminarraum());
}
public void testCheckConsistency() {
assertTrue(this.getFixture().checkKonsistenz());
}
...
Taentzer
Modellgetriebene Softwareentwicklung
155
Beispiel für einen zweiten Testfall
HoersaalTest.java:
public class HoersaalTest {
...
public void setUp() throws Exception{
VorlesungsverzeichnisFactory vFactory =
VorlesungsverzeichnisFactory.eINSTANCE;
Vorlesungen vorlesungen = vFactory.createVorlesungen();
Raumverzeichnis verzeichnis =
vFactory.createRaumverzeichnis();
vorlesungen.setRaumverzeichnis(verzeichnis);
Raum raum = vFactory.createHoersaal();
verzeichnis.getRaum().add(raum);
Vorlesung vl1 = vFactory.createVorlesung();
vl1.setTag(Tag.DI);
vl1.setZeit(Zeit.ZWEI);
vl1.setRaum(raum);
vorlesungen.getLv().add(vl1);
...
Taentzer
Modellgetriebene Softwareentwicklung
156
Beispiel für einen zweiten Testfall
HoersaalTest.java:
...
Vorlesung vl2 = vFactory.createVorlesung();
vl2.setTag(Tag.DI);
vl2.setZeit(Zeit.ZWEI);
vl2.setRaum(raum);
vorlesungen.getLv().add(vl2);
setFixture(raum);
}//setUp()
...
Taentzer
Modellgetriebene Softwareentwicklung
157
Beispiel für einen zweiten Testfall
RaumTest.java:
public void testCheckKonsistenz() {
// TODO: implement this operation test method
// Ensure that you remove @generated or mark it
@generated NOT
assertTrue(getFixture().checkKonsistenz());
}
Taentzer
Modellgetriebene Softwareentwicklung
158
Wie wird generiert?
Applikation
MDD-Infrastruktur
modelliert mit
Domänenspezif.
Modell
Domänenspezifische
Modellierungssprache
transformiert in
Generator
Code
Generator Templates
(Modell-zu-Code Tr. )
Wie wird dieser allgemeine Ansatz durch EMF konkretisiert?
Taentzer
Modellgetriebene Softwareentwicklung
159
Zusammenfassung
 Die Beziehung zwischen Modell und Code ist recht
direkt. Die Codegenerierung lässt sich gut durch das
EMF-Modell steuern.
 Der generierte Code hat eine gute Qualität:
 Java-Konventionen werden eingehalten.
 Code Smells werden vermieden, wo möglich.
 Passende Design-Patterns werden verwendet.
 Generierter Code kann durch handgeschriebenen so
erweitert werden, dass der Generator diesen nicht
überschreibt.
Taentzer
Modellgetriebene Softwareentwicklung
160
Herunterladen