Lade Inhalt...

Yakindu SCT Plugin für die Generierung von endlichen Automaten in Swift

Projektarbeit 2017 53 Seiten

Informatik - Software

Leseprobe

Inhaltsverzeichnis

Abbildungsverzeichnis

Quellcodeverzeichnis

Abkürzungsverzeichnis

1 Einleitung

2 Grundlagen
2.1 Endliche Automaten
2.2 Yakindu Statechart Tools (Yakindu SCT)
2.3 Swift

3 Architektur von Yakindu SCT
3.1 Übersicht
3.2 Entwicklungssprache
3.3 Klassenarchitektur

4 Entwurf des Generators
4.1 Voraussetzungen
4.2 Endgültiger Entwurf

5 Realisierung des Generators
5.1 Relevante Klassen und Definitionen
5.2 Timer
5.3 Statemachine

6 Validierung der Implementation
6.1 Statemachine UnitTest Befehle
6.2 Definition der Befehle in Swift
6.3 Generieren und Ausführen der Tests

7 Zusammenfassung und Ausblick

Literaturverzeichnis

Stichwortverzeichnis

Abbildungsverzeichnis

2.1 Beispiel eines endlichen Automaten

2.2 Composite State

2.3 Zeitabhängige Ausführung

2.4 Choice

2.5 Junction

2.6 Synchronisation

2.7 Exit State

2.8 Interface

2.9 Designer

2.10 Simulation

2.11 Generation

3.1 Architektur

3.2 Dependency Injection

3.3 GeneratorModule

3.4 IExecutionFlowGenerator

3.5 ICodegenTypeSystemAccess

3.6 placeholder

3.7 SExecExtensions

3.8 StextNameProvider

3.9 ITypeSystem

3.10 Generator Steps

3.11 Generator Ausdrücke

4.1 Swift Aufbau

4.2 Endgültiger Generator Entwurf

6.1 endlicher Automat für die Choice-Testgruppe

6.2 Testergebniss des Choice-Tests

Quellcodeverzeichnis

3.1 Xtend vs Java

3.2 Xtend Extension Methods

3.3 Xtend Template Expressions

3.4 Xtend Template Expressions Output

3.5 Vereinfachter Xtext Auszug aus Yakindu SCT

3.6 Dependency Injection Code

5.1 GeneratorModule

5.2 Plguin XML

5.3 Generator

5.4 TypeSystemAccess

5.5 NamingService

5.6 FlowCode

5.7 ExpressionCode

5.8 FileGenerator

5.9 ITimer

5.10 ITimerCallback

5.11 TimerService

5.12 IStatemachine

5.13 StatemachineInterface

5.14 Statemachine

6.1 Statechart Operationen

6.2 If-Befehl für den bedingten Ablauf

6.3 While-Befehl für den bedingten Ablauf

6.4 Setzten von Variablen

6.5 Überprüfen von Variablen

6.6 Auslösen von Events

6.7 Zustände Überprüfen

6.8 Unit Test für die Choice-Testgruppe

6.9 Swift Vorlage für eine Testgruppe

6.10 Swift Vorlage für die Statemachine Operationen

6.11 Swift Vorlage für den bedingten Ablauf

6.12 Swift Vorlage für Variablen

6.13 Swift Vorlage für Variablen

6.14 Swift Vorlage für Events

6.15 Swift Vorlage für Zustände

6.16 Unit Test in Swift

6.17 Einstiegspunkt fürs Testen unter Swift

Abkürzungsverzeichnis

Abbildung in dieser Leseprobe nicht enthalten

1 Einleitung

In der Softwarebranche gibt es viele verschiedene Entwicklungssprachen für die unterschied­lichsten Anwendungszwecke und Plattformen. Einige dieser Plattformen ermöglichen dabei die Entwicklung von Programmen in den unterschiedlichsten Sprachen, während andere die Entwick­lung auf einige wenige beschränken. Im Vergleich dazu beschreiben Konzepte, wie z.B. endliche Automaten, sprachunabhängig ein Konzept, welches dann in die jeweilige Sprache übertragen werden kann. Solche Entwicklungskonzepte können daher einmal in einer generellen Form be­schrieben und dann in den unterschiedlichen Sprachen generiert werden. Dies hat den Vorteil, dass komplexe Abläufe wie endliche Automaten nur einmal definiert werden müssen, um dann in mehreren Sprachen angewandt zu werden.

Yakindu SCT ist ein Programm, welches die grafische Modellierung eines endlichen Automaten sprachunabhängig ermöglicht. Dazu werden z.B. eigene Datentypen definiert, welche dann inner­halb des endlichen Automaten verwendet werden können. Im zweiten Schritt kann der endliche Automat dann in der gewünschten Programmiersprache generiert und damit in dieser verwendet werden. Dies realisiert die oben erwähnte semantische Trennung zwischen einem sprachunabhän- gigen Konzept und dessen Implementierung in einer Sprache. Sollte die gewünschte Sprache noch nicht vorhanden sein, besteht die Möglichkeit diese als Plugin hinzuzufügen.

Dies ist z.B. notwendig für die Verwendung von Yakindu SCT in der Mobilen Entwicklung. Während die Entwicklungssprache Java, welche für Android verwendet wird, bereits implemen­tiert ist, gibt es für die noch relativ junge Sprache Swift, die unter iOS verwendet wird, keine entsprechende Implementierung. Diese Projektarbeit soll sich daher mit der Entwicklung eines Yakindu SCT Generators für die Sprache Swift befassen, um die Verwendung von Yakindu SCT in der mobilen iOS Entwicklung zu ermöglichen.

Ziel der Arbeit

Das Ziel dieser Arbeit besteht darin, Yakindu SCT um die Entwicklungssprache Swift zu er­weitert und damit die Generierung von endlichen Automaten z.B. für die iOS Entwicklung zu ermöglichen. Ein weiteres Ziel ist die Darstellung der Architektur, welche für das Hinzufügen von neuen Sprachen benötigt wird, um zukünftigen Entwicklern die Integration einer neuen Sprache zu vereinfachen. Es ist allerdings nicht das Ziel, eine vollständige Anleitung für das Integrieren einer neuen Sprache zu erstellen. Viel mehr soll es darum gehen, dass notwendige Wissen über die Architektur und den Ablauf zu vermitteln.

Um das Problem anzugehen, werden im ersten Schritt die benötigten Grundlagen angesprochen. Diese werden, abgesehen von der Entwicklungssprache Swift, ebenfalls für die Integration jeder anderen Sprache benötigt und stellen das Fundament für die Entwicklung eines Generators dar.

Der zweite Schritt befasst sich mit der Architektur von Yakindu SCT, welche z.B. die Klassen beinhaltet, die im Generator verwendet oder implementiert werden müssen. In dem Kapitel wird es zusätzlich um verwendete Entwicklungssprachen und Konzepte gehen, welche in Yakindu SCT, und daher auch im Generator, verwendet werden. Im dritten Schritt wird ein Entwurf des Ge­nerators erstellt, der auf die von Swift bereitgestellten Funktionalitäten angepasst ist.

Die Implementierung dieses Entwurfs wird im vierten Schritt beispielhaft veranschaulicht. Der letzte Schritt befasst sich mit der Qualitätskontrolle des Generators. Dazu bietet Yakindu SCT entsprechende vordefinierte Testfälle, welche überprüfen, ob die verschiedenen Funktionalitäten eines endlichen Automaten funktionsfähig in der neuen Sprache generiert werden. In diesem Schritt muss ein zweiter Generator erstellt werden, welcher die Testfälle in einem Testframework von Swift generiert, damit diese dann auf dem generierten endlichen Automaten ausgeführt werden können. Abgeschlossen wird die Arbeit mit einer Zusammenfassung, einem Ausblick und einer kritischen Reflexion.

2 Grundlagen

Für die Erstellung eines neuen Yakindu SCT Generators werden entsprechende Grundlagen be­nötigt, welche in diesem Kapitel angesprochen werden sollen. Dazu werden im Folgenden die notwendigen Informationen über die verwendete Sprache Swift, Yakindu SCT und endliche Au­tomaten vermittelt. Dies soll dazu dienen, eine Wissensbasis sicherzustellen, auf der diese Arbeit aufbauen kann.

2.1 Endliche Automaten

Endliche Automaten sind ein Verhaltensmodel und werden u.a. verwendet für die Definition einer Operation oder einen Ablauf. Sie bestehen aus sogenannten Zuständen, welche durch Transitionen verbunden sind. Diese Transitionen ermöglichen den Wechsel von einem Zustand in den Nächsten in Abhängigkeit von einer Bedingung. Eine solche Bedingung ist dabei entweder ein Event, eine Zeitspanne oder eine Variable. Eine Aktion kann entweder in einer Transition oder einem Zustand ausgeführt werden und führt z.B. dazu, dass Variablen manipuliert oder Funktionen aufgerufen werden. Das Beispiel in der Abbildung 2.1 zeigt den grundsätzlichen Aufbau eines solchen endlichen Automaten.

Abbildung in dieser Leseprobe nicht enthalten

Abbildung 2.1: Beispiel eines endlichen Automaten

Unterschieden wird in der Automatentheorie zwischen den folgenden Arten von endlichen Auto­maten.

2.1.1 Moore

Der Moore Automat, benannt nach seinem Erfinder Edward Moore, beinhaltet Zustände und Transitionen. Die Aktionen werden bei diesem Modell nur in Zuständen durchgeführt und nicht in Transitionen. Der endliche Automat aus Abbildung 2.1 wird zu einem Moore Automat, wenn die Aktion aus der Transition zwischen dem ersten und dem zweiten Zustand entfernt wird.

2.1.2 Mealy

Der Mealy Automat, benannt nach George H. Mealy, beinhaltet die gleichen Objekte wie der Moore Automat. Im Vergleich zu diesem werden die Aktionen allerdings nicht in den Zuständen, sondern nur in den Transitionen durchgeführt. In diesem Fall müssten aus der Abbildung 2.1 die Aktionen im ersten und zweiten Zustand entfernt werden.

2.1.3 Harel

Die Mealy und Moore Automaten sind die Basisautomaten in der Automatentheorie. Da diese al­lerdings eine flache Hierarchie verwenden, wird das Erstellen von komplexen endlichen Automaten unübersichtlich und unstrukturiert. David Harel hat aus diesem Grund zusätzliche Elemente wie z.B. “composite states“ mit Orthogonalität hinzugefügt, welche im folgenden kurz erklärt werden.

Composite State

Ein “Composite State“ ist in Abbildung 2.2 als “State 2“ dargestellt. Dieser Zustand beinhal­tet zusätzliche Unterautomaten, welche ausgeführt werden, wenn der “State 2“ aktiv wird. Ein “Composite State“ wird zusätzlich als orthogonal bezeichnet, wenn mehr als nur ein Unterau­tomat vorhanden ist. Diese Unterautomaten werden gleichzeitig und unabhängig voneinander ausgeführt und verlieren ihren Zustand, sobald der “State 2“ verlassen wird.

Abbildung in dieser Leseprobe nicht enthalten

Statechart State

Ein “Statechart State“ ist vergleichbar mit einem “Composite State“. Der Unterschied zwischen den beiden ist, dass der “Statechart State“ den Unterautomaten nicht direkt beinhaltet, sondern stattdessen referenziert. Damit ist es möglich, einen Unterautomaten zu definieren und diesen dann in mehreren “Statechart States“ zu verwenden.

History

Die “History“ ermöglicht es den Zustand eines Unterautomaten zu speichern. In der Abbildung 2.2 hat der eine Unterautomat einen anderen Startpunkt als der Andere. Dieser Startpunkt bein­haltet ein “H“ und symbolisiert damit, dass der Zustand des Unterautomaten beim Verlassen von “State 2“ gespeichert wird. Ein erneutes Aktivieren von “State 2“ führt dann dazu, dass der zuletzt aktive Zustand des Unterautomaten aktiv wird. Man unterscheidet bei der “History“ zwischen “Shallow“ und “Deep“, wobei die “Deep History“ zusätzlich rekursiv den Zustand aller Unterau­tomaten speichert. Dies bringt den Vorteil, dass nicht jeder Unterautomat mit einer “History“ ausgestattet werden muss, sofern der Zustand aller Unterautomaten gespeichert werden soll. Auf der anderen Seite bringt es den Nachteil, dass ein Unterautomat nicht direkt offensichtlich zeigt, ob dieser seinen Zustand speichert oder nicht. Dies kann zu Fehlern führen, da der Ersteller nicht erwartet, dass der Zustand über die übergeordnete “History“ gespeichert wird. Diese beiden Fälle sollten beim Einsatz entsprechend beachtet werden.

Events

Events sind eine besondere Form von Bedingungen für Transitionen. Nach dem Auslösen eines Events wird dieses beim nächsten Durchlauf ausgewertet. Nach dem Durchlauf werden dann alle Events zurückgesetzt, unabhängig davon, ob sie zur Ausführung einer Transition geführt haben oder nicht. Damit sind Events vergleichbar mit einer Variable, dessen Typ einem Wahrheitswert entspricht und die nach jedem Durchlauf zurückgesetzt wird.

Zeitabhängige Ausführung

Die zeitabhängige Ausführung ermöglicht einen Wechsel zwischen Zuständen oder das Ausführen einer Aktion nach einer bestimmten Zeit. Ein Beispiel dafür ist dargestellt in der Abbildung 2.3.

Abbildung in dieser Leseprobe nicht enthalten

Abbildung 2.3: Zeitabhängige Ausführung

Choice und Junction

Abbildung in dieser Leseprobe nicht enthalten

Ein “Choice“ Element ermöglicht das Separieren von ähnlichen Bedingungen. Als Beispiel dafür ist in Abbildung 2.4 ein Zustand dargestellt, welcher zu drei weiteren Zuständen führt, sobald ein Event ausgelöst wird. In welchen der drei Zustände gewechselt wird, ist abhängig von einer Variable, welche den Wert 0, 1 oder 2 beinhalten kann. Normalerweise müssen nun drei Tran­sitionen erstellt werden, mit den Bedingungen “event [var % 3 == x ]“. Eine Choice dagegen verhindert, dass “event“ in jeder Transition angegeben werden muss. Statt dessen wird die Tran­sition zum “Choice“ durchgeführt, sobald das Event ausgelöst wird. Danach gibt es dann drei weitere Transitionen, welche die Variable unabhängig vom Event auswerten. Dies vereinfacht z.B. die Umbenennung des Events, da dieses dann nicht dreimal, sondern nur einmal angepasst werden muss.

Abbildung in dieser Leseprobe nicht enthalten

Abbildung 2.5: Junction

Die “Junction“ funktioniert prinzipiell entgegengesetzt vom “Choice“. Während die “Choice“ eine Eingaben- und mehrere Ausgabentransitionen besitzt, hat die “Junction“ mehrere Eingaben- und nur eine Ausgabentransition. Dies kann z.B. verwendet werden, wenn drei Transitionen die gleiche Operation ausführen und zu gleichen “States“ führen (siehe Abbildung 2.5). Mit einer “Junction“ ist es in diesem Fall nicht notwendig, jede Transition mit der Bedingung und Operation “end / do()“ auszustatten. Stattdessen wird dreimal die Bedingung und einmal die Operation angegeben.

Zuletzt ist es außerdem möglich “Junction“ und “Choice“ zu verbinden. In diesem Fall gibt es dann mehrere Eingaben- und mehrere Ausgabenentransitionen. Dies kann z.B. verwendet werden, wenn mehrere Zustände abhängig von der gleichen Bedingung zu dem gleichen Zuständen führen.

Fork und Join

Die beiden Elemente “fork“ und “join“ werden gemeinsam verwendet, um einen Ablauf simultan durchzuführen. Dabei werden im ersten Schritt über ein “Fork“ Transitionen von einem Zustand auf zwei oder mehr Zustände erstellt. Diese Zustände werden dann gleichzeitig und unabhängig voneinander ausgeführt und können zu weiteren Zuständen führen. Um diesen parallelen Ablauf wieder zu beenden, wird ein “Join“ Element verwendet. Bei diesem wird eine Transition von jedem Endzustand zu dem “Join“ erstellt. Sobald alle Abläufe im “Join“ geendet sind, wird der Zustand ausgeführt, auf den der “Join“ verweist. Ein Beispiel dafür ist unter Abbildung 2.6 dargestellt, welches einen parallelen Ablauf von zwei Zuständen darstellt. Der finale Zustand wird erst erreicht, sobald die Bedingungen der Transitionen von beiden Zuständen zum “Join“ erfüllt sind.

Abbildung in dieser Leseprobe nicht enthalten

Abbildung 2.6: Synchronisation

2.1.4 UML

Der UML Automat ist die aktuellste Variante und basiert auf den Harel Automaten. In diesem werden zusätzlich die folgenden zwei Funktionalitäten hinzugefügt. [SC]

Exit State

Die erste Funktionalität ist ein “Exit State“, welcher verwendet werden kann, um die Ausführung eines Unterautomaten zu beenden. Damit ist es möglich, eine Transition vom “Composite State“ zum nächsten State zu erstellen, ohne eine Bedingung anzugeben. Diese wird dann automatisch durchgeführt, sobald der “Exit State“ im Unterautomaten erreicht wird. Ein endlicher Automat mit einem “Exit State“ ist dargestellt unter Abbildung 2.7.

Abbildung in dieser Leseprobe nicht enthalten

Abbildung 2.7: Exit State

Interface

Die zweite Funktionalität ermöglicht das Angeben vom Variablen, Events und Operationen in einem Interface. Es ist damit z.B. möglich, diese zu gruppieren und Namen wiederzuverwenden. Ein Beispiel dafür ist ein Interface mit dem Namen “Knopf“. Dieses beinhaltet dann die Ope­rationen “gedrueckt“ und “nichtGedrueckt“. Aufgerufen werden können diese Operationen durch das Angeben von “Knopf.gedrueckt()“ oder “Knopf.nichtGedrueckt()“. Die Abbildung 2.8 zeigt diese Funktionalität mit zwei zusätzlichen Events, welche ebenfalls in dem Interface definiert sind.

Abbildung in dieser Leseprobe nicht enthalten

Abbildung 2.8: Interface

2.2 Yakindu SCT

Yakindu SCT ist ein von der itemis AG entwickeltes Programm, welches das Modellieren, Simu­lieren und Generieren von endlichen Automaten anhand einer grafischen Oberfläche ermöglicht.

Designer

Der Designer ermöglicht das Erstellen eines endlichen Automaten. Dazu ist es möglich die ver­schiedenen Objekte in der grafischen Oberfläche zu platzieren und mit Transitionen zu verbinden. Zusätzlich gibt es einen Bereich, in denen die Operationen, Variablen und Events definiert werden können. Die Abbildung 2.9 zeigt die Designeransicht, bei der links z.B. die Variablen angegeben werden können, in der Mitte der aktuelle endliche Automat angezeigt wird und rechts die ent­sprechenden Elemente ausgewählt werden können.

Abbildung in dieser Leseprobe nicht enthalten

Abbildung 2.9: Designer

Simulation

Die Simulation ermöglicht das Ausführen des endlichen Automaten und ist in Abbildung 2.10 dargestellt. In dieser Ansicht gibt es rechts die Möglichkeit, Variablen zu verändern und Events auszulösen. Anhand von diesen Änderungen werden dann Transitionen ausgelöst und der aktuelle Zustand verändert.

Generierung

Zuletzt gibt es noch die Möglichkeit den endlichen Automaten in den unterschiedlichsten Spra­chen zu generieren. Als Beispiel dafür ist unter Abbildung 2.11 eine Generator-Datei dargestellt, welche angibt, dass der endliche Automat aus Abbildung 2.9 in der Sprache Java generiert werden soll. Die Angaben “targetProject“, “targetFolder“ und “libraryTargetFolder“ geben zusätzlich die Ordnerstruktur an, in der die Dateien erstellen werden sollen. Diese Struktur ist von der jewei­ligen Sprache abhängig und entspricht unter Java “targetProject/targetFolder“ für das Interface des endlichen Automaten und “targetProject/libraryTargetFolder“ für den endlichen Automaten selbst. Ein Rechtsklick auf die Datei ermöglicht das Generieren der entsprechenden Dateien.

Abbildung in dieser Leseprobe nicht enthalten

Abbildung 2.11: Generation

2.3 Swift

Swift ist die Programmiersprache, welche im Juni 2014 von Apple veröffentlicht wurde. Sie ver­wendet die Low Level Virtual Machine (LLVM) Kompiler Infrastruktur und die Objective-C Runtime und ermöglicht durch letzteres das Verwenden von Swift und Objective-C Quellcode in einem gemeinsamen Projekt. Dies entfernt z.B. die Notwendigkeit vorhandene Bibliotheken erneut zu schreiben und vereinfacht den Umstieg auf die neue Sprache. [SEV] In erster Linie wird Swift für die Entwicklung von iOS und MacOS Apps verwendet, allerdings sind Swift Kom­piler auch außerhalb von Apple Systemen verwendbar. Zum Beispiel gibt es eine funktionsfähige Version für Linux Systeme, welche das Kompilieren von Programmen ermöglicht. Diese können allerdings keine Referenzen auf iOS oder Mac Funktionalitäten verwenden, wodurch keine Cross­Compilation ermöglicht wird. Eine entsprechende Windows Version ist zum Veröffentlichungs­zeitpunkt dieser Arbeit nicht vorhanden bzw. nur über inoffizielle Kompilationen erhältlich.

Yakindu SCT soll um die Entwicklungssprache Swift erweitert werden, da dies eine Verwendung der Automatengeneration für iOS Apps ermöglicht. Da Android über die Entwicklungssprache Java bereits unterstützt wird, ist es eine Priorität iOS ebenfalls zu unterstützten, da diese Systeme im Smartphone Bereich am meisten verbreitet sind.

3 Architektur von Yakindu SCT

Damit eine neue Sprache für die Generierung von endlichen Automaten hinzugefügt werden kann, muss im ersten Schritt die Architektur von Yakindu SCT verständlich werden. Dieses Kapitel befasst sich mit der näheren Beschreibung der Struktur und schafft damit die Voraussetzungen für die Implementierung.

3.1 Übersicht

Der Aufbau von Yakindu SCT ist getrennt zwischen dem Hauptsystem, welches zum Beispiel die grafische Oberfläche und die Logik für die Generation beinhaltet, und Plugins, die das Hinzufügen einer neuen Sprache ermöglichen. Um eine neue Sprache hinzuzufügen muss lediglich ein neues Projekt erstellt und dann Yakindu SCT erneut kompiliert werden. Durch die“plugin.xml“ erkennt Yakindu SCT die neue Sprache und kann diese dann für die Generierung verwenden. In dieser “plugin.xml“ wird eine Klasse definiert, welche von der Klasse “GeneratorModule“ erbt und als Einstieg für den Generator dient. In dieser werden dann die restlichen Klassen über “Dependency Injection“ bekannt gegeben. Wie dies prinzipiell funktioniert, wird im nächsten Abschnitt genauer beschrieben. Das oben erwähnte Schema ist für ein besseres Verständnis unter Abbildung 3.1 dargestellt.

Abbildung in dieser Leseprobe nicht enthalten

Abbildung 3.1: Architektur

3.2 Entwicklungssprache

Yakindu SCT verwendet die Entwicklungssprache Java in Verbindung mit Xtend und Xtext und verbindet Abhängigkeiten zwischen dem Plugin und dem Hauptsystem über “Dependency Injection “. Da die Entwicklung des Plugins unter den gleichen Bedingungen durchgeführt werden muss, werden diese Technologien im Folgendem kurz vorgestellt.

Xtend

Xtend[XTEND] ist eine Programmiersprache, welche dass Entwickeln von Java Anwendungen vereinfachen soll. Sie wird direkt nach Java generiert und ermöglicht damit den Einsatz in be­stehenden Technologien wie z.B. der Android Entwicklung. Die Vorteile diese Sprache sind unter anderem, dass zusätzliche Schreibarbeit reduziert wurde, welche z.B. durch die explizite Angabe von Typen erzeugt wird. Ein Beispiel dafür ist unter Codebereich 3.1, der das Erstellen von Va­riablen und Funktionen mit deren Rückgabewerten aufzeigt. Dies ist möglich, da die Zuweisung oder die Rückgabe eines Wertes bereits angibt, welchen Typ eine Variable oder eine Funktion besitzen muss.

Abbildung in dieser Leseprobe nicht enthalten

Codebereich 3.1: Xtend vs Java

Ein weiterer Vorteil besteht darin, sogenannten “Extension Methods“ zu erstellen. Diese ermögli­chen es, zusätzliche Methoden zu bestehenden Typen hinzuzufügen. Als Beispiel dafür kann eine Methode zum String-Typen hinzugefügt werden, welche alle Vokale in diesem entfernt. Wie im Codebereich 3.2 dargestellt, ist es dann möglich, diese Funktion direkt auf einem String aufzu­rufen.

Abbildung in dieser Leseprobe nicht enthalten

Codebereich 3.2: Xtend Extension Methods

Zwei weitere Vorteile sind zum einen “Lambda Expressions“, welche allerdings inzwischen in Java 8 eingeführt wurden und daher nicht weiter angesprochen werden, und “Template Expressions“. “Template Expressions“ ermöglichen ein einfaches Erstellen von z.B. Dateivorlagen als Strings, welche im Quellcode korrekt formatiert werden. Um dies etwas einfacher dazustellen, wird im Codebereich 3.3 das Aussehen einer Datei definiert und ausgegeben. Die Ausgabe ist im Codebe­reich 3.4 dargestellt. Innerhalb der Definition ist es möglich, vorher definierte Variablen z.B. in For-Schleifen zu verwenden. Dabei ist es möglich, den Inhalt der For-Schleife einzurücken, ohne das diese zusätzliche Einrückung in der Ausgabe übernommen wird. Damit behält sowohl die Ausgabe als auch das Template im Quellcode eine Struktur, welche einfach lesbar und verständ­lich ist.

Abbildung in dieser Leseprobe nicht enthalten

Codebereich 3.4: Xtend Template Expressions Output

Xtend ist für die Entwicklung relevant, da der überwiegende Teil des Plugins in Xtend geschrieben wird.

Xtext

Xtext[XTEXT] ermöglicht das Erstellen einer “domain specific language (DSL)“ und ist Teil vom “Eclipse-Modeling-Framework (EMF)“. Anders gesagt bedeutet dies, dass mit Xtext z.B. eine Programmiersprache für einen spezifischen Zweck erstellt werden kann. Die Aufgabe dieser Sprache ist es nur diesen Zweck gut zu erfüllen und dadurch möglichst einfach anwendbar zu sein. Ein Beispiel dafür ist der vereinfachte Auszug aus Yakindu SCT für die Auswertung von “State“ Operationen dargestellt im Codebereich 3.5. In diesem Auszug wurde die Definition einer Expression ausgelassen, da diese eine zusätzliche Komplexität mitbringt. Für das Beispiel wird eine Expression definiert als eine Mathematische Operation oder eine Zuweisung zwischen zwei Variablen.

Abbildung in dieser Leseprobe nicht enthalten

Codebereich 3.5: Vereinfachter Xtext Auszug aus Yakindu SCT

Mit dieser Sprachdefinition und dem direkt mitgelieferten Compiler von Xtext ist es dann möglich folgende Ausdrücke zu validieren.

Abbildung in dieser Leseprobe nicht enthalten

Der erste Ausdruck ist ungültig, da “LocalReactions“ genau einen “ReactionTrigger“ erwartet. Wenn man dieses durch “(trigger=ReactionTrigger)?“ ersetzt, wäre dieser ebenfalls valid. Beim zweiten Ausdruck ist es ähnlich, da “LocalReactions“ genau ein “ReactionEffect“ erfordert. Eine Änderungen zu “(’/’ (effect=ReactionEffect)?)“ würde auch diesen Ausdruck gültig machen.

Xtext ist relevant für die Entwicklung, da die unterschiedlichen Definitionen wie z.B. “Local- Reactions“ in Xtend generiert werden müssen. Das heißt, dass die Eingabe für das Plugin ein vollständiger endlicher Automat ist, welcher in diese Bausteine aufgeteilt ist. Diese Bausteine werden dann einzeln verarbeitet und in der entsprechenden Sprache generiert. Xtext wird zu­sätzlich verwendet bei der Definition von Yakindu SCT Tests. Diese werden in einer in Xtext definierten Sprache geschrieben und müssen ebenfalls in der entsprechenden Sprache generiert werden.

Dependency Injection

Die Funktionalität eines Yakindu SCT Plugins basiert auf “Depdency Injection“. Die einfachs­te Form dieser Entwicklung besteht aus dem Ändern der Funktionalität einer Klasse durch die Übergabe einer anderen Implementierung im Konstruktor.

Folgendes Beispiel soll dies dabei etwas klarer darstellen. Die Darstellung 3.2 zeigt die Klasse Ausgabe, welche das Interface “IData“ verwendet. Bei der “Dependency Injection“ ist die Funk­tionalität von der Klasse Ausgabe abhängig von der übergebenen Implementierung von IData.

Abbildung in dieser Leseprobe nicht enthalten

Abbildung 3.2: Dependency Injection

Im Codebereich 3.6 wurde dieses Beispiel realisiert. Wenn die erste Implementierung von IData verwendet wird, gibt das Programm “datai“ aus. Bei der zweiten Implementierung ist es ent­sprechend “data2“. “Dependency Injection“ würde in diesem Beispiel das Erstellen der “Ausgabe“ Klasse übernehmen und erwartet, dass der Anwender die “IData“ Klasse spezifiziert, welche ver­wendet werden soll. Diese Spezifizierung wird im Plugin durchgeführt und ermöglicht es die Funktionalität von Yakindu SCT auf die Entwicklungssprache anzupassen.

Abbildung in dieser Leseprobe nicht enthalten

Codebereich 3.6: Dependency Injection Code

3.3 Klassenarchitektur

Yakindu SCT besteht aus vielen verschiedenen Klassen von denen einige erforderlich sind für die Entwicklung eines neuen Plugins. Im Folgenden werden diese Klassen vorgestellt. Der ers­te Bereich besteht aus den “Relevanten Klassen“ welche entweder implementiert oder dessen Funktionen verwendet werden müssen. Die beiden anderen Bereiche “Steps“ und “Ausdrücke“ befassen sich mit den Objekten, welche in der Sprache generiert werden müssen. Beispiele dafür sind Vergleiche und Operationen auf Variablen oder die Definition einer Funktion.

3.3.1 Relevante Klassen

Jedes Generator-Plugin besteht aus mindestens vier Klassen, von denen drei über DepdencyIn- jection mit dem Hauptsystem verbunden werden. Zusätzlich gibt es drei weitere Klassen, welche für die Implementierung auf jeden Fall benötigt werden. Diese insgesamt sieben Klassen werden im Folgenden kurz erläutert.

Abbildung in dieser Leseprobe nicht enthalten

Abbildung 3.3: GeneratorModule

Das “GeneratorModule“ kümmert sich um die “Dependency Injection“ der drei nachfolgenden Klassen. Es wird in der “plugin.xml“ angegeben und dient als Einstieg für den Generator. Die “con- figure“ Funktion liefert den “Binder“, welcher die Verbindungen zwischen den internen Klassen (“IExecutionFlowGenerator“, “ICodegenTypeSystemAccess“, “INamingService“) und deren Im­plementationen im Plugin über “Dependency Injection“ herstellt.

Abbildung in dieser Leseprobe nicht enthalten

Abbildung 3.4: IExecutionFlowGenerator

Der “IExecutionFlowGenerator“ wird im Plugin implementiert und via “Dependency Injection“ im “GeneratorModule“ bekannt gegeben. Die “generate“ Funktion löst das Generieren des endli­chen Automaten aus und beinhaltet den “ExecutionFlow“, welcher dessen Bestandteile wie z.B. Zustände beinhaltet. Außerdem gibt es den “GeneratorEntry“, welcher z.B. die Lizenz für die zu generierenden Dateien bereitstellt und den “IFileSystemAccess“, der den Zugriff auf das Datei­system ermöglicht. In diesem wird dann die Generierung von Dateien durchgeführt.

Abbildung in dieser Leseprobe nicht enthalten

Abbildung 3.5: ICodegenTypeSystemAccess

Die Klasse “ICodegenTypeSystemAccess“ wird ebenfalls im Plugin implementiert und über das “GeneratorModule“ bekannt gegeben. In diesem werden die allgemeinen Typen des endlichen Automaten auf die vorhandenen Typen der Entwicklungssprache übersetzt. Dazu gibt es die Funktion “getTargetLanguageName“ mit zwei unterschiedlichen Varianten. Die Variante mit dem “TypeSpecifier“ kann direkt auf die andere Variante angewandt werden, indem der “Type“ des “TypeSpecifier“ abgefragt und übergeben wird. In der zweiten Variante kann dann mit einer Abfrage der übergebene Typ mit den internen Typen verglichen und abhängig davon der Typ der Entwicklungssprache zurückgegeben werden. Ein Beispiel dafür ist der interne Typ “INTEGER“, welcher auf den Swift Typ “Int“ übersetzt wird.

DefaultNamingService

Abbildung in dieser Leseprobe nicht enthalten

Abbildung 3.6: placeholder

Der “DefaultNamingService“ ist eine Standardimplementierung des “INamingService“. Dieser “IN- amingService“ muss innerhalb des Plugins implementiert und als dritte Klasse im Bunde über den “GeneratorModule“ bekannt gegeben werden. Durch den “DefaultNamingService“ wird diese Implementierung vereinfacht. Die “prefix“ Funktion stellt den Prefix für die Namen der Auto­matenfunktionen. Als Beispiel dafür ist die Funktion “exitSequence_main_region_A“, welche Aufgerufen wird, wenn der Zustand “main_region_A“ verlassen wird. “exitSequence“ ist in die­sem Fall der Prefix dieser Funktion. Die nächste Funktion ist “asIdentifier“. Dieser Funktion wird ein Name übergeben, welcher dann entsprechenden verändert werden soll um einem Identifier in der Entwicklungssprache zu entsprechen. Als Beispiel dafür ist die Kleinschreibung des ersten Buchstaben bei Java. Zu dieser Funktion gibt es die Variante “asEscapedIdentifier“. In dieser muss zusätzlich sichergestellt werden, dass der übergebene Name keinem Keyword aus der Ent­wicklungssprache entspricht. In Swift wäre das z.B. “Int“. Zurückgegeben wird dann ein gültiger

Identifier, welcher bei einer Kollision z.B. durch einen Seperator ergänzt wird. Die letzte Funk­tion ist “isKeyword“. Diese bekommt einen Namen übergeben und muss überprüfen, ob dieser einem Keyword entspricht. Die Rückgabe entspricht dabei dem Wahrheitswert der Frage “ist dieser Name ein Keyword“.

SExecExtensions

Abbildung in dieser Leseprobe nicht enthalten

Abbildung 3.7: SExecExtensions

Die “SExecExtensions“ ist die erste Helferklasse und bietet einige Funktionen wie z.B. “isTimed“, welche zurückgibt ob der endliche Automat zeitgesteuerte Komponenten verwendet, oder “ha- sHistory“, welche angibt ob History-Zustände im endlichen Automaten benötigt werden. Diese Funktionen ermöglichen es, entsprechende Codebereiche bei der Generierung auszulassen, wenn diese nicht benötigt werden.

StextNameProvider

Abbildung in dieser Leseprobe nicht enthalten

Abbildung 3.8: StextNameProvider

Eine weitere Helferklasse ist “StextNameProvider“. Diese erstellt qualifizierte Namen für z.B. Zustände, welche dann über den “INamingService“ zu Identifier umgewandelt werden können.

ITypeSystem

Abbildung in dieser Leseprobe nicht enthalten

Abbildung 3.9: ITypeSystem

Das “ITypeSystem“ definiert die internen Typen und ermöglicht Vergleiche zwischen diesen. Dies ist z.B. notwendig im “ICodegenTypeSystemAccess“, da dort ein gegebener Typ mit einem internen verglichen werden muss um den entsprechenden Typen der Entwicklungssprache zurück­zugeben. Ein weiterer Anwendungsfall ist das “TypeCasting“, in dem ebenfalls vergleicht wird, welcher Typ in den jeweils anderen konvertiert werden muss. In Swift ist es z.B. notwendig bei einer Multiplikation zwischen einem “Double“ und einem “Int“ den “Int“ zuerst in einen “Double“ umzuwandeln.

3.3.2 Steps

Die Abbildung 3.10 beinhaltet eine Liste aller “Steps“, welche im Plugin implementiert werden müssen. Diese “Steps“ bilden den sogenannten “FlowCode“ und geben an, wie eine bestimmte Funktionalität in der jeweiligen Sprache dargestellt wird. Im Folgenden werden diese kurz Grup­penweise vorgestellt.

Abbildung in dieser Leseprobe nicht enthalten

Abbildung 3.10: Generator Steps

State

Die Zustandsschritte bestehen aus “EnterState“ und “ExitState“. Sie werden ausgeführt bevor in einen Zustand gewechselt oder dieser wieder verlassen wird und haben die Aufgabe den aktuellen Zustand im Zustandsarray zu speichern oder zu löschen. Das Zustandsarray selbst beinhaltet alle aktiven Zustände und identifiziert diese über einen Index. Der Index ist immer im Übergabe­parameter angegeben, der zu setzende Zustand ist beim “EnterState“ ebenfalls angegeben und beim “ExitState“ der leere Wert.

[...]

Details

Seiten
53
Jahr
2017
ISBN (eBook)
9783668593701
ISBN (Buch)
9783668593718
Dateigröße
1.1 MB
Sprache
Deutsch
Katalognummer
v383804
Institution / Hochschule
Fachhochschule Dortmund
Note
1.0
Schlagworte
yakindu plugin generierung automaten swift

Autor

Zurück

Titel: Yakindu SCT Plugin für die Generierung von endlichen Automaten in Swift