Thema 01 Endabgabe - University of Augsburg...3 deklarativer Validator, was Validierungsregeln und...

49
Editor für eine DSL anhand der Spring Validierungssprache Praktikum MDSD SS008 Uni Augsburg Hadi Deniz Wissam Odeh Wei Zhao 15.05.2008

Transcript of Thema 01 Endabgabe - University of Augsburg...3 deklarativer Validator, was Validierungsregeln und...

Editor für eine DSL anhand der Spring­Validierungssprache   Praktikum MDSD SS008 Uni Augsburg     Hadi Deniz     Wissam Odeh      Wei Zhao  15.05.2008 

   

1

Gliederung Einleitung …………………………………………………………………………… 1 1. Spring Validation …………………………………………………………………...1

1.1. Validation………………………………………………………………………..1 1.1.1 Einführung…………………………………………………………………1 1.1.2 Validator allgemein……………………………………….………………..1 1.1.3 Valang Validator………………………………………….………………..2

1.2. Valang ……...………………………………………………….………………...3 1.2.1. Valang Syntax………………………………………….…………………3

1.2.1.1. Regelkonfiguration………………………………….………………..3 1.2.1.2. Aussagen……………………………………………….…………….4 1.2.1.3. Operatoren…………………………………………………………...4

2. OAW und XText …………………………………………………………………...6 2.1. MDSD …………...……………………………………………………………...6

2.1.1. Modell …………………………………………………………………....6 2.1.2. Metamodell ………………………………………………………………6 2.1.3. MDSD Definition ………………………………………………………..6

2.2. OpenArchitectureWare………………………………………………………….7 2.2.1. OpenArchitectureWare Definition ………………………………………7 2.2.2. OpenArchitectureWare Komponente ……………………………………7 2.2.3. Vor- und Nachteile ………………………………………………………7

2.3. XText Framework ………………………………………………………………8 2.3.1. XText Architektur ……………………………………………………….8 2.3.2. Language Projekt in Details …………………………………………......9 2.3.3. Editor Projekt in Details ………………………………………………...10 2.3.4. Generator Projekt ………………………………………………………..10 2.3.5. xText Grammatik ………………………………………………………..11

2.4. XPand Framework ……………………………………………………………...13 2.4.1. Struktur ………………………………………………………………….13 2.4.2. Wichtige Befehle in Überblick ………………………………………….13

3. Die Eclipce Rich Client Plattform......…………………………………………......15 3.1. Plattform für Rich-Clients ..………...………………………………………......15 3.2. Die Eclipse RCP für das Projekt ……………………………………………….16

3.2.1. Oberfläche für Editor …………………….……………………………...17 3.2.2. Integration von Plug-in ……………………………………………….....17 3.2.3. Erstellung einer Aplikation ……………………………………………...17

4. Implementierung …………………………………….…………………………......18 4.1. OpenArchitectureWare- (Implemnierung) …..………………………………… 18

4.1.1. DSL für Valang ………..……………………...........................................19 4.1.2. Constraints……………………………………………………............…...22 4.1.3. Extentions………………...............................................................……….25 4.1.4. Outline…………………………………………………………………..…30 4.1.5. Auto-Complete (Syntaxvervollständigung) ……………………………… 32 4.1.6. xPand-Templates…………………………………………………………..34

4.2 Die Eclipse Rich Client Plattform – (Implementierung) ………….……………..40 4.2.1 Eclipse Plattform für Rich-Clients………………………………………….40 4.2.2 Die Eclipse RCP für das Projekt…...……………………………………….41 4.2.3 RCP-Implementierung……………………………………………………....42 4.2.4.Architekturen von Editor…………………………………………………....44

4.3 Zusammenfassung und Ausblick ……………………………………………..….46

2

Einleitung

Software Projekte sind immer von Umfang her großer und komplexer geworden. Um diese Komplexität zu vermeiden, bietet MDSD die Möglichkeit ein Teil dieser Software automatisch zu generieren und Subsysteme wieder zu verwenden. In unserem Projekt werden wir mit Hilfe von OpenArchitekturWare(OAW) Framework ein Editor für eine DSLs anhand der Spring-Validierungssprache realisieren. In dieser Dokumentation stellen wir in erstem Kapitel Validierung und Validator von Spring vor. Im nächsten Kapitel kennen wir xText und xPand von OAW lernen und in drittem Kapitel behandeln wir die Architektur und Konzept von Eclipse RCP. Im letzten Kapitel wird die konkrete Implementierung durchgeführt. 1. Spring Validation 1.1 Einführung Validierung(Validation) ist die dokumentierte Beweisführung, dass ein System die Anforderungen in der Praxis erfüllt. In der Softwaretechnik bezeichnet Validierung (auch Plausibilisierung, als Test auf Plausibilität, oder engl. Sanity Check genannt) die Kontrolle eines konkreten Wertes darauf, ob er zu einem bestimmten Datentyp gehört oder in einem vorgegebenen Wertebereich oder einer vorgegebenen Wertemenge liegt. Sie ist ein wichtiger Aspekt der Qualitätssicherung, der sicherstellen soll, dass ein implementiertes Programm den vorher aufgestellten Anforderungen genügt. Die meisten Programmfehler und Sicherheitsprobleme sind letztlich auf fehlende Plausibilisierung von Eingabewerten zurückzuführen1. Die Validierung ist ein wichtiges Instrument, um die Qualität von Arbeitsergebnissen sicherzustellen, in der pharmazeutischen Technologie, Biotechnologie, analytischen Chemie, klinischen Medizin oder Computertechnologie. Zu diesem Zweck wird ein dokumentierter Nachweis erbracht, der stets vor der Entwicklung oder Einführung eines Computersystems geführt wird. Validierung und Verifizierung werden manchmal verwechselt. Verifikation ist die Überprüfung, ob ein System die formale Spezifikation erfüllt. Umgangssprachlich ist die Validierung Antwort auf die Frage : baue ich das richtige Haus? Und Verifizierung ist die Antwort auf die Frage: baue ich das Haus richtig? 1.1.1 Validator Validators sind die Werkzeuge die uns ermöglichen die Gültigkeit von unserem Kode festzustellen. Validator die wir hier benutzen sind die implementierungen von Springframework. Springframework hat zwei Arten von Validators; Einer ist programmatischer Validator,in dem Validierungsregeln schon kodiert sind und der andere ist

1 http://de.wikipedia.org/wiki/Validierung_%28Informatik%29

3

deklarativer Validator, was Validierungsregeln und Beschränkungen auf Konstruktionen beruhen2. In unserem Fall werden wir die zweite Validator behandeln. Für die declarativer Validator hat Spring drei Validierungswerkzeuge

• Commons Validator • Valang Validator • Bean Validation Framework

Der Commons Validator verwendet eine XML-Konfigurationsdatei um die Beschränkung declerativ zu spezifizieren. Allerdings, ist die Konfiguration nicht intuitiv, und seine Konfiguration-Format ist sehr verbose. Das Bean Validation Framework ist das neueste und wurde entwickelt, um die Lücken in den anderen verfügbaren Validierung Werkzeuge, nämlich commons Validator und Valang Validator zu füllen. Die wichtigsten Ziele dieses Framework sind:

• Ermöglichen klare Trennung von Interessen, wenn es zur Validierung kommt. • Extrahieren Sie die besten Eigenschaften von den anderen Ansätze(Werkzeuge) und

vereinigen sie in einem Rahmen • Die neueste Technologie und und Methoden verwenden • Macht die die Validierungsregeln so intuitiv und einfach wie möglich für die

Definition in der Anwendungen. Bean validation Framework-Validator ist das Beste unter diesen Tools, weil es flexibler , leistungsfähiger ist. Ausserdem unterstützt es auch XML Deklaration. (hier wird noch erweitert ) Da unsere Arbeit auf Valang basiert werden wir uns hier hauptsächlich auf Valang-Validator konzentrieren. 1.1.2 Valang Validator Valang, das für Validierungssprache steht, ist eine Sprache, die spezifisch für die Validierung der Zielobjekte bestimmt ist. Seine Darstellung ist kurz und spezifisch auf das Erhalten von valiedierende Daten ausgerichtet. Das ist ein Opensource Projekt und in Spring Modulen zu erhalten. Wie man eigenes Validator schreibt werden wir mit dem Beispile in Syntaxteil verdeutlichen. Die zwei wichtigste Klasse von Spring-Validation sind die Klassen org.springframework.validation.Validator und org.springframework.validation.Errors. Die Klasse Errors bedient wie eine Registry für die Errors, die mit dem ziel Objekt kombiniert sind. Validator interface bietet einen Vorgang um ziel Objekt zu validieren und kombinierte Errors zu registrieren. Unsere Kode werden hier überprüft und im Fall eines Fehlers wird ein gebundenen Fehler vom Errors geholt und angezeigt. 1.2 Valang Valang(Validation Language), bietet einen einfachen und intuitiven Weg zum Erstellen von Spring Validator. Valang hat drei wichtige Ziele 2 Expert Spring MVC and Web Flow

4

• Validierungsregeln Schnell und ohne Java Klassen zu schreiben • Vereinfacht die Verwendung von Spring Validation Werkzeuge • Erstellt die Validationsregeln kompakt, lesbar und einfach bedienbar

Hier unten werden wir ein Beispiel überprüfen <bean id="personValidator" class="org.springmodules.validation.valang.ValangValidator"> <property name="valang"> <value> <![CDATA[ { firstName : length(?) < 30 : 'First name too long' : 'first_name_length' : 30} { lastName : length(?) < 50 : 'Last name too long' : 'last_name_length' : 50 } ]]> </value> </property> </bean> Hier wie wir sehen erstens keine neue klasse wurde erstellt aber man verwendet hier eine vordefinierte Klasse . Zweitens PersonValidator ist kein Teil von Java Kode aber könnte eine java Klasse(ValangValidator) instanzieren. Als drittes die Validationsregeln wurden mit Valang expression Language geschrieben, welche sehr einfach und schnell zu schreiben sind. Um diese regeln zu schreiben hat Valang einen umfangreichen Syntax. 1.2.1 Valang Syntax Valang Syntax basiert auf Valang Expression language und valang validation rule configration. Ein Teil von diesen Regeln und funktionen sins vordefiniert ein Teil können wir selber definieren. 1.2.1.1 Regelkonfiguration: Alle Regeln werden in geschweifte Klammer geschrieben und die Felder werden mit : trennen. Es gibt obligatorische Felder und optionale Felder mit folgendem Beispiel lernen wir Grundstruktur kennen. Bsp; { firstName : length(?) < 30 : 'First name too long' : 'first_name_length' : 30} Grundstruktur { <key> : <predicate_expression> : <message> [: <error_code> [: <args> ]] } <key>=firstName- das ist der Schlüßelname mit dem ein Error verbunden ist. Das ist validierende Zielobjekt. : <predicate_expression>=length(?)-das ist eine Valangaussage was das prädikat definiert. Das ist die Beschränkung die gesucht ist. ? ist für firstName damit wird Redundant vermieden

5

<message> =‘first name too long’ das ist Error Nachricht kann leer gelassen werden. In dem Fall wird ein default Nachricht ausgegeben Die oberen drei Felder sind obligatorisch den Rest ist optional die sind die Nachrichten die man über Error Kode mehr details geben kann. 1.2.1.2 Aussagen: Die Prädikate(Aussagen ), die wir bei den Regeln verwenden, werden mit Expression Language wie folgend definiert. <expression> ::= <expression> ( ( "AND" | "OR" ) <expression> )+ | <predicate> <predicate> besteht aus operatoren, literalen, bean properties, Funktionen, und mathematische Ausdrücken. 1..2.1.3 Operatoren Binary Operators: diese haben Leftseite und Linkeseite String, Boolean, Date and Number Operatoren: = | == | IS | EQUALS != | <> | >< | IS NOT | NOT EQUALS Number und Date Operatoren: > | GREATER THAN | IS GREATER THAN < | LESS THAN | IS LESS THAN >= | => | GREATER THAN OR EQUALS | IS GREATER THAN OR EQUALS <= | =< | LESS THAN OR EQUALS | IS LESS THAN OR EQUALS Unary Operatoren: Die haben nur Linkeseite. Object Operatoren: NULL | IS NULL NOT NULL | IS NOT NULL String Operatoren: HAS TEXT / HAS NO TEXT HAS LENGTH / HAS NO LENGTH IS BLANK / IS NOT BLANK IS UPPERCASE | IS UPPER CASE | IS UPPER IS NOT UPPERCASE | IS NOT UPPER CASE | IS NOT UPPER IS LOWERCASE | IS LOWER CASE | IS LOWER IS NOT LOWERCASE | IS NOT LOWER CASE | IS NOT LOWER IS WORD / IS NOT WORD Speziale Operatoren:

6

BETWEEN / NOT BETWEEN IN / NOT IN NOT Bsp: width between 10 and 90 length(name) between minLength and maxLength Funktionen : Funktion Syntax ist wie folgend; function ::= <function_name> "(" ( <literal> | <bean_property> | <function> ) ( "," ( <literal> | <bean_property> | <function> ) )* ")" Es gibt auch vordefinierte Funktionen : Length, size, count : die ergeben die Länge ein Objekt Match, matchs : vergleicht zwei Objekte Upper,lower : konvertiert die Strings nach groß bzw. Klein Buchstaben

Unterstütze Mathematische Operatoren:

• + • - • * • / | div • % | mod3

2 OpenArchitectureWare, xText und xPand 3 https://springmodules.dev.java.net/docs/reference/0.8/html/validation.html alle beispiele sind aus der Seite

7

Einleitung Nachdem wir im letzten Kapitel den Valang Validator von Spring dargestellt haben und die Valang Syntax im letzten Abschnitt vorgestellt haben, führen wir in diesem Kapitel ein ganz anderes Thema ein, und zwar das Tool, dass wir nutzen werden, um ein Text-Editor für die Valang-Sprache zu erstellen. In Diesem Kapitel werden wir mit einer groben Definition des „MDSD“ Begriffs anfangen, gefolgt von der Vorstellung des „OpenArchitectureWare“ Projekts und seine Hauptkomponente, danach werden wir die xText und xPand Frameworks und ihre Grammatiken und Strukturen detaillierter besprechen. 2.1 Model Driven Software Development (MDSD) 2.1.1 Modell „Ein Modell ist allgemein eine auf bestimmte Zwecke ausgerichtete vereinfachende Beschreibung der Wirklichkeit. In der wissenschaftlichen Theoriebildung ist ein Modell das Ergebnis einer abstrahierenden und Relationen hervorhebenden Darstellung des behandelten Phänomens. Ein Modell entsteht, wenn Elemente aus dem Phänomen abstrahiert und zueinander in Beziehung gesetzt werden. Die Funktion des Modells besteht darin, aus den dargestellten Zusammenhängen Bedingungen und Prognosen bezüglich des Phänomens (oder Problems) ableiten zu können.“ (Wikipedia) 2.1.2 Metamodell Das Metamodell ist ein auf höhere Abstraktionsschicht liegende Modell. Dieses beschreibt die Struktur der Domäne formal und hilft bei der Festlegung welche Elemente im Modell vorkommen dürfen und wie sie zueinander in Beziehung stehen. Diese formale Beschreibung ermöglicht erst die spätere Automatisierung der Outputgenerierung. 2.1.3 MDSD-Definition „Modellgetriebene Softwareentwicklung (Model Driven Software Development, MDSD) ist ein Oberbegriff für Techniken, die aus formalen Modellen automatisiert lauffähige Software erzeugen.“(Stahl/Völter 2007, S.11) Formale Modelle: Sind die Modelle, die klare eindeutige Aussagen über einen Aspekt der zu entwickelnden Software ermitteln. Lauffähige Software erzeugen: Ziel eines MDSD ist eine lauffähige Software zu erzeugen. Wenn die formale Modelle nur die Dokumentation dienen, heißt das nicht, dass wir uns mit einem MDSD Project beschäftigen, da in diesem Fall keine Erzeugung stattfindet. Zwei Methoden zur Erzeugung lauffähige Software aus Modelle sind bekannt, Generatoren und Interpreter, wobei Generator aus einem Modell Quelltext einer andere Programmiersprache erzeugt und wird als Bestandteil des Build-Prozesses betrachtet, ein Interpreter, auf der anderen Seite, ist dazu verantwortlich, ein Modell zur Laufzeit einliest und abhängig von seinem Inhalt verschiedene Aktionen ausführt. Automatisch: Das bedeutet, dass es mindestens ein Teil der Software Automatisch durch Eingabe des Modells erzeugt wird. Hier wird noch mal betönt, dass das Modell nicht nur zur Dokumentation zur Verfügung steht, sondern ist ein wichtiger Teil bei der Erzeugung der Software. Das bedeutet, dass die Modelle als Quelletexte betrachtet werden, auf denen Änderungen vorgenommen werden, diese Änderungen werden später bei der Generierung reflektiert.

8

2.2 OpenArchitectureWare 2.2.1 OpenArchitectureWare (OAW) openArchitectureWare ist ein Generator Framework für die Modell getriebene Softwareentwicklung (MDSD) bzw. Modell getriebene Architecture (MDA), OAW Baut auf Eclipse-Plugins des "Eclipse Modeling Project" auf, z.B. EMF, GMF, UML2. es ist ein Opensource Projekt und seit der Version 4 ist ein Subprojekt bei Eclipse geworden. OAW unterstützt den Entwicklungsprozess eines MDSD Projekt von Erstellung und Überprüfung des Eingabemodells, Erstellung des Metamodells bis zur Codegenerierung in verschiedene Formen (Java, XML ..). 2.2.2 OpenArchitectureWare Komponente OAW besteht aus einer Vielzahl von Einzelkomponenten:

• Workflow: Workflow ermöglicht ein flexibel konfigurierbares Genratorprozess. • Check-Framework: Modellvalidierung mit OCL-basierten Templates. • xPand Framework: zur Erzeugung beliebiger Ausgabedateien, Modell zu Text

Transformation (M2T). • Extend Framework: Modell zu Modell (M2M) Transformation. • xText Framework: Modellerstellung durch Parsen von Text-Dateien. • Expression-Framework: Es besteht aus einem Typsystem (engl. Type System) und

einer Expression-Sprache. Dieses Framework kommt sowohl innerhalb von xPand als auch in Check-Language zum Einsatz. Es bietet die Möglichkeit auf unterschiedliche Metamodelle immer mit der gleichen Syntax zuzugreifen.

2.2.3 Vor- und Nachteile OAW stellet ein umfangreiches flexibles Framework für MDSD Entwicklung und hat viele Vorteile, von denen:

• Sehr gut in Eclipse Integriert und können Java Erweiterung zugefügt werden. • Es lassen sich beliebige Metamodelle verwendet, hat keine Einschränkung auf UML

Modelle • Auch in der Ausgabe hat sich erwiesen, dass OAW flexible ist. Es können beliebige

Textdateien generiert werden • Das xText-Framework stellt für den Projektstart ein gutes Werkzeug zur Erzeugung

von Metamodell und Modelleditor mit zahlreichen Erweiterungsoptionen wie Codevervollständigung und Syntaxhighlighting.

Neben den Vorteilen gibt es einige Aspekte, die als Nachteile betrachtet werden können.

• Der Installationsvorgang ist ziemlich komplex, es werden nicht nur OAW Plugins installiert sondern auch zusätzliche Plugins wie EMF, GMF, UML etc.

• Das Verstehen von den verschiedenen Komponenten und ihrer Beziehung zueinander am Anfang ist nötig

• Die Dokumentation von OAW ist teilweise veraltet oder nicht vollständig 2.3 xText-Framework Für die Erstellung eines eigenen Metamodells bringt OAW das xText-Framework mit. Mit xText kann man eigene textuelle DSLs erstellen. Daraus erzeugt xText ein Metamodell, einen Parser für das Modell und ein Editor-Plugin mit Codevervollständigung und Syntaxhighlighting für Eclipse. Die Grammatik der Metasprache und des Modells wird mit einer an die erweiterte Backus-Naur-Form (EBNF) angelehnten Sprache beschrieben.

9

2.3.1 Architecture Bei Erstellung eines xText-Projekt werden drei Subprojekte automatisch erstellt (doch nicht die vollständige Inhalte) Language-Projekt, Editor-Projekt und Generator-Projekt. Wie wird der ganze Ablauf aussehen? zuerst kommt das DSL (.xtxt Datei) ins Spiel, nachdem die Grammatik in der xtxt Datei definiert wird und der Generator Eigenschafen eingestellt sind, kann der Generator ausgeführt werden. Wenn diese Ausführung Fehlerfrei erfolgt, werden das Metamodell, den Parser und den Editor-Projekt-Inhalt erstellt, dann können die optionale Bereiche manuell ergänzt werden(siehe Abbildung 2.1, 2.2,2.3).

Abbildung 2.1 2.3.2 Language Projekt in Details Hier ist ein Überblick auf die wichtigen Dateien im Language Projekt

10

(Abbildung 2.2)

2.3.3 Editor Projekt in Details

Language Project Checkdatei, hier können Semantik-Constrains zur Sprache zugefügt werden. Enthält die Metamodell -Extensions. Workflow Datei für den xText Generator. Generator-Properties Die Grammatik, die das DSL beschreibt. Generierte Basis Dateien Von der Grammatik Generiertes Metamodell Generierte xText Regeln Datei Generierte Antlr Parserartefakt

11

(Abbildung 2.3)

2.3.4 Generator Projekt wie früher erwähnt, OAW unterstützt die MDSD-Projekt bis zur Erzeugung von Ausgabedateien in verschiedenen Formaten wie XML, Java etc. dies erfolgt mit Hilfe der xPand-Templates (und Plattform-Spezifische Extend Dateien). Diese Dateien befinden sich im Generator Projekt. die xPand-Templates werden wir im Letzten Abschnitt dieses Kaptitels näher besprechen. 2.3.5 xText Grammatik

Editor Projekt Vervollständigung anpassen Outline-Ansicht anpassen. “find Reference” und “go to” Definition anpassen. Outline Labels und Icons anpassen Enthält die wichtige DSL-spezifische Informationen, Änderungen sind durchführbar in Unterklassen, in diesem Fall soll die MydslEditorPlugin.java Datei entsprechend angepasst werden. Generierte Basis Dateien Outline Icons

12

xText Grammatik basiert sich auf das extended Backus–Naur form (EBNF) und besteht aus einer Sammlung von Regeln, eine Regel muss einen Name haben, gefolgt von „:“ und endet mit „;“ dazwischen befindet sich die Beschreibung der Regel. Die Regeln können in 4 Kategorien eingeteilt werden:

• String Regel: um selbstdefinierte Zeichensequenz zu definiert. String JavaIdentifier :

ID ("." ID)*; • Enum Regel: geeignet für Aufzählungstypen, die in einem endlichen Wertebereich

liegen. Enum Farbe: green=“GRÜN“|blue=“BLAU“|red=“ROT“ ;

• Native Regel: um lexerregeln zu definieren, die nicht mit den normalen xText-Syntax ausdrückbar sind. Z.B. um Float Ausdruck zu definieren, kann die Folgende Regel hilfreich sein. Native FLOAT: „(‚-‚)?(‚0’..’9’)+’.’(‚0’..’9’)+“;

• Type Regel: ist im DSL Grammatik am meisten zu sehen, sie beginnt mit einem Name, dieser Name wird im Metamodell als „EClass“ abgebildet, gefolgt von „:“ dann kommt die Relgelbeschreibung, die Beschreibung ist eine Sammlung von Token, die Token sind Keywords (String) ,Properties, andere selbstdefinierte Typen oder Instanzen von den sogenannten „Built-in Lexer“.

ein Beispiel wird dies anschaulicher machen aber vorher stellen wir die Build-in Lexer vor:

• ID: Identifier, erlaubt den folgenden Sequenz (‚a-zA-Z_’ (‚a-zA-Z_0-9’)*)

• STRING: erlaubt einen Zeichenkettenausdruck. • INT: erlaubt einen Integerausdruck (kein Float). • LINE: Manchmal will man keinen Text innerhalb von Terminals einschließen,

sondern will alles zwischen eine Charakterreihenfolge und das Ende der Zeile bekommen. z.B. ein Kommentar der mit # beginnt und endet mit dem Zeilenende wird in der folgenden Regel beschrieben. Attribute :

(comment=LINE("#"))? type=DataType name=ID;

Mit dieser Regel können wir die folgende Syntax ausdrücken entity Customer {

string name; #should include the street number, too. string street; int age; bool isPremiumCustomer;

}

13

Einfaches Beispiel: Entity :

„entity“ name=ID „{„ (features+=Feature)* „}“ ;

Unsere Typregel hat den Name „Entity“, dieser Name wird auch so im Metamodell als „EClass“ abgebildet. die Beschreibung besteht aus einem „name“ als ID, den Keywords „entity“ und die geschtreifte Klammern und einem Ausdruck „(features+=Feature)*“ mit dem Property „+=“ und dem „*“. Dieser Ausdruck besagt, dass ein Entity Type kann beliebig viele Instanzen von dem Typ Feature enthalten und wird im Metamodell als „EAttribute“ Abgebildet. Ein Feature Beschreibung kann so aussehen:

Feature : type=ID name=ID „;“;

Was kann man mit dieser Grammatik ausdrücken? entity Customer {

String name; String street; Integer age; Boolean isPremiumCustomer;

} Es sind drei Mögliche Properties mit vier möglichen Kardinalitäten:

„=“ : Gleichheitszuweisung „+=“ : Additionszuweisung „?=“ : Boolean-Zuweisung „*“ : Beliebig viele (0..n) „+“ : Mindestens Eins (1..n) „?“ : Optional (0 oder 1) Nichts: Eins zu Eins Abbildung (1..1)

14

2.4 xPand Framework xPand ist eine Sprache des OAW und wird in die Templates genutzt, um die generierte Ausgabe zu kontrollieren, mit Hilfe der xPand-Templates können verschiedene Modell-zu-Text Transformationen durchgeführt werden, z.B. Java, XML oder selbstdefinierte Textausgaben. Das Haupttemplate befindet sich in dem Generator Projekt unter den Name „main.xpt“. Wir werden in den folgenden Abschnitt die Struktur und kurz die vorliegende Befehle vorstellen.

2.4.1 Struktur Ein xPand Template besteht aus den Befehlen der xPand-Sprache und normalem Text, xPand Befehle werden zwischen einem öffnenden und schließenden Guillemot geschrieben «XPand/Befehl». Mit Hilfe der xPand-Befehle können die verschiedene Elemente und ihre Eigenschaften aufgerufen werden. Generelle Template-Struktur:

«IMPORT meta::model» «EXTENSION my::ExtensionFile» «DEFINE javaClass FOR Entity» «FILE fileName()» package «javaPackage()»; public class «name» { // implementation } «ENDFILE» «ENDDEFINE»

Ein Template-Datei enthält beliebig viele Importbefehle, beliebig viele Extenstionsbefehle gefolgt von einem oder mehreren Definitonsblöcken. 2.4.2 Wichtige Befehle in Überblick

• IMPORT: IMPORT Befehl ermöglicht es, ein namespace einzubinden, ähnlich wie die Import Befehl in java, «IMPORT meta::model» = import meta.model.*; , Unterscheidet sich nur daran, dass in xPand nur komplette Pakete importiert werden können.

• EXTENSION: Bindet die Extend-Datei ein, die die nötigen Extensions enthält. «EXTENSION my::ExtensionFile»

• DEFINE: Das DEFINE-Block ist das eigentliche Template, enthält einen Name als Referenz, der von der Workflow-Datei oder andere Templates genutzt werden kann, gefolgt von „FOR“ gefolgt von der Elementtyp des Metamodells, für das das Template definiert ist. Der DEFINE-Block endet mit einem «ENDDEFINE» Befehl.

• FILE: Enthält einen Name, einen Outletname und beliebig viele Befehle, diese Befehle werden ausgewertet und in der generierten Zieldatei reflektiert. «FILE expression [outletName]»

a sequence of statements «ENDFILE»

15

• EXPAND: Um ein anderes Define-Block innerhalb ein eXpand-Template hinzufügen. «EXPAND definitionName [(parameterList)]

[FOR expression | FOREACH expression [SEPARATOR expression] ]» • FOR: bezeichnet den Elementtyp, zu dem das/der Define-Block/Expand-Befehl

ausgeführt wird. • FOREACH: Um Befehle auf eine Menge von Elemente durchzuführen.

«FOREACH expression AS variableName [ITERATOR iterName] [SEPARATOR expression]»

a sequence of statements using variableName to access the current element of the iteration

«ENDFOREACH» • IF: Unterstützt bedingte Anfragen, endet mit ENDIF Befehl

«IF expression» a sequence of statements [ «ELSEIF expression» ] a sequence of statements ] [ «ELSE» a sequence of statements ] «ENDIF»

• LET: um lokale Variablen zu spezifizieren «LET expression AS variableName» a sequence of statements «ENDLET»

• ERROR: bricht die Auswertung des Templates mit einer xPand-Exception ab. «ERROR expression»

• Comments: Kommentare können mit Hilfe des REM Befehls eingefügt werden «REM» text comment «ENDREM»

16

3 Die Eclipse Rich Client Plattform Auf serverbasierten Systemen und mobilen Endgeräten ist die Java-Technologie weit verbreitet und erfolgreich im Einsatz. Bei vielen Unternehmen hat sich die Java EE als Standard für die Entwicklung von Geschäftsanwendungen etabliert. Die Benutzerschnittstelle – sofern innerhalb der Java-Anwendung überhaupt vorhanden – wird vorrangig auf Basis von Web-Technologie entwickelt, der clientseitige Zugriff für den Anwender erfolgt demnach mit einem Web-Browser als Thin-Client. Thin-Client (z.B. Web-Anwendungen) werden zentral betrieben und bieten deshalb Vorteile bei Roll-Out, Verwaltung und Pflege. Clientseitig müssen nur Grundvoraussetzungen erfüllt werden, beispielsweise das Vorhandensein eines Browsers. Anforderungen wie z.B. die Nutzung des lokalen Dateisystems bzw. anderer lokaler Ressourcen oder etwa Offline-Funktionalität mit anschließender Datensynchronisierung ließen sich mit Web-Clients, wenn überhaupt, nur unter größten Schwierigkeiten umsetzen. Auf dem Desktop hingegen war die Akzeptanz von Java bis zuletzt sehr gering. Erst seit kurzer Zeit kann Java auch in diesem Bereich ein stetiges Wachstum an Popularität verzeichnen. Dieser Trend ist eng mit dem Begriff des Rich-Clients verbunden. Ein Framework zur Entwicklung von Rich-Clients bietet allerdings nicht nur ein vorgefertigtes, umfangreiches Set an Oberflächenkomponenten, sondern bringt üblicherweise eine modulare Grundstruktur und ein einheitliches Modell zur Entwicklung von eigenen Komponenten mit. 3.1 Eclipse Plattform für Rich-Clients Das Anforderungsprofil für Rich-Clients ist umfangreich und der Einsatz eines umfassenden Applikation Frameworks für die verschiedensten Problemstellungen ist damit ein kritischer Erfolgsfaktor für Realisierungsprojekte. In diesem Umfeld hat sich die "Rich Client Plattform" von Eclipse (Eclipse RCP) etabliert und zeigt momentan eindrucksvoll wie erfolgreich Java-basierte Anwendungen auf dem Desktop entwickelt werden können. Die Eclipse RCP selbst ist im Wesentlichen in zwei Bereiche gegliedert: Einerseits Equinox, die Laufzeitumgebung für Komponenten, den so genannten Plug-In, und andererseits die "Workbench" als eine Art Baukastensystem für Benutzeroberflächen. Equinox basiert auf der Spezifikation der Open Services Gateway initiative (OSGi), und ermöglicht die Steuerung des Lebenszyklus der Plug-In. So können beispielsweise Plug-In während der Laufzeit installiert, ausgeschaltet oder ausgetauscht werden. Equinox verwaltet dabei die Abhängigkeiten zwischen den einzelnen Plug-In und bildet das Fundament der Eclipse RCP.

17

Abbildung 3.1 Architektur von Eclipse RCP Die Workbench bietet eine erweiterbare Infrastruktur für die Darstellung von Oberflächenkomponenten wie Dialoge, Menüs oder Toolbars und koordiniert ihr Zusammenspiel in den verschiedenen Fenstern einer Anwendung. Wichtige Kernbestandteile der Workbench sind das bereits erwähnte SWT und das darauf aufbauende JFace-Toolkit. JFace standardisiert einige Anforderungen mit denen Entwickler häufig konfrontiert werden: Damit sind beispielsweise die Entwicklung von Wizards, die Verwaltung von Ressourcen für die Benutzeroberfläche oder die saubere Trennung zwischen den Komponenten und den dahinter liegenden Aktionen gemeint. Auf dieser Basis hält Eclipse RCP noch viele weitere, optionale Komponenten, wie ein Hilfesystem, einen Update-Manager, Reporting-Tools und Frameworks für Text- oder graphische Editoren bereit. Auch das individuelle "Branding" des Richt-Clients an einen gewünschten Styleguide ist möglich. Die Eclipse RCP ermöglicht es dem Entwickler sich größtenteils auf die Entwicklung der eigentlichen Anwendungskomponenten und deren Integration in die Plattform zu konzentrieren. Der Ansatz der Rich-Clients, insbesondere in der Ausprägung der Eclipse RCP, hat sich in der Praxis als sehr geeignete Plattform erwiesen, um auch in Java performante und den üblichen Standards und Gewohnheiten entsprechende Desktop-Applikationen im Enterprise-Umfeld zu entwickeln. 3.2 Die Eclipse RCP für das Projekt 3.2.1 Oberfläche für Editor

Views sind bei Eclipse kleine Fenster, welche Aufgabenbereiche unter verschiedenen Sichtweisen anzeigen. Diese Fenster können durch Drag und Drop beliebig angeordnet werden, in Form von Tabs, die durch Klick auf den Reiter aktiviert werden, in Form von dauerhaft sichtbaren Fenstern oder in Form von fast Views, die als Symbole in einer weitgehend frei positionierbaren Leiste angeordnet sind und die nur bei Klick auf das Symbol

18

eingeblendet werden. Beispiele für Views sind der Klassenexplorer, der baumartig strukturiert Symbole für die Klassen, Funktionen und Eigenschaften eines geöffneten Quelltextes anzeigt oder das Suchfenster, das die Ergebnisse einer Suche auflistet. Editoren sind die Sichtfenster, die meist den Quelltext mit Syntaxhervorhebung anzeigen, wobei es meist für jede unterstützte Programmiersprache einen eigenen Editor gibt (zum Beispiel für DSL). Genauso gibt es aber auch visuelle Editoren oder die Baumstrukturen anzeigen. Mehrere geöffnete Quelltexte werden als Reiter geöffnet, die über Tabs am oberen Rand in den Vordergrund gebracht werden können, weiterhin können Tabs fixiert werden, so dass der zugehörige Quelltext nicht versehentlich geschlossen wird. Auch Editoren können weitgehend frei per Drag und Drop angeordnet werden. Eine Datei kann in mehreren Editoren gleichzeitig geöffnet werden. Menü und Tools-bar sind Schnellzugriff auf bestimmte, häufig verwendete Funktion ermöglicht, z.B. ‘‘Öffnen‘‘, ‘‘Speichern‘‘ . 3.2.2 Integration von Plug-In DSL-Module wird als ein Plug-In in Editor integriert, so dass Quelltexte von DSL unterstützt werden. 3.2.3 Erstellung einer Applikation

Nach der Integration von DSL-Module werden die Programme als eine Standalone -Applikation exportiert.

19

4. Implementierung 4.1 OpenArchitectureWare (Implementierung) Aufgabenstellung: Erstellung eines Editors für eine textuelle DSL zur Definition von Validierungsregeln mit entsprechender Generierung von Regeln in XML/VALANG. Gefordert ist ein Editor, der einen Modellierer bei der Formulierung der Regeln unterstützt (z.B. mit Syntaxhighlighting, Syntax-Prüfung und –Vervollständigung). 4.1.1 Domain Spezifische Sprache (DSL) für Valang xText bietet die Möglichkeit, Eigene DSLs anhand der erweiterten Backus-Naur-Form (EBNF) zu erstellen. xText hat vier Buuild-in Lexer (ID, INT, STRING, LINE), weiterhin gibt es vier mögliche Regeln (Typregel, String-Regel, Enum-Regel, Nativ-Regel) um die Grammatik zu definieren. Unsere Grammatik soll die häufig verwendeten Funktionen und Attributtypen, die bei Formular-Validierung verkommen, unterstützen. Die behandelten Attributtypen:

• Integer = NUMBER • Float = GLEITKOMMAZAHL • String = TEXT • Boolaen = BOOLEAN • Date = DATUM • Und Objekte, die Kombinationen von den genannten Attributtypen bilden

Die verfügbaren Funktionen

• Länge Funktionen o Laenge o Minimale Laenge o Maximale Laenge o Wertebereich (für Integer)

• Match Funktionen o Match o Match mit case o Match ohne case

• Numerische Funktionen o ist grosser als o ist kleiner als o ist grosser gleich o ist kleiner gleich o ist gleich o ist nicht gleich

• Boolean Funktionen o ist True o ist False

• Datum Funktionen o vor o nach o ist den

20

o zwischen • Pruefe Syntax Funktionen

o Nur Ziffern o Nur Buchstaben o Nur Kleinbuchstaben o Nur Grossbuchstaben o E-Mail o Beginnt mit o Endet mit

Da Datum Syntax und Float nicht von den Build-in Lexer, haben wir die in Nativregeln definiert. DSL Definition in xText: Modell: (entitaet+=Entitaet)*; Entitaet: "Entitaet" entitaetName=EntitaetName "{" attBlock=AttributeBlock

regelnBlock=RegelnBlock "}" ; EntitaetName: entName=ID; AttributeBlock: "Attribute" "{" (attribute+=Attribute)* "}" ; //selbstdefinierterAttrTyp: gedacht für Instanzen der definierten Entitaeten Attribute: (vordefinierterAttrTyp=VordefinierterAttrTyp

|selbstdefinierterAttrTyp=SelbstdefinierterAttrTyp) name=ID; SelbstdefinierterAttrTyp: sdAttrTyp=ID; Enum VordefinierterAttrTyp: text="TEXT"|number="NUMBER"|datum="DATUM"| boolean="BOOLEAN"|gleitkommazahl="GLEITKOMMAZAHL";//... RegelnBlock: "Regeln" "{" (regel+=Regel)* "}" ; Regel: attrName=ID (verketteteAttribute+=VerketteteAttribute)* ":" ausdrueck=Ausdrueck ':' message=STRING (':'regExp=RegExp)? ; VerketteteAttribute : '.'attrName=ID; Ausdrueck: (vordefinierteFunk=VordefinierteFunk|selbstdefinierteFunk=SelbstdefinierteFunk); SelbstdefinierteFunk: funkName=ID ('()'|'('(arg=Argument)(',' args+=Argument)*')') ; Argument: (idArg=ID|zeichen=STRING|number=INT); VordefinierteFunk:

(lengthFunkName=LengthFunkName '('lengthArg=LengthArg')'| matchFunkName=MatchFunkName '('matchArg=MatchArg')'| numFunkName=NumFunkName (numWert=NumWert|float=Float)| boolFunkName=BoolFunkName| datumFunkName=DatumFunkName datumVariante=DatumVariante| 'zwischen' komplexDatumVariante=KomplexDatumVariante) ;

21

Enum LengthFunkName: laenge="Laenge"|wertebereich="Wertebereich"| minLaenge="minimale Laenge"|maxLaenge="maximale Laenge"; //... Enum MatchFunkName: match="match"|matchMitCase="match mit Case"| matchOhneCase="match ohne Case"; Enum BoolFunkName: istTrue="ist True"|istFalse="ist False"; Enum NumFunkName: istGroesserAls="ist groesser als"| istKleinerAls="ist kleiner als"| istGroessegleich="ist groessergleich"| istKleinergleich="ist Kleinergleich"| istGleich="ist gleich"| istNichtGleich="ist nicht gleich"; Enum DatumFunkName: vor="vor"|nach="nach"|ist="ist den"; LengthArg: (Nmin=INT'-'Nmax=INT)|numWert=NumWert ; NumWert: wert =INT; //Argument für Match Funktionen, entweder String oder ein anderes Attribute MatchArg: st=STRING|id=ID; RegExp: pruefe="Pruefe Syntax" (exp1=Exp|complexExp1=ComplexExp) ((and="und"|or="oder") (exp2=Exp|complexExp2=ComplexExp))?

(':' message2=STRING)?; Enum Exp: nurZiffern="nur Ziffern"| nurBuchstaben="nur Buchstaben"| nurKleinbuchstaben="nur Kleinbuchstaben"| nurGrossbuchstaben="nur Grossbuchstaben"| email="E-Mail"| url="URL"; ComplexExp: complexExpName=ComplexExpName "("expArg=STRING")" ; Enum ComplexExpName: beginntMit="Beginnt mit"|endetMit="Endet mit"; DatumVariante: (date=Date|time=Time|dateUndTime=DateUndTime) ; KomplexDatumVariante: date1=Date "and" date2=Date|time1=Time "and" time2=Time|

dut1=DateUndTime "and" dut2=DateUndTime; Date:"Datum" '('datum=Datum')' ; Time: "Zeit" '('zeit=Zeit')' ; DateUndTime: datumUndZeit="Datum&Zeit"'('dDatum=Datum ',' tTime=Zeit ')'; Native Datum: "'['(('0''1'..'9')|('1'..'2''0'..'9')|('3''0'..'1'))'.'(('0''1'..'9')|('1''0'..'2'))'.'('1'..'2''0'..'9''0'..'9''0'..'9')']'"; Native Zeit: "'['(('0'..'1''0'..'9')|('2''0'..'3'))':'('0'..'5''0'..'9')':'('0'..'5''0'..'9')']'"; Native Float: "('-')?('0'..'9')+'.'('0'..'9')+";

22

Für bessere Übersicht haben wir den folgenden Graph erstellt:

23

(Abbildung 4.1.1 , Graphische Darstellung der DSL) 4.1.2 Constraints Constraints werden verwendet, um die von dem DSL erhaltene Grammatik zu verfeinern und zusätzliche Einschränkungen hinzufügen. In Xtext werden Constraints in der Check-Datei in ähnlicher Sprache als das Object Constraint Language (OCL) erstellt. Weiterhin können weitere Erweiterungen (Extensions), die als Hilfsmethoden betrachtet werden können, in der Extensions-Datei implementiert. Constraints haben die folgende Syntax:

‚context’ ECore-Objekt (‚ERROR’|’WARNING’) Message ‚:’ OCL-Statement ‘;’ Die behandelte Constraints (Inhalt der Check.chk Datei): import beanvalidationdsl; extension org::openarchitectureware::util::stdlib::naming ; extension org::example::dsl::Extensions ; //untersucht ob eine andere Entitaet derselbe Name als der aktuelle Entitaetname hat context EntitaetName ERROR " Duplizierter Entitaetname " + '"'+ entName+'"': allElements().typeSelect(Entitaet).select(e|e.entitaetName.entName ==

entName).size == 1 ; //see Extensions context EntitaetName WARNING "Entitaet soll mit Grossbuchstaben anfangen!" : firstLetter(); //see Extensions context EntitaetName ERROR "Der Entitaetname "+ '"' +entName + '"' +" ist verboten" : verboteneSchluesselwoerter(); //untersucht Duplikate im AttributeBlock context Attribute ERROR "Duplizierter Attributname " + '"' + name +'"' : getAttrBlock().attribute.select(e|e.name == name).size == 1 ; //see Extensions context Attribute WARNING "Attributname soll mit Kleinbuchstaben anfangen!": firstLetterSmall(); //untersucht ob es Attribute gibt, die derselbe Name als Entitaet haben context Attribute ERROR "Attributname ist gleich Entitaetname!" : allElements().typeSelect(Entitaet).notExists(e|e.entitaetName.entName == name); //untersucht ob es selbstdefinierte Attribute gibt, die keine entsprechende Entitaet haben context Attribute if(selbstdefinierterAttrTyp != null ) ERROR "Entitaet " + '"' + selbstdefinierterAttrTyp.sdAttrTyp + '"' + "ist nicht definiert": allElements().typeSelect(Entitaet).select(e|e.entitaetName.entName ==

selbstdefinierterAttrTyp.sdAttrTyp).size != 0 ;

24

//untersucht ob es Attribute in Regelnblock gibt, die nicht im Attributblock zu finden context Regel ERROR "Attributname " + '"' + attrName +'"'+ " wuerde nicht im Attributeblock gefunden!" : getRegelnBlock().getEntR().attBlock.attribute.select(e|e.name ==

attrName).size != 0 ; //untersucht ob es verkettete Attribute in Regelnblock gibt, die sich nicht in den entsprechenden Entitaeten befinden context Regel if(!verketteteAttribute.isEmpty) ERROR '"' + verketteteAttribute.first().attrName +'"'+ " koennte nicht im

Entitaet "+ '"'+ step1().first().selbstdefinierterAttrTyp.sdAttrTyp + '"' +

" gefunden!" :

step4(step(),verketteteAttribute).size == 1; /*untersucht ob es verkettete Attribute in Regelnblock gibt, die sich nicht in den entsprechenden Entitaeten befinden*/ //höhere Verkettungsgrad context Regel if(verketteteAttribute.size > 1) ERROR "ein der verketteten Attribute wuerde nicht gefunden!": stepA(step1(),verketteteAttribute,{}).forAll(e|e == true); //untersucht ob die minimale Grenze kleiner als die maximale Grenze context Regel ERROR "Die minimale Grenze ist groesser als die maximale Grenze!" : ausdrueck.vordefinierteFunk.lengthArg.Nmin <=

ausdrueck.vordefinierteFunk.lengthArg.Nmax ; //untersucht ob die verwendete Funktion das verwendete Attribut passt context VordefinierteFunk if(istBoolFunk()) ERROR "Attribut " +'"'+ getAttr()+ '"'+ " muss vom Typ 'BOOLEAN' sein!": getStep1().first().vordefinierterAttrTyp.toString() == "boolean" ; //untersucht ob die verwendete Funktion das verwendete Attribut passt context VordefinierteFunk if(istBoolFunk2()) ERROR "Attribut " +'"'+ getAttr() + '"'+ " muss vom Typ 'BOOLEAN' sein!" : stepB(getStep1(),va()).first().vordefinierterAttrTyp.toString()== "boolean"; //untersucht ob die verwendete Funktion das verwendete Attribut passt context VordefinierteFunk if(istNumFunk()) ERROR "Attribut " +'"'+ getAttr() + '"'+ " muss vom Typ 'NUMBER' sein!": getStep1().first().vordefinierterAttrTyp.toString() =="number"|| getStep1().first().vordefinierterAttrTyp.toString() =="gleitkommazahl"; //untersucht ob die verwendete Funktion das verwendete Attribut passt context VordefinierteFunk if(istNumFunk2()) ERROR "Attribut " +'"'+ getAttr() + '"'+ " muss vom Typ 'NUMBER' sein!" : stepB(getStep1(),va()).first().vordefinierterAttrTyp.toString() == "number"

|| stepB(getStep1(),va()).first().vordefinierterAttrTyp.toString() == "gleitkommazahl" ;

//untersucht ob die verwendete Funktion das verwendete Attribut passt context VordefinierteFunk if(istFloatFunk()) ERROR "Der zugewiesene Wert ist fuer GLEITKOMMAZAHL geeignet nicht fuer NUMBER!" : getStep1().first().vordefinierterAttrTyp.toString() =="gleitkommazahl";

25

//untersucht ob die verwendete Funktion das verwendete Attribut passt context VordefinierteFunk if(istFloatFunk2()) ERROR "Der zugewiesene Wert ist fuer GLEITKOMMAZAHL geeignet nicht fuer NUMBER!" : stepB(getStep1(),va()).first().vordefinierterAttrTyp.toString() ==

"gleitkommazahl" ; //untersucht ob die verwendete Funktion das verwendete Attribut passt context VordefinierteFunk if(istMatchFunk()) ERROR "Attribut " +'"'+ getAttr() + '"'+ " muss vom Typ 'TEXT' sein!" : getStep1().first().vordefinierterAttrTyp.toString() == "text" ; //untersucht ob die verwendete Funktion das verwendete Attribut passt context VordefinierteFunk if(istMatchFunk2()) ERROR "Attribut " +'"'+ getAttr() + '"'+ " muss vom Typ 'TEXT' sein!" : stepB(getStep1(),va()).first().vordefinierterAttrTyp.toString() == "text" ; //untersucht ob die verwendete Funktion das verwendete Attribut passt context VordefinierteFunk if(istLengthFunk()) ERROR "Attribut " +'"'+ getAttr() + '"'+ " muss vom Typ 'TEXT' sein!" : getStep1().first().vordefinierterAttrTyp.toString() == "text" ; //untersucht ob die verwendete Funktion das verwendete Attribut passt context VordefinierteFunk if(istLengthFunk2()) ERROR "Attribut " +'"'+ getAttr() + '"'+ " muss vom Typ 'TEXT' sein!" : stepB(getStep1(),va()).first().vordefinierterAttrTyp.toString() == "text" ; //untersucht ob die verwendete Funktion das verwendete Attribut passt context VordefinierteFunk if(istDatumFunk()) ERROR "Attribut " +'"'+ getAttr() + '"'+ " muss vom Typ 'DATUM' sein!" : getStep1().first().vordefinierterAttrTyp.toString() == "datum" ; //untersucht ob die verwendete Funktion das verwendete Attribut passt context VordefinierteFunk if(istDatumFunk2()) ERROR "Attribut " +'"'+ getAttr() + '"'+ " muss vom Typ 'DATUM' sein!" : stepB(getStep1(),va()).first().vordefinierterAttrTyp.toString() == "datum" ; //untersucht ob die Funktion "Wertebereich" minimale und maximale Grenze hat context VordefinierteFunk if( lengthFunkName.toString() == "wertebereich" && lengthArg.Nmax == 0) ERROR "Wertebereichfunktion braucht eine minimale und maximale Grenze": false ; //untersucht ob es eine gueltige Kombination mit "oder" Verknuepfung ist context RegExp if((or=="oder")&&((complexExp1==null)&&(complexExp2==null)))

ERROR "Ungueltige Kombination " + '"'+ exp1.toString()+ " oder " + exp2.toString()+'"!' :

exp1.toString()!=exp2.toString(); //untersucht ob es eine gueltige Kombination mit "und" Verknuepfung ist context RegExp if(and=="und") ERROR "Ungueltige Kombination!" : exp1.toString()!=exp2.toString() ||

complexExp1.complexExpName!=complexExp2.complexExpName ; //untersucht ob es eine gueltige Kombination mit "und" Verknuepfung ist context RegExp if((and=="und")&&((complexExp1==null)&&(complexExp2==null))) ERROR "Ungueltige Kombination " + '"' + exp1.toString()+ " und " +

26

exp2.toString()+'"!' : false; //untersucht ob RegExp fuer Zeichenkette verwendet ist context RegExp ERROR "Pruefe Syntax ist nur fuer Zeichenketten geeignet!" : getRegel().ausdrueck.vordefinierteFunk.lengthFunkName.toString() !=

"wertebereich" ; //untersucht ob RegExp fuer Zeichenkette verwendet ist context RegExp ERROR "Pruefe Syntax ist nur fuer Zeichenketten geeignet!" : (getRegel().ausdrueck.vordefinierteFunk.lengthArg != null || getRegel().ausdrueck.vordefinierteFunk.matchArg != null);

4. 1.3 Extentions Extentions (Erweiterungen) sind Hilfsmethoden sowohl für die Constraints in der Check-Datei als auch für die XPand-Templates. Extensions haben die folgende Syntax: RückgabeTyp MethodenName ‚(‚ Parameter-1,…, Parameter-n’)’ ‚:’ OCL-Statement ‚;’ Die zugehörige Extensions für die Check-Datei: import beanvalidationdsl; extension org::example::dsl::GenExtensions reexport; //Get-Container methoden AttributeBlock getAttrBlock(Attribute this): eContainer ; RegelnBlock getRegelnBlock(Regel this): eContainer ; Entitaet getEntR(RegelnBlock this): eContainer ; Entitaet getEntA(AttributeBlock this): eContainer ; Modell getModell(Entitaet this): eContainer; RegExp getRegExp (ComplexExp this): eContainer ; Attribute getAttribute(SelbstdefinierterAttrTyp this): eContainer; Regel getRegel(RegExp this): eContainer; Ausdrueck getAusdrueckV (VordefinierteFunk this) : eContainer; Regel getRegelA ( Ausdrueck this): eContainer ; //Liefert True zurueck, wenn der Entitaetname mit Grossbuchstabe anfaengt Boolean firstLetter(EntitaetName this): let list ={'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O',

'P','Q','R','S','T','U','V','W','X','Y','Z'}: list.select(e|e == entName.subString(0,1)).size == 1 ;

27

//Liefert True zurueck, wenn der Attributename mit kleinbuchstabe anfaengt Boolean firstLetterSmall(Attribute this): let list = {'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O'

,'P','Q','R','S','T','U','V','W','X','Y','Z'}: list.select(e|e.toLowerCase() == name.subString(0,1)).size == 1; //Liefert True zurueck, wenn der Entitaetname nicht in der Liste ist Boolean verboteneSchluesselwoerter(EntitaetName this): let list = {"class","interface","abstract","final","throw","throws",

"static","public","protected","private","package"}://.. list.select(e|e == entName).size == 0 ;

//Liefert True zurueck, wenn boolean Funktion verwendet ist und es keine verkettete Attribute gibt Boolean istBoolFunk(VordefinierteFunk this): boolFunkName.toString() != "NULL" && getAusdrueckV().getRegelA().verketteteAttribute.isEmpty ; //Liefert True zurueck, wenn boolean Funktion verwendet ist und es verkettete Attribute gibt Boolean istBoolFunk2 (VordefinierteFunk this): boolFunkName.toString() != "NULL" && !getAusdrueckV().getRegelA().verketteteAttribute.isEmpty ; //Liefert True zurueck, wenn match Funktion verwendet ist und es keine verkettete Attribute gibt Boolean istMatchFunk (VordefinierteFunk this): matchFunkName.toString() != "NULL" && getAusdrueckV().getRegelA().verketteteAttribute.isEmpty ; //Liefert True zurueck, wenn match Funktion verwendet ist und es verkettete Attribute gibt Boolean istMatchFunk2 (VordefinierteFunk this): matchFunkName.toString() != "NULL" && !getAusdrueckV().getRegelA().verketteteAttribute.isEmpty ; //Liefert True zurueck, wenn length Funktion verwendet ist und es keine verkettete Attribute gibt. Boolean istLengthFunk (VordefinierteFunk this):

lengthFunkName.toString() != "NULL" && lengthFunkName.toString() != "wertebereich" && getAusdrueckV().getRegelA().verketteteAttribute.isEmpty ;

//Liefert True zurueck, wenn length Funktion verwendet ist und es verkettete Attribute gibt. Boolean istLengthFunk2 (VordefinierteFunk this): lengthFunkName.toString() != "NULL" && lengthFunkName.toString() != "wertebereich" && !getAusdrueckV().getRegelA().verketteteAttribute.isEmpty ; //Liefert True zurueck, wenn datum Funktion verwendet ist und es keine verkettete Attribute gibt. Boolean istDatumFunk (VordefinierteFunk this): (datumFunkName.toString() != "NULL" || komplexDatumVariante != null )&& getAusdrueckV().getRegelA().verketteteAttribute.isEmpty ; //Liefert True zurueck, wenn datum Funktion verwendet ist und es verkettete Attribute gibt. Boolean istDatumFunk2 (VordefinierteFunk this): (datumFunkName.toString() != "NULL" || komplexDatumVariante != null )&&

28

!getAusdrueckV().getRegelA().verketteteAttribute.isEmpty ; //Liefert True zurueck, wenn Number Funktion verwendet ist und es keine verkettete Attribute gibt. Boolean istNumFunk(VordefinierteFunk this):

(numFunkName.toString() != "NULL" || lengthFunkName.toString() == "wertebereich")&& getAusdrueckV().getRegelA().verketteteAttribute.isEmpty ;

//Liefert True zurueck, wenn Number Funktion verwendet ist und es verkettete Attribute gibt. Boolean istNumFunk2(VordefinierteFunk this):

(numFunkName.toString() != "NULL" || lengthFunkName.toString() == "wertebereich") && !getAusdrueckV().getRegelA().verketteteAttribute.isEmpty;

//Liefert True zurueck, wenn Float Funktion verwendet ist und es keine verkettete Attribute gibt. Boolean istFloatFunk(VordefinierteFunk this): float != null && getAusdrueckV().getRegelA().verketteteAttribute.isEmpty ; //Liefert True zurueck, wenn Float Funktion verwendet ist und es verkettete Attribute gibt. Boolean istFloatFunk2(VordefinierteFunk this): float != null && !getAusdrueckV().getRegelA().verketteteAttribute.isEmpty ; //Liefert Attributename zurueck wenn es keine verkettete Attribute gibs, //sonst der letzte Atrributname in der verketteten Attribute String getAttr (VordefinierteFunk this): getAusdrueckV().getRegelA().verketteteAttribute.isEmpty ? getAusdrueckV().getRegelA().attrName : getAusdrueckV().getRegelA().verketteteAttribute.last().attrName; //Hilfsmethoden um den Aufruf in den Checkdatei zu verkürzen List[VerketteteAttribute] va(VordefinierteFunk this): getAusdrueckV().getRegelA().verketteteAttribute; List[Attribute] getStep1(VordefinierteFunk this): getAusdrueckV().getRegelA().step1(); Verkettete Attribute: Zwischen den Attributnamen im Attributeblock und Regelnblock gibt es eine Beziehung und zwar: es können keine Regeln für Attribute definiert, die nicht vorhanden sind. Wenn es keine verketteten Attribute vorhanden sind, ist die Untersuchung sehr leicht, einfach prüft man ob der Attributname im Regelnblock auch im AttributeBlock vorhanden ist. Entitaet Firma { Attribute { TEXT name NUMBER anzahlDerAngestellter Angestellter angestellter1 } Regeln {

Entitaet Adresse { Attribute { TEXT strasse TEXT hausnr BOOLEAN eigenesHaus NUMBER plz }

29

Regeln { } }

name : minimale Laenge ( 2 ) : "Laenge Fehler" : Pruefe Syntax nur Buchstaben anzahlDerAngestellter : ist groesser als 10 : "Number Fehler" angestellter1 .name : Laenge ( 2 - 22 ) : "Laenge Fehler" angestellter1 .adresse.plz : Wertebereich (80000 - 99999) : "Wertebereich Fehler" } }

Entitaet Angestellter { Attribute { TEXT name TEXT vorname Adresse adresse } Regeln {} }

(Abbildung 4.1.2) Ein verkettetes Attribut: Wie man in Abbildung # sieht, der Vorgang ist etwas komplexer geworden, das Attribut „angestellter1“ muss im AttributeBlock geprüft werden und das verkettete Attribut „name“ muss im zugehörigen Entität auch geprüft werden.

Entitaet Angestellter { Attribute { TEXT name TEXT vorname Adresse adresse } Regeln {} }

Entitaet Firma { Attribute { TEXT name NUMBER anzahlDerAngestellter Angestellter angestellter1 } Regeln { name : minimale Laenge ( 2 ) : "Laenge Fehler" : Pruefe Syntax nur Buchstaben anzahlDerAngestellter : ist groesser als 10 : "Number Fehler" angestellter1 .name : Laenge ( 2 - 22 ) : "Laenge Fehler" angestellter1.adresse.plz : Wertebereich (80000 - 99999) : "Wertebereich Fehler" } }

Entitaet Adresse { Attribute { TEXT strasse TEXT hausnr BOOLEAN eigenesHaus NUMBER plz } Regeln { } }

(Abbildung 4.1.3: Ein verkettetes Attribut) //Liefert das Attribut zurück, das der Attributname im Regelnblock entspricht. List[Attribute] step1(Regel r):

getRegelnBlock(r).getEntR().attBlock.attribute.select(e|e.name == r.attrName);

Step1

Step2

Step3

Step4

30

//Liefert den Typ dieses Attribute zurück SelbstdefinierterAttrTyp step2(List[Attribute] a): a.first().selbstdefinierterAttrTyp; //sucht die Entität aus, die den Typ entspricht Entitaet step3(SelbstdefinierterAttrTyp s): s.getAttribute().getAttrBlock().getEntA().getModell().entitaet.select(e|e.en

titaetName.entName == s.sdAttrTyp).first(); //prüft ob das verkettete Attribut in der ausgesuchten Entität vorhanden ist List[Attribute] step4(Entitaet e,List[VerketteteAttribute] verketteteAttribute): e.attBlock.attribute.select(e|e.name ==

verketteteAttribute.first().attrName); //Hilfsmethode, step 1 bis step 3 Entitaet step1bis3(Regel r): step3(step2(step1(r))); Mehrere verkettete Attribute (Rekursiver Vorgang) : Man seht in der Abbildung, dass die Schritte (1-4) sich wiederholen, was sich ändert, ist das zu untersuchende Attribut von der verketteten Attribute und die zu untersuchende Entität.

Entitaet Angestellter { Attribute { TEXT name TEXT vorname Adresse adresse } Regeln {} }

Entitaet Firma { Attribute { TEXT name NUMBER anzahlDerAngestellter Angestellter angestellter1 } Regeln { name : minimale Laenge ( 2 ) : "Laenge Fehler" : Pruefe Syntax nur Buchstaben anzahlDerAngestellter : ist groesser als 10 : "Number Fehler" angestellter1 .name : Laenge ( 2 - 22 ) : "Laenge Fehler" angestellter1 .adresse .plz : Wertebereich (80000 - 99999) : "Wertebereich Fehler" } }

Entitaet Adresse { Attribute { TEXT strasse TEXT hausnr BOOLEAN eigenesHaus NUMBER plz } Regeln { } }

(Abbildung 4.1.4 : Mehrere verkettete Attribute)

/* eine Rekursive Methode, die eine Liste von Boolean zurückliefert. Wenn alle werte in der Liste „True“ sind, heißt das, dass alle verkettete Attribute in den zugehörigen Entitäten gefunden sind */

Step1

Step2

Step3

Step1.1

Step2.1

Step3.1

Step4.1

31

List[Boolean] stepA(List[Attribute] atr, List[VerketteteAttribute] verketteteAttribute, List[Boolean] list): let va = verketteteAttribute: va.isEmpty ? list: stepA(step4(step3(step2(atr)),va),va.withoutFirst(),

l(list,step4(step3(step2(atr)),va))); //Hilfsmethode List[Boolean] l(List[Boolean] li,List[Attribute] a): li.add(a.size==1); /* eine Rekursive Methode, die das letzte Attribut der verketten Attribute

Zurückliefert, um seinem Typ für andere Verwendung zu ermitteln */ List[Attribute] stepB(List[Attribute] atr, List[VerketteteAttribute]

verketteteAttribute): let va = verketteteAttribute: va.size == 1 ? step4(step3(step2(atr)),va):

stepB(step4(step3(step2(atr)),va),va.withoutFirst()); 4.1.4 Outline In Xtext kann auch das Outline angepasst werden, sowohl der angezeigte Name als auch das angezeigte Icon können selber verfeinert.

32

(Abbildung 4.1.5: Outline)

Die Outline-Konfiguration wird in den Editor Erweiterungen (EditorExtensions.ext) erstellt, der Vorgang erfolgt bei der Überschreibung von der allgemeinen Regel, die sich in der GenEditorExtensions-Datei befindet, durch die label- und image-Methode.

• label ( ) : ist für den angezeigten Name in der Outline zuständig • image ( ) : ist für den angezeigten Image in der Outline zuständig

Selbsterstellte Icon sollen sich in der Icon Folder im Editor-Project befinden. Inhalt der EditorExtensions.ext Datei: import beanvalidationdsl; extension org::example::dsl::Extensions reexport; extension org::example::dsl::GenEditorExtensions reexport; /* * use this file to overwrite the label() and the image() * extension for your model elements */

33

//optimierung von Outline, null wenn das Objekt nicht im Outline betrachtet soll label (Entitaet this): "Entitaet " + entitaetName.entName ; label (AttributeBlock this): "Attribute" ; label (RegelnBlock this) : "Regeln" ; label (Regel this) : attrName ; label (EntitaetName this): null; label ( Ausdrueck this): null; label ( RegExp this) : null; label ( SelbstdefinierterAttrTyp this) : null ; label ( VerketteteAttribute this) : null ; //selbsterstellte Icons image (Entitaet this) : "Entitaet.gif" ; //verschiedene Icons fur selbstdefinierte und vordefinierte Attribute image (Attribute this) : selbstdefinierterAttrTyp == null ? "Attribut.gif" :

"SDAttribute.gif" ; image (Regel this) : "Regel.gif" ; image (AttributeBlock this) : "AttributeBlock.gif"; image (RegelnBlock this) : "RegelnBlock.gif";

4.1.5 Auto-Complete (Syntaxvervollständigung): Xtext unterstützt auch die Syntaxvervollständigung (Autocomplete), dies wird anhand der erstellten Grammatik (DSL) erfolgen und in der Datei „GenContentAssist.ext“ generiert, weiterhin können die angezeigten Namen in dem Vervollständigungsfenster angepasst werden, dafür sollen die zu ändernden Namen in der „ContentAssist.ext“ Datei überschrieben.

(Abbildung 4.1.6: Autocomplete) Inhalt der ContentAssist.ext Datei import beanvalidationdsl;

34

import codeassist; extension org::example::dsl::Extensions; extension org::example::dsl::GenContentAssist reexport; //Optimiertung von Autocomplete, ueberschreibung der generierten methoden in GenExtensions.ext //'_' soll den Benutzer informieren, dass er selber diesen Eintrag eingeben soll List[Proposal] completeComplexExp_expArg(emf::EObject ctx, String prefix) : {newProposal("_Zeichenkette")}; /* proposals for Feature VerketteteAttribute::attrName */ List[Proposal] completeVerketteteAttribute_attrName(emf::EObject ctx, String prefix) : {newProposal("_Attribute Name")}; /* proposals for Feature SelbstdefinierteFunk::funkName */ List[Proposal] completeSelbstdefinierteFunk_funkName(emf::EObject ctx, String prefix) : {newProposal("_Selbstdefinierte Funktion Name")}; /* proposals for Feature Entitaet::name */ List[Proposal] completeEntitaet_name(emf::EObject ctx, String prefix) : {newProposal("_Entitaet Name")}; /* proposals for Feature Regel::message */ List[Proposal] completeRegel_message(emf::EObject ctx, String prefix) : {newProposal("_Message")}; /* proposals for Feature MatchArg::id */ List[Proposal] completeMatchArg_id(emf::EObject ctx, String prefix) : {newProposal("_Attribute Name")}; /* proposals for Feature Time::zeit */ List[Proposal] completeTime_zeit(emf::EObject ctx, String prefix) : {newProposal("_Zeit")}; /* proposals for Feature LengthArg::Nmax */ List[Proposal] completeLengthArg_Nmax(emf::EObject ctx, String prefix) : {newProposal("_Maximale Grenze-Integer")}; /* proposals for Feature Attribute::name */ List[Proposal] completeAttribute_name(emf::EObject ctx, String prefix) : {newProposal("_Attribute Name")}; /* proposals for Feature NumWert::wert */ List[Proposal] completeNumWert_wert(emf::EObject ctx, String prefix) : {newProposal("_Integer")}; /* proposals for Feature DateUndTime::tTime */ List[Proposal] completeDateUndTime_tTime(emf::EObject ctx, String prefix) : {newProposal("_Zeit")}; /* proposals for Feature Argument::number */ List[Proposal] completeArgument_number(emf::EObject ctx, String prefix) : {newProposal("_Integer")}; /* proposals for Feature Regel::attrName */ List[Proposal] completeRegel_attrName(emf::EObject ctx, String prefix) : {newProposal("_Attribute Name")};

35

/* proposals for Feature LengthArg::Nmin */ List[Proposal] completeLengthArg_Nmin(emf::EObject ctx, String prefix) : {newProposal("_Minimale Grenze-Integer")}; /* proposals for Feature DateUndTime::dDatum */ List[Proposal] completeDateUndTime_dDatum(emf::EObject ctx, String prefix) : {newProposal("_Datum")}; /* proposals for Feature Argument::zeichen */ List[Proposal] completeArgument_zeichen(emf::EObject ctx, String prefix) : {newProposal("_Zeichenkette")}; /* proposals for Feature SelbstdefinierterAttrTyp::sdAttrTyp */ List[Proposal] completeSelbstdefinierterAttrTyp_sdAttrTyp(emf::EObject ctx, String prefix) : {newProposal("_Entitaet Name")}; /* proposals for Feature MatchArg::st */ List[Proposal] completeMatchArg_st(emf::EObject ctx, String prefix) : {newProposal("_Zeichenkette")}; /* proposals for Feature Date::datum */ List[Proposal] completeDate_datum(emf::EObject ctx, String prefix) : {newProposal("_Datum")}; /* proposals for Feature RegExp::message2 */ List[Proposal] completeRegExp_message2(emf::EObject ctx, String prefix) : {newProposal("_Message")}; /* proposals for Feature Argument::idArg */ List[Proposal] completeArgument_idArg(emf::EObject ctx, String prefix) : {newProposal("_Argument-id")}; List[Proposal] completeEntitaetName_entName(emf::EObject ctx, String prefix) : {newProposal("_Entitaet Name")}; 4.1.6 xPand-Templates: Das Main Template befindet sich im Generator Projekt, mit Hilfe der xPand-Templates können verschiedene Modell-zu-Text Transformationen durchgeführt werden. In unserem Projekt, sind zwei Text-Dateien zu Generieren, eine JavaBean-Datei und eine XML-Datei.

• JavaBean: Die definierte Entitäten in dem erstellten Code werden zu Java-Klassen übersetzt, und die Attribute in dem zugehörigen AttributeBlock zu Java-Attribute.

o NUMBER int o GLEITKOMMAZAHL float o TEXT String o DATUM Date o BOOLEAN boolean

Es sollen auch setter und getter Methoden generiert • XML-Datei: die definierten Regeln im Regelnblock sollen entsprechend zu Valang-

Regeln übersetzt. Z.B. o Prüfe Syntax Regeln Match Funktion mit dem entsprechenden Parameter o Numerische Funktionen (? > , ? >= , ? < , ? <= , ? = , ? != )

36

o Boolean Funktionen is true , is false o Datum funktionen (? > , ? < , ? == )

Extentions befinden sich in der util.ext Datei Inhalt der xPand Templaes: «IMPORT beanvalidationdsl» «EXTENSION org::example::dsl::util» «REM» Autor: Wissam Odeh «ENDREM» «DEFINE main FOR Modell» «REM»Ruft javabean für jede Entitaet auf«ENDREM» «EXPAND javaBean FOREACH entitaet.typeSelect(Entitaet)» «REM»Ruft xmlDatei für jede Entitaet auf«ENDREM» «EXPAND xmlDatei FOREACH entitaet.typeSelect(Entitaet)» «ENDDEFINE» «REM»javaBean Definition«ENDREM» «DEFINE javaBean FOR Entitaet» «REM»Definition der Datei«ENDREM» «FILE entitaetName.entName.toFirstUpper() + ".java"» «REM»wenn ein Attribute von Typ 'Date' verwendet ist, importiere java.util.Date «ENDREM» «IF attBlock.attribute.vordefinierterAttrTyp.contains

(VordefinierterAttrTyp::datum)» import java.util.Date; «ENDIF» public class «entitaetName.entName.toFirstUpper()» { «REM»Attribute der Klasse«ENDREM» «FOREACH attBlock.attribute AS attr» private «EXPAND aType FOR attr.selbstdefinierterAttrTyp» «EXPAND aType FOR attr.vordefinierterAttrTyp»«attr.name»; «ENDFOREACH» «REM»setter Methoden«ENDREM» «FOREACH attBlock.attribute AS attr» /** * sets the «attr.name» * @param «attr.name» */ public void set«attr.name.toFirstUpper()-»(«

EXPAND aType FOR attr.selbstdefinierterAttrTyp-»«EXPAND aType FOR

attr.vordefinierterAttrTyp-»«attr.name»){ this.«attr.name» = «attr.name»; } «REM»getter Methoden«ENDREM» /** * @return the «attr.name» */ public «EXPAND aType FOR attr.selbstdefinierterAttrTyp»

«EXPAND aType FOR attr.vordefinierterAttrTyp» get«attr.name.toFirstUpper()»(){

return «attr.name»; } «ENDFOREACH»

37

} «ENDFILE» «REM»Ende der javeBean Definition«ENDREM» «ENDDEFINE» «REM»Hilfsmethode fuer javabean«ENDREM» «DEFINE aType FOR Attribute-»«ENDDEFINE» «REM»"«null -»" wird verwendet um den Generator zu informieren, dass es keine neue Zeile bei der Generierung noetig ist, sonst hat keinen Einfluss auf die Funktionalitaet «ENDREM» «DEFINE aType FOR VordefinierterAttrTyp-» «IF this.toString()=="text"-»String «null -» «ELSEIF this.toString()=="number"-»int «null -» «ELSEIF this.toString()=="datum"-»Date «null -» «ELSEIF this.toString()=="boolean"-»boolean «null -» «ELSEIF this.toString()=="gleitkommazahl"-»float «null -»

«ELSE-»«ENDIF-»«ENDDEFINE» «DEFINE aType FOR SelbstdefinierterAttrTyp»«this.sdAttrTyp»«ENDDEFINE» «REM»Definition der XML-Datei«ENDREM» «DEFINE xmlDatei FOR Entitaet-» «FILE entitaetName.entName.toFirstUpper() + ".xml"-» <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd"> <bean id="SteaValidator" class="org.springmodules.validation.valang.ValangValidator"> <property name="valang"> <value><![CDATA[ «FOREACH regelnBlock.regel AS rgl-» { «rgl.attrName-»«EXPAND verketteteAttr FOR rgl-» :«null -»

«EXPAND funktion FOR rgl.ausdrueck.vordefinierteFunk-» «EXPAND pruefeSyntax FOR rgl.regExp-» : '«rgl.message-» «IF rgl.regExp.message2!=null-» , «rgl.regExp.message2-

»«ENDIF-»' } «ENDFOREACH-» ]]></value> </property> </bean> </beans> «ENDFILE-» «ENDDEFINE» «REM»Aufruf der verschidenen Funktionen«ENDREM» «DEFINE funktion FOR VordefinierteFunk-» «EXPAND lengthFunk FOR lengthFunkName-»«EXPAND lenArg FOR lengthArg-» «EXPAND boolFunk FOR boolFunkName-» «EXPAND matchFunk FOR matchFunkName-»«EXPAND mtchArg FOR matchArg-» «EXPAND numFunk FOR numFunkName-»

«IF numWert != null-» «numWert.wert-»«ENDIF-» «IF float != null-»«float-»«ENDIF-»

«EXPAND datumFunk FOR datumFunkName-»«EXPAND variante FOR datumVariante-» «EXPAND komplexDatumFunk FOR komplexDatumVariante-»

38

«ENDDEFINE» «REM»uebersetzung der Lengthfunkionen in Valang«ENDREM» «REM» "«null -»" wird verwendet um den Generator zu informieren, dass es keine neue Zeile bei der Generierung noetig ist, sonst hat keinen Einfluss auf die Funktionalitaet «ENDREM» «DEFINE lengthFunk FOR LengthFunkName-» «IF this.toString()=="laenge"-» length(?) «null -» «ELSEIF this.toString()=="maxLaenge"-» length(?) < «null -» «ELSEIF this.toString()=="minLaenge"-» length(?) > «null -» «ELSEIF this.toString()=="wertebereich"-»? BETWEEN «null -» «ENDIF-» «ENDDEFINE» «REM»uebersetzung der LengthArgument«ENDREM» «DEFINE lenArg FOR LengthArg-» «IF vorDefFunk().lengthFunkName.toString()=="laenge"-» «IF numWert == null -»BETWEEN «Nmin-» AND «Nmax-»«ELSE-»== «numWert.wert-»«ENDIF-» «ELSEIF vorDefFunk().lengthFunkName.toString()=="wertebereich"-»«Nmin-» AND «Nmax-» «ELSE-»«numWert.wert-» «ENDIF-» «ENDDEFINE» «REM»uebersetzung der booleanFunktionen«ENDREM» «DEFINE boolFunk FOR BoolFunkName-» «IF this.toString()== "istTrue"-» ? == TRUE«null -» «ELSEIF this.toString()== "istFalse"-» ? == FALSE«null -» «ENDIF-» «ENDDEFINE» «REM»uebersetzung der MatchFunktionen«ENDREM» «DEFINE matchFunk FOR MatchFunkName-» «IF this.toString()=="match"-»match(?,«null -» «ELSEIF this.toString()=="matchMitCase"-»match(?,«null -» «ELSEIF this.toString()=="matchOhneCase"-»match(lower(?),lower(«null -» «ENDIF-» «ENDDEFINE» «REM»uebersetzung der MatchArgumente«ENDREM» «DEFINE mtchArg FOR MatchArg-» «IF vorDefFunkMatch().matchFunkName.toString()== "matchMitCase"-»«id-»«st-») is true «null -» «ELSEIF vorDefFunkMatch().matchFunkName.toString()== "matchOhneCase"-» «id-» «st-»)) is true«null -» «ELSEIF vorDefFunkMatch().matchFunkName.toString()== "match"-»«id-»«st-») is true«null -» «ENDIF-» «ENDDEFINE» «REM»uebersetzung der NumberFunktionen«ENDREM» «DEFINE numFunk FOR NumFunkName-» «IF this.toString()== "istGroesserAls"-» ? > «null -» «ELSEIF this.toString()== "istKleinerAls"-» ? < «null -» «ELSEIF this.toString()=="istGroessegleich"-» ? >= «null -» «ELSEIF this.toString()=="istKleinergleich"-» ? <= «null -» «ELSEIF this.toString()=="istGleich"-» ? == «null -» «ELSEIF this.toString()=="istNichtGleich"-» ? != «null -» «ENDIF-» «ENDDEFINE» «REM»uebersetzung der DatumFunktionen«ENDREM»

39

«DEFINE datumFunk FOR DatumFunkName-» «IF this.toString()=="vor"-» ? < «null -» «ELSEIF this.toString()=="nach"-» ? > «null -» «ELSEIF this.toString()=="ist"-» ? == «null -» «ENDIF-» «ENDDEFINE» «REM»uebersetzung der komplexeren DatumFunktionen«ENDREM» «DEFINE komplexDatumFunk FOR KomplexDatumVariante-» «IF this != null-»? BETWEEN «null -» «EXPAND dateArg FOR date1-» «EXPAND timeArg FOR time1-» «EXPAND dateUndTimeArg FOR dut1-» AND «null -» «EXPAND dateArg FOR date2-» «EXPAND timeArg FOR time2-» «EXPAND dateUndTimeArg FOR dut2-» «ENDIF-» «ENDDEFINE» «REM»uebersetzung der DatumVarianten«ENDREM» «DEFINE variante FOR DatumVariante-» «IF this != null-» «EXPAND dateArg FOR date-» «EXPAND timeArg FOR time-» «EXPAND dateUndTimeArg FOR dateUndTime-» «ENDIF-» «ENDDEFINE» «REM»uebersetzung der DatumArgumente«ENDREM» «DEFINE dateArg FOR Date-» «IF this != null-» [«datum.subString(7,11)-».«datum.subString(4,6)-».«datum.subString(1,3)-»]«null -» «ENDIF-» «ENDDEFINE» «DEFINE timeArg FOR Time-» «IF this != null-» «zeit»«null -» «ENDIF-» «ENDDEFINE» «DEFINE dateUndTimeArg FOR DateUndTime-» «IF this != null-» [«dDatum.subString(7,11)-».«dDatum.subString(4,6)-».«dDatum.subString(1,3)-» «tTime.subString(1,tTime.length)»«null -» «ENDIF-» «ENDDEFINE» «REM»uebersetzung der pruefeSyntax Terme«ENDREM» «DEFINE pruefeSyntax FOR RegExp-» «IF exp1 != null || complexExp1 != null-» AND ( «EXPAND PSFunktion1 FOR this-»«EXPAND PSFunktion2 FOR this-» )«null -» «ENDIF-» «ENDDEFINE» «REM»uebersetzung des ersten Teils von pruefeSyntaxFunktionen«ENDREM» «DEFINE PSFunktion1 FOR RegExp-» «IF exp1.toString() == "nurZiffern"-»match('[1-9][0-9]*',?) is true«null -» «ELSEIF exp1.toString() == "nurBuchstaben"-»match('[a-zA-Z]+',?) is true«null -»

40

«ELSEIF exp1.toString() == "nurKleinbuchstaben"-»match('[a-z]+',?) is true«null -» «ELSEIF exp1.toString() == "nurGrossbuchstaben"-»match('[A-Z]+',?) is true«null -» «ELSEIF exp1.toString() == "email"-»email(?)==true«null -» «ELSEIF exp1.toString() == "url"-» url(?)«null -» «ELSEIF complexExp1.complexExpName.toString()=="beginntMit"-»

match('«complexExp1.expArg-».*',?) is true«null -» «ELSEIF complexExp1.complexExpName.toString()=="endetMit"-»

match('.*«complexExp1.expArg-»',?) is true«null -» «ENDIF-» «ENDDEFINE» «REM»uebersetzung des zweiten Teils von pruefeSyntaxFunktionen«ENDREM» «DEFINE PSFunktion2 FOR RegExp-» «IF exp2 != null || complexExp2 != null-» «IF and=="und"-» AND «ENDIF-»«IF or=="oder"-» OR «ENDIF-» «IF exp2.toString() == "nurZiffern"-»match('[1-9][0-9]*',?) is true«null -» «ELSEIF exp2.toString() == "nurBuchstaben"-»match('[a-zA-Z]+',?) is true«null -» «ELSEIF exp2.toString() == "nurKleinbuchstaben"-»match('[a-z]+',?) is true«null -» «ELSEIF exp2.toString() == "nurGrossbuchstaben"-»match('[A-Z]+',?) is true«null -» «ELSEIF exp2.toString() == "email"-»email(?)==true«null -» «ELSEIF exp2.toString() == "url"-» url(?)«null -» «ELSEIF complexExp2.complexExpName.toString()=="beginntMit"-»match('«complexExp2.expArg-».*',?) is true«null -» «ELSEIF complexExp2.complexExpName.toString()=="endetMit"-»match('.*«complexExp2.expArg-»',?) is true«null -» «ENDIF-» «ENDIF-» «ENDDEFINE» «REM»uebersetzung der verketteten Attribute«ENDREM» «DEFINE verketteteAttr FOR Regel-» «FOREACH verketteteAttribute AS e-» «IF e.attrName !=null-».«e.attrName-»«ENDIF-» «ENDFOREACH-» «ENDDEFINE» «ENDDEFINE»

41

4.2 Die Eclipse Rich Client Plattform – (Implementierung) Auf serverbasierten Systemen und mobilen Endgeräten ist die Java-Technologie weit verbreitet und erfolgreich im Einsatz. Bei vielen Unternehmen hat sich die Java EE als Standard für die Entwicklung von Geschäftsanwendungen etabliert. Die Benutzerschnittstelle – sofern innerhalb der Java-Anwendung überhaupt vorhanden – wird vorrangig auf Basis von Web-Technologie entwickelt, der clientseitige Zugriff für den Anwender erfolgt demnach mit einem Web-Browser als Thin-Client. Thin-Client (z.B. Web-Anwendungen) werden zentral betrieben und bieten deshalb Vorteile bei Roll-Out, Verwaltung und Pflege. Clientseitig müssen nur Grundvoraussetzungen erfüllt werden, beispielsweise das Vorhandensein eines Browsers. Anforderungen wie z.B. die Nutzung des lokalen Dateisystems bzw. anderer lokaler Ressourcen oder etwa Offline-Funktionalität mit anschließender Datensynchronisierung ließen sich mit Web-Clients, wenn überhaupt, nur unter größten Schwierigkeiten umsetzen. Auf dem Desktop hingegen war die Akzeptanz von Java bis zuletzt sehr gering. Erst seit kurzer Zeit kann Java auch in diesem Bereich ein stetiges Wachstum an Popularität verzeichnen. Dieser Trend ist eng mit dem Begriff des Rich-Clients verbunden. Ein Framework zur Entwicklung von Rich-Clients bietet allerdings nicht nur ein vorgefertigtes, umfangreiches Set an Oberflächenkomponenten, sondern bringt üblicherweise eine modulare Grundstruktur und ein einheitliches Modell zur Entwicklung von eigenen Komponenten mit. 4.2.1 Eclipse Plattform für Rich-Clients Das Anforderungsprofil für Rich-Clients ist umfangreich und der Einsatz eines umfassenden Applikation Frameworks für die verschiedensten Problemstellungen ist damit ein kritischer Erfolgsfaktor für Realisierungsprojekte. In diesem Umfeld hat sich die "Rich Client Plattform" von Eclipse (Eclipse RCP) etabliert und zeigt momentan eindrucksvoll wie erfolgreich Java-basierte Anwendungen auf dem Desktop entwickelt werden können. Die Eclipse RCP selbst ist im Wesentlichen in zwei Bereiche gegliedert: Einerseits Equinox, die Laufzeitumgebung für Komponenten, den so genannten Plug-In, und andererseits die "Workbench" als eine Art Baukastensystem für Benutzeroberflächen. Equinox basiert auf der Spezifikation der Open Services Gateway initiative (OSGi), und ermöglicht die Steuerung des Lebenszyklus der Plug-In. So können beispielsweise Plug-In während der Laufzeit installiert, ausgeschaltet oder ausgetauscht werden. Equinox verwaltet dabei die Abhängigkeiten zwischen den einzelnen Plug-In und bildet das Fundament der Eclipse RCP.

42

Abbildung 4.2.1 Architektur von Eclipse RCP Die Workbench bietet eine erweiterbare Infrastruktur für die Darstellung von Oberflächenkomponenten wie Dialoge, Menüs oder Toolbars und koordiniert ihr Zusammenspiel in den verschiedenen Fenstern einer Anwendung. Wichtige Kernbestandteile der Workbench sind das bereits erwähnte SWT und das darauf aufbauende JFace-Toolkit. JFace standardisiert einige Anforderungen mit denen Entwickler häufig konfrontiert werden: Damit sind beispielsweise die Entwicklung von Wizards, die Verwaltung von Ressourcen für die Benutzeroberfläche oder die saubere Trennung zwischen den Komponenten und den dahinter liegenden Aktionen gemeint. Auf dieser Basis hält Eclipse RCP noch viele weitere, optionale Komponenten, wie ein Hilfesystem, einen Update-Manager, Reporting-Tools und Frameworks für Text- oder graphische Editoren bereit. Auch das individuelle "Branding" des Richt-Clients an einen gewünschten Styleguide ist möglich. Die Eclipse RCP ermöglicht es dem Entwickler sich größtenteils auf die Entwicklung der eigentlichen Anwendungskomponenten und deren Integration in die Plattform zu konzentrieren. Der Ansatz der Rich-Clients, insbesondere in der Ausprägung der Eclipse RCP, hat sich in der Praxis als sehr geeignete Plattform erwiesen, um auch in Java performante und den üblichen Standards und Gewohnheiten entsprechende Desktop-Applikationen im Enterprise-Umfeld zu entwickeln. 4.2.2Die Eclipse RCP für das Projekt 4.2.2.1 Oberfläche für Editor

Editoren sind die Sichtfenster, die meist den Quelltext mit Syntaxhervorhebung anzeigen, wobei es meist für jede unterstützte Programmiersprache einen eigenen Editor gibt (zum Beispiel für DSL). Genauso gibt es aber auch visuelle Editoren oder die Baumstrukturen anzeigen. Mehrere geöffnete Quelltexte werden als Reiter geöffnet, die über Tabs am oberen Rand in den Vordergrund gebracht werden können, weiterhin können Tabs fixiert werden, so

43

dass der zugehörige Quelltext nicht versehentlich geschlossen wird. Auch Editoren können weitgehend frei per Drag und Drop angeordnet werden. Eine Datei kann in mehreren Editoren gleichzeitig geöffnet werden. Menü und Tools-bar sind Schnellzugriff auf bestimmte, häufig verwendete Funktion ermöglicht, z.B. ‘‘Öffnen‘‘, ‘‘Speichern‘‘ . 4.2.2.2 Integration von Plug-In DSL-Module wird als ein Plug-In in Editor integriert, so dass Quelltexte von DSL unterstützt werden. 4.2.2.3 Erstellung einer Applikation

Nach der Integration von DSL-Module werden die Programme als eine Standalone -Applikation exportiert. 4.2.3 Implementierung Abbildung 3.3.1 zeigt die Übersicht der Oberfläche.

44

Abbildung 4.2.2 Übersicht der Oberfläche Die Oberfläche bestand aus drei Teilen.

1. Menü

File Abbildung 3.3.2

Edit Abbildung 3.3.3

Search Abbildung 3.3.4

Help Abbildung 3.3.5

Abbildung 4.2.3 Menü - File

45

Abbildung 4.2.4 Menü - Editor

Abbildung 4.2.5 Menü - Search

Abbildung 3.3.4 Menü - help

2. Toolbar – die häufig verwendete Funktionen wurden in toolbar gesetzt. Z.B. öffnen, speichern, neues Dokument, Exportieren ,Suchen.

Abbildung 4.2.6 toolbar

3. Editor – wie in der Übersicht der Oberfläche,. Der Benutzer kann in diesem Bereich Text eingeben.

4.2.4 Architektur des Editors

Nachdem Auswahl des Dokuments wurde RCP einen Editor, die schon in RCP eingetragen wurde, automatisch aufgerufen, z.B. der Benutzer öffnete ein DSL Dokument, dann wurde VALANG-DSL-Editor aufgerufen. In dem Projekt wurde drei verschiedenen Editors eingetragen im RCP. VALANG-DSL-Editor ist für DSL Dokument, er basiert auf dem Plug-In von OWA. XML_HTML Text Editor ist speziell für XML oder HTML Dokument, die Syntax von XML und HTML wurde verfärbt. Wenn das Dokument als anderes Format gespeichert wurde, wurde es als Text Dokument von Default Simple Text Editor öffnet. Abbildung 3.4.2 zeigt diese Architektur. Abbildung 3.4.1 zeigt die Methode getEditorId in dem Code. private String getEditorId(File file) { if (file.getName().endsWith("xml")||

file.getName().endsWith("html"))

46

return org.eclipse.ui.examples.rcp.texteditor.editors.xml.XMLEditor"; if (file.getName().endsWith("dsl")) return "org.example.dsl.editor.BeanValidationdslEditor"; else return "org.eclipse.ui.examples.rcp.texteditor.editors.SimpleEditor"; Abbildung 4.2.7 getEditorID

47

4.3 Zusammenfassung und Ausblick Valang ist für die Benutzer lesbar und einfach, aber auch umfangreich. Von außen betrachtet auch ein bisschen komplex. Unser Ziel ist mit der DSL die Formularausfüllung von Internetseiten zu validieren. Deswegen haben wir uns auf die Datentypen und Wertebereiche von möglichen Formularen beschränkt. Dadurch wollten wir die Komplexität der Sprache vermeiden. Warum braucht man überhaupt Valang-XML Datei für die Formulare? Damit man viele eventuelle Fehler vermeiden kann, ohne sich mit einer Datenbank zu verbinden oder mit komplexen Programmen zu bearbeiten. Wir haben uns immer wieder mit den Fragen beschäftigt, wie man einen Feldbereich definieren sollte. Zum Beispiel wollen wir einen Wertebereich definieren zwischen 5 und 20. Hier könnten wir mit dem BETWEEN Operator, mit der Length Funktion oder Match() Funktion arbeiten. Wir haben im Internet verschiedene Seiten angeschaut und unsere DSL so gestaltet, dass eventuelle Fehler sofort festgestellt werden können. Unsere Grammatik unterstützt die häufig verwendeten Attributtypen und Funktionen. Mit den Constraints werden die meisten Syntaxfehler behandelt, weiterhin sind Syntaxvervollständigung und Outline-Fenster angepasst. Mögliche Erweiterungen: DSL-Erweiterungen: es können zusätzliche Funktionen und Attributtypen definiert.

• URL-Prüfung Funktion • Negierung Funktion (not) • Unterstützung von Felder (Arrays)

Constraints-Erweiterungen: • Zusätzliche Syntax- und Semantikfehler behandeln • Verbotene Schlüsselwörter hinzufügen

Outline-Erweiterungen: • Unser Outline merkt die Entitäten, Attribute und Regeln, eine weitere

Verschachtelung in den Regeln ist noch möglich, z.B. dass das Outline noch die Funktionen und deren Parameter merkt.

xPand-Templates Erweiterungen: • Beanvalidation-XML Template • Ein Template für JUnit-Test, die für die angegebenen Attribute ein GUI erstellt, in

dem die werte der Attribute zugewiesen können und damit das Test leichter gestaltet.

48

Referenzen: Stahl, Thomas / Völter, Markus u.a. : Modellgetriebene Softwareentwicklung, dpunkt, 2. Auflage, 2007. Wikipedia, die freie Enzyklopädie, http://de.wikipedia.org/wiki/Modell OpenArchitectureWare: www.openarchitectureware.org/ xText Referenz: www.eclipsecon.com/gmt/oaw/doc/4.1/r80_xtextReference.pdf

www.eclipse.org/gmt/oaw/doc/4.3beta/xtext-4.3.pdf xPand Referenz: www.eclipse.org/gmt/oaw/doc/4.1/r20_xPandReference.pdf