Erstellen eines Ameos-Templates zum Erzeugen von GXL

Werbung
Universität Koblenz-Landau
Fachbereich Informatik
Institut für Softwaretechnik
Studienarbeit
Erstellen eines Ameos-Templates zum Erzeugen
von GXL-Dateien
Andreas Kern
Erlenring 6
56424 Mogendorf
[email protected]
betreut von Prof. Dr. Jürgen Ebert
und Dr. Andreas Winter
04.02.05
Inhaltsverzeichnis
iii
Inhaltsverzeichnis
1. Einleitung...............................................................................................................................1
2. Grundlagen.............................................................................................................................2
2.1. GXL................................................................................................................................2
2.2. Ameos und TDL...........................................................................................................11
3. Anforderungen......................................................................................................................21
3.1. Überführung von Graphelementen...............................................................................21
3.2. Überführung von Schemaelementen.............................................................................23
3.3. Arbeitsweise des Templateskripts................................................................................26
4. Implementierung des Templateskripts.................................................................................28
4.1. Implementation des Instanzteils....................................................................................28
4.2. Implementation des Schemateils..................................................................................30
4.3. Implementation des Hauptteils.....................................................................................33
5. Einführung in die Bedienung des Templateskripts..............................................................35
5.1. Installation und Benutzung...........................................................................................35
5.2. Erstellen von Instanzgraphen........................................................................................37
5.3. Erstellen von Schemata.................................................................................................39
6. Fazit......................................................................................................................................41
Literaturverzeichnis..................................................................................................................43
iv
Abbildungsverzeichnis
Abbildungsverzeichnis
Abbildung 1: typisierter, attributierter, gerichteter, angeordneter Graph...................................3
Abbildung 2: GXL-Code............................................................................................................4
Abbildung 3: Hypergraph...........................................................................................................5
Abbildung 4: GXL-Code einer Hyperkante...............................................................................6
Abbildung 5: hierarchischer Graph............................................................................................6
Abbildung 6: GXL-Code eines hierarchischen Graphen............................................................7
Abbildung 7: Schema eines Graphen.........................................................................................8
Abbildung 8: Hierarchischer Graph Schema..............................................................................8
Abbildung 9: Hypergraphschema...............................................................................................8
Abbildung 10: Graphdarstellung eines Schemas........................................................................9
Abbildung 11: Graphdarstellung eines Hypergraphschemas.....................................................9
Abbildung 12: Graph des Schemas in Abb. 8..........................................................................10
Abbildung 13: GXL-Metaschema............................................................................................12
Abbildung 14: attributierte Kante.............................................................................................14
Abbildung 15: Templateskript..................................................................................................15
Abbildung 16: if-Statement......................................................................................................16
Abbildung 17: switch-Statement..............................................................................................16
Abbildung 18: Metamodell......................................................................................................17
Abbildung 19: loop-Statement.................................................................................................18
Abbildung 20: loop-Anweisung...............................................................................................18
Abbildung 21: verschachtelte loop-Anweisungen....................................................................19
Abbildung 22: Knoten..............................................................................................................21
Abbildung 23: GXL-Code zu Abb. 22.....................................................................................22
Abbildung 24: Kante................................................................................................................22
Abbildung 25: GXL-Code der Kante aus Abb. 24 ..................................................................22
Abbildung 26: Klasse...............................................................................................................23
Abbildung 27: Graph zur Klasse in Abb. 26............................................................................23
Abbildung 28: Assoziation.......................................................................................................24
Abbildung 29: Graph zu Abb. 28.............................................................................................24
Abbildung 30: Aggregation......................................................................................................25
Abbildung 31: Graph zu Abb. 30.............................................................................................25
Abbildung 32: Graph zu Abb. 33.............................................................................................25
Abbildung 33: Generalisierung................................................................................................25
Abbildung 34: Scriptmanager...................................................................................................35
Abbildung 35: Eigenschaftenfenster........................................................................................40
1. Einleitung
1
1. Einleitung
Graphen sind ein beliebtes und häufig verwendetes Mittel zur Darstellung von Daten. Viele
Programme verwenden Graphen für das Vorhalten von zur Verarbeitung benötigten Daten.
Mit GXL (Graph eXchange Language), einer XML-Subsprache, existiert ein standardisiertes
Dateiformat zum Austausch von Graphen.
Programme verwenden zwar oft Graphen zur Repräsentation ihrer Daten, aber es gibt nur
wenige Programme, mit denen der Benutzer einen beliebigen Graphen manuell erstellen und
als GXL-Datei speichern kann.
Da auch UML-Objektdiagramme Graphen sind, kann man entsprechende UML-Tools dazu
verwenden, um Graphen zu erzeugen. Außerdem kann man mit UML-Klassendiagrammen
Graphschemata darstellen. Was UML-Tools aber nicht können, ist aus einem
Objektdiagramm eine GXL-Datei zu erzeugen.
Das Programm Ameos der Firma Aonix ist ein UML-Werkzeug, das man benutzen kann, um
Graphen und Schemata zu erstellen. Außerdem enthält Ameos so genannte Templates, mit
denen es möglich ist, aus Diagrammen Code zu erzeugen. Aonix liefert mit Ameos Templates
zum Generieren von unter anderem Java-Code, C++-Code und noch einigen anderen
Sprachen. Die Templates sind in der Sprache TDL (transformation description language)
geschrieben. Mit Kenntnissen dieser Sprache ist es möglich, vorhandene Templates zu ändern
oder neue zu erstellen.
Ziel dieser Studienarbeit ist es, ein Template zu entwerfen und zu implementieren, das aus
einem Graphen bzw. einem Schema eine passende GXL-Datei erzeugt.
Mit TDL ist es nicht möglich, aus Code ein Diagramm zu erstellen. Es ist daher nicht
möglich, ein Template zu entwerfen, mit dem man eine GXL-Datei nach Ameos importieren
kann. Allein das Exportieren von Graphen und Graphschemata soll in dieser Arbeit realisiert
werden.
In Kapitel 2 werden die notwendigen Grundlagen erklärt. Es wird ein kurzer Überblick über
GXL gegeben und erläutert, welche Arten von Graphen man damit darstellen kann. Des
weiteren wird in diesem Kapitel Ameos vorgestellt und eine Einführung in TDL gegeben.
Im darauf folgenden Kapitel werden die Anforderungen an das Template festgehalten.
Zunächst wird beschrieben, wie man einen Graphen und ein Schema in GXL überführt.
Danach wird die Arbeitsweise des Templates erläutert. Es wird erklärt, welche Arbeitsschritte
das Template durchzuführen hat und in welcher Reihenfolge sie ausgeführt werden.
In Kapitel 4 wird die Implementierung des Templates dokumentiert. Es werden die Probleme
erläutert, die während der Implementation auftraten und wie diese gelöst wurden.
Einschränkungen in Hinblick auf die Verwendung des Templates werden, sofern sie durch die
Lösung eines Problems entstanden sind, aufgeführt und erklärt.
Als nächstes folgt in Kapitel 5 eine Einführung in die Benutzung des Templates. Es wird
beschrieben, wie das Template installiert wird. Anschließend wird erklärt, wie man Graphen
und Schemata erstellt und was der Benutzer dabei beachten muss.
Das darauf folgende Kapitel schließt die Arbeit ab. Hier werden die Erfahrungen, die
während der Arbeit gesammelt wurden, zusammengefasst und ein Fazit gezogen. Außerdem
wird noch ein Ausblick auf mögliche weitere Entwicklungen, die sich an die Arbeit
anschließen können, gegeben.
2
2. Grundlagen
2. Grundlagen
In diesem Kapitel werden in die zum Verständnis der Arbeit notwendigen Grundlagen
eingeführt. Dazu wird als erstes das GXL-Dateiformat beschrieben und erläutert. Als nächstes
wird dann das Programm Ameos vorgestellt und kurz erklärt, wie man damit Graphen
erstellen kann. Abgeschlossen wird dieses Kapitel mit einer Einführung in die Sprache TDL.
Es wird vorausgesetzt, dass bekannt ist was Graphen sind und das die in diesem
Zusammenhang benutzten Fachbegriffe, (z.B. TGraphen, Hypergraphen, Kantenattribute
usw.) geläufig sind und ihre Bedeutung bekannt ist. Ebenfalls bekannt sein sollte XML.
Außerdem wird vorausgesetzt, dass UML bekannt ist, wobei für das Verständnis der Arbeit
vor allem der Umgang mit und die Bedeutung von Klassen- und Objektdiagrammen bekannt
sein muss.
2.1. GXL
GXL (Graph eXchange Language) ist ein XML-basiertes Dateiformat, mit dem es möglich ist
Graphen zwischen verschiedenen Tools auszutauschen. Mit GXL kann man typisierte,
attributierte, gerichtete und angeordnete Graphen (TGraphen), sowie Hypergraphen und
hierarchische Graphen darstellen. GXL wurde im Januar 2001 auf dem Dagstuhl Seminar
"Interoperability of Reengineering Tools" als Standardaustauschformat für Software
Reengineering ratifiziert [EKM01]. Aber nicht nur für Reengineering kann man GXL
verwenden, sondern für beliebige Anwendungen, die Graphen zur Repräsentation von Daten
verwenden. Die XML-DTD, welche die Syntax von GXL beschreibt, findet man im Internet
auf der GXL-Homepage [GXL].
Jede GXL-Datei kann beliebig viele Graphen enthalten. Somit kann man mehrere Graphen
auf einmal austauschen. In der Praxis findet man aber meistens Dateien, die nur einen
Graphen enthalten.
2.1.1. Austausch von Graphen mit GXL
Im folgenden soll anhand von Beispielen der Aufbau von GXL-Dateien erläutert werden. Die
Beispiele und Abbildungen stammen, wenn nicht anders angegeben, von [GXL].
TGraphen
Der Graph in Abbildung 1 ist ein gerichteter, typisierter, attributierter und angeordneter
Graph. Solche Graphen werden auch TGraphen genannt. Mit diesem Graphen werden zwei
Funktionsaufrufe dargestellt. Die Funktion main, dargestellt durch einen Knoten vom Typ
Function, ruft in Zeile 8 die Funktion max und in Zeile 19 die Funktion min auf. Die
aufgerufenen Funktionen werden ebenfalls durch Knoten vom Typ Function repräsentiert.
Die eigentlichen Aufrufe werden durch Knoten vom Typ FunctionCall dargestellt. Welche
Funktion bei einem Funktionsaufruf die aufrufende und welche die aufgerufene Funktion ist,
wird mit Kanten vom Type isCaller bzw. isCallee dargestellt. Die isCaller-Kanten haben
ein Attribut, welches die Zeile des Aufrufs angibt. Die Variablen a und b dienen jeweils als
Eingabeparameter. Beim Aufruf von max ist a der erste und b der zweite Parameter, beim
Aufruf von min ist die Reihenfolge umgekehrt. Das Ergebnis von Funktion max wird in der
Variablen a, das von min in b gespeichert.
2. Grundlagen
3
Abbildung 1: typisierter, attributierter, gerichteter, angeordneter Graph
Der Inhalt der dazu passenden GXL-Datei ist in Abbildung 2 zu sehen. Als erstes wird in der
Datei die verwendete XML-Version (1.0) und DTD (gxl-1.0.dtd) angegeben. Der Rest der
Datei wird in <gxl>-Tags eingeschlossen, d.h. er steht zwischen einem öffnenden <gxl>- und
einem schließenden </gxl>-Tag. Graphen werden in GXL durch <graph>-Tags dargestellt.
Ein Graph beginnt mit einem <graph>-Tag, es folgen dann die einzelnen Elemente des
Graphen, die durch passende Tags dargestellt werden, und dann wird der Graph mit einem
</graph>-Tag beendet. Ein <graph>-Tag enthält mehrere Attribute. Das Attribut id
identifiziert den Graphen, gibt ihm also einen eindeutigen Namen. Im Beispiel ist das
Example-instance. Mit dem Attribut edgeids wird festgehalten, ob die Kanten des Graphen
einen Identifier (kurz Id, plural Ids), also eindeutige Namen, haben können. Die möglichen
Werte des Attributs sind daher true und false. Im Beispiel ist er true, die Kanten haben also
ids. Das Attribut hypergraph legt fest, ob es sich um einen Hypergraphen handelt oder nicht.
Die möglichen Werte des Attributs sind demnach true und false, im Beispiel letzteres.
Hypergraphen sind Graphen, die sogenante Hyperkanten enthalten. Hyperkanten werden auch
n-äre Kanten genannt und sie verbinden nicht nur zwei Knoten miteinander, sondern n Stück.
Das letzte Attribut eines <graph>-Tags ist edgemode. Dieses Attribut hat vier mögliche
Werte, und zwar directed, undirected, defaultdirected und defaultundirected. Der Wert
directed bedeutet, das alle Kanten des Graphen gerichtet sind. Analog bedeutet undirected,
das alle Kanten ungerichtet sind. Die Werte defaultdirected und defaultundirected legen
fest, das die Kanten Standardmäßig gerichtet bzw. ungerichtet sind. Einzelne Kanten können
dies aber überschreiben, was bei directed und undirected nicht möglich ist. Im Beispiel ist
der Wert directed, es sind also alle Kanten gerichtet.
Die Knoten eines Graphen werden durch <node>-Elemente und Kanten durch <edge>Elemente dargestellt. Diese enthalten das Attribut id, die dem Knoten bzw. der Kante einen
eindeutigen Identifier zuweisen. Alle Ids in einem GXL-Dokument müssen eindeutig sein. Es
dürfen keine zwei Elemente dieselbe Id haben. Die Start- und Endknoten einer Kante werden
mit den Attributen from und to festgehalten. Der Wert dieser Attribute ist die Id des Startbzw. Endknoten. Falls die Kanten an einem Knoten angeordnet sind, enthalten die <edge>-
4
2. Grundlagen
<?xml version="1.0"?>
<type xlink:href="Schema.gxl#
<!DOCTYPE gxl SYSTEM gxl-1.0.dtd">
isCaller"/>
<gxl xmlns:xlink="http://www.w3.org/1999/xlink">
<attr name="line">
<graph id="Example-Instance" edgeids="true"
<int>8</int>
hypergraph="false" edgemode="directed">
</attr>
<type xlink:href="Schema.gxl#Schema"/>
</edge>
<node id="v1">
<edge id="e2" from="v1" to="v3">
<type xlink:href="Schema.gx#
<type xlink:href="Schema.gxl#
Function"/>
isCaller"/>
<attr name="name">
<attr name="line">
<string>main</string>
<int>19</int>
</attr>
</attr>
</node>
</edge>
<node id="v2">
<edge id="e3" from="v4" to="v2">
<type xlink:href="Schema.gxl#
<type xlink:href="Schema.gxl#
FunctionCall"/>
isCallee"/>
</node>
</edge>
<node id="v3">
<edge id="e4" from="v5" to="v3">
<type xlink:href="Schema.gxl#
<type xlink:href="Schema.gxl#
FunctionCall"/>
isCallee"/>
</node>
</edge>
<node id="v4">
<edge id="e5" from="v6" to="v2"
<type xlink:href="Schema.gxl#
toorder="1">
Function"/>
<type xlink:href="Schema.gxl#isInput"/>
<attr name="name">
</edge>
<string>max</string>
<edge id="e6" from="v7" to="v2"
</attr>
toorder="2">
</node>
<type xlink:href="ExampleSchema.gxl#
<node id="v5">
isInput"/>
<type xlink:href="Schema.gxl#
</edge>
Function"/>
<edge id="e7" from="v6" to="v3"
<attr name="name">
toorder="2">
<string>min</string>
<type xlink:href="ExampleSchema.gxl#
</attr>
isInput"/>
</node>
</edge>
<node id="v6">
<edge id="e8" from="v7" to="v3"
<type xlink:href="Schema.gxl#
toorder="1">
Variable"/>
<type xlink:href="ExampleSchema.gxl#
<attr name="name">
isInput"/>
<string>a</string>
</edge>
</attr>
<edge id="e9" from="v6" to="v2">
</node>
<type xlink:href="ExampleSchema.gxl#
<node id="v7">
isOutput"/>
<type xlink:href="Schema.gxl#
</edge>
Variable"/>
<edge id="e10" from="v7" to="v3">
<attr name="name">
<type xlink:href="ExampleSchema.gxl#
<string>b</string>
isOutput"/>
</attr>
</edge>
</node>
</graph>
<edge id="e1" from="v1" to="v2">
</gxl>
Abbildung 2: GXL-Code
Tags dieser Kanten noch das Attribut fromorder, wenn es sich um vom Knoten ausgehende
Kanten handelt, oder toorder, wenn die Kanten in den Knoten hineinlaufen.
Graphen und Graphelemente können typisiert sein. Der Typ eines Elements wird mit einem
<type>-Tag, das innerhalb des jeweiligen Elements steht, angegeben. Der Typ eines Graphen
wird mit einem <type>-Tag festgehalten, welches innerhalb des <graph>-Elementes, also
2. Grundlagen
5
zwischen dem <graph> und dem </graph>-Tag,steht. Analog werden die Typen von Knoten
und Kanten mit einem <type>-Tag innerhalb des entsprechenden <node>- bzw. <edge>Tags festgehalten. Ein <type>-Tag enthält einen Verweis auf ein entsprechendes
Schemaelement, das den Typ des Knoten bzw. der Kante oder des Graphen repräsentiert. Der
Verweis kann auch auf Elemente in einer anderen GXL-Datei zeigen, es muss nicht in der
selben Datei sein.
Das <attr>-Element dient der Repräsentation von Knoten- und Kantenattributen eines
Graphen. Es steht daher innerhalb eines <node>- oder <edge>-Elements. Ein <attr>-Tag
besitzt das Attribut name, welches den Namen des Attributs angibt. Der Wert des Attributes
steht innerhalb des <attr>-Elements zwischen Tags der Art <domain> und </domain>.
Beispielsweise steht der Wert eines ganzzahligen Attributes zwischen <int> und </int>.
Außerdem gibt es in GXL noch die Domains <bool>, <float>, <string>, <enum>,
<locator>, sowie die zusammengesetzten Domains Mengen (<set>), Sequenzen (<seq>),
Multimengen (<bag>) und Tupel (<tup>).
Hypergraphen
Mit GXL kann man aber nicht nur TGraphen repräsentieren, sondern auch Hypergraphen und
hierarchische Graphen. Die Abbildung 3 zeigt einen einfachen Hypergraphen mit einer n-ären
Kante. Im Gegensatz zu einer normalen Kante, die nur zwei Graphelemente miteinander
verbindet (deshalb auch binäre Kante genannt), verbinden n-äre Kanten n Elemente
miteinander. Eine solche Kante wird durch eine Raute dargestellt, die mit den einzelnen
Knoten verbunden ist. Die Linien, welche die Raute mit den Knoten verbinden, nennt man
Tentakel (engl. tentacles). Wie mit dem Graph in Abbildung 1 wird auch mit diesem Graph
ein Funktionsaufruf dargestellt. Die Funktion main ruft in Zeile 8 die Funktion max auf, die
Variablen a und b sind Eingabeparameter und a dient zur Aufnahme des Ergebnisses. Die
beiden Funktionen main und max werden durch Knoten vom Typ Function dargestellt, die
Variablen a und b durch Variable-Knoten. Der eigentliche Funktionsaufruf wird nun durch
die n-äre Kante vom Typ FunctionCall2 dargestellt. Am Ende der Tentakel stehen die Rollen
der Elemente. Im Beispiel sind die Rollen callee, caller, output und zweimal input.
Abbildung 3: Hypergraph
Der GXL-Code für diese Hyperkante ist in Abbildung 4 zu sehen. Hyperkanten werden durch
<rel>-Tags dargestellt. Sie enthalten wie die anderen Elemente auch ein Attribut id, das sie
eindeutig identifiziert. Mit dem Attribut isdirected wird festgelegt, ob es sich um eine
gerichtete oder ungerichtete Kante handelt. Im Beispiel ist sie ungerichtet. Ebenso wie
Knoten und normale Kanten und auch Graphen können n-äre Kanten einen Typ haben,
6
2. Grundlagen
welcher mit einem <type>-Tag angegeben wird. Analog zu den anderen Elementen kann man
auch hier <attr>-Elemente verwenden, um Attribute darzustellen. Mit <relend>-Tags werden
die Enden der Tentakel angegeben. Das Attribut target hat dabei die Id des Elements am
Ende des Tentakels als Wert und mit role wird die Rolle dieses Elements festgehalten. Mit
dem Attribut startorder werden die Tentakel angeordnet, und zwar an der Hyperkante. Mit
dem (im Beispiel nicht vorhanden) Attribut endorder werden die Tentakel ebenfalls
angeordnet, allerdings nicht an der Kante, sondern an den Enden der Tentakel. Ist in einem
Graphen mindestens eine n-äre Kanten vorhanden, dann muss das Attribut hypergraph im
<graph>-Tag den Wert true haben.
<rel id="r1" isdirected="false">
<type xlink:href="hypergraphSchema.gxl#FunctionCall2"/>
<attr name="line">
<int>8</int>
</attr>
<relend target="v1" role="callee"/>
<relend target="v4" role="caller"/>
<relend target="v6" role="output"/>
<relend target="v6" role="input" startorder="1"/>
<relend target="v7" role="input" startorder="2"/>
</rel>
Abbildung 4: GXL-Code einer Hyperkante
Hierarchsiche Graphen
Eine weitere Art von Graphen, die man mit GXL darstellen kann, sind hierarchische Graphen.
Ein hierarchischer Graph ist ein Graph, in dem ein oder mehrere Elemente selbst wieder
Graphen enthalten. Abbildung 5 zeigt einen Graphen, in dem der Knoten v4 einen Graphen
enthält. Dieser Knoten, der die Funktion max auf den vorangegangenen Beispielen
repräsentiert, enthält einen Subgraphen, der den Rumpf der Funktion darstellt.
Abbildung 5: hierarchischer Graph
2. Grundlagen
7
Der GXL-Code für diesen Knoten ist in Abbildung 6 angedeutet. Der Subgraph mit der Id
max unterscheidet sich durch nichts von einem normalen TGraphen. Seine Knoten und
Kanten werden mit <node>- und <edge>-Tags innerhalb eines <graph>-Elements
dargestellt. Das <graph>-Element steht innerhalb des <node>-Elements mit der Id v4. Der
Graph max ist Subgraph des Knoten v4. Der Knoten v4 ist übergeordnetes Element des
Graphen max.
<node id="v4">
<type xlink:href="hierarchicalSchema.gxl#Function"/>
<attr name="name">
<string>max</string>
</attr>
<graph id="max" edgeids="true" hypergraph="false" edgemode="defaultdirected">
<type xlink:href="hierarchicalSchema.gxl#Asg"/>
<node id="v4.1">
<type xlink:href="hierarchicalSchema.gxl#Interface"/>
</node>
....
<edge id="e4.12" from="v4.7" to ="v4.5">
<type xlink:href="hierarchicalSchema.gxl#isReturnValue"/>
</edge>
</graph>
</node>
Abbildung 6: GXL-Code eines hierarchischen Graphen
Nicht nur Knoten können Subgraphen enthalten, sondern auch Kanten und Hyperkanten.
Außerdem muss ein solcher Graph nicht ein TGraph sein, denn es ist auch möglich, das der
untergeordnete Graph ein Hypergraph ist. Oder er ist ein hierarchischer Graph, wodurch
Graphen mit beliebig vielen Hierarchieebenen entstehen können.
2.1.2. Austausch von Schemata
Die Beispielgraphen im vorigen Abschnitt waren alle typisierte Graphen. Die Typen der
Knoten und Kanten werden mit dem <type>-Tag angegeben. Mit diesem Tag wird auch auf
ein Schema verwiesen. Ein Schema beschreibt:
welche Typen von Knoten und Kanten (binäre und n-äre) in einem Graphen benutzt
werden können,
welche Beziehungen zwischen Knoten, Kanten und Hyperkanten bestehen können,
welche Attribute einem Graphelement zugeordnet sind,
welche Graphhierarchien benutzt werden können, d.h. welche Element Subgraphen eines
bestimmten Types haben können.
Unter der Beziehung zwischen Knoten, Kanten und Hyperkanten ist zu verstehen, dass mit
dem Schema festgelegt wird, das die Kanten eines bestimmten Types nur die Knoten von
bestimmten Typen miteinander verbinden können, und nicht die Knoten eines beliebigen
Types. Ein Schema legt somit das Format fest, das Instanzgraphen haben können. Folgt ein
Instanzgraph diesem Format, dann sagt man, der Graph passt zu dem Schema oder der Graph
ist schemakonform.
Schemata als UML-Klassendiagramme
Graphschemata können mit UML-Klassendiagrammen beschrieben werden. Abbildung 7
zeigt das Schema zum Graphen aus Abbildung 1.
Zu jedem Knotentyp, der in dem Instanzgraphen verwendet wird, existiert eine Knotenklasse
8
2. Grundlagen
Abbildung 7: Schema eines Graphen
im Klassendiagramm. Es existieren daher die Klassen Function, FunctionCall und Variable.
Die Klasse Function hat das Attribut name, welches wiedergibt, dass im Instanzgraphen
Knoten von eben diesem Typ mit dem Funktionsnamen attributiert sind. Analog ist die Klasse
Variable attributiert. Kantentypen werden durch Assoziationen dargestellt. Im Beispiel
existieren daher die Assoziationen isCaller, isCallee, isInput und isOutput. Falls die
Kanten attributiert sind, dann existiert eine entsprechende assoziierte Klasse. Im Beispiel ist
das die Klasse isCaller, die genauso wie Knotenklassen ein entsprechendes Attribut enthält.
Die Richtung der Kanten wird durch ein ausgefülltes Dreieck dargestellt. Die Anordnung von
Kanten wird mit dem Schlüsselwort {ordered} festgehalten. Multiplizitäten legen
Restriktionen des Grads eines Knotentyps fest, z.B. kann in einen Knoten vom Typ
FunctionCall nur genau eine Kante vom Type isOutput hineingehen.
Der Typ von Hyperkanten wird mit n-ären Assoziationen dargestellt. Die Rollen werden wie
im Instanzgraphen an die Enden der Tentakel geschrieben. Ein attributierter n-ärer Kantentyp
enthält eine passend attributierte assoziierte Klasse. Abbildung 9 zeigt das Schema zum
Hypergraphen aus Abbildung 3.
Abbildung 9: Hypergraphschema
Abbildung 8: Hierarchischer Graph Schema
Das Schema des hierarchischen Graphen aus Abbildung 5 wird in Abbildung 8 gezeigt. Im
Schema wird ein Stereotyp «Graphclass» namens asg verwendet, um Klassen, die einen
Subgraphen enthalten, von normalen Knotenklassen zu unterscheiden. Die Zugehörigkeit
eines Graphen zu einer Klasse wird mit Komposition dargestellt.
Um Schemata mit GXL austauschen zu können, muss man die Klassendiagramme in Graphen
überführen. Bei UML-Klassendiagrammen handelt es sich um strukturierte Informationen,
die sich als Graphen darstellen lassen. Daher ist die Überführung eines Schemas in einen
Graphen möglich und erlaubt, deshalb auch Schemata mit GXL darzustellen und
auszutauschen.
2. Grundlagen
9
Graphrepräsentation von Schemas
Abbildung 10: Graphdarstellung eines Schemas
Abbildung 10 zeigt die Graphrepräsentation des Schemas aus Abbildung 7. Jede Knotenklasse des Schemas wird durch einen Knoten vom Typ NodeClass dargestellt. Für jeden
Kantentyp existiert ein Knoten vom Typ EdgeClass. Beispielsweise wird aus der
Assoziation isCallee ein Knoten mit dem Namen isCallee und dem Typ EdgeClass. Die
Verbindungen einer isCallee-Kante werden durch Kanten vom Typ from und to dargestellt.
Die Kardinalität einer Assoziation wird durch das Attribut limits der from- und to-Kanten
beschrieben, wobei der Wert -1 unendlich bedeutet. Attribute werden durch Knoten vom Typ
AttributClass repräsentiert. Die Informationen, zu welcher Klasse ein Attribut gehört und
Abbildung 11: Graphdarstellung eines Hypergraphschemas
10
2. Grundlagen
welche Domain es besitzt, wird durch Kanten vom Typ hasAttribute respektive hasDomain
dargestellt. Außerdem enthält der Graph noch einen Knoten vom Typ GraphClass, der mit
contains-Kanten mit jedem Knoten verbunden ist, der ein Element des Klassendiagramms
repräsentiert.
Bei der Graphdarstellung eines Schemas eines Hypergraphen wird die n-äre Assoziation
durch einen Knoten vom Typ RelationClass repräsentiert. Die Rollen der Assoziation
werden durch Knoten vom Typ RelationEndClass dargestellt. Der Zusammenhang
zwischen diesen Knoten wird dargestellt durch Kanten vom Typ hasRelationEnd, die von
einem RelationClass- zu einem RelationEndClass-Knoten führen. Knoten vom Typ
relatesTo stellen die Verbindung von Rollen zu den Klassen her, die diese Rollen
einnehmen. In Abbildung 11 wird der Graph zum Schema aus Abbildung 9 gezeigt.
Abbildung 12: Graph des Schemas in Abb. 8
2. Grundlagen
11
Bei dem Schema eines hierarchischen Graphen wird der Subgraph wie ein gewöhnlicher
Graph dargestellt, mit Knoten vom Typ GraphClass, NodeClass, EdgeClass, usw. und
Kanten vom Type to, from, contains, etc. Die Zugehörigkeit eines Subgraphen zu seinem
übergeordneten Graphelement wird durch eine Kante vom Typ hasAsComponentGraph,
von diesem Graphelement zum GraphClass-Knoten des Subgraphen festgehalten. Der
Graph, der zum Schema aus Abbildung 8 passt ist in Abbildung 12 gezeigt.
Die Graphrepräsentationen aller Schemata sind TGraphen und können daher auch, wie in
Abschnitt 2.1.1. beschrieben, mit GXL dargestellt werden. Da es auch möglich ist, in einer
GXL-Datei mehrere Graphen unterzubringen, kann man einen Instanzgraphen zusammen mit
seinem Schema in der Graphrepräsentation in einer einzigen Datei austauschen. Dies wird
allerdings nur selten so gemacht, weil man oft viele Instanzen zu einem Schema hat und
bestehende Schemata häufig wiederverwendet. Ein Schema wird daher sinnvollerweise
alleine als einziger Graph in einer GXL-Datei dargestellt. Die Instanzgraphen werden dann
immer in separate GXL-Dateien gepackt.
2.1.3. Das GXL-Metaschema
Wie im vorigen Unterabschnitt schon erwähnt, ist die Graphdarstellung von einem Schema
immer ein TGraph. Sie haben alle dieselbe Struktur und verwenden dieselben Typen von
Knoten (z.B. NodeClass, EdgeClass, usw.) und Kanten (z.B. to, from, hasAttribute etc.).
Es muss daher ein Schema geben, zu dem diese Graphen passen. Dieses Schema nennt man
das Metaschema. In Abbildung 13 ist das Metaschema in der Darstellung als UML-Klassendiagramm zu sehen.
Wie jedes Schema, das als Klassendiagramm dargestellt ist, kann man auch das Metaschema
in eine Graphdarstellung überführen, dessen Schema das Metaschema ist. Zu jedem
Instanzgraphen gibt es also ein passendes Schema, das zum Metaschema passt, welches
wiederum zu sich selbst schemakonform ist.
Kompositionen und Aggregationen werden mit den Klassen CompositionClass und
AggregationClass dargestellt. Die Klasse CompositionClass ist eine Spezialisierung der
Klasse AggregationClass, die wiederum eine Spezialisierung von EdgeClass ist.
Generalisierung wird mit Kanten vom Typ isA modelliert. Eine isA-Kante ist eine gerichtete
Kante, die von der speziellen Klasse zu ihrer Superklasse geht.
2.2. Ameos und TDL
Die Zielsetzung dieser Arbeit ist es, mit dem Programm Ameos und der Sprache TDL
Graphen und Schemata zu erstellen und als GXL-Dateien zu speichern. Daher wird nun im
Unterabschnitt 2.2.1. Ameos das Programm vorgestellt und kurz erläutert, wie man damit
Graphen und Graphschemata erstellt. Im Unterabschnitt 2.2.2. TDL folgt dann eine
Einführung in diese Sprache.
2.2.1. Ameos
Der eigentlicher Zweck von Ameos ist die Modellierung und Codegenerierung von
Softwaresystemen mit UML. Ein sogenanntes UML-Klassendiagramm kann sowohl Klassen
als auch Objekte enthalten. Es wird nicht zwischen Objekt- und Klassendiagrammen
unterschieden. Im folgenden bedeutet der Begriff Objektdiagramm ein UMLKlassendiagramm, das Objekte aber keine Klassen enthält. Ein Klassendiagramm ist analog
12
2. Grundlagen
graph part:
attribute part:
value part:
Abbildung 13: GXL-Metaschema
2. Grundlagen
13
ein Diagramm, das Klassen, aber keine Objekte enthält.
Objektdiagramme eignen sich zur Darstellung von Instanzgraphen und Klassendiagramme
zum Darstellen ihrer Schemata. Andere Arten von UML-Diagrammen eignen sich nicht zur
Darstellung von Graphen oder Schemata und werden daher hier nicht behandelt.
Ein Schema lässt sich mit Ameos recht einfach erstellen. Man öffnet ein neues Klassendiagramm und fügt die notwendigen Elemente hinzu. Die Benutzeroberfläche zum Erstellen
und Bearbeiten von Klassendiagrammen ist intuitiv gestaltet. Es gibt eine Liste, aus der man
die verschiedenen Diagrammelemente (z.B. Klassen, Objekt, Assoziationen, Generalisierung,
usw.) auswählen kann und durch ein Klick auf die Arbeitsfläche wird an dieser Stelle das
ausgewählte Element erzeugt. Wenn man ein Element selektiert hat, kann man seine
Eigenschaften in einem Dialogfenster bearbeiten. Dieses Fenster kann man über ein
passendes Icon in der Iconleiste öffnen. Alternativ lässt sich das Fenster auch über den
Menüpunkt Edit Properties aufrufen.
Das Erzeugen einer assoziierten Klasse geschieht, indem man zuerst eine gewöhnliche
Assoziation erzeugt, dann die Klasse, die assoziiert werden soll, wie eine gewöhnliche
Klasse, erzeugt. Als nächstes selektiert man die Assoziation und wählt im Menü den Punkt
UML Create Association Class. Mit einem Klick auf die Klasse wird diese dann mit der
Assoziation verbunden.
Wenn man mehrere Klassen gleichzeitig selektiert und dann im Menü UML Create N-ary
Association auswählt, wird eine n-äre Assoziation erzeugt, welche die Klassen miteinander
verbindet. Hiermit ist es möglich Schemata für Hypergraphen zu erzeugen.
Das Erstellen eines Schemas eines hierarchischen Graphen ist nicht möglich, weil in Ameos
eine Klasse kein Klassendiagramm enthalten kann. Es besteht keine Möglichkeit, dass eine
Klasse oder ein anderes Element eines Diagramms selber ein Klassendiagramm enthalten
kann.
Das Erstellen von Instanzgraphen ist nicht ganz so einfach. Ebensowenig wie Klassen können
auch Objekte keine Diagramme enthalten. Die Erzeugung einer Instanz eines hierarchischen
Graphen schlägt somit auch fehl. Man kann also weder Instanz noch Schema von
hierarchischen Graphen mit Ameos erstellen.
Auch das Erstellen eines Hypergraphen ist nicht möglich. Dies scheitert daran, dass es keine
n-ären Objektassoziationen gibt, mit denen man Hyperkanten repräsentieren könnte. Daraus
folgt, dass man zwar Hypergraphschemata, aber keine Hypergraphinstanzen erzeugen kann.
Da es wenig Sinn macht nur Schemata und keine Instanzen erzeugen zu können, werden im
folgenden keine Hypergraphen mehr betrachtet. Auch hierarchische Graphen sind nicht mehr
im Fokus der Arbeit. Nur TGraphen werden noch behandelt.
Aber auch das Erstellen von TGraphen ist mit Ameos nicht problemlos machbar. Das
Erzeugen von Objekten zum Darstellen von Knoten ist kein Problem. Problematisch ist die
Darstellung von Kanten. Um zwei Objekte miteinander zu verbinden, bietet Ameos nur
Dependencies und Object Asssociations an. Da Dependencies mit einer Pfeilspitze
visualisiert werden und Object Associations nicht, eignen sich erstere zum Repräsentieren
von gerichteten Kanten und letztere von ungerichteten Kanten. Aber weder einer Object
Association noch einer Dependency kann man Attribute hinzufügen. Die Darstellung von
attributierten Kanten ist auf diese Weise nicht möglich. Man kann sich daher darauf
beschränken nur Graphen ohne attributierte Kanten zu verwenden.
Oder man verwendet folgende Lösung, um attributierte Kanten darzustellen. Man erzeugt
eine Kante (Dependency oder Object Association) und dazu dann ein Objekt mit exakt
14
2. Grundlagen
dem gleichen Namen. Dem Objekt können dann Attribute hinzugefügt werden. Das Objekt
zusammen mit der Kante repräsentiert dann eine attributierte Kante. Abbildung 14 zeigt, wie
eine isCaller-Kante aus Abbildung 1 mit der beschriebenen Lösung aussieht. Diese Lösung
ist nur dann möglich, wenn die Namesräume der Knoten und der Kanten disjunkt sind, also
keine gemeinsamen Elemente enthalten. Die Bedingung disjunkter Namensräume muss aber
auch bei Graphen ohne attributierte Kanten gelten, weil in einem XML-Dokument und somit
auch einem GXL-Dokument alle Identifier eindeutig sein müssen.
2.2.2. TDL
Allgemeines
Das Kürzel TDL steht für Transformation Description Language und ist eine Sprache, die in
Ameos enthalten ist. Ihre Aufgabe ist es, aus Diagrammen Code zu erzeugen. Die mit TDL
entwickelten Scripte nennt man Templates. Ein Template hat die Möglichkeit, auf die
Elemente von Diagrammen zuzugreifen und in Abhängigkeit vom Element Code auszugeben.
Mit Ameos mitgeliefert werden schon Templates für z.B. Codegenerierung in Java, C++ und
Ada95. Diese Templates können auf Diagrammelemente zugreifen und einen passenden
Programmcode erzeugen. So kann zum Beispiel das Java-Template für jede Klasse, die im
System existiert, eine passende Java-Datei erstellen und mit Code in Java ausfüllen.
Ein Benutzer, der TDL beherrscht, kann vorhandene Templates ändern oder neue erstellen.
Zunächst wird nun eine Einführung in TDL gegeben. Später in der Studienarbeit wird dann
TDL verwendet, um ein Template zu entwickeln, das GXL-Code erzeugen kann. Der
Benutzer kann dann schließlich mit Ameos Graphen und Schemata erstellen und diese dann
in eine GXL-Datei exportieren.
In TDL gibt es zwei unterschiedliche Typen von Funktionen und zwar Prozeduren und
Templates. Bevor die beiden Typen erklärt werden, ist es wichtig darauf hinzuweisen, dass
der Begriff Template in zwei verschiedenen Bedeutungen benutzt wird. Einerseits meint man
mit Template das ganze mit TDL entwickelte Script zur Codeerzeugung, auf der anderen
Seite wird der Begriff auch benutzt, um eine der beiden Typen von Funktionen zu
bezeichnen. Damit es zu keinen Verwechslungen der Begriffe kommt, wird im Rest dieser
Arbeit immer, wenn das ganze Script gemeint ist, das Wort Templateskript verwendet. Wenn
hingegen der Funktionstyp gemeint ist, wird das Wort Template benutzt.
2. Grundlagen
15
Prozeduren und Templates
Der Aufbau der beiden Typen von Funktionen ist ähnlich. Eine Prozedur beginnt mit dem
Schlüsselwort proc, ein Template mit dem Wort template. Es folgt in beiden Fällen der
Name der Prozedur bzw. des Templates und dann eine, eventuell leere, Liste von Parametern,
die in Klammern geschrieben wird. Danach folgt der Rumpf der Funktionen, die mit den
Schlüsselwörtern end proc, respektive end template beendet werden.
Der Text im Rumpf eines Templates wird einfach so, wie er dort steht, ausgegeben.
Ausnahme sind Statements die in eckigen Klammern [] stehen. Mit diesen Statements ist es
möglich auf Variablen zuzugreifen, andere Templates oder Prozeduren aufzurufen oder den
Kontrollfluss zu steuern. Textabschnitte, die in eckigen Klammern stehen, sind daher als
Befehle zu verstehen, die ausgeführt werden. Abschnitte, die nicht in eckigen Klammern
stehen, sind als Ausgabe zu verstehen.
Um auf eine Variable zugreifen zu können, schreibt man ihren Namen und nur ihren Namen
und nichts sonst, in eckige Klammern. Das Template gibt dann den aktuellen Wert der
Variablen aus. Steht in eckigen Klammern ein Prozeduraufruf, wird dieser ausgeführt und
sein Rückgabewert ausgegeben. Hat die Prozedur keinen Rückgabewert, dann wird sie zwar
ausgeführt, aber nichts ausgegeben. Ruft ein Template ein anderes Template auf, dann wird
die Ausgabe des aufgerufenen Templates vom aufrufenden Template genau an der Stelle
ausgegeben, wo der Aufruf steht.
Im Gegensatz zu Templates ist in Prozeduren der gesamte Text als Befehl zu verstehen. Um
Text in einer Prozedur auszugeben, schreibt man out= gefolgt von dem Text, der ausgegeben
werden soll. Funktionsaufrufe und Kontrollflussanweisungen werden in Prozeduren nicht in
eckigen Klammern geschrieben, müssen aber mit einem Semikolon beendet werden. Der
Zugriff auf Variablen erfolgt in Prozeduren, genauso wie in Templates dadurch, dass man den
Variablennamen in eckige Klammern schreibt. In einer Prozedur kann man auf Variablen
lesend und schreibend zugreifen. In Templates ist nur lesender Zugriff möglich, d.h. in einem
Template kann man den Wert einer Variablen nicht ändern, sondern nur lesen und ausgeben.
Der Startpunkt der Ausführung des Templateskripts, also der Beginn der Codegenerierung, ist
eine Prozedur mit dem Namen main. Sie wird als erstes ausgeführt, wenn man das
Templateskript startet.
Abbildung 15 zeigt ein einfaches Templateskript und die erzeugte Ausgabe. Die Prozedur
main ruft das Template t1 auf und übergibt dabei den String "Hallo Welt" als Parameter. Im
Template erfolgt der Zugriff auf diesen Parameter wie der Zugriff auf eine Variable. Mit dem
Befehl [var] wird der Wert des Parameters, also "Hallo Welt", ausgegeben.
Templateskript: Ausgabe:
proc main()
out=t1("Hallo
Welt");
end proc
Hello World
Hallo Welt
template t1(var)
Hello World
[var]
end template
Abbildung 15: Templateskript
16
2. Grundlagen
Kontrollflussanweisungen
Für die Steuerung der Codegenerierung gibt es in TDL drei Kontrollflussanweisungen. Das
if-, das switch- und das loop-Statement.
1) if-Statement
Die einfachste dieser Anweisungen ist die if-Anweisung. Ihre allgemeine Syntax ist in
Abbildung 16 gezeigt. Wie in anderen Sprachen auch werden die Statements im Rumpf der ifAnweisung in Abhängigkeit zur Bedingung am Anfang der Anweisung ausgeführt.
if (condition)
statements;
end if
oder
if (condition)
statements;
else
other_statements
end if
Abbildung 16: if-Statement
2) switch-Statement
Das switch-Statement wertet als erstes einen Ausdruck aus und kann dann in Abhängigkeit
vom Ergebnis der Auswertung unterschiedliche Anweisungen ausführen. In Abbildung 17 ist
die Syntax der switch-Anweisung zu sehen. Eine switch-Anweisung enthält mehrere caseswitch (expression)
case expression1:
statements1;
break;
case expression2:
statements2;
break;
default:
default_statements;
end switch
Abbildung 17: switch-Statement
Markierungen und eine optionale default-Markierung. Zuerst wird der Ausdruck (expression)
im Kopf der Anweisung ausgewertet und dann der Reihe nach mit den Ausdrücken
(expression1, expression2, usw.) der case-Markierungen verglichen und bei Gleichheit werden
die auf die Markierung folgenden Anweisungen ausgeführt. Es werden alle Anweisungen bis
zum Ende der switch-Anweisung oder bis zur nächsten break-Anweisung, je nachdem was
zuerst kommt, ausgeführt. Falls der Ausdruck im Kopf des switch mit keinem der Ausdrücke
der case-Markierungen übereinstimmt, dann werden die Anweisungen nach der defaultMarkierung ausgeführt. Ist keine default-Markierung vorhanden, wird nichts ausgeführt.
3) loop-Statement
Um die Funktionsweise des loop-Statements zu verstehen, muss man das Metamodell von
Ameos kennen. Daher wird nun zuerst in einem Einschub das Metamodell erklärt und danach
das loop-Statement erläutert.
Einschub: Ameos-Metamodell
Abbildung 18 (Quelle: [AAD]) zeigt das Metamodell von Ameos bezogen auf
2. Grundlagen
Klassendiagramme. Es beschreibt die UML-Klassendiagramme in Ameos. So ist zum
Beispiel jede Klasse, die der Benutzer in einem Diagramm erzeugt, eine Instanz der
Metamodellklasse MClass und jede Assoziation eine Instanz von MAssociation. Auf
diese Art gibt es für jeden Typ von Objekten, die in einem Diagramm vorkommen
17
18
2. Grundlagen
können, eine entsprechende Klasse im Metamodell, deren Name in der Regel mit einem
M beginnt (z.B. MAttribute, MClass, MDependency).
Um zu verhindern, dass sich im Diagramm einige Assoziationen kreuzen und die
Abbildung dadurch unübersichtlich wird, existieren einige Klassen mehrfach.
Beispielsweise existiert in der Abbildung zweimal die Klasse MObject. Es handelt sich
hierbei nicht um zwei verschiedene Klassen mit demselben Namen, sondern um eine
einzige Klasse, die zur besseren Übersicht der Abbildung an zwei verschiedenen Stellen
hinzugefügt wurde.
In der Abbildung wird nicht das gesamte Metamodell gezeigt, sondern nur der Teil, der
sich auf Klassendiagramme bezieht. Die Teile, die sich auf andere Diagramme (Use
Case Digramm, Sequenzdiagramm, etc.) beziehen sind für das Verständnis des loopStatements und dieser Arbeit nicht notwendig und werden daher hier nicht behandelt.
Das loop-Statement ist eine Schleife. Mit ihr kann man über die Objekte eines in Ameos
erstellten Diagramms navigieren und innerhalb der Schleife auf diese Objekte zugreifen. Das
ist die einzige Möglichkeit, die TDL bietet, um auf Objekte zuzugreifen.
Abbildung 19 zeigt die allgemeine Syntax eines loop-Statements. Mit den navigation_rules
werden Navigationsregeln festgelegt, die bestimmen, über welche Objekte man navigieren
möchte. Der Schleifenrumpf wird dann für jedes der Objekte einmal durchlaufen.
loop (navigation_rules)
statements;
end loop
Abbildung 19: loop-Statement
Mit dem Befehl loop(Instances->MClass) erzeugt man eine Schleife über alle Instanzen
von MClass. Das Wort Instances ist ein Schlüsselwort von TDL. Es signalisiert, dass man
über alle Instanzen, die im System existieren, navigieren will. In den Navigationsregeln kann
man jede Klasse des Metamodells benutzen. Man kann in einer Navigationsregel also jeden
Namen einer Klasse des Diagramms in Abbildung 18 benutzen. Damit navigiert man dann
über alle Instanzen der entsprechenden Klasse.
Damit man innerhalb einer Schleife auf ein Objekt und ihre Attribute zugreifen kann,
existieren Metaattributvariablen (engl.: metaattribute variables, vgl. [ACD1]). Eine Metaattributvariable wird wie jede Variable, wenn man auf sie zugreifen will, in eckige Klammern
geschrieben. Der Name einer solchen Variablen besteht aus zwei Teilen, die durch einen
Punkt getrennt werden. Der erste Teil wird durch die Instanzreferenz des loop-Statements
festgelegt, der zweite durch den Namen des Attributs, das gelesen werden soll. Beispielsweise
kann man mit [MClass.name] auf den Namen einer Klasse zugreifen.
Das Beispiel in Abbildung 20 zeigt ein Template, das eine Liste aller Klassennamen erzeugt,
die in einem Diagramm vorkommen. Außerdem zeigt die Abbildung noch die Ausgabe, die
Template:
template classList()
Klassenliste:
[loop(Instances->MClass)]
-[MClass.name]
[end loop]
end template
Ausgabe:
Klassenliste:
-Function
-FunctionCall
-isCaller
-Variable
Abbildung 20: loop-Anweisung
2. Grundlagen
19
erzeugt wird, wenn man dieses Template auf das Klassendiagramm in Abbildung 7 anwendet.
Loop-Schleifen können auch ineinander verschachtelt sein, wobei sich die innere Schleife auf
eine Instanz der äußeren Schleife beziehen kann. Abbildung 21 zeigt zwei verschachtelte
loop-Schleifen. Im linken Beispiel wird sich in der inneren Schleife auf die aktuelle Instanz
von MClass bezogen und nur über deren Attribute navigiert. Rechts läuft die innere Schleife
über alle Instanzen von MAttribute, unabhängig von der aktuellen Instanz von MClass.
loop(Instances->MClass)
//Schleife über alle Klassen
loop(MClass->MAttribute)
/* Schleife über alle
Attribute der aktuellen
Klasse */
end loop
end loop
loop(Instances->MClass)
//Schleife über alle Klassen
loop(Instances->MAttribute)
/* Schleife über alle
Attribute unabhängig
von der aktuellen Klasse */
end loop
end loop
Abbildung 21: verschachtelte loop-Anweisungen
Das Schlüsselwort Instances ist nur in der äußeren Schleife unbedingt erforderlich. Es dient
als Einstiegspunkt in das Metamodell. Wenn man einmal im Modell drin ist kann man vom
aktuellen Punkt aus weiter navigieren. Dies geschieht im linken Beispiel in Abbildung 21. Im
rechten Beispiel der Abbildung wird in der inneren Schleife erneut in das Metamodell
eingestiegen und nicht vom aktuellen Punkt aus weiter navigiert.
Desweiteren können die Navigationsregeln eine where-Klausel enthalten, um die Menge der
Objekte, über die navigiert wird, einzuschränken. Zum Beispiel iteriert man mit dem Befehl
loop(Instances->MClass Where [MClass.isAbstract]==FALSE) nur über die nicht
abstrakten Klassen.
Eine weitere Möglichkeit, nur über eine bestimmte Menge von Objekte zu iterieren, ist eine
Id-Liste. Jede Instanz einer Metamodellklasse hat eine eindeutige Id, die man in eine Liste
eintragen kann. Um dann nur über die Elemente einer Liste zu iterieren, wird diese den
navigation_rules angehängt, z.B. loop(Instances->MClass([eineIdListe])). Eine Id-Liste
kann mit dem Befehl getIdList(navigation_rules) erzeugt werden, wobei die Navigationsregeln analog sind zu denen der loop-Anweisung. Zum Beispiel erhält man mit [eineIdListe]
=getIdList(MClass->SuperClass) eine Liste der Superklassen der aktuellen Klasse.
Außerdem gibt es die Möglichkeit zu einem loop-Statement eine Liste von Prozeduren
hinzuzufügen. Die Syntax hierfür ist: loop(navigation_rules; proc1(); proc2(); ...). Zu
Beginn des ersten Schleifendurchlaufs wird die erste Prozedur ausgeführt, gefolgt vom
Rumpf der loop-Schleife. Beim zweiten Durchlauf der Schleife wird zuerst die zweite
Prozedur, gefolgt vom Rumpf, ausgeführt usw. Falls die Schleife mehr Iterationen hat wie
Prozeduren, dann wird die letzte Prozedur der Liste wiederholt ausgeführt. Hat die Liste zum
Beispiel drei Prozeduren, dann wird zu Beginn der ersten Iteration die erste Prozedur
aufgerufen, im zweiten Schleifendurchlauf die zweite Prozedur und im dritten und allen
weiteren Durchläufen immer die dritte.
USES-Statement und die TDL Standard Library
Mit dem USES-Statement kann man andere TDL-Dateien zu einem Templateskript
hinzufügen und die dort enthaltenen Prozeduren und Templates verwenden. Das USESStatement darf nicht in einer Prozedur oder einem Template stehen, sondern muss außerhalb
zu Beginn einer TDL-Datei stehen. Beispielsweise ermöglicht der Befehl USES std; alle in
der Datei std.tdl vorhandenen Funktionen zu benutzen.
20
2. Grundlagen
Ameos besitzt eine sogenannte TDL Standard Library, die einige nützliche Funktionen
enthält. Die Library befindet sich in der Datei std.tdl und kann wie beschrieben mit USES
verwendet werden. Einige der Funktionen sind die folgenden:
getLength(string) liefert die Länge des Strings.
output(file) setzt den Output auf die Datei, die mit file angegeben wird und die Ausgaben
des Templateskripts werden in diese Datei geschrieben.
getOutput() liefert den Namen der aktuellen Ausgabedatei.
Dies ist nur ein Auszug aus der Liste der Prozeduren der TDL Standard Library. Eine
vollständige Liste findet sich in der TDL Dokumentation von Ameos [ACD1].
3. Anforderungen
21
3. Anforderungen
Nachdem im vorigen Kapitel die Grundlagen erläutert wurden, werden in diesem Kapitel die
Anforderungen an das Templateskript beschrieben. Es wird anhand von Beispielen zunächst
detailliert erklärt, wie man einzelne Graphelemente (z.B. Knoten, Kanten, usw.) nach GXL
überführt, d.h. es wird genau aufgeführt, wie der zu einem Element passende Code aussieht.
Ein Graph wird dann in GXL überführt, indem man die einzelnen Elemente eins nach dem
anderen überführt.
Danach wird erklärt, wie man Schemaelemente nach GXL überführen kann, indem gezeigt
wird, wie die Graphrepräsentation für ein Element (z.B. Klasse, Aggregation) aussieht. Der
Graph kann dann wie vorher beschrieben in GXL überführt werden. Man kann also ein
Schema nach GXL überführen, indem man zuerst die Elemente einzeln nacheinander in einen
Graphen überführt und dann die Graphen wie zuvor beschrieben nach GXL überführt. Wenn
man dies einmal gemacht hat, dann ist klar, wie der GXL-Code für einzelne Schemaelemente
aussieht. Man kann dann das Schema direkt nach GXL überführen, ohne die passende
Graphrepräsentation zu erstellen. Das Templateskript führt diese direkte Überführung von
Schemaelementen nach GXL durch.
Im letzten Abschnitt dieses Kapitels wird dann die Arbeitsweise des Templateskripts
beschrieben. Es wird erklärt, welche Arbeitsschritte das Templateskript in welcher
Reihenfolge ausführt, um den passenden GXL-Code zu einem Graphen oder einem Schema
zu generieren.
3.1. Überführung von Graphelementen
Da es mit Ameos nicht möglich ist, in geeigneter Weise Hypergraphen und hierarchische
Graphen darzustellen, wird sich in diesem Kapitel darauf beschränkt, nur die Elemente zu
beschreiben, die in einem TGraphen vorkommen können.
Knoten
Abbildung 22 zeigt einen typisierten und attributierten Knoten. Sein Typ ist Function und
seine Attribute sind line und file. Die Werte der Attribute sind 1 bzw. das Tupel bestehend
aus "main" und "cpp". Der Name des Knotens ist main. Der zu diesem Knoten passende
GXL-Code ist in Abbildung zu 23 sehen.
Ein Knoten wird in GXL durch ein node-Element dargestellt. Es besitzt das Attribut id,
welches den Namen des Knotens repräsentiert, im Beispiel main. Der Name jedes Knotens
muss innerhalb eines GXL-Dokuments eindeutig sein. Auch darf keine Überschneidung mit
dem Namensraum anderer Elemente, z.B. Kanten, auftreten. Dieses Attribut ist Pflicht und
kann daher nicht weggelassen werden.
Innerhalb des node-Elements gibt es das type-Element, das den Knotentyp angibt. Im
Beispiel wird angenommen, dass das Schema zu diesem Graph in einer GXL-Datei namens
22
3. Anforderungen
<node id="main">
<type xlink:href="schema.gxl#Function"/>
<attr name="line">
<int>1</int>
</attr>
<attr name="file">
<tup>
<string>main</string>
<string>cpp</string>
</tup
</attr>
</node>
Abbildung 23: GXL-Code zu Abb. 22
schema.gxl gespeichert ist, und dass dort ein Graphelement mit der Id Function existiert.
Falls der Knoten untypisiert ist, wird das type-Element einfach weggelassen.
Die Attribute eines Knotens werden durch attr-Elemente repräsentiert. Sie enthalten ein
Attribut name, das den Namen des Knotenattributs angibt. Innerhalb des attr-Elements wird
der Wert des Attributs festgehalten, wobei der eigentliche Wert innerhalb eines Elements
steht, das die Domain des Attributs festlegt. Im Beispiel ist das Attribut line ein Ganzzahlwert und daher der Wert zwischen einem <int> und einem </int>-Tag eingeschlossen. Das
Attribut file ist ein Tupel, das zwei Zeichenketten enthält, die beide jeweils in ein stringElement eingeschlossen sind, welche wiederum in einem tup-Element enthalten sind. Die
Anzahl der Attribute (im Beispiel: zwei) ist beliebig und kann auch null sein.
Kanten
Abbildung 24 zeigt einen Graphen mit zwei Knoten, die durch eine gerichtete, typisierte und
attributierte Kante verbunden sind. Die Abbildung wurde mit Ameos erstellt. Die Kante wird
durch eine Dependency und ein Objekt gleichen Namens dargestellt.
Die beiden Knoten lassen sich wie oben beschrieben in GXL überführen. Der GXL-Code für
die Kante ist in Abbildung 25 zu sehen.
<edge id="e1" from="main" to="a" isdirected="true">
<type xlink:href="schema.gxl#Ref"/>
<attr name="line">
<int>37</int>
</attr>
<edge>
Abbildung 25: GXL-Code der Kante aus Abb. 24
Kanten werden in GXL durch edge-Elemente dargestellt. Das edge-Tag enthält die Attribute
id, from, to und isdirected. Die from und to-Attribute sind Pflicht und können unter keinen
Umständen weggelassen werden. Das from-Attribut identifiziert den Startknoten der Kante.
Sein Wert entspricht dem Wert des id-Attributs des Startknotens. Analog wird mit dem toAttribut der Endknoten festgehalten. Die anderen Attribute sind optional. Hat eine Kante
beispielsweise keinen Namen, wird das id-Attribut weggelassen. Mit dem isdirected-Attribut
wird festgehalten, ob die Kante gerichtet oder ungerichtet ist. Wenn das isdirected-Attribut
3. Anforderungen
23
weggelassen wird, hat die Kante die Standardausrichtung, die für den Graphen festgelegt
wurde.
Der Kantentyp wird mit einem type-Element, welches sich innerhalb des edge-Elements
befindet, festgelegt. Das type-Element einer Kante ist analog aufgebaut wie das eines
Knotens. Es wird bei einer untypisierten Kante weggelassen.
Die Attribute einer Kante werden genauso wie die Attribute eines Knotens dargestellt,
nämlich durch passende attr-Elemente. Ebenso wie bei Knoten kann die Anzahl der Attribute
beliebig sein und bei einer Kante ohne Attribute enthält das edge-Element auch keine attrElemente.
3.2. Überführung von Schemaelementen
In diesem Abschnitt wird erklärt, wie man einzelne Elemente eines Schemas, das als UMLKlassendiagramm dargestellt ist, in einen Graphen überführt. Die Elemente des Graphen
können dann wie zuvor beschrieben in GXL überführt werden.
Klassen
Abbildung 26 zeigt eine Klasse, wie sie in einem Schema vorkommen kann. Der Name der
Klasse entspricht dem Knotentyp, d.h. in einem Instanzgraphen der zu dem Schema, in dem
die Klasse vorkommt, passt, können Knoten vom Typ Proc enthalten sein. Außerdem wird
festgelegt, das Knoten vom Typ Proc ein Attribut file haben und dessen Domain string ist.
Beim Überführen in einen Graphen wird aus einer Klasse ein Knoten vom Typ NodeClass.
Der Name des Knotens entspricht dem Namen der Klasse. Ein NodeClass-Knoten hat die
Attribute name und isabstract. Der Wert von name entspricht ebenfalls dem Namen der
Klasse. Das Attribut isabstract hält fest, ob die Klasse abstrakt ist oder nicht.
Für jedes Attribut der Klasse wird ein Knoten vom Typ AttributeClass erzeugt. Der Name
des Knotens entspricht dem Namen des Attributs, im Beispiel also file. Jeder Knoten vom
Typ AttributeClass hat ein Attribut name, dessen Wert ebenfalls dem Namen des Attributs
entspricht, im Beispiel also auch wieder file. Vom NodeClass-Knoten führt eine gerichtete
Kante zum Knoten vom Typ AttributeClass. Die Kante ist vom Typ hasAttribute und hat
keine Attribute.
Die Domain von Attributen wird mit Knoten entsprechenden Typs dargestellt. Hat, wie im
Beispiel, ein Attribut die Domain String, dann wird das modelliert durch einen Knoten mit
dem Namen domainString und Typ String. Die Domain Integer würde durch einen Knoten
domainInt vom Typ Int dargestellt. Andere Domains werden analog dargestellt. Eine Kante
vom Typ hasDomain verbindet einen Attributknoten mit seinem passenden Domainknoten.
24
3. Anforderungen
Der zur Klasse in Abbildung 26 passende Graph ist in Abbildung 27 zu sehen. Die Elemente
des Graphen lassen sich wie im vorigen Abschnitt beschrieben in GXL überführen.
Assoziationen
Eine Assoziation in einem Schema repräsentiert einen Kantentyp. Zu jedem Kantentyp, der in
einem Instanzgraphen vorkommt, existiert eine Assoziation im zugehörigen Schema. Die
Abbildung 28 zeigt eine Assoziation, die den Kantentyp Ref darstellt. Bei Kantentypen, die
Attribute enthalten, haben die Assoziationen eine assoziierte Klasse, die das Attribut enthält.
Typen von Kanten ohne Attribute werden durch Assoziationen ohne assoziierte Klasse
dargestellt.
Der Graph zum Schema in Abbildung 28 ist in der Abbildung 29 zu sehen. Bei der
Überführung in einen Graphen wird aus einer Assoziation ein Knoten vom Typ EdgeClass.
Er hat die Attribute name, isabstract und isdirected. Das erste Attribut beschreibt, wie
auch bei den Klassen, den Namen. Das zweite Attribut legt fest, ob es sich um eine abstrakte
Klasse handelt oder nicht. Mit dem isdirected-Attribut wird festgehalten, ob der Kantentyp
gerichtet ist. Dass die Assoziation von der Klasse Function zur Klasse Variable geht wird
mit einer from- und einer to-Kante dargestellt. Die from-Kante geht vom Knoten Ref zum
Knoten Function, die to-Kante von Function zu Variable. Diese Kanten haben die Attribute
limits und isordered. Mit limits wird die Kardinalität dargestellt, wobei der Wert -1
unendlich bedeutet. Das Attribut isordered hält fest, ob die Kanten geordnet sind. Bei fromKanten wird mit dem Attribut eine Startordnung und bei to-Kanten eine Endordnung
festgehalten.
Typ AttributeClass und entsprechenden Domainknoten dargestellt. Auch werden sie mit
Kanten von denselben Typen (hasAttribute, hasDomain) verbunden.
3. Anforderungen
25
Aggregation und Komposition
Aggregationen und Kompositionen sind weitere Elemente, die in einem Schema vorkommen
können. Die Aggregation in Abbildung 30 beispielsweise ist im GXL-Metaschema enthalten.
Die Überführung in einen Graphen funktioniert ähnlich wie die einer Assoziation. Der Unterschied besteht darin, dass aus einer Aggregation kein Knoten vom Typ EdgeClass wird,
sondern einer vom Typ AggregationClass. Ein Knoten vom Typ AggregationClass hat
dieselben Attribute wie ein EdgeClass-Knoten, weil im Metaschema die Klasse
AggregationClass eine Spezialisierung von EdgeClass ist. Zusätzlich zu den Attributen,
die von EdgeClass geerbt werden, hat AggregationClass noch das Attribut aggregate.
Die möglichen Werte dieses Attributs sind from und to, womit festgelegt wird, ob am
Eine Komposition wird in einen Knoten vom Typ CompositionClass überführt, ansonsten
ist die Überführung analog zu der einer Aggregation, weil CompositonClass eine
Spezialisierung von AggregationClass ist.
Generalisierung
Ein weiteres Element, das in einem Schema enthalten sein kann, ist Generalisierung. In
Abbildung 33 ist eine Generalisierung zu sehen.
26
3. Anforderungen
Zur Überführung in einen Graphen werden die Ober- und Unterklasse wie gewöhnliche
Klassen überführt. Im Gegensatz zu Assoziationen, Aggregationen und Kompositionen
werden Generalisierungen nicht in einen Knoten eines bestimmten Types überführt. Eine
Generalisierung wird zu einer gerichteten Kante vom Typ isA, die von der Unterklasse zur
Oberklasse führt. Abbildung 32 zeigt den zu Abbildung 33 passenden Graph.
3.3. Arbeitsweise des Templateskripts
TDL bietet keine Möglichkeit zur Benutzerinteraktion, d.h. während der Ausführung des
Templateskripts sind keine Eingaben des Benutzers möglich. Daher müssen alle
Informationen, die das Templateskript zum Erzeugen von Code benötigt, entweder im
Graphen bzw. Schema vorhanden sein oder vor dem Start der Ausführung als Parameter
festgehalten werden. Sobald das Templateskript gestartet ist, hat der Benutzer keine
Möglichkeit mehr die Arbeit des Templateskript zu beeinflussen. Das Templateskript arbeitet
die einzelnen Arbeitsschritte, die zur Codeerzeugung notwendig sind nur eins nach dem
anderen ab.
Die Arbeitsschritte sind wie folgt:
1) Der erste Arbeitsschritt ist, zu entscheiden, ob der Code für einen Instanzgraphen oder ein
Schema generiert werden soll. Danach folgt die Codegenerierung, die in beiden Fällen
nach demselben Muster verläuft.
Als erstes wird der Kopf der GXL-Datei erzeugt. Der Kopf besteht aus den Tags, welche
die verwendete XML-Version und DTD angeben. Ebenfalls zum Kopf gehört noch das
<gxl>-Element, das den Rest der Datei einschließt. Dann wird das <graph>-Element
erzeugt, welches den zu erzeugenden Graphen umschließt. Dieser Arbeitsschritt ist
unabhängig von der Entscheidung, ob ein Instanzgraph oder ein Schema erzeugt wird. Er
ist in beiden Fällen gleich.
2) Im nächsten Schritt wird der Code der einzelnen Knoten erzeugt. Hier unterscheiden sich
die beiden Fälle. Die Codeerzeugung der Knoten eines Instanzgraphen verläuft anders wie
die der Knoten eines Schemas.
Bei einem Schema muss man für jede Klasse, jede Assoziation, jedes Attribut und deren
Domain einen Knoten eines entsprechenden Types (NodeClass, EdgeClass, etc.)
erzeugen. Dieser Schritt wird in mehrere Teilschritte gegliedert. Als erstes wird ein
Knoten vom Typ GraphClass erzeugt. Als nächstes wird für jede Assoziation ein
passender Knoten erzeugt. Da Aggregationen und Kompositionen Spezialfälle von
Assoziationen sind, erfolgt die Erzeugung von Knoten für diese Fälle ebenfalls in diesem
Teilarbeitsschritt. Im nächsten Schritt wird dann für alle Klassen ein Knoten vom Typ
NodeClass erzeugt. Danach werden im letzten Teilschritt für jedes Attribut und dessen
Domain die passenden Knoten erzeugt. Es wird ein Knoten für jedes Attribut und ein
Knoten für jede Domain erzeugt.
Bei einem Instanzgraphen erfolgt die Generierung der Knoten in einem Teilschritt. Für
jedes Objekt, zu dem keine Abhängigkeit mit gleichem Namen existiert, wird ein Knoten
erstellt. Wenn zu einem Objekt eine Abhängigkeit mit identischem Namen existiert,
erzeugt dieser Teilschritt keinen Knoten.
3) Im letzten Arbeitsschritt generiert das Templateskript die Kanten. Auch hier unterscheiden
sich die Teilschritte in Abhängigkeit davon, ob ein Schema oder Instanzgraph erzeugt
wird.
3. Anforderungen
27
Bei Instanzgraphen geschieht die Erzeugung des GXL-Codes wieder in einem Teilschritt.
Für jede Abhängigkeit wird eine Kante erzeugt. Existiert zu einer Abhängigkeit ein Objekt
mit dem gleichen Namen, wird eine attributierte Kante erzeugt, ansonsten eine
unattributierte Kante.
Bei einem Schema ist dieser Schritt in mehrere Teilschritte zerlegt. Zuerst werden die
Kanten vom Typ contains erzeugt, welche den GraphClass-Knoten mit allen Knoten
verbindet, die ein Element des Schemas repräsentieren. Im nächsten Teilschritt werden die
to- und from-Knoten erzeugt. Für jede Assoziation entsteht eine Kante vom Typ from und
eine vom Typ to. In den darauf folgenden Teilschritten werden zunächst alle Kanten vom
Typ hasAttribute und dann die hasDomain-Kanten erzeugt. Als letztes werden die
Kanten vom Typ isA, mit denen Generalisierung dargestellt wird, generiert.
Wenn alle Kanten erzeugt wurden, ist das Templateskript mit seiner Arbeit fertig und die
Ausführung wird beendet.
Der Prozess der eigentlichen Codeerzeugung lässt sich also in drei Schritte einteilen:
1. Generierung des Kopfes der GXL-Datei
2. Generierung des GXL-Codes der Knoten
3. Generierung des GXL-Codes der Kanten
Vor der eigentlichen Codeerzeugung wird entschieden, ob die GXL-Datei für einen Instanzgraphen oder ein Schema erzeugt werden soll. Je nach Entscheidung bestehen die drei
Schritte, wie oben beschrieben, aus unterschiedlichen Teilschritten.
28
4. Implementierung des Templateskripts
4. Implementierung des Templateskripts
In diesem Kapitel wird nun die Implementierung des Templateskripts beschrieben. Es werden
vor allem die aufgetretenen Probleme erklärt und deren Lösungen erläutert. Das
Templateskript ist in drei Teile gegliedert, die alle in einer eigenen tdl-Datei enthalten sind.
Das Kapitel gliedert sich daher auch in drei Teile. Der erste Teil beschäftigt sich mit dem Teil
des Templateskripts, der dazu benötigt wird, um den GXL-Code für einen Instanzgraphen zu
erzeugen. Dieser Teil des Templateskripts ist in der Datei instance.tdl enthalten. Im zweiten
Teil wird die Entwicklung der Funktionen zum Erzeugen des GXL-Code passend zu einem
Schema beschrieben. Diese Funktionen werden in der Datei schema.tdl zusammengefasst.
Der dritte Teil des Templateskripts besteht aus dem Inhalt der Datei main.tdl, welche auch
die Prozedur main enthält, die der Startpunkt bei der Ausführung des Templateskripts ist.
Außerdem enthält diese Datei noch Funktionen, die zur Initialisierung benötigt werden, unter
anderem muss entschieden werden, ob die GXL-Datei für einen Instanzgraphen oder ein
Schema erzeugt werden muss. Die Entwicklung dieses Teils des Templateskripts wird im
letzten Abschnitt dieses Kapitels dokumentiert.
4.1. Implementation des Instanzteils
Wenn im Hauptteil des Templateskripts entschieden wird, dass das System einen Graphen
und kein Schema enthält, dann wird das Template genInstanceGraph aufgerufen. Dieses
Template erzeugt dann unter Zuhilfenahme weiterer Templates und Prozeduren den zum
Graphen passenden GXL-Code. Das Templateskript erzeugt immer erst den Code für alle
Knoten und danach alle Kanten. Im Instanzteil des Templateskripts ruft das Template
genInstanceGraph daher zuerst die Prozedur genInstanceNodes und danach
genInstanceEdges auf.
Die Knoten eines Instanzgraphen werden mit Ameos durch Objekte dargestellt. Aber nicht
alle Objekte in einem Diagramm repräsentieren Knoten, sondern auch attributierte Kanten
werden mit Hilfe von Objekten dargestellt. Die ursprüngliche Idee bei der Entwicklung des
Templateskripts war es, Kanten durch Abhängigkeiten (engl. Dependencies) und Objektassoziationen (engl. ObjectAssociations) darzustellen. Da diese Kanten aber keine Attribute
haben können, wurde entschieden, eine attributierte Kante durch eine Abhängigkeit oder
Objektassoziation und dazu ein Objekt mit exakt dem gleichen Namen darzustellen. Auf
Grund ihrer visuellen Repräsentation in einem Objektdiagramm sollten gerichtete Kanten mit
Abhängigkeiten und ungerichtete mit Objektassoziationen dargestellt werden. Es stellte sich
aber heraus, dass das Metamodell an dieser Stelle eine schwerwiegende Lücke hat. Es
existiert zwar eine Klasse MDependency und jede Abhängigkeit in einem Objektdiagramm
ist eine Instanz hiervon, aber es existiert keine entsprechende Klasse für Objektassoziationen.
Eine Klasse MObjectAssociation kommt im Metamodell nicht vor. Kein Templateskript
kann deshalb auf Objektassoziationen zugreifen und den davon abhängigen Code erzeugen.
Somit ist es auch nicht möglich, ungerichtete Kanten mit Objektassoziationen darzustellen.
Eine andere Möglichkeit wurde bis jetzt nicht gefunden. Es können also nur gerichtete
Kanten dargestellt werden. Der Benutzer des Templateskripts muss also darauf achten, dass
er ausschließlich gerichtete Kanten, also Abhängigkeiten, in seinen Graphen verwendet.
Durch die Lösung des Problems, wie eine attributierte Kante repräsentiert wird (Dependency
und Objekt mit gleichen Namen), kann die Prozedur genInstanceNodes nicht einfach in
4. Implementierung des Templateskripts
29
einer Schleife über alle Objekte (loop(Instances->MObject)) jeweils den GXL-Code eines
Knoten erzeugen. Die Prozedur muss daher zuerst eine Liste mit den Namen aller Kanten
erstellen und dann nur für die Objekte, deren Namen nicht in der Liste ist den GXL-Code
eines Knoten erstellen. Nachdem diese Liste erstellt wurde, geht die Prozedur in eine Schleife
über alle Objekte. Wenn der Name des Objekts nicht in der Liste der Kanten ist, dann
repräsentiert das Objekt einen Knoten und das Template zum Erzeugen des entsprechenden
GXL-Codes wird aufgerufen. Falls das Objekt in der Liste der Kanten enthalten ist, dann wird
der Name in eine weitere Liste eingetragen. Diese Liste enthält, nachdem die Schleife alle
Objekte durchlaufen hat, die Namen aller attributierten Kanten.
In einem Objektdiagramm werden die Attribute von Objekten in der Regel in der Form
Name=Wert dargestellt. Der Typ eines Attributs wird hiermit nicht festgehalten. Das führt
dazu, dass die Variable MAttribute.type den leeren String enthält. Auf diese Weise lässt sich
also nicht die Domain eines Attributs bestimmen. Um den GXL-Code für ein Attribut zu
erzeugen, muss man aber dessen Domain kennen. Das Templateskript enthält eine Prozedur
getDomain, die ein Attribut übergeben bekommt und dessen Domain zurückgibt. Die
Prozedur ist allerdings nur in der Lage einfache Domains zu erkennen. Es werden nur die
Domains bool, int und float erkannt und der entsprechende Wert zurückgeben. In allen
anderen Fällen wird der Wert string zurückgegeben. Strings werden also auch korrekt als
solche erkannt, andere Domains, z.B. Tupel oder Menge, werden aber auch als String erkannt.
Nachdem alle Knoten erstellt wurden, d.h. das Templateskript hat für alle Knoten des
Graphen den passenden GXL-Code erzeugt, werden die Kanten von der Prozedur
genInstanceEdges erstellt. Diese Prozedur enthält eine Schleife über alle Abhängigkeiten.
In jedem Schleifendurchlauf wird geprüft, ob der Name der aktuellen Abhängigkeit in der
Liste der attributierten Kanten ist. Falls dem so ist, wird in einer weiteren Schleife das dazu
passende Objekt gesucht und dann ein Template aufgerufen, das aus dem Objekt und der
Abhängigkeit den GXL-Code einer attributierten Kante erzeugt. Falls die Abhängigkeit nicht
in der Liste der attributierten Kanten enthalten ist, dann repräsentiert sie eine unattributierte
Kante und es wird ein Template aufgerufen, das den Code für eine solche Kante erzeugt.
Ein weiteres Problem, das bei der Implementierung des Templateskripts auftrat, betrifft die
Eingabe von Namen und Typ eines Knotens. In UML werden bekanntlich Objektname und
Klassenname durch einen Doppelpunkt getrennt. Wenn man in Ameos den Namen eines
Objekts auf diese Weise eingibt, dann erkennt das Programm, welcher Teil der eigentliche
Objektname ist und welcher Teil die Klasse des Objekts bezeichnet. Beim Erstellen eines
Graphen kann man diese Notation verwenden, um den Namen und den Typ des Knotens
einzugeben und voneinander zu trennen. Man schreibt also Knotenname:Knotentyp.
Bei den ersten Testläufen des Templateskripts zeigte sich ein Problem, das damit in
Zusammen-hang steht. Ameos beendete die Ausführung des Templateskripts mit einer
Fehlermeldung der Art "error: Interface-File (Dependency) : cannot
find corresponding supplierId ID "278" in semantical interface
format". Die Meldung wurde genauso oft ausgegeben wie es Abhängigkeiten im Diagramm
gibt, nur jedes Mal mit einer anderen ID. Die Dokumentation von Ameos gab keine
Rückschlüsse auf die Ursache dieses Fehlers. Durch einiges Ausprobieren konnte jedoch
festgestellt werden, dass der Fehler mit der Namensgebung zu tun hat. In einem weiteren
Testlauf stellte sich nämlich heraus, dass der Fehler nicht auftrat, wenn die Knoten keinen
Typ haben. Auch der Versuch, den Namen und den Typ eines Knoten nicht durch einen
Doppelpunkt, sondern ein anderes Zeichen zu trennen, führte zu keiner Fehlermeldung beim
Ausführen des Templateskripts. Es wurde daraufhin entschieden, dass der Name eines
30
4. Implementierung des Templateskripts
Knotens und dessen Typ durch einen Unterstrich zu trennen sind. Das Templateskript arbeitet
einwandfrei, wenn man den Namen und den Typ angibt, in der Form
Knotenname_Knotentyp. Es existiert zwar somit eine Lösung des Problems, die dafür
sorgt, dass die Fehlermeldung nicht mehr auftritt, die Ursache bleibt aber weiterhin unklar.
Im späteren Verlauf der Entwicklung kam die Vermutung auf, dass der Fehler auch damit zu
tun haben könnte, dass die passenden Klassen im System nicht vorhanden sind. Das bedeutet,
wenn man den Namen und den Typ der Knoten mit einem Doppelpunkt trennt, dann gibt man
aus Sicht von Ameos einen Objektnamen und einen Klassennamen an. Ameos erwartet dann,
dass die Klasse auch im System, egal ob im selben Diagramm oder einem anderen, existieren
muss. Bis jetzt war es bei den Tests aber immer so, wenn im System ein Instanzgraph
vorhanden war, keine Klassen im System existierten. Es stellte sich heraus, wenn die
entsprechenden Klassen vorhanden sind, die Codeerzeugung ohne Fehlermeldung
funktioniert, auch wenn Knotenname und -typ durch einen Doppelpunkt getrennt sind.
Daraus ergeben sich jetzt zwei Möglichkeiten der Vorgehensweise beim Erstellen von
Graphen und dem Ausführen des Templateskripts.
1. Der Benutzer erstellt nur den Instanzgraphen und trennt dabei den Namen und den Typ der
Knoten mit einem Unterstrich
oder
2. er erstellt den Instanzgraphen und das passende Schema. Die Trennung von Namen und
Typ erfolgt dann durch einen Doppelpunkt.
Im zweiten Fall wird sowohl der GXL-Code für den Instanzgraphen, als auch der des
Schemas erzeugt. Nur den Instanzgraphen oder nur das Schema zu erzeugen wird vom
Templateskript nicht unterstützt. Instanzgraph und Schema werden in zwei verschiedenen
Dateien gespeichert.
Ein weiteres Problem bei der Darstellung von Kanten ist, dass es keine Möglichkeit gibt mit
Abhängigkeiten eine Kantenordnung festzuhalten. Es wurde bis jetzt keine Lösung für dieses
Problem gefunden. Das Templateskript unterstützt nur Graphen, deren Kanten alle nicht
angeordnet sind.
4.2. Implementation des Schemateils
Die Erzeugung des GXL-Codes passend zu einem Schema verläuft nach einem einfachen
Muster. Der Hauptteil des Templateskripts ruft dazu das Template genSchemaGraph auf.
Das Template erzeugt zuerst den Code des Knoten vom Typ GraphClass, der in jedem
Schemagraphen vorhanden ist. Dann werden die Templates genNodes und genEdges
aufgerufen. Ersteres generiert den Code für alle Knoten, letzteres den für alle Kanten. Danach
ist dann das komplette Schema nach GXL überführt und die Codeerzeugung fertig.
Das Template genNodes generiert zuerst die Knoten vom Typ EdgeClass oder einer der
Subklassen, dann die Knoten vom Typ NodeClass, dann die AttributeClass-Knoten und als
letztes die Domain-Knoten. Dazu ruft das Template immer eine entsprechende Prozedur auf,
die diese Knoten erzeugt.
Die Prozedur genEdgeClassNodes erzeugt den Code der Knoten vom Typ EdgeClass.
Auch die Knoten von den Typen AggregationClass und CompositionClass werden in
dieser Prozedur erzeugt, da es sich bei diesen beiden Typen um Spezialisierungen von
EdgeClass handelt. Das Erzeugen des Codes geschieht in einer Schleife über alle
Assoziationen. In der Schleife wird zuerst geprüft, ob zu der Assoziation eine assoziierte
4. Implementierung des Templateskripts
31
Klasse existiert und, falls dem so ist, der Name der Klasse in eine Liste eingetragen. Die Liste
wird später beim Erzeugen der Knoten vom Typ NodeClass benötigt. Danach wird dann
geprüft, ob eine Assoziation oder eine der Spezialisierungen vorliegt. Dementsprechend wird
dann entweder ein Knoten vom Typ EdgeClass oder einer der Spezialisierungen
AttributeClass oder CompositionClass erzeugt. Die Erzeugung des Codes für einen
Knoten einer dieser Klassen geschieht relativ problemlos. Der Wert des Attributs id eines
solchen Knoten entspricht dem Namen der assoziierten Klasse, falls eine solche existiert.
Wenn keine assoziierte Klasse existiert und der Benutzer der Assoziation einen Namen
gegeben hat, dann entspricht der Wert von id diesem Namen. Hat der Benutzer der
Assoziation keinen Namen gegeben, dann wird der Wert der Metaattributvariablen
MAssociation.id benutzt.
Im Zusammenhang mit der Erzeugung des Codes für das Attribut isdirected gilt es einiges zu
beachten. Die Darstellung, ob eine Assoziation einen gerichteten oder ungerichteten
Kantentyp festlegt, geschieht mit Hilfe der "Role Navigability". Die Role Navigability kann
man im Eigenschaftenmenü einer Assoziation bearbeiten (Assoziation auswählen, dann im
Menü Edit Properties wählen). In diesem Menü sind neben der Bezeichnung "Role
Navigability" zwei Kästchen vorhanden, für jedes Ende der Assoziation eines, in die man
durch einen Mausklick einen Haken hinzufügen kann oder, falls ein Haken vorhanden ist,
diesen entfernen. Ist in einem Kästchen der Haken vorhanden, dann ist die Role Navigability
gesetzt, andernfalls nicht. Falls für beide Enden der Assoziation die Role Navigability gesetzt
ist, dann wird die Assoziation im Diagramm durch eine Linie ohne Pfeilspitze dargestellt.
Falls an einem Ende der Assoziation die Role Navigability gesetzt ist und am anderen Ende
nicht, dann wird die Assoziation durch eine Linie mit einer Pfeilspitze dargestellt. Die Spitze
befindet sich an dem Ende, an dem die Role Navigability gesetzt ist. Wenn eine Assoziation
einen Kantentyp darstellen soll, der ungerichtet ist, dann muss die Role Navigability an
beiden Enden der Assoziation gesetzt sein. Wenn der Kantentyp gerichtet sein soll, dann
muss die Role Navigability an dem Ende gesetzt sein, zu dem die Kante hingeht. Am anderen
Ende darf sie nicht gesetzt sein. Mit der Role Navigability wird also festgehalten, ob ein
Kantentyp gerichtet ist oder nicht und bei einem gerichteten Typ wird damit auch noch
zusätzlich die Richtung festgelegt.
Der Fall, dass die Role Navagability an beiden Enden der Assoziation nicht gesetzt ist, wird
von Ameos mit einer Fehlermeldung quittiert und die Role Navigability an beiden Enden
gesetzt. Es entsteht also eine Assoziation, die einen ungerichteten Kantentyp beschreibt.
Bei einer Assoziation, die von einer Klasse zu derselben Klasse geht, also nicht zwei
verschiedene Klassen verbindet, und die gerichtet sein soll, muss man den Enden Rollen
zuweisen. Ohne Rollen kann Ameos die Enden der Assoziation nämlich nicht unterscheiden
und es ist dann nur möglich, dass an beiden Enden die Role Navigability gesetzt ist. Ohne
Rollen kann man also nur einen ungerichteten Kantentyp darstellen. Mit Rollen ist es
möglich, dass die Role Navigability an einem Ende gesetzt wird und am anderen nicht.
Knoten vom Typ NodeClass werden von der Prozedur genNodeClassNodes generiert,
d.h. die Prozedur erzeugt den GXL-Code für alle Knoten von diesem Typ. Die Prozedur
enthält eine Schleife über alle Klassen. In dieser Schleife wird zuerst geprüft, ob die Klasse
sich in der Liste der assoziierten Klassen befindet. Diese Liste wurde vorher in der Prozedur
genEdgeClassNodes erstellt. Wenn eine Klasse in dieser Liste steht, dann wurde für sie
schon ein Knoten vom Typ EdgeClass erzeugt und die Prozedur genNodeClassNodes
muss nichts weiter tun. Ist die Klasse nicht in der Liste enthalten, dann muss ein Knoten vom
Typ NodeClass erzeugt werden. Dazu wird ein Template aufgerufen, welches den GXL-
32
4. Implementierung des Templateskripts
Code für einen solchen Knoten erzeugt.
Die Prozeduren genAttributeClassNodes und genDomainNodes generieren den GXLCode für die Attribute und ihre Domains. Die Prozedur genAttributeClassNodes erzeugt
für jedes Attribut einen Knoten. Wenn mehrere Klassen ein Attribut mit gleichem Namen
haben werden mehrere Knoten erzeugt. Haben beispielsweise drei Klassen ein Attribut mit
dem Name line dann werden drei Knoten vom Typ AttributeClass erzeugt. Die drei Knoten
haben unterschiedliche Ids, aber der Wert des Attributs name dieser Knoten ist bei allen drei
line. Dadurch ist es möglich, dass die Attribute von mehreren Klassen den gleichen Namen
aber nicht dieselbe Domain haben. Die Domain von line könnte also zum Beispiel einmal int,
einmal string und einmal float sein. Würde nur ein Knoten erstellt, dann müsste die Domain
bei allen vorkommen des Attributs gleich sein.
Da es vorkommen kann, dass mehrere Attribute dieselbe Domain haben können, benutzt die
Prozedur genDomainNodes eine Liste mit den bisher erzeugten Knoten. Nur wenn für eine
Domain noch kein Knoten erzeugt wurde, dann generiert die Prozedur genDomainNodes
den entsprechende Code und fügt den Namen der Domain zu der Liste hinzu. Bei den
Schemata werden wie bei den Instanzgraphen nur einfache Domains unterstützt.
Nachdem der GXL-Code für die Knoten erfolgreich erzeugt wurde, generiert das Template
genEdges den Code für die Kanten. Dabei werden zuerst die Kanten vom Typ contains
erzeugt, dann die to- und from-Kanten, danach die hasAttribute-Kanten, gefolgt von den
Kanten vom Typ hasDomain und als letztes dann die isA-Kanten.
Die Kanten vom Typ contains sind gerichtete Kanten, die von dem Knoten vom Typ
GraphClass zu den Knoten von NodeClass und EdgeClass gehen. Diese Kanten haben
keine Attribute und sind ohne Probleme zu erzeugen.
Die Kanten vom Typ hasAttribute, hasDomain und isA haben ebenfalls keine Attribute und
sind problemlos zu generieren. Die einzigen attributierten Kanten sind die from- und toKanten. Die Erzeugung dieser Kanten erscheint ein wenig aufwendiger, denn es müssen
mehrere Fälle unterschieden werden. Die zu beachtenden Fälle sind, dass ein Kantentyp
gerichtet oder ungerichtet sein kann und unabhängig davon können zwei verschiedene
Knotentypen miteinander verbunden werden oder aber nur ein Typ. Insgesamt ergeben sich
damit vier unterschiedliche Fälle, die es zu beachten gilt. Da die Fälle sich aber nicht
großartig unterscheiden, ist die Erzeugung der from- und to-Kanten doch nicht so aufwendig.
Das Attribut limits der to- und from-Kanten hält die Kardinalitäten eines Kantentyps fest. In
Ameos kann der Benutzer diese mit dem Attribut Multiplicity einer Assoziation festsetzen.
Das Templateskript kann dann mit der Variablen MAssociationEnd.multiplicity auf diesen
Wert zugreifen. Da es sich bei dieser Variablen um eine Zeichenkette handelt, die sowohl den
unteren als auch den oberen Grenzwert der Multiplizität enthält, das Attribut limits aber ein
Tupel ist, das die untere und obere Grenze als Bestandteile hat, muss das Templateskript die
Zeichenkette zuerst zerlegen und dann das entsprechende Tupel bilden. Dies geschieht mit
der Prozedur setLimits, die von den Prozeduren zum Generieren von to- und from-Kanten
aufgerufen wird und dabei eine Assoziation als Parameter übergeben bekommt. Die Prozedur
setzt dann für die übergebene Assoziation den Wert von limits fest. Setzt der Benutzer für
eine
Assoziation
keine
Multiplizität
fest,
dann
ist
der
Wert
von
MAssociationEnd.multiplicity der leere String. Die Prozedur setLimits legt dann als obere
und untere Grenze den Wert 1 fest.
4. Implementierung des Templateskripts
33
4.3. Implementation des Hauptteils
Der sogenannte Hauptteil des Templateskripts ist der Startpunkt der Codegenerierung. In
diesem Teil ist die Prozedur main enthalten. Wie bei jedem Templateskript wird auch bei
diesem die Prozedur main als allererstes aufgerufen und ausgeführt.
Von der Prozedur main wird als erstes die Prozedur init aufgerufen. Die Prozedur init
initialisiert das Templateskript. Unter anderem wird in dieser Prozedur die Ausgabe auf eine
passende Datei gesetzt, d.h. es wird die Datei festgelegt, in die der zu erzeugende GXL-Code
geschrieben wird.
Nachdem init abgearbeitet ist, ruft main die Prozedur genGXL, welche dann die Codeerzeugung startet, auf. Das Template entscheidet, ob ein Instanzgraph vorhanden ist oder ein
Schema und ruft dann entweder das Template genInstanceGraph im Instanzteil oder
genSchemaGraph im Schemateil auf. Die Entscheidung, ob Instanzgraph oder Schema,
wird ganz einfach gefällt, und zwar wird, wenn im System Objekte vorhanden sind, das
Template genInstanceGraph aufgerufen, ansonsten genSchemaGraph. Diese
Entscheidung hat dann auch zur Folge, wenn im System Objekte und Klassen vorhanden sind,
also ein Instanzgraph und ein Schema existieren, nur der GXL-Code für den Instanzgraphen
erzeugt wird.
Desweiteren werden im Hauptteil des Templateskripts sogenannte Scriptparameter definiert.
Die Definition dieser Parameter, die auch Externe Variablen genannt werden, erfolgt durch
einen speziell formatierten Kommentar in der Datei main.tdl. Die Parameter können dann
vom Templateskript wie eine Variable gelesen werden. Der Benutzer kann die Werte der
Parameter im Script Manager Fenster von Ameos ändern. Das Templateskript enthält vier
Scriptparameter:
FILENAME
GRAPHID
SCHEMAFILE
SCHEMAID.
Der Parameter FILENAME gibt den Namen der zu erzeugenden GXL-Datei für einen
Instanzgraphen an. Der Name ist ohne die Endung .gxl anzugeben, diese wird vom
Templateskript automatisch angehängt. Der Standardwert des Parameters ist GXLfilename.
Wenn der Benutzer den Wert nicht ändert, wird also der vom Templateskript generierte Code
in die Datei GXLfilename.gxl geschrieben. Ändert der Benutzer den Wert, beispielsweise in
MeinErsterGraph, dann wird die Datei MeinErsterGraph.gxl erzeugt und der generierte
Code in diese geschrieben.
Beim Erzeugen des GXL-Codes zu einem Schema wird der Name der zu erzeugenden Datei
mit dem Parameter SCHEMAFILE angegeben. Der Parameter FILENAME wird nicht
benötigt.
Hat man im System einen Instanzgraphen und das passende Schema erstellt, dann wird der
GXL-Code für den Graphen in die Datei geschrieben, die mit FILENAME angegeben wird.
Der Code des Schemas wird in die Datei geschrieben, die mit dem Parameter
SCHEMAFILE angegeben wird.
Den Dateinamen der zu erzeugenden GXL-Datei mit einem Scriptparameter festzulegen, war
bei der Entwicklung des Templateskripts nur zweite Wahl. Die erste Wahl war es, den Namen
des Objektdiagramms zu verwenden, das den Graphen enthält. Dies scheiterte daran, dass es
keine Möglichkeit gibt, mit TDL auf den Namen eines Diagramms zuzugreifen, und das,
34
4. Implementierung des Templateskripts
obwohl es im Metamodell eine Klasse MDiagram gibt, die das Attribut name besitzt. Das
Problem ist, dass selbst wenn in einem System mehrere Diagramme vorhanden sind, eine
Schleife über alle Diagramme (loop(Instances->MDiagram)) nicht betreten wird. Die Schleife
wird nullmal durchlaufen, es existiert also keine Instanz von MDiagram. Eventuell liegt das
daran, dass die Klasse MDiagram im Package GraphicalStructure enthalten ist, alle anderen
Klassen, auf die das Templateskript zugreift und wo dies ohne Probleme funktioniert, sind
aber in ClassStructure enthalten. Da die Dokumentation hierüber nicht genügend Auskunft
gibt, ist dies nur eine Vermutung.
Auch der Scriptparameter GRAPHID ist nur zweite Wahl, weil es nicht möglich ist, auf den
Namen eines Diagramms zuzugreifen. In GXL sind die einzelnen Elemente eines Graphen in
einem <graph>-Tag enthalten. Dieses Tag besitzt ein Attribut id, welches dem Graphen
einen eindeutigen Namen zuweist. Die ursprüngliche Idee war es, den Diagrammnamen für
dieses Attribut zu verwenden. Da dies bekanntlich nicht geht, musste eine andere Lösung
gefunden werden. Die Verwendung eines weiteren Scriptparameters war die einzige Lösungsmöglichkeit. Der Standardwert dieses Parameters ist GraphID.
Der Typ von Graphelementen wird in GXL mit Hilfe des <type>-Tags festgehalten. Ein
solches Tag enthält einen Verweis auf ein entsprechendes Element im Schema. Ein Graph
und das dazu passende Schema müssen aber nicht in derselben Datei sein, sie können auch in
unterschiedlichen Dateien enthalten sein. Wenn ein Graph und das Schema nicht in derselben
Datei sind, muss in dem <type>-Tag nicht nur auf ein passendes Element im Schema
verwiesen werden, sondern auch eine Referenz enthalten sein auf die Datei, in der das
Element enthalten ist. Der Name der Datei, die das Schema enthält, wird, wenn ein
Instanzgraph erzeugt wird, mit dem Parameter SCHEMAFILE festgehalten. Der
Standardwert ist SchemaFilename und genauso wie bei FILENAME wird auch an den Wert
dieses Parameters die Endung .gxl angehängt. Beim Generieren des Codes zu einem Schema
wird vom Templateskript automatisch ein Verweis auf das GXL-Metaschema erzeugt.
Der Typ eines Graphen wird ebenfalls mit einem <type>-Tag festgehalten. Die Knoten eines
Graphen werden in einem Objektdiagramm durch Objekte dargestellt. Ein Objekt enthält
neben seinem Namen auch die Information, zu welcher Klasse es gehört. Die Klasse
repräsentiert den Typ des Knoten. Mit dem <type>-Tag innerhalb des <node>-Elements
wird auf einen Knoten vom Typ NodeClass im Schema verwiesen. In ähnlicher Weise sind
auch Informationen zu den Typen der Kanten vorhanden. Eine Information zu dem Typ des
Graphen ist aber nicht vorhanden. Das <type>-Tag in einem <graph>-Element verweist auf
einen Knoten vom Typ GraphClass. Die Id dieses Knotens ist im Diagramm nirgends
vorhanden. Daher wird sie mit dem Scriptparameter SCHEMAID festgelegt. Der Standardwert ist SchemaID.
Wenn das Templateskript den GXL-Code zu einem Instanzgraphen generiert, wird der Wert
des Parameters SCHEMAID im <type>-Tag innerhalb des <graph>-Elements verwendet.
Falls der Code zu einem Schema generiert wird, dann wird der Wert von SCHEMAID als Id
des Knotens vom Typ GraphClass benutzt.
5. Einführung in die Bedienung des Templateskripts
35
5. Einführung in die Bedienung des Templateskripts
Im vorigen Kapitel wurde die Implementation des Templateskripts beschrieben. In diesem
Kapitel folgt nun eine kurze Einführung in die Benutzung. Im ersten Abschnitt wird die
Installation erklärt und der allgemeine Umgang mit dem Templateskript beschrieben. Der
darauf folgende Abschnitt beschäftigt sich mit dem Erstellen von Instanzgraphen. Es wird vor
allem erklärt, welche Einschränkungen sich aus der Benutzung von Ameos und TDL ergeben
und was daher zu beachten ist, wenn man einen Instanzgraphen erstellt und von dem
Templateskript eine passende GXL-Datei erzeugen lassen will. Im letzten Abschnitt geht es
um das Erstellen von Schemata und was hierbei zu beachten ist, damit das Templateskript
fehlerfrei eine GXL-Datei erstellen kann, welche das Schema enthält.
Bei der Entwicklung des Templateskripts wurde mit der Version 9.1 von Ameos gearbeitet.
Das Templateskript wurde bisher nur mit dieser Version verwendet und getestet. Es kann
daher keine Garantie übernommen werden, dass das Skript auch mit anderen Versionen von
Ameos einwandfrei funktioniert.
5.1. Installation und Benutzung
Das Templateskript besteht aus den drei Dateien main.tdl, instance.tdl und schema.tdl. Um
das Templateskript benutzen zu können müssen diese Dateien in ein spezielles Verzeichnis
kopiert werden. Und zwar existiert im Installationsverzeichnis von Ameos (z.B.
C:\Ameos9.1) das Unterverzeichnis templates\uml\tdl\basic. In diesem Verzeichnis legt man
ein neues Unterverzeichnis mit dem Namen GXL an und kopiert die drei Dateien des
Templateskripts in dieses neu angelegte Unterverzeichnis. Der vollständige Pfad des
Templateskripts ist also C:\Ameos9.1\templates\uml\tdl\basic\GXL. Damit ist die
Installation fertig und nach dem nächsten Start von Ameos steht das Templateskript zur
Benutzung bereit.
Zum Ausführen des Templateskripts benötigt man den Scriptmanager von Ameos. Falls der
Script-manager nicht angezeigt wird wählt man im Menü den Befehl View Show Script
Manager aus. Im Scriptmanager (siehe Abb. 34) wählt man im linken Ausschnitt das
Abbildung 34: Scriptmanager
36
5. Einführung in die Bedienung des Templateskripts
Templateskript aus. Es ist zu finden unter Product Scripts basic GXL. Im rechten Teil
des Managers kann man die Parameter des Templateskripts ändern. In der Rubrik General
Parameters findet man allgemeine Parameter, die unabhängig sind vom ausgewählten
Templateskript. Zum Beispiel findet sich dort der Parameter Output to, mit dem das
Verzeichnis festgelegt wird, in welches die Ausgabedateien eines Templateskripts
geschrieben werden. Unter Script Parameters findet man Parameter, die vom ausgewählten
Templateskript abhängig sind.
Wenn man das Templateskript ausgewählt und alle Parameter eingestellt hat, kann man das
Templateskript ausführen. Entweder man macht im Scriptmanager einen Rechtsklick auf das
Templateskript und wählt Run Script oder man wählt im Menü Script den Befehl Run
Script.
Die Scriptparameter, auch externe Variablen genannt, für das GXL-Templateskript sind
FILENAME, GRAPHID, SCHEMAFILE und SCHEMAID. Mit FILENAME und
SCHEMAFILE legt man die Namen der zu erzeugenden GXL-Dateien fest. Ein Instanzgraph
wird in die Datei geschrieben, die mit FILENAME festgelegt wird. Ein Schema wird in die
mit SCHEMAFILE festgelegte Datei geschrieben. Mit GRAPHID wird die Id des
Instanzgraphen, der generiert wird, festgelegt. Wenn ein Instanzgraph erzeugt wird, dann hält
man mit dem Parameter SCHEMAFILE den Namen der Datei fest, die das zum Graphen
passende Schema enthält. Der Wert des Parameters wird bei der Codeerzeugung nicht
geprüft, d.h. das Templateskript überprüft nicht, ob die angegebene Datei existiert. Der
Parameter SCHEMAID wird verwendet, um den Typ des Graphen festzulegen. Wenn das
Templateskript ein Schema nach GXL überführt, dann wird auch ein Knoten vom Typ
GraphClass erzeugt. Die Id dieses Knotens entspricht dem Wert des Parameters
SCHEMAID. In einem Instanzgraphen wird in dem <type>-Tag innerhalb des <graph>Elementes auf einen Knoten vom Typ GraphClass im Schema verwiesen. Das
Templateskript verwendet beim Erzeugen eines Instanzgraphen an dieser Stelle auch den
Wert von SCHEMAID.
Ameos ist eigentlich ein Programm, mit dem man Softwaresysteme mit UML modellieren
kann. Es wird daher der Begriff System verwendet, um die einzelnen modellierten
Softwaresysteme voneinander abzugrenzen. Will man eine neue Software modellieren, legt
man in Ameos ein neues System an. Im System kann man dann alle in UML vorhandenen
Diagramme erstellen und bearbeiten, um seine Software zu modellieren.
Um mit Ameos einen Graphen oder ein Schema zu erstellen, öffnet man zuerst ein neues
System, dazu wählt man im Menü File den Befehl New System. Danach erstellt man ein
neues Klassendiagramm, indem man im Menü File den Befehl New Class Diagram
auswählt. In dem Editor, den Ameos daraufhin öffnet, kann man dann seinen Graphen oder
sein Schema erstellen.
Das Templateskript erzeugt immer nur genau einen Graphen. Falls mehr als ein Graph oder
ein Schema im System vorhanden sind, dann wird vom Templateskript trotzdem nur ein
Graph generiert, der dann alle Elemente aller vorhandenen Graphen bzw. Schemata enthält.
Ist ein Graph und ein Schema im System enthalten, erzeugt das Templateskript nur den GXLCode für den Graphen, nicht aber das Schema. Eine zu einem Schema passende GXL-Datei
lässt sich nur generieren, wenn ausschließlich das Schema im System vorhanden ist.
5. Einführung in die Bedienung des Templateskripts
37
5.2. Erstellen von Instanzgraphen
Mit GXL kann man TGraphen, Hypergraphen und hierarchische Graphen repräsentieren.
Bevor man beginnt, mit Ameos einen Graphen zu erstellen, sollte man sich bewusst sein, dass
man damit keine Hypergraphen und hierarchische Graphen darstellen kann. Mit Ameos kann
man nur TGraphen erstellen.
Bevor man mit Ameos Graphen erstellt sollte der Benutzer in der Lage sein mit Ameos
Objekt- und Klassendiagramme erstellen zu können. Die Dokumentation und die Hilfe von
Ameos können bei der Einarbeitung hilfreich sein. Wenn der Benutzer sich mit Ameos
vertraut gemacht hat und in der Lage ist Objektdiagramme zu erstellen, ist es nicht schwierig
auch Graphen mit Ameos zu erstellen.
Jeder Knoten eines Graphen wird durch ein Objekt dargestellt. Wenn man also einen Knoten
erstellen will, dann erzeugt man einfach ein Objekt. Der Objektname entspricht dann dem
Namen des Knotens und der Klassenname entspricht dem Typ des Knotens. Knotenattribute
werden durch Attribute des entsprechenden Objekts dargestellt. D.h. wenn man zu einem
Knoten ein Attribut hinzufügen will, dann fügt man dem Objekt, das diesen Knoten darstellt,
ein passendes Attribut hinzu.
Eine Kante wird dargestellt durch eine Abhängigkeit. Eine Kante in einem TGraphen
verbindet immer zwei Knoten miteinander. In Ameos werden diese Knoten durch Objekte
dargestellt. Die Kante wird dann repräsentiert durch eine Abhängigkeit, die diese beiden
Objekte miteinander in Verbindung setzt. Wenn der Benutzter mit Ameos eine Kante
erstellen will, dann erzeugt er einfach eine Abhängigkeit.
Einer Kante ein Attribut hinzuzufügen geschieht dadurch, dass man ein Objekt erzeugt und
diesem Objekt den selben Namen gibt wie der Abhängigkeit, welche die Kante darstellt. Dem
Objekt werden dann die Attribute hinzugefügt, analog wie wenn man einem Knoten ein
Attribut hinzufügt.
Wenn man Ameos benutzt um Graphen zu erstellen sollte man sich im Klaren sein, dass sich
nicht jeder TGraph mit Ameos erstellen lässt. Aufgrund der Tatsache, dass im Metamodell
von Ameos keine Klasse existiert, die Objektassoziationen repräsentiert, ist es nicht möglich,
ungerichtete Kanten darzustellen. Man kann daher mit Ameos nur Graphen erstellen, die
ausschließlich gerichtete Kanten besitzen. Eine gerichtete Kante wird durch eine
Abhängigkeit (engl. Dependency) dargestellt. Außerdem gibt es keine Möglichkeit die
Kanten anzuordnen, d.h. man kann den Kanten keine Position innerhalb einer Ordnung
zuweisen. Attributierte Kanten lassen sich auch nur über einen Umweg darstellen, weil
Abhängigkeiten keine Attribute besitzen können. Man erstellt daher eine Abhängigkeit und
ein Objekt mit demselben Namen und weist dem Objekt die Attribute zu, welche die Kante
haben soll. Die Graphen, die sich mit einem Objektdiagramm in Ameos darstellen lassen,
sind also Graphen mit attributierten und typisierten Knoten und attributierten, typisierten und
gerichteten Kanten.
Beim Erstellen von attributierten Kanten ist höchste Aufmerksamkeit gefordert. Man muss
stets darauf achten, dass der Name der Abhängigkeit und des Objekts identisch ist. Die
Identität der Namen ist die einzige Verbindung zwischen dem Objekt und der Abhängigkeit.
Sind die Namen nicht identisch, z.B. durch einen Tippfehler, dann besteht keine Verbindung
zwischen den beiden Elementen und das Templateskript generiert nicht mehr eine
attributierte Kante, sondern einen Knoten und eine Kante ohne Attribute. Das Templateskript
ist nur in der Lage, die Gleichheit von Namen festzustellen. Die Ähnlichkeit von Namen, mit
38
5. Einführung in die Bedienung des Templateskripts
der man eventuell in der Lage wäre auf einen Fehler bei der Eingabe der Namen zu schließen,
kann das Templateskript nicht feststellen. Es liegt daher beim Benutzer, immer darauf zu
achten, dass die Namen gleich sind.
Bei der Verwendung von Attributen ist zu bedenken, dass das Templateskript nur die
Domains bool, int, float und string kennt. Alle Werte von Attributen, die nicht eindeutig
einer der drei erstgenannten Domains zugeordnet werden können, werden als string
gehandhabt. Die Verwendung von anderen Domains ist nicht möglich. Dies betrifft sowohl
die Attribute von Knoten als auch die von Kanten.
Die Typisierung von Knoten und Kanten kann auf zwei unterschiedliche Arten geschehen.
Wenn man ein Objekt oder eine Abhängigkeit erstellt und ihr einen Namen gibt, dann kann
man den Namen und den Typ des Knoten bzw. der Kante durch einen Unterstrich (_) oder
durch einen Doppelpunkt trennen. Also entweder Name_Typ oder Name:Typ.
Unterstrich und Doppelpunkt dienen zum Trennen von Name und Typ, sie dürfen daher
weder im Namen noch im Typ vorkommen. Falls man sich für die erste Variante entscheidet,
darf trotzdem kein Doppelpunkt im Namen oder Typ enthalten sein. Umgekehrt darf im
zweiten Fall nirgends ein Unterstrich vorkommen.
Der Unterschied der beiden Fälle ist, dass im zweiten Fall, also wenn mit Doppelpunkt
getrennt wird, das zum Graphen passende Schema im System vorhanden sein muss. Ist das
Schema nicht vorhanden, dann bricht Ameos die Ausführung des Scripts mit der Meldung
"error: Interface-File (Dependency) : cannot find corresponding
supplierId ID "XXX" in semantical interface format" ab, wobei an der
Stelle XXX eine meistens dreistellige Zahl steht. Im ersten Fall, wenn man die Trennung von
Name und Typ mit einem Unterstrich vornimmt, funktioniert das Templateskript ohne
Probleme, selbst wenn das passende Schema nicht im System vorhanden ist.
Das Templateskript erzeugt aber immer nur den GXL-Code für den Instanzgraphen, auch
wenn das passende Schema vorhanden ist. Der Code für ein Schema wird nur dann erzeugt,
wenn es im System keinen Instanzgraphen gibt.
Man hat also die Wahl, ob man sich die Mühe macht, ein zum Graphen passendes Schema zu
erstellen und dann die Trennung von Name und Typ mit Doppelpunkt vorzunehmen oder ob
man nur den Graphen erstellt und dann die Trennung mit Unterstrich vornehmen muss.
Zusammenfassend lässt sich sagen, dass
man mit Ameos nur TGraphen erstellen kann, deren Kanten alle gerichtet und nicht
angeordnet sind
man beim Erstellen von attributierten Kanten genauestens darauf achten muss, dass das
Objekt und die Abhängigkeit exakt den gleichen Namen haben
das Templateskript nur die Domains bool, int, float und string unterstützt
der Name und der Typ von Graphelementen auf zwei Arten getrennt werden kann,
entweder mit
a) einem Doppelpunkt; hierbei muss dann das zum Graphen passende Schema im System
vorhanden sein
oder
b) einem Unterstrich; ein Schema muss hierbei nicht vorhanden sein.
5. Einführung in die Bedienung des Templateskripts
39
5.3. Erstellen von Schemata
Mit GXL kann man nicht nur Graphen repräsentieren, sondern auch die dazu passenden
Schemata. Es lassen sich neben den Schemata von TGraphen auch die Schemata von
Hypergraphen und hierarchischen Graphen darstellen. Weil sich mit Ameos aber nur
TGraphen erstellen lassen, kann das Templateskript auch nur Schemata von TGraphen nach
GXL überführen, nicht aber von Hypergraphen und hierarchischen Graphen.
Das erstellen eines Schemas mit Ameos ist recht einfach. Jeder Knotentyp wird durch eine
Klasse dargestellt. Will man also zu seinem Schema einen neuen Knotentyp hinzufügen, dann
erstellt man einfach eine neue Klasse. Der Klassenname repräsentiert dann den Bezeichner
des Knotentyps. Um festzulegen welche Attribute ein Knoten eines bestimmten Typs hat, fügt
man der Klasse, die diesen Knotentyp darstellt, Attribute mit passendem Bezeichner und
passender Domain hinzu. Wenn bespielsweise in einem Schema eine Klasse proc existiert
und diese ein Attribut file mit der Domain string besitzt, dann wird damit festgelegt, dass
Knoten vom Typ proc ein Attribut mit dem Namen file haben dessen Domain string ist.
Kantentypen werden durch Assoziationen repräsentiert. Um einen Kantentyp zu einem
Schema hinzuzufügen erstellt man eine geeignete Assoziation. Wenn zum Beispiel Knoten
vom Typ proc durch eine Kante vom Typ ref mit Knoten vom Typ var verbunden werden,
dann erzeugt man eine Assoziation, welche die Klassen proc und var miteinander verbindet
und gibt dieser Assoziation den Namen ref.
Wenn die Kanten eines Typs Attribute haben sollen, dann muss man zu der entsprechenden
Assoziation eine assoziierte Klasse hinzufügen. Diese Klasse werden dann die Attribute
hinzugefügt, analog wenn man einem Knotentyp ein Attribut hinzufügt.
Wie bei den Instanzgraphen auch unterstützt das Templateskript bei den Schemata nur die
Domains bool, int, float und string. Falls der Bezeichner für eine Domain unbekannt ist,
verwendet das Templateskript die Domain string.
In einem Schema werden Kantentypen durch Assoziationen dargestellt. Falls eine Assoziation
einen Kantentyp darstellt, der attributiert ist, dann existiert zu der Assoziation eine assoziierte
Klasse. Assoziationen ohne assoziierte Klasse repräsentieren Kantentypen ohne Attribute. Bei
der Überführung eines Schemas in einen Graphen wird für jeden Kantentyp ein Knoten vom
Typ EdgeClass erzeugt. Die Id eines solchen Knotens ergibt sich wie folgt: Existiert eine
assoziierte Klasse, dann wird deren Name verwendet, existiert keine assoziierte Klasse, wird
der Name der Assoziation verwendet. Hat die Assoziation keinen Namen, wird die Id
verwendet, die Ameos der Assoziation, wie jedem Element eines Diagramms, bei dessen
Erzeugung zugewiesen hat.
Die Richtung eines Kantentyps wird mit der "Role Navigability" einer Assoziation modelliert.
Man legt damit fest, ob die Kanten dieses Typs gerichtet oder ungerichtet sind und, falls sie
gerichtet sind, wird auch festgelegt welchen Typ der Start- und Endknoten haben soll. Ändern
kann man die Role Navigability einer Assoziation im Eigenschaftenfenster. Dieses wird
geöffnet, wenn man eine Assoziation selektiert und dann im Menü Edit Properties
auswählt.
Abbildung 35 zeigt das Eigenschaftenfenster für eine Assoziation, welche die beiden Klassen
Function und Variable miteinander verbindet. Die Role Navigability ist nur an einem der
beiden Enden der Assoziation gesetzt, und zwar an dem Ende, das mit der Klasse Variable
verbunden ist. Hiermit wird dargestellt, dass der Kantentyp, den die Assoziation repräsentiert,
gerichtet ist und dass die Startknoten vom Typ Function und die Endknoten vom Typ
40
5. Einführung in die Bedienung des Templateskripts
Abbildung 35: Eigenschaftenfenster
Variable sind.
Wenn die Role Navigability nur an einem Ende einer Assoziation gesetzt ist, wird damit
dargestellt, dass es sich um einen gerichteten Kantentyp handelt. Außerdem wird damit auch
die Richtung selber vorgegeben, und zwar von dem Ende ohne Role Navigalility zu dem
Ende mit Role Navigability. Falls die Role Navigability an beiden Enden der Assoziation
gesetzt ist, dann wird damit ein ungerichteter Kantentyp repräsentiert.
Dass die Role Navigability an beiden Enden nicht gesetzt ist, ist nicht möglich. Die Role
Navigability wird dann von Ameos automatisch an beiden Enden gesetzt. Dies wird leider
nicht sofort sichtbar. Wenn man nämlich im Eigenschaftenfenster bei Role Navigability beide
Haken entfernt und dann auf Apply klickt, passiert in der Anzeige erst einmal nichts. Erst
wenn man das Fenster schließt und wieder neu öffnet, ist sichtbar, dass die Role navigability
an beiden Enden gesetzt wurde.
Zusammenfassend kann man sagen, dass
das Templateskript nur Schemata von TGraphen nach GXL überführen kann
nur die Domains bool, int, float und string unterstützt werden
eine assoziierte Klasse die Id eines EdgeClass-Knoten festlegt
nur, wenn eine Assoziation keine assoziierte Klasse hat, die Id des passenden EdgeClassKnoten von der Assoziation festgelegt wird
die Richtung eines Kantentyps mit der Role Navigability dargestellt wird.
6. Fazit
41
6. Fazit
Das im Rahmen dieser Studienarbeit erstellte Templateskript ist ein einfaches Hilfsmittel, das
es dem Benutzer erlaubt, die Graphen und Schemata, die er mit Ameos erstellt, als GXLDateien zu exportieren.
Die Entwicklung des Templateskripts war zeitweise ein recht steiniger Weg, der mit allerlei
Hindernissen gespickt war. So kann man beispielsweise nicht alle Arten von Graphen, die
man mit GXL darstellen kann, auch mit UML und Ameos darstellen, sondern nur eine
Teilmenge davon. Man kann mit UML nur TGraphen mit gerichteten und nicht angeordneten
Kanten darstellen. Hier kann man in Zukunft sicherlich noch einige Arbeit investieren, um
Lösungen zu finden, damit man weitere Arten von Graphen mit UML darstellen und mit
Ameos erstellen kann und dann das Templateskript so zu ergänzen, dass auch die GXLDateien für diese Graphen erzeugt werden können. Außerdem unterstützt das Templateskript
zur Zeit auch nur einfache Domains. Die Erweiterung zur Unterstützung komplexer Domains
ist eine weitere Aufgabe für zukünftige Arbeiten.
Ein weiteres Hindernis auf dem Weg war der Umgang mit TDL. Diese Sprache unterscheidet
sich in vielen Punkte von bekannten und vertrauten Programmier- und Scriptsprachen. Die
Einarbeitung in die Sprache gestaltete sich daher recht langwierig und auch die Arbeit mit der
Sprache während der Implementation lief nicht immer reibungslos.
Der erste ungewohnte Punkt waren die Templates, also die Funktionen deren Rumpf einfach
ausgegeben wird. Die Tatsache, dass alles einfach so ausgegeben wird, war hier das
Ungewohnte. Von anderen Programmiersprachen ist man gewöhnt, dass es zum Ausgeben
von Text eine Funktion gibt, so wie zum Beispiel die Funktion printf in C++ oder out in den
Prozeduren von TDL. Auch ungewohnt war, dass man in einem Template den Wert von
Variablen nicht ändern konnte, sondern dies nur in Prozeduren möglich war.
Den Namen von Variablen immer in eckige Klammern zu schreiben, benötigte ebenfalls eine
Eingewöhnungsphase. Ein Dollarzeichen ($) vor dem eigentlichen Variablennamen, so wie es
beispielsweise in Perl und PHP gehandhabt wird, hätte diese Phase sicherlich deutlich
verkürzen können.
Ein weiteres Manko von TDL sind die Schleifen. Das loop-Statement war ebenfalls
ungewohnt und sehr gewöhnungsbedürftig. Man muss aber fairerweise sagen, dass es in
anderen Programmiersprachen kein solches Metamodell wie in Ameos gibt, auf das man mit
seinem Programm zugreift und TDL deshalb eine Möglichkeit braucht, um Zugriffe auf das
Modell zu ermöglichen. Daher ist das loop-Statement eine annehmbare, aber gewöhnungsbedürftige Lösung. Hier gibt es noch Möglichkeiten TDL zu verbessern, indem eine weniger
ungewohnte Lösung für die Schleifenkonstruktion gefunden wird.
Wenn Programmierer von Schleifen reden, denken sie oft an while- oder for-Schleifen. Diese
fehlen in TDL aber und erfordern daher von einem TDL-Einsteiger eine Änderung seines
gewohnten Verhaltens und Programmierstils. Das Erlernen von und die Arbeit mit TDL wäre
sicherlich einfacher, wenn es eine while- und eine for-Schleife in der Sprache gäbe.
Eine weitere Hürde, die bei der Entwicklung des Templateskripts genommen werden musste,
war es herauszufinden, wie Scriptparameter definiert werden. Diese Parameter werden auch
externe Variablen genannt und in der Dokumentation steht nur: "these variables reside as a
specially formatted comment in the file main.tdl"[ACD2]. Das bedeutet, dass die Variablen in
einem speziell formatierten Kommentar in der Datei main.tdl stehen. Eine Beschreibung
42
6. Fazit
dieser speziellen Formatierung fehlt allerdings in der Dokumentation. Das entwickelte
Templateskript verwendet trotzdem Scriptparameter, weil es möglich war, aus der Definition
der Parameter in den Templateskripts, die bei Ameos schon vorhanden sind, auf die
Formatierung zu schließen und dann selber zu benutzen.
Auch wenn es einfach war, die Formatierung aus den vorhandenen Templateskripts
herzuleiten, sollte diese dennoch in der Dokumentation erklärt werden. Generell ist die
Dokumentation von Ameos verbesserungsfähig. Besonders der Teil, der die Sprache TDL
[ACD1] erklärt, hat so seine Mankos. Sie enthält zwar eine umfangreiche Beschreibung, wie
man Templateskripts mit TDL entwickelt, was aber fehlt, ist wie die Sprache selber
funktioniert und warum sie so ist wie sie ist. Diese fehlenden Punkte würden zum besseren
Verständnis der Sprache beitragen und damit die Entwicklung von Templateskripts
vereinfachen.
Zusammenfassend kann man sagen, dass es in jeder Hinsicht noch viele Entwicklungsmöglichkeiten gibt. Einerseits lässt sich Ameos und TDL, sowie die zugehörige
Dokumentation, noch verbessern. Andererseits kann sicherlich auch das Templateskript noch
verbessert werden.
Zum Schluss bleibt noch zu sagen, dass trotz der vielen Hindernisse und Probleme die Arbeit
an der Entwicklung und Implementierung des Templateskripts eine lehrreiche Erfahrung war,
die es auf jeden Fall Wert war, diese Studienarbeit zu schreiben.
Literaturverzeichnis
43
Literaturverzeichnis
[AAD]
Aonix: Ameos Dokumentation, Unterverzeichnis documentation im Installationsverzeichnis von Ameos
[ACD1] Aonix: ACD Programming Guide, 2004
[ACD2] Aonix: Using ACD Templates, 2004
[EKM01] J. Ebert, K.Kontogiannis, J. Mylopoulos: Interoperability of Reverse Engineering
Tools. http://www.dagstuhl.de/DATA/Reports/01041/, 2001
[GXL] GXL Hompepage. http://www.gupro.de/GXL/
Herunterladen