oAW Workshop Teil 2 – openArchitectureWare

Am Donnerstag und Freitag habe ich einen 2-tägigen Workshop zu openArchitectureWare besucht. In zwei Blogeinträgen berichte ich über das Gelernte. (Zu Teil 1)

Teil 2: Überblick über openArchitectureWare

OpenArchitectureWare ist eine Sammlung von Tools für die Modellgetriebene Software-Entwicklung. Die oAW ist Open Source, in Java implementiert und befindet sich gerade auf dem Weg in das Eclipse Modeling Framework. Schon jetzt gibt es für oAW eine gute Eclipse-Editorunterstützung

Die wesentlichen Modellierungskomponenten sind die Code-Generierung (M2T, Xpand), Modelltransformationen (M2M, Xtend), Validierung (Check) sowie die Unterstützung durch grafische und textuelle Editoren.

oAW versteht eine ganze Menge von Modellen und Modellformaten. oAW berücksichtigt die Eigenheiten der von diversen Tool-Herstellern erzeugten UML 1 und 2 XMIs in einer Masse von Parsern und formt sie zu typisierten Modellen um. Seit einiger Zeit exportieren jedoch so gut wie alle Tools konformes EMF UML 2.0, das von oAW vollständig unterstützt wird.

Sprachen in oAW

Im Rahmen der oAW wurden drei neue Sprachen erfunden, die speziell darauf abgestimmt sind, aus Modellen andere Modelle, Source Code oder andere Artefakte zu generieren. Jede Sprache beleuchtet einen definierten Aspekt, alle verfügen jedoch über ein gemeinsames Typsystem, eine einheitliche Expression-Syntax und sie lassen sich teilweise untereinander aufrufen.

Eine ausführliche Referenz zu den drei Sprachen gibt es hier.

Xtend

Xtend ist eine in Ihrer Syntax an funktionale Programmiersprachen angelegte Sprache, die zur Erweiterung der durch oAW definierten Funktionsbiliothek dient.

In einer auf “.ext” endenden Datei werden Funktionen mit Rückgaben definiert. Etwas gewöhnungsbedürftig ist, das es kein return-Schlüsselwort gibt.

Eine Methode kann auch auf dem Typ des ersten Parameters aufgerufen werden. Definiert man also eine Methode foo(String), kann diese auf einem String direkt aufgerufen werden: “hello”.foo()

Einige Beispiele:

  • // Definiert eine Methode foo() für String
    String foo(String s): s.toUpperCase();
  • // Der Parameter this ist der Kontext für direkt aufgerufene Methoden
    String foo(String this): toUpperCase();
  • // Wenn expressions mit "->" gechained werden, ist das letzte Element der
    // Chain die Rückgabe.
    // Der Aufruf erfolgt über eine Entity: myEntity.prependName("Abstract")
    Entity prependName(Entity this, String prepend): setName(prepend + name) -> this;

Aus Extend kann zusätzlich auf statische Java-Methoden zugegriffen werden. Dazu dient das Schlüsselwort JAVA.

// Die Java-Methode und ihre Signatur muss voll qualifiziert werden
String formattedToday(String format):
  JAVA myPackage.MyClass.myStaticTodayMethod(java.lang.String);

Ausführliche Referenz zu Xtend

Xpand

Xpand ist eine XSLT-ähnliche Template-Sprache, die jedoch auf die Generierung von Dateien spezialisiert ist. Neben einigen gewohnten Sprachkonstrukten wie foreach, if-then-else helfen defines und expands bei der Strukturierung der Templates.

Wie man es aus Template-Sprachen kennt, werden in die Ausgabe Codeblöcke hinein codiert. Dazu dienen die Guillements « und ».

Über das Schlüsselwort DEFINE werden Template-Methoden deklariert. Wie bei Xtend wird das Template an einen Typen (meist aus dem Metamodell) geknüpft. Die Methoden unterstützten Polimorphismus.

«DEFINE name[(parameterlist)] FOR type»
  ...code...
«ENDDEFINE»

Mittels EXPAND werden diese Templates aufgerufen:

«EXPAND name[(parameterlist)] FOR|FOREACH expression»
«REM»Kommentar: FOR ruft das Template auf dem Ergebnis der expression auf,
     FOREACH geht von einer Ergebnismenge aus und führt die Templates
     einzeln aus.«ENDREM»

Mit FILE wird der Output eines Bereiches des Templates in eine Datei umgelenkt.

«FILE "filename.java" [outlet]»
/*Dieser Inhalt wird direkt in das file "filename.java" geschrieben.
Über das outlet können zusätzlich Postprozessoren oder verschiedene Ausgabe-
Verzeichnisse angesteuert werden.*/
«EXPAND JavaClass FOREACH model().allContents.typeSelect(Entity)»
«ENDFILE»

oAW unterstützt protected regions, d.h. dass Teile des Generats beim nächsten Generieren nicht überschrieben werden und somit manuell modifiziert werden können. Diese definiert man mit PROTECT.

«PROTECT CSTART "<!--" CEND "-->" ID expression»
// TODO: Hier bitte die Methode xy ausimplementieren
throw new NotImplementedException();
«ENDPROTECT»

Wie bei den meisten Template- oder Scriptsprachen hat der Entwickler die Wahl zwischen Pest und Cholera: Soll das Generat schön aussehen, oder lieber das Template übersichtlich bleiben. Xpand bietet zwei Hebel, mit denen man dieses Problem in den Griff bekommt.

Mit einem “-” vor dem schließenden Guillement eines Script-Blocks lässt sich die Ausgabe der folgenden Whitespaces unterdrücken.

«FILE "test.txt" -»

   A ist der erste Buchstabe im Textfile. «"Und weiter? " -»
   B folgt noch in der selben Zeile.
«ENDFILE»

Zusätzlich lassen sich für bestimmte Outlets Beautifier als Postprozessoren konfigurieren, die nachträglich z.B. alle Java-Klassen vernünftig formatieren.

«FILE "TestClass.java" javaOutlet»
public
class
TestClass{
  /* Gerade bei verschachtelten Templates, die Schlüsselwörte und
     Befehle ausgeben wäre es sehr aufwendig, alle Umbrüche, Einrückungen
     und Zeilenabstände perfekt zu kontrolieren. */
}
«ENDFILE»

Dies war nur ein kleiner Auszug aus Xpand. Alle Xpand Schlüsselwörter und deren Syntax hier.

Check

Check ist eine an OCL angelehnte Sprache zur Validierung von Metamodellen oder anderen Objektbäumen. Baut man Code anhand von modellen auf, ist es wichtig, das diese formalen Regeln folgen und eindeutig sind. Diese Regeln werden mit check ausgedrückt. Besonders wichtig ist es, check bei Modell-zu-Modell-Transformationen zu verwenden, um sicherzustellen, dass das Zielmodell korrekt ist.

Einer Definition eines Fehlers oder einer Warnung für einen Typ folgen die Regeln, die nicht verletzt werden dürfen.

context type ERROR|WARNING "Message":
  rule_expression;

Beispiele:

  • context Class ERROR "Eine Klasse muss einen Namen besitzen!":
      name != null && name.lenght > 0;
  • context Entity IF isAbstract WARNING
      "Der Name abstrakter Entitäten sollte mit 'Abstract' beginnen.":
      name.startsWith("Abstract");

AOP in oAW

Die Sprachen Xtend und Xpand unterstützen Ansätze der Aspektorientierten Programmierung (AOP).

So kann man sich von außen um Templates und Extensions legen und die Kontrolle übernehmen. Das Schlüsselwort dazu ist in beiden Sprachen around.

Um die in Dateien “*.xpt” oder “*.ext” abgelegten Aspekte anzuwenden, konfiguriert man sogenannte advices.

Workflow

Als Start-Script für oAW dient ein Workflow Script das in XML beschrieben wird. Die Syntax erinnert ein wenig an Ant. In diesem Workflow werden Konfiguration, Transformationen, Generatoren, Aspekte usw. in aufeinanderfolgenden Schritten Konfiguriert.



  
    
  
  

oAW führt u.a. Komponenten für die Ausführung von Check, XPand, Xtend, Aspekte (Advices). Zur strukturierung kann man auch andere workflows aufrufen, oder mit Java eigene Komponenten erstellen.

Zwischen Komponenten werden Parameter über sog. Slot-Objekt übermittelt.

Cartridges

Cartridges sind komplette oAW-Pakete für bestimmte Anwendungsfälle. Sie bringen gewöhnlicherweise eine DSL sowie dazugehörige Metamodelle, Checks, Extensions und Generatoren.

Ein Beispiel ist die Hibenate Cartridge von Darius Jockel, mit dessen Hilfe sich Entities für die Persistenz mit Hibernate mittels UML2 modelieren lassen.

Auf der Fornax-Plattform sind viele Cartridges wie z.B. für EJB oder Spring zu finden.

Weiterführende Links

Advertisement

oAW Workshop Teil 1 – MDSD

Am Donnerstag und Freitag habe ich einen 2-tägigen Workshop zu openArchitectureWare besucht. In zwei Blogeinträgen berichte ich über das Gelernte. (zu Teil 2)

Teil1: Einführung in die MDSD

Modellgetriebene Softwareentwicklung

Mit den steigenden non-funktionalen Anforderungen und zuliebe “schönen” Designs, OOP, moderner Sprachen und komplizierten Patterns wird die Fachlogik von schematischem Architekturcode ertränkt und ist kaum noch auffindbar.

Durch MDSD soll diese oft nötige Komplexität verborgen werden. Der Fokus geht zurück auf die Fachlogik; um die technischen Details kümmert sich der Generator. So lassen sich Redundanzen im Code vermeiden und es lässt sich sicherstellen, dass Architekturrichtlinien eingehalten werden. Als geliebter Nebeneffekt sinkt die Fehlerrate während die Produktivität besonders in großen Projekten schnell steigt.

Wenn ein Technologiewechsel stattfinden soll, liegen die anzupassenden Details im Generator. Die Wiederverwendung eines Models für eine vollständig andere Zielplattform ist kaum realistisch. Man kann jedoch mit relativ überschaubarem Aufwand Teilaspekte der Architektur anpassen oder austauschen.

Begriffe

Domäne: Alle Aspekte einer Applikation werden in Domänen eingeteilt uns seperat modelliert. Die richtige Aufteilung ist grundlegend für den Erfolg von MDSD.

Modell: Ein abstrahiertes Abbild eines Teilaspektes der Realität. Bei Modellen ist wichtig nur einen sehr deutlich abgegrenzten Aspekt zu betrachten. Aus mehreren eindeutigen Modellen entsteht das Gesamtbild.

Metamodell: Beschreibt die Struktur für ein Modell. Im Vergleich zu Objektorientierung ist das Metamodell die Klasse, wärend das Modell die Instanz ist. Ein Metamodell ist in vielen Fällen die Implementierung einer DSL, d.h. die Verwendung fachlicher Begrifflichkeiten der Domäne sind erwünscht.

Metametamodell: Ein selbstbeschreibendes meist recht einfaches Modell zur Beschreibung der Grammatik von Metamodellen. Hier wird keine Rücksicht auf fachliche Domänen genommen, sondern der Bezug ist rein technisch. Beispielsweise MOF oder EMF. Diese nimmt man normalerweise als gegeben, und fängt nicht an sie selbst zu bauen.

Die funktionsweise von MDSD

Aus dem formalen Modell wird gewöhnlicherweise ein auf die technische Problemstellung abgestimmtes Zwischenmodell generiert. Daraus erstellt der Generator Code um diesen mit manuell geschriebener Fachlogik zusammenzuführen. Das Ergebnis ist lauffähiger Code.

MDSD vs. MDA

Die MDA ist ein OMG-Standard, der sehr teoretisch ist. In MDA wird optimalerweise vollkommen platformabhängig definiert, während in MDSD gerne etwas mehr Bezug auf die Platttform, den Prozess und die Quellcodegenerierung genommen wird.

Domänenspezifische Sprachen (DSL)

DSLs werden auf eine bestimmte Problem-Domäne zugeschnitten und sind somit ein Metamodell. Eine DSL muss eindeutig sein, sprich eine formale Syntax und eine formale Semantik besitzen.

Gute DSLs sind einfach und nicht redundant. Sie reflektieren die Sprache des Domänenexperten und sind von solchen zumindest lesbar. Dies macht Teile der Dokumentation überflüssig.

Tools wie Xtext, EMF/Ecore oder Language Workbench helfen bei der Erstellung von DSLs. Bei der Konzeption muss darauf geachtet werden, dass sie für Änderungen offen bleibt.

DSLs und UML

Oft werden DSLs mit UML2 beschrieben. Dies hat den wesentlichen Vorteil, dass UML ein Standard ist und viele grafische Tools beim erstellen der Modelle unterstützen. Leider ist UML praktisch nicht einschränkbar, sondern nur durch Profile und Beschränkungen erweiterbar. Da diese von Tools nicht durchgehend unterstützt werden, ist es jedoch so gut wie unmöglich eindeutige DSLs zu definieren.

Das einzige Format, das zum Austausch von UML-Modellen taugt ist EMF UML2. Der Export in dieses Format wird jedoch noch nicht von allen Toolherstellern unterstützt.

DSLs mit EMF/Ecore

Ein DSL kann it EMF modelliert werden. Eine grafische Unterstützung kann man über GMF erstellen.

DSLs mit xtext

Xtext ist eine DSL zur Beschreibung der Grammatik von textuellen DSLs. Xtext ist Teil des oAW-Projektes und bietet dem Entwickler Möglichkeiten zur formalen Validierung seiner Modelle sowie in Eclipse integrierte Editoren mit Intellisense, etc.