Wikipedia (siehe Kasten) [1] beschreibt sehr gut, was eine domänenspezifische Sprache (DSL) ist. DSLs werden an vielen Stellen verwendet. Zum Beispiel sind die build.xml von Ant eine domänenspezifische Sprache für die Domäne Build von Projekten. Der große Vorteil einer DSL ist, dass lediglich die relevanten Informationen erwähnt werden müssen. Sämtliche Zusatzinformationen (z.B. Informationen über benötigte Infrastrukturen bei Serverkonfigurationen) werden von den Komponenten hinter der DSL beigesteuert. Jede DSL besteht aus der eigentlichen Sprache und einer oder mehrere Komponenten, die die Sprache interpretieren und ausführen können. Für Sie als Domänenspezialisten ist dieses Zusatzwissen nicht interessant. Sie wollen lediglich die Informationen niederschreiben, die fachlich für die Domäne interessant sind.
Eine domänenspezifische Sprache (engl. Domain-specific Language, DSL) ist eine formale Sprache, die speziell für ein bestimmtes Problemfeld (die Domäne) entworfen und implementiert wird. Beim Entwurf einer DSL wird man bemüht sein, einen hohen Grad an Problemspezifität zu erreichen: Die Sprache soll alle Probleme der Domäne darstellen können und nichts darstellen können, was außerhalb der Domäne liegt. Dadurch ist sie durch Domänenspezialisten ohne besonderes Zusatzwissen bedienbar.
Groovy und DSLs
Groovy unterstützt Sie bei der Erstellung von DSLs mit den Groovy-Buildern und den erweiterten Sprachfeatures, z.B. Closures und Maps. Die Groovy-Builder implementieren das Builder Pattern.
- ein komplexes Objekt in unterschiedlichen Ausprägungen erzeugt werden soll
- die Details der Erzeugung des komplexen Objekts gekapselt werden soll
- die Erzeugung einen Status erfordert, den Sie vor dem Entwickler verbergen wollen
In Abb. 1 sehen Sie den schematischen Aufbau des Builder Patterns. Ein Director ruft den Builder bzw. die konkrete Implementierung auf. Der Builder erzeugt das komplexe Objekt, das in diesem Pattern Produkt genannt wird. Der Director bekommt das fertige Produkt und kann damit weiter arbeiten.
Groovy liefert bereits einige Builder mit. Dazu gehören unter anderem:
- MarkupBuilder – erzeugt beliebigen Markup-Code (HTML, XML)
- AntBuilder – führt Ant-Tasks aus
- GraphicsBuilder – erzeugt Grafiken, Diagramme
- NodeBuilder – erzeugt XML-Nodes
- DomBuilder – erzeugt ein DOM-Dokument
Listing 1
def builder = new MarkupBuilder(writer)builder.html{head{title ‘Built by the Groovy MarkupBuilder’}body{h1 ‘Sample Webpage’p(style=’font-weight :bold’, ‘Built by the Groovy MarkupBuilder’)}}
In Listing 1 sehen Sie den MarkupBuilder in Aktion. Der Builder versteckt die Details, wie HTML-Tags und Attribute notiert werden müssen. Der Anwender braucht sich hier nur noch auf die relevanten Dinge zu konzentrieren, nämlich welche HTML-Elemente auf die zu erstellende Seite gehören. In diesem kleinen Codeschnipsel sehen sie schon alle notwendigen Sprachfeatures. Elemente (head, title, body, h1, p) können optional Attribute oder den Inhaltstext enthalten. Attribute werden als Map dargestellt. Der Elementtext ist immer der letzte Parameter, der übergeben wird. Hat ein Element ein oder mehrere Kindelemente, werden diese als Closure definiert. Die Elemente in einer solchen Closure folgen den gleichen Regeln für Attribute, Text und Kindelementen.
Vorteile von Visualisierung
DSLs auf Basis von Groovy besitzen erst einmal eine textuelle Notation. Das ist für viele Fälle vollkommen ausreichend. In dem obigen Beispiel ist es wenig sinnvoll eine HTML-Seite mittels eines grafischen Editors zusammenzuklicken – damit sind ausdrücklich HTML-Editoren ausgenommen, die einem anderen Konzept folgen. Haben Sie jedoch eine DSL für eine Prozessabfolge, die an vielen Stellen Abzweigungen folgt, stößt die textuelle Notation schnell an die Grenzen. Wird diese DSL von verschiedenen Rollen in Ihrem Projekt benötigt, ernten Sie schnell verständnislose Blicke, wenn Sie eine Datei mit viel Text, Klammern und Sonderzeichen verteilen. Aus diesem Grund ist eine grafische Repräsentation der DSL hilfreich, da diese eher auch von den Fach- und Betriebsabteilungen verstanden wird.
Das Eclipse Graphical Modeling Framework (GMF)
Zur Visualisierung der DSL bietet sich GMF [2] an, ein Eclipse-Projekt mit dem Ziel der Generierung von grafischen Editoren. Dazu baut GMF auf zwei weiteren Eclipse-Projekten – GEF (Graphical Editor Framework) [3] und EMF (Eclipse Modeling Framework) [4] – auf. EMF ist ein Framework zur Modellierung und Generierung von Code auf Basis eines strukturierten Datenmodells und unterstützt bei der automatischen Erstellung die dem Editor zugrunde liegenden (Ecore-)Modelle.GEF stellt den meisten grafischen Editoren gemeinsame Bestandteile zur Verfügung. Beispiele hierfür sind Benutzerinteraktionen (Verschieben, Größenänderung, Drag & Drop), Layouting und Routing von Verbindungen zwischen Diagrammelementen sowie allgemeine Darstellungslogik. GEF orientiert sich an der Model-View-Controller-Architektur. Der View bestimmt die grafische Notation und benutzt zur Darstellung der Elemente (Figures) Draw2d. Die Controller werden in GEF EditParts genannt und verbinden die Views mit den dazugehörigen Modellelementen. Ein EditPart ist für die Interpretation von Benutzeranfragen zuständig, indem es zu allen unterstützten Interaktionen, die durch Requests repräsentiert werden, die passenden Commands ermittelt. Typische Commands sind z.B. Erstellen, Löschen und das Verschieben von Views in der Zeichnung. Commands werden in unterschiedliche Bereiche, so genannte Rollen gruppiert. Die Auswahl eines passenden Commands geschieht dabei über EditPolicies, von denen jedem EditPart je eine Rolle zugeordnet werden kann.
GMF besteht aus zwei Teilen. Der erste Teil stellt die Runtime dar, dessen Kern das Notational Model bildet. Dieses Metamodell stellt die Verbindung zwischen dem EMF-Metamodell und dem auf GEF basierten Teil des GMF-Editors her. Da GEF mit jeglicher Art von Modellen zurechtkommt, in GMF prinzipiell aber nur mit Ecore-Modellen gearbeitet wird, erweitert GMF die aus GEF stammenden Teile, um sie an diese spezielle Gegebenheit anzupassen. In der Tat finden sich viele Klassen aus GEF in erweiterter Form in GMF wieder. Der andere Teil von GMF ist das Tooling. Dieses stellt verschiedene Modelle bereit, die es erlauben, die einzelnen Bestandteile des zu erstellenden Editors zu konfigurieren, also festzulegen, welches Metamodell verwendet, wie die grafische Notation aussehen und welche Tools angeboten werden sollen. Aus diesen Modellen wird der Quellcode generiert, aus dem der Editor besteht. Im günstigsten Fall muss somit gar nichts oder nur sehr wenig selbst implementiert werden. Dieser Vorgang erlaubt eine wesentlich schnellere und weniger fehleranfällige Editorerstellung als eine komplette Eigenentwicklung. Auch Änderungen lassen sich einfacher durchführen, da nur die Modelle geändert werden und der Code neu generiert wird. Der generierte Quellcode lässt sich an die eigenen Anforderungen anpassen, es sollte lediglich darauf geachtet werden, dass diese Änderungen mit denen der Modelle verträglich sind, da sonst Inkonsistenzen bei der Neugenerierung auftreten können. Anhand der Fülle der generierten Klassen lässt sich schon erahnen, wie mächtig und umfangreich GMF ist. In der Tat ist die Lernkurve sehr steil. Insbesondere wenn die ersten noch so kleinen manuellen Anpassungen am generierten Quellcode vorgenommen werden müssen, stellt sich schnell die Frage, an welcher Stelle man jetzt eingreifen sollte. Zum besseren Verständnis hilft dann nur noch ein tieferes Eindringen in den GMF-Code mithilfe des Debuggers.




