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/