Grundlagen der modellgetriebenen Softwareentwicklung Teil 4

Werbung
Grundlagen der modellgetriebenen
Softwareentwicklung
Teil 4: Modelltransformation
Prof. Dr. H. Drachenfels
Hochschule Konstanz
Version 10.0
26.1.2017
Modelltransformation: Klassifikation
Modell-zu-Modell-Transformation (M2M):
• Abbildung eines Quellmodells auf ein Zielmodell
• Formulierung der Transformationsvorschriften auf der Ebene der Metamodelle
• beide Metamodelle müssen das gleiche Meta-Metamodell haben
erlaubt mehrstufige Transformationen
erlaubt Anpassung von Modellen an neue DSL- und Metamodell-Versionen
(Model Refactoring, Model Migration)
Modell-zu-Text-Transformation (M2T):
• Abbildung eines Quellmodells direkt auf eine
textuelle Repräsentation des Zielmodells
• für die Abbildung wird kein Ziel-Metamodell und
damit auch kein gemeinsames Meta-Metamodell benötigt
M2T ist der übliche Weg bei der Software-Generierung
Prof. Dr. H. Drachenfels
Hochschule Konstanz
Grundlagen der modellgetriebenen Softwareentwicklung
4-1
Modelltransformation: prinzipieller Ablauf
Frontend
Quellmodell
(konkreteSyntax)
Instanz des
Quell-Metamodells
abstrahieren
Quellmodell
(abstrakte Syntax)
Transformationsvorschriften
API
transformieren
Application
Programming
Interface
Zielmodell
(abstrakte Syntax)
Zielmodell
(konkreteSyntax)
Instanz des
Ziel-Metamodells
konkretisieren
Backend
Prof. Dr. H. Drachenfels
Hochschule Konstanz
4-2
Grundlagen der modellgetriebenen Softwareentwicklung
Modelltransformation: vereinfachter Ablauf
Software-Generierung mit Templates (Modell-zu-Text-Transformation):
Frontend
Modell
(konkreteSyntax)
abstrahieren
Modell
(abstrakte Syntax)
Templates
Generierter Code
(konkreteSyntax)
Prof. Dr. H. Drachenfels
Hochschule Konstanz
API
generieren
Die Transformationsvorschriften
liegen als Templates vor,
d.h. als Code in konkreter Syntax,
der an besonders markierten Stellen
vom Generator vervollständigt wird.
Grundlagen der modellgetriebenen Softwareentwicklung
4-3
M2M: Eigenschaften
Aspekte für die Klassifikation von M2M-Transformationen:
• Kardinalität
1:1
aus einem Quellmodell entsteht ein Zielmodell
M:1
Zusammenfassung mehrere Quellmodelle zu einem Zielmodell
• Richtung
unidirektional
bidirektional
Quellmodell wird in Zielmodell überführt
wechselseitige Synchronisation von Quell- und Zielmodell
• Metamodell
einheitlich
verschieden
Refactoring von Modellen
echte Transformation (Meta-Metamodell ist einheitlich)
• Modellzugriff
erhaltend
modifizierend
Quellmodell wird nur gelesen, Zielmodell ist neue Instanz
Quellmodell wird geändert, z.B. beim Refactoring
Standardfall: unidirektionale, erhaltende 1:1-Transformation mit verschiedenem Metamodell
Prof. Dr. H. Drachenfels
Hochschule Konstanz
Grundlagen der modellgetriebenen Softwareentwicklung
4-4
M2T: Eigenschaften
Klassifikation von M2T-Transformationen:
• Spezialgenerator mit interner Abbildungsvorschrift
Der Generator gibt die Abbildung von Modellen auf Text fest vor.
Änderung der Abbildung nur durch Umprogrammieren des Generators
kein offen gelegtes API für den abstrakten Syntaxbaum
Beispiel: Stub-Generatoren für den Fernaufruf von Methoden in verteilten Systemen
• universeller Generator mit externer Abbildungsvorschrift
Die Abbildung von Modellen auf Text ist in Templates ausgelagert.
Änderung der Abbildung durch Verwendung anderer Templates
offen gelegtes API für den abstrakten Syntaxbaum
Templates werden mit einer Templatesprache formuliert
Prof. Dr. H. Drachenfels
Hochschule Konstanz
Grundlagen der modellgetriebenen Softwareentwicklung
4-5
M2T: Modell – Programm – Plattform
Modelle
<<generiert aus>>
Generierter Code
Manueller Code
Programm
<<benötigt>>
Plattform
Prof. Dr. H. Drachenfels
Hochschule Konstanz
• Im Modellen enthaltene
Aspekte eines Programms
werden durch Generierung
automatisch in Code überführt.
(verhindert Inkonsistenzen
durch vertikale Redundanz)
• Im Modell nicht enthaltene
Aspekte eines Programms
werden manuell codiert.
(zwischen generiertem Code
und manuell erstelltem Code
bestehen Abhängigkeiten,
im Extremfall bis hin zu
völliger Durchmischung)
• Programme werden für eine
Plattform erstellt.
Grundlagen der modellgetriebenen Softwareentwicklung
4-6
Plattform: Begriffsdefinition
klassischer Plattform-Begriff
Plattform
von einer Software als gegeben vorausgesetzte Umgebung, typischerweise
bestehend aus Hardware-Architektur, Betriebsystem und Laufzeitbibliotheken
Eine Software wird dementsprechend oft als plattform-unabhängig bezeichnet, wenn sie
auf unterschiedlichen Betriebssystemen und / oder Hardwarearchitekturen lauffähig ist.
vereinfachter Plattform-Begriff
(hinreichend im Umfeld Modellgetriebene Softwareentwicklung)
Software-Plattform
System von APIs (Application Programming Interfaces),
das eine Anwendung benötigt, um ablauffähig zu sein.
Die Bezeichnungen Plattform und Anwendung sind dabei relativ. Eine Anwendung kann
ihrerseits wieder Plattform für Code einer nächst höheren Abstraktionsebene sein.
Zu den APIs können Systemaufrufe des Betriebssystems, die Schnittstellen von
Standardsoftware (z.B. Datenbanksystem), die Laufzeitbibliothek der Programmiersprache,
domänenspezifische Frameworks usw. gehören.
Prof. Dr. H. Drachenfels
Hochschule Konstanz
Grundlagen der modellgetriebenen Softwareentwicklung
4-7
Plattform: Abstraktionsebenen
Unterscheidung von Plattformen nach Abstraktionsebene:
• elementare Software-Plattform
nur Betriebssystem mit etwas Standardsoftware und der Laufzeitbibliothek der
Programmiersprache
Art des generierten Codes:
normaler Programmcode
Umfang des generierten Codes:
vergleichsweise groß
Generierung erlaubt es, statt komplizierter Abstraktionsmechanismen
eine einfache Softwarearchitektur mit viel horizontaler Redundanz zu wählen.
• komplexe Software-Plattform
Verwendung domänenspezifischer Frameworks
Art des generierten Codes:
vorrangig Konfiguration
Umfang des generierten Codes:
vergleichsweise gering
Generierung vereinfacht die Konfiguration der Frameworks
und erleichtert die Migration auf andere Frameworks
Prof. Dr. H. Drachenfels
Hochschule Konstanz
Grundlagen der modellgetriebenen Softwareentwicklung
4-8
Plattform: Verwendungszweck
Unterscheidung von Plattformen nach Verwendungszweck:
• Zielplattform: darauf soll das fertige Programm letztendlich produktiv laufen
• Entwicklungs- und Testplattform: vorläufiger Ersatz für die Zielplattform
Gründe für eine Entwicklungs- und Testplattform:
• Zielplattform wird auch erst entwickelt
Abgrenzung zwischen Anwendungs- und Plattformcode dann mitunter unscharf
• Zielplattform nur eingeschränkt verfügbar
z.B. weil Hardware oder Softwarelizenzen nur in geringer Stückzahl vorhanden sind
• Zielplattform mühsam zu benutzen
z.B. lange Compile-Load-Run-Zyklen bei Spezialhardware
oder eingeschränkte Debug-Möglichkeiten
• Zielplattform ungeeignet für Komponententests (Unit-Tests)
z.B. weil ein Testframework verwendet werden soll
Prof. Dr. H. Drachenfels
Hochschule Konstanz
Grundlagen der modellgetriebenen Softwareentwicklung
4-9
Generierter und manueller Code: Abhängigkeiten
• Generierter und manueller Code in getrennten Übersetzungseinheiten:
Abhängigkeiten entstehen durch die wechselseitige Verwendung von Namen
(z.B. Variablenzugriffe, Methodenaufrufe, Typinstanzierungen, ...)
kein prinzipieller Unterschied zu den Abhängigkeiten vom Plattform-Code
zur Entschärfung der Abhängigkeiten allgemeine Regeln zur losen Kopplung beachten
• Generierter und manueller Code in einer Übersetzungseinheit gemischt:
Abhängigkeiten entstehen durch die Einbettung
(z.B. in generierter Methode Implementierung ganz oder teilweise manuell, ...)
manuelle Teile gehen bei erneutem Generierungslauf verloren,
wenn sie nicht besonders geschützt werden
deshalb vermischten Code möglichst vermeiden
Prof. Dr. H. Drachenfels
Hochschule Konstanz
Grundlagen der modellgetriebenen Softwareentwicklung
4-10
Generierter und manueller Code: Präprozessortechnik
Präprozessortechnik trennt Codeanteile auf Dateiebene
• generierten und manuellen Code in getrennten Dateien erstellen
und per Präprozessor zu übersetzbarem Code kombinieren
z.B. Einbettung manuellen Codes in generierten Code mittels C++-Präprozessor
(umgekehrte Einbettung von generiertem in manuellen Code funktioniert analog):
// GenerierteKlasse.cpp
#include "GenerierteKlasse.h"
...
void GenerierteKlasse::GenerierteMethode() {
#include "manuelle_methodenimplementierung.h"
}
Include-Datei bleibt bei Neugenerierung erhalten
...
und kann in Versionsverwaltung gepflegt werden
• Dateiaufteilung führt tendenziell zu schwer lesbarem unübersichtlichem Code,
erleichtert aber die Versions- und Konfigurationsverwaltung
Prof. Dr. H. Drachenfels
Hochschule Konstanz
Grundlagen der modellgetriebenen Softwareentwicklung
4-11
Generierter und manueller Code: Entwurfsmuster
Objektorientierte Entwurfsmuster trennen Codeanteile auf Klassenebene
• abstrakte Oberklasse (oder ein Interface) generieren und
abstrakte Methoden in konkreter Unterklasse manuell implementieren
(oder auch umgekehrt)
// GenerierteKlasse.java
public abstract class GenerierteKlasse {
...
public abstract void generierteMethode();
...
Unterklasse bleibt bei Neugenerierung der Oberklasse erhalten
}
und kann separat in Versionsverwaltung gepflegt werden
// ManuelleKlasse.java
public final class ManuelleKlasse extends GenerierteKlasse {
public void generierteMethode() {
... // Implementierung
}
}
komplexere Vermischungen von generiertem und manuellem Code
können mit dem Template-Entwurfsmuster entflochten werden
Prof. Dr. H. Drachenfels
Hochschule Konstanz
Grundlagen der modellgetriebenen Softwareentwicklung
4-12
Generierter und manueller Code: geschützte Bereiche
Geschützte Bereiche erlauben Einbettung von manuellem in generierten Code
• im generierten Code den manuellen Code mit speziellen generatorspezifischen
Kommentaren markieren, damit er bei Neugenerierungen übernommen wird
// GenerierteKlasse.java
eindeutige Kennung
public class GenerierteKlasse {
...
des Modellelements
void generierteMethode() {
// PROTECTED REGION ID(123456) START
... // manueller Code
// PROTECTED REGION END
}
...
}
• auch geschützter manueller Code kann bei Neugenerierungen verloren gehen
z.B. kann nach dem Umbenennen oder Löschen von Modellelementen
der geschützte manuelle Code eventuell nicht mehr zugeordnet werden
• geschützte Bereiche erschweren die Versions- und Konfigurationsverwaltung
Prof. Dr. H. Drachenfels
Hochschule Konstanz
Grundlagen der modellgetriebenen Softwareentwicklung
4-13
Generierter und manueller Code: Templates
Codetemplates erlauben Einbettung von generiertem in manuellen Code
• in manuellen Code spezielle generatorspezifische Anweisungen einbetten,
die den generierten Code einfügen
// ${entity.name}.java
public class ${entity.name} extends ManuelleKlasse {
...
#foreach($attribute in $entity.attributes)
public ${attribute.type} get${attribute.name}() {
return this.${attribute.name};
}
private ${attribute.type} ${attribute.name};
#end
...
}
• aktuell die bevorzugte Technik für das Mischen der beiden Codeanteile
Prof. Dr. H. Drachenfels
Hochschule Konstanz
Grundlagen der modellgetriebenen Softwareentwicklung
4-14
Generierter und manueller Code: Modellanreicherung
Modellanreicherung erlaubt Einbettung von manuellem Code auf Modellebene
• manuellen Code in das Modell einbetten statt in den daraus generierten Code
z.B. beim Scanner-Generator flex und dem Parser-Generator bison
wird die Grammatikspezifikation um C-Code angereichert
• vermeidet im Vergleich zu geschützten Bereichen die Probleme
mit der Versions- und Konfigurationsverwaltung
• aber führt tendenziell zu schwer lesbaren unübersichtlichen Modellen
• beeinträchtigt die Plattformunabhängigkeit des Modells
durch den eingebetteten Code legt ein angereichertes Modell bereits
die Programmiersprache und einige benötigte APIs fest
Prof. Dr. H. Drachenfels
Hochschule Konstanz
Grundlagen der modellgetriebenen Softwareentwicklung
4-15
Transformationssprachen
Templatesprachen beschreiben die Einbettung von Modellelementen in Zielcode
• bieten Sprachmittel für den Zugriff auf den abstrakten Syntaxbaum des Modells
• erlauben auch Transformationen in nicht-formale Sprachen
• Templates ähneln weitgehend dem zu generierenden Code
und lassen sich deshalb leicht aus Beispielcode ableiten
Beispiele: VTL (Velocity Template Language), StringTemplate
M2M-Sprachen (Relationssprachen) beschreiben Relationen zwischen
Elementen der Quellsprache und Elementen der Zielsprache
• erlauben das Formulieren von Regeln für die Abbildung von
Knoten des Quell-AST auf Knoten des Ziel-AST
• verlangen in der Regel eine gemeinsames Meta-Metamodell für Quelle und Ziel
Beispiele: ATL (Atlas Transformation Language), XSLT
Prof. Dr. H. Drachenfels
Hochschule Konstanz
Grundlagen der modellgetriebenen Softwareentwicklung
4-16
Templatesprachen: VTL
VTL ist die Templatesprache des Apache Velocity Projekts.
• Referenzen erlauben den Zugriff auf Java-Objekte eines Modells:
$name.property
$name.method(Parameter)
Die Objekte werden Java-seitig in Form einer Hashtabelle bereitgestellt.
Schlüssel ist ein String name, der dann im Template als $name angegeben wird.
Properties werden auf getter-Methoden abgebildet.
Modellzugriffe liefern als Ergebnis immer einen String.
• Iteration über Modellelemente:
#foreach( $i in Referenz ) ... #end
• Bedingte Template-Abschnitte:
#if( Bedingung ) ... #elseif( Bedingung ) ... #else ... #end
• Aufteilung und Gliederung von Templates:
unter anderem mit #include(...), #parse(...), #macro(...) ... #end
Prof. Dr. H. Drachenfels
Hochschule Konstanz
Grundlagen der modellgetriebenen Softwareentwicklung
4-17
Templatesprachen: StringTemplate
StringTemplate ist die Templatesprache des ANTLR Parser Generators,
ist aber unabhängig von ANTLR verwendbar.
• Referenzen erlauben den Zugriff auf Java-Objekte eines Modells:
<attribute.property>
Attribute sind sozusagen Parameter von Templates und werden Java-seitig
mit Objekten des Modells initialisiert.
Properties werden auf getter-Methoden abgebildet.
• funktionaler Stil für die Iteration über Modellelemente:
<attribute.property:Template()>
<attribute.property:Template(); separator=”…”>
Auf alle Elemente der Property das angegebene Template anwenden.
• Bedingte Template-Abschnitte:
<if( Bedingung )> ... <elseif( Bedingung )> ... <else> ... <end>
Prof. Dr. H. Drachenfels
Hochschule Konstanz
Grundlagen der modellgetriebenen Softwareentwicklung
4-18
Beispiel: Codegenerierung für Joi (1)
Die Sprache Joi (Java Objects by Interface) erlaubt die Modellierung von
"Komponenten im Kleinen", d.h. von Klassen,
• die nicht per Vererbung erweitert werden können
• deren Instanzen nur per Fabrikmethode erzeugt werden können
• deren Instanzen nur per Schnittstellenreferenz benutzt werden können
Konkrete Syntax (vereinfacht) in EBNF:
"component" Name "implements" Schnittstelle {"," Schnittstelle} "{"
{Methodenimplementierung}
{Datenfeld}
"}"
Abstrakte Syntax (vereinfacht) als Metamodell:
Prof. Dr. H. Drachenfels
Hochschule Konstanz
Grundlagen der modellgetriebenen Softwareentwicklung
4-19
Beispiel: Codegenerierung für Joi (2)
• Beispielmodell HelloWorld.joi (konkrete Syntax):
component HelloWorld implements Hello, Goodbye {
@method
void sayHello( ) {
Die Schnittstellen werden ganz normal
System.out.println("Hello world!");
in Java programmiert:
hello = true;
public interface Hello {
}
void sayHello();
@end
}
@method
public interface Goodbye {
void sayGoodbye( ) {
void sayGoodbye();
if (!hello) sayHello();
System.out.println("Goodbye world!");
}
}
@end
@field
boolean hello;
@end
}
Prof. Dr. H. Drachenfels
Hochschule Konstanz
Die Methodenimplementierungen und
Felddefinitionen sind als manueller
Java-Code in das Modell eingebettet
(Modellanreicherung)
4-20
Grundlagen der modellgetriebenen Softwareentwicklung
Beispiel: Codegenerierung für Joi (3)
• Beispielmodell als UML Objektdiagramm (abstrakte Syntax)
:JoiMethod
code = "void sayHello( ) { ... }"
:JoiMethod
:JoiInterface
name = "Hello"
:JoiInterface
code = "void sayGoodbye( ) { ... }"
:JoiComponent
name = "HelloWorld"
name = "Goodbye"
:JoiField
code = "boolean hello;"
Prof. Dr. H. Drachenfels
Hochschule Konstanz
Grundlagen der modellgetriebenen Softwareentwicklung
4-21
Beispiel: Codegenerierung für Joi (4)
• Beispielmodell mit manuellem Java-Code instanziiert (abstrakte Syntax):
JoiComponent c = new JoiComponent(
bei Verwendung einer DSL
"HelloWorld",
übernimmt der Parser die
new JoiInterface[] {
Instanziierung
new JoiInterface("Hello"),
new JoiInterface("Goodbye")
},
new JoiMethod[] {
new JoiMethod("void sayHello( ) { ... }"),
new JoiMethod("void sayGoodbye( ) { ... }")
},
new JoiField[] {
new JoiField("boolean hello;")
}
);
Prof. Dr. H. Drachenfels
Hochschule Konstanz
4-22
Grundlagen der modellgetriebenen Softwareentwicklung
Beispiel: Codegenerierung für Joi (5)
• zu generierende Java-Realisierung HelloWorld.java des Beispielmodells:
public final class HelloWorld {
private HelloWorld() { }
public static Implementation getInstance() {
return new Implementation();
}
Fabrikmethode
private static final
class Implementation implements Hello, Goodbye {
public void sayHello( ) { ... }
gekapselte Implementierung
public void sayGoodbye( ) { ... }
private boolean hello;
}
}
Prof. Dr. H. Drachenfels
Hochschule Konstanz
Grundlagen der modellgetriebenen Softwareentwicklung
4-23
Beispiel: Codegenerierung für Joi mit Velocity (1)
• Transformationstemplate joi2java.vtl:
## joi2java.vtl
public final class $component.name {
private ${component.name}() { }
public static Implementaion getInstance() {
Fabrikmethode
return new Implementation();
}
private static final class Implementation implements
#foreach($i in $component.interfaces)
Schnittstellen
#if($velocityCount > 1) , #end $i.name #end {
#foreach($m in $component.methods)
Methodenimplementierungen
public $m.code
#end
#foreach($f in $component.fields)
private $f.code
Felddefinitionen
#end
}
}
Prof. Dr. H. Drachenfels
Hochschule Konstanz
Grundlagen der modellgetriebenen Softwareentwicklung
4-24
Beispiel: Codegenerierung für Joi mit Velocity (2)
• Codegenerator JoiToJava.java:
... // import-Anweisungen für org.apache.velocity- und java.io-Klassen
public final class JoiToJava {
private JoiToJava() { }
public static void main(String[] args) throws Exception {
// AST für HelloWorld instanziieren:
JoiComponent ast = ...
// Template anwenden:
Writer writer = new OutputStreamWriter(System.out);
VelocityContext context = new VelocityContext();
context.put("component", ast);
VelocityEngine velocity = new VelocityEngine();
velocity.init();
velocity.mergeTemplate("joi2java.vtl", context, writer);
writer.close();
}
}
Prof. Dr. H. Drachenfels
Hochschule Konstanz
Grundlagen der modellgetriebenen Softwareentwicklung
4-25
Beispiel: Codegenerierung für Joi mit Stringtemplate (1)
• Transformationstemplate joi2java.stg:
component(c) ::= <<
public final class <c.name> {
private <c.name>() { }
public static Implementation getInstance() {
return new Implementation();
}
private static final class Implementation
implements <c.interfaces:interface(); separator=", "> {
<c.methods:method(); separator="\n\n">
<c.fields:field(); separator="\n">
}
}
wendet das Template field (siehe nächste Seite)
>>
auf alle fields der Komponente c an,
...
nach jedem field wird ein Zeilenwechsel eingefügt
Prof. Dr. H. Drachenfels
Hochschule Konstanz
Grundlagen der modellgetriebenen Softwareentwicklung
4-26
Beispiel: Codegenerierung für Joi mit Stringtemplate (2)
...
Schnittstelle
interface(i) ::= "<i.name>"
method(m) ::= <<
public <m.code>
Methodenimplementierung
>>
field(f) ::= <<
private <f.code>
Felddefinition
>>
• Codegenerator:
...
JoiComponent ast = ... // AST für HelloWorld instanziieren
ST templ = new STGroupFile("joi2java.stg")
.getInstanceOf("component");
templ.add("c", ast);
System.out.println(templ.render());
...
Prof. Dr. H. Drachenfels
Hochschule Konstanz
Grundlagen der modellgetriebenen Softwareentwicklung
4-27
M2M-Sprachen: XSLT
XSLT ist eine M2M-Sprache für die Umwandlung von XML-Dokumenten in andere
XML-Dokumente (oder auch sonstige Textformate).
• Templates werden auf Knoten im DOM-Tree angewendet:
<xsl:template match="XPath-Ausdruck"> ... </xsl:template>
• funktionaler Stil für die Iteration über Kindknoten im DOM-Tree:
<apply-templates/>
XPath ist eine Sprache für die Navigation in DOM-Trees.
• XPath-Ausdrücke bestehen aus einer durch Schrägstriche '/' getrennten
Folge von Lokalisierungsschritten:
axis::nodetest[predicate]
Achsen sind u.a. self
descendant
ancestor
following
preceeding
Prof. Dr. H. Drachenfels
Hochschule Konstanz
der aktuelle Knoten
alle Knoten unterhalb im Baum
alle Knoten oberhalb im Baum
alle Knoten rechts im Baum = unterhalb im Dokument
alle Knoten links im Baum = oberhalb im Dokument
4-28
Grundlagen der modellgetriebenen Softwareentwicklung
Beispiel: M2M-Transformation für Joi (1)
• M2M-Transformationsregeln werden auf Ebene der Metamodelle fomuliert:
Quellmetamodell für Joi
Zielmetamodell für die Java-Realisierung von Joi
JavaMethod
JavaInterface
+name : String
JavaClass
JavaField
Prof. Dr. H. Drachenfels
Hochschule Konstanz
Grundlagen der modellgetriebenen Softwareentwicklung
4-29
Beispiel: M2M-Transformation für Joi (2)
• Beispiel-Quellmodell in abstrakter Syntax
:JoiMethod
code = "void sayHello( ) { ... }"
:JoiMethod
:JoiInterface
name = "Hello"
:JoiInterface
code = "void sayGoodbye( ) { ... }"
:JoiComponent
name = "HelloWorld"
name = "Goodbye"
:JoiField
code = "boolean hello;"
Prof. Dr. H. Drachenfels
Hochschule Konstanz
Grundlagen der modellgetriebenen Softwareentwicklung
4-30
Beispiel: M2M-Transformation für Joi (3)
• Beispielmodell mit java.beans.XMLEncoder serialisiert (abstrakte Syntax):
<?xml version="1.0" encoding="UTF-8"?>
<java version="1.8.0_66" class="java.beans.XMLDecoder">
<object class="JoiComponent">
<string>HelloWorld</string>
<array class="JoiInterface" length="2">
<void index="0">
<object class="JoiInterface">
<string>Hello</string>
</object>
</void>
<void index="1">
<object class="JoiInterface">
<string>Goodbye</string>
</object>
</void>
</array>
...
Prof. Dr. H. Drachenfels
Hochschule Konstanz
Grundlagen der modellgetriebenen Softwareentwicklung
4-31
Beispiel: M2M-Transformation für Joi (4)
...
<array class="JoiMethod" length="2">
<void index="0">
<object class="JoiMethod">
<string>void sayHello( ) { ... }</string>
</object>
</void>
<void index="1">
<object class="JoiMethod">
<string>void sayGoodbye( ) { ... }</string>
</object>
</void>
</array>
<array class="JoiField" length="1">
<void index="0">
<object class="JoiField">
<string>boolean hello;</string>
</object>
</void>
</array>
</object>
</java>
Prof. Dr. H. Drachenfels
Hochschule Konstanz
4-32
Grundlagen der modellgetriebenen Softwareentwicklung
Beispiel: M2M-Transformation für Joi (5)
• Beispiel-Zielmodell in abstrakter Syntax
:JavaMethod
modifier = "private"
code = "HelloWorld( ) { }"
:JavaClass
modifier = "public final"
name = "HelloWorld"
e
:JavaMethod
modifier = "public static"
code = "Implementation getInstance( ) {...}"
:JavaMethod
:JavaInterface
name = "Hello"
:JavaClass
modifier = "private static final"
modifier = "public"
code = "void sayHello( ) {...}"
name = "Implementation"
:JavaInterface
name = "Goodbye"
:JavaMethod
modifier = "public"
code = "void sayGoodbye( ) {...}"
:JavaField
modifier = "private"
code = "boolean hello;"
Prof. Dr. H. Drachenfels
Hochschule Konstanz
Grundlagen der modellgetriebenen Softwareentwicklung
4-33
Beispiel: M2M-Transformation für Joi (6)
• Beispiel-Zielmodell mit java.beans.XMLEncoder serialisiert (abstrakte Syntax):
<?xml version="1.0" encoding="UTF-8"?>
<java version="1.8.0_66" class="java.beans.XMLDecoder">
<object class="JavaClass">
<string>public final</string><string>HelloWorld</string>
<array class="JavaInterface" length="0"/>
<array class="JavaMethod" length="2">
<void index="0">
<object class="JavaMethod">
<string>private</string><string>HelloWorld( ) { }</string>
</object>
</void>
<void index="1">
<object class="JavaMethod">
<string>public static</string>
<string>Implementation getInstance( ) { ... }</string>
</object>
</void>
</array>
<array class="JavaField" length="0"/>
...
Prof. Dr. H. Drachenfels
Hochschule Konstanz
Grundlagen der modellgetriebenen Softwareentwicklung
4-34
Beispiel: M2M-Transformation für Joi (7)
...
<array class="JavaClass" length="1">
<void index="0">
<object class="JavaClass">
<string>private static final</string><string>Implementation</string>
<array class="JavaInterface" length="2"> ... </array>
<array class="JavaMethod" length="2">
<void index="0">
<object class="JavaMethod">
<string>public</string><string>void sayHello( ) { ... }</string>
</object>
</void>
...
</array>
<array class="JavaField" length="1"> ... </array>
<array class="JavaClass" length="0"/>
</object>
</void>
</array>
</object>
</java>
Prof. Dr. H. Drachenfels
Hochschule Konstanz
Grundlagen der modellgetriebenen Softwareentwicklung
4-35
Beispiel: M2M-Transformation für Joi mit XSLT (1)
• die XML-Serialisierung des Quell- und Zielmodells ermöglicht eine
M2M-Transformation mittels XSLT
• XSLT-Transformation am besten in mehrere Schritte aufteilen,
beim Joi-Beispiel z.B. wie folgt:
schritt1.xsl Klassennamen des Quellmetamodells JoiXXX durch
Klassennamen des Zielmetamodells JavaXXX ersetzen
schritt2.xsl überall das modifier-Attribut einfügen
schritt3.xsl Struktur mit äußerer Komponenten-Klasse und
eingebetter Implementation-Klasse erzeugen
Prof. Dr. H. Drachenfels
Hochschule Konstanz
Grundlagen der modellgetriebenen Softwareentwicklung
4-36
Beispiel: M2M-Transformation für Joi mit XSLT (2)
• XSLT-Transformation schritt1.xsl:
<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="node()|@*">
<xsl:copy><xsl:apply-templates select="node()|@*"/></xsl:copy>
</xsl:template>
<xsl:template match="@class[.='JoiComponent']">
<xsl:attribute name="class">JavaClass</xsl:attribute>
</xsl:template>
<xsl:template match="@class[.='JoiInterface']">
<xsl:attribute name="class">JavaInterface</xsl:attribute>
</xsl:template>
<xsl:template match="@class[.='JoiField']">
<xsl:attribute name="class">JavaField</xsl:attribute>
</xsl:template>
<xsl:template match="@class[.='JoiMethod']">
<xsl:attribute name="class">JavaMethod</xsl:attribute>
</xsl:template>
</xsl:stylesheet>
Prof. Dr. H. Drachenfels
Hochschule Konstanz
Grundlagen der modellgetriebenen Softwareentwicklung
4-37
Beispiel: M2M-Transformation für Joi mit XSLT (3)
• XSLT-Transformation schritt2.xsl (graue Teile wie schritt1.xsl):
...
<xsl:template match="string">
<xsl:choose>
<xsl:when test="../@class='JavaClass'">
<string></string>
<xsl:copy-of select="." />
</xsl:when>
<xsl:when test="../@class='JavaInterface'">
<xsl:copy-of select="." />
</xsl:when>
<xsl:when test="../@class='JavaMethod'">
<string>public</string>
<xsl:copy-of select="." />
</xsl:when>
<xsl:when test="../@class='JavaField'">
<string>private</string>
<xsl:copy-of select="." />
</xsl:when>
</xsl:choose>
</xsl:template>
...
Prof. Dr. H. Drachenfels
Hochschule Konstanz
Grundlagen der modellgetriebenen Softwareentwicklung
4-38
Beispiel: M2M-Transformation für Joi mit XSLT (4)
• XSLT-Transformation schritt2.xsl (graue Teile wie schritt1.xsl):
...
<xsl:template match="/java/object">
Name der Komponente
<object class="JavaClass">
<string>public final</string>
<string><xsl:value-of select="string[2]" /></string>
<array class="JavaInterface" length="0" />
<array class="JavaMethod" length="2">
<void index="0">
<object class="JavaMethod">
<string>private</string>
<string><xsl:value-of select="string[2]" />( ) { }</string>
</object>
</void>
<void index="1">
<object class=" JavaMethod">
<string>public static</string>
<string>Implementation getInstance( ) { ... }</string>
</object>
</void>
</array> ...
Prof. Dr. H. Drachenfels
Hochschule Konstanz
Grundlagen der modellgetriebenen Softwareentwicklung
4-39
Beispiel: M2M-Transformation für Joi mit XSLT (5)
...
<array class="JavaField" length="0" />
<array class="JavaClass" length="1">
<void index="0">
<object class="JavaClass">
<string>private static final</string>
<string>Implementation</string>
Interfaces, Methoden und
Felder der Komponente
<xsl:copy-of select="array" />
<array class="JavaClass" length="0" />
</object>
</void>
</array>
</object>
</xsl:template>
...
Prof. Dr. H. Drachenfels
Hochschule Konstanz
Grundlagen der modellgetriebenen Softwareentwicklung
4-40
Beispiel: M2M-Transformation für Joi mit XSLT (6)
• Transformator JoiToJava.java:
... // import-Anweisungen für javax.xml.transform-Klassen usw.
public final class JoiToJava {
private JoiToJava() { }
public static void main(String[] args) throws Exception {
Source[] xslt = new Source[] {
new StreamSource(Files.newInputStream(Paths.get("schritt1.xsl"))),
new StreamSource(Files.newInputStream(Paths.get("schritt2.xsl"))),
new StreamSource(Files.newInputStream(Paths.get("schritt3.xsl")))
};
StreamSource source = ... // XML-serialisiertes Quellmodell
StreamResult result = ...
TransformerFactory factory = TransformerFactory.newInstance();
for (Source transformation: xslt) {
factory.newTransformer(transformation).transform(source, result);
... // result als source für nächsten Schritt setzen
}
... // XML-serialisiertes Zielmodell ausgeben
}
Prof. Dr. H. Drachenfels
Hochschule Konstanz
Grundlagen der modellgetriebenen Softwareentwicklung
4-41
Beispiel: M2M-Transformation für Joi mit ATL (1)
• ATL Transformationsregeln Joi2Java.atl:
module Joi2Java;
create OUT: Java from IN: Joi;
-- Namen der Metamodelle
rule JoiComponent2Class { -- "Matched Rule" für Komponenten
from
f : Joi!JoiComponent
to
t : Java!Class (
modifier <- 'public final ',
name <- f.name,
methods <- Sequence{tc,tf},
classes <- Sequence{ti}
),
...
Prof. Dr. H. Drachenfels
Hochschule Konstanz
Grundlagen der modellgetriebenen Softwareentwicklung
4-42
Beispiel: M2M-Transformation mit ATL (2)
-- Fortsetzung "Matched Rule" für Komponenten
tc : Java!Method (
modifier <- 'private',
code <- f.name + '( ) { }'
),
tf : Java!Method (
modifier <- 'public',
code <- 'Implementation getInstance( ) { return new Implementation( ); }'
),
ti : Java!Class (
modifier <- 'private static final',
name <- 'Implementation ',
interfaces <- f.interfaces,
methods <- f.methods,
fields <- f.fields
)
}
...
Prof. Dr. H. Drachenfels
Hochschule Konstanz
Grundlagen der modellgetriebenen Softwareentwicklung
4-43
Beispiel: M2M-Transformation mit ATL (3)
...
rule JoiInterface2Interface {
from
f : Joi!JoiInterface
to
t : Java!Interface (
name <- f.name
)
}
rule JoiMethod2Method {
from
f : Joi!JoiMethod
to
t : Java!Method (
modifier <- 'public',
code <- f.code
)
}
...
Prof. Dr. H. Drachenfels
Hochschule Konstanz
...
rule JoiField2Field {
from
f : Joi!JoiField
to
t : Java!Field (
modifier <- 'private',
code <- f.code
)
}
Grundlagen der modellgetriebenen Softwareentwicklung
4-44
Generieren oder manuell erstellen?
Grundsätzlich alles generieren, was sich aus dem Modell herleiten lässt
und in der gewählten Plattform nicht bereits abgedeckt ist
• aber Modell nicht um der Generierung willen aufblähen
bei Modellen auf klar umrissene Domänen und auf Plattformunabhängigkeit achten
• entweder generieren, oder manuell erstellen
generierten Code möglichst nicht manuell nachbearbeiten
• gut lesbaren Code generieren
in der Regel die gleichen Qualitätskriterien erfüllen wie bei manuell erstelltem Code,
z.B. Formatierungsregeln einhalten, Entwurfsmuster einsetzen
• nicht nur für Zielplattform, sondern auch für Testplattform(en) generieren
z.B. Mocks und Dummies für Komponententests generieren
• nicht nur Programmcode generieren
z.B. Dokumentation generieren,
z.B. Skripte für Buildprozess, Deployment, Datenmigration usw. generieren
Prof. Dr. H. Drachenfels
Hochschule Konstanz
Grundlagen der modellgetriebenen Softwareentwicklung
4-45
Generieren oder wiederverwenden?
Grundsätzlich nichts generieren, was es bereits fertig zum wiederverwenden gibt
• wiederverwendeten Code in Plattform integrieren
bei Wiederverwendung von Komponenten braucht oft nur noch
einfacher Glue-Code generiert zu werden
• aber Plattform auch nicht zu sehr aufblähen
oft wird nur ein Bruchteil der Funktionalität einer wiederverwendeten Komponente
tatsächlich genutzt und der Rest als toter Code mitgeschleppt (Rattenschwanzeffekt)
• auch Generierungen wiederverwenden, d.h. die Generierung kaskadieren
z.B. aus dem Modell einer verteilten Anwendung
im 1. Schritt IDL-Beschreibungen generieren und daraus
im 2. Schritt per wiederverwendetem Generator die Client- / Server-Stubs generieren
Prof. Dr. H. Drachenfels
Hochschule Konstanz
Grundlagen der modellgetriebenen Softwareentwicklung
4-46
Herunterladen