Wissenserwerb für ressourcenorientiertes Konfigurieren

Transcrição

Wissenserwerb für ressourcenorientiertes Konfigurieren
Humboldt-Universität zu Berlin
Institut für Informatik
Unter den Linden 6
10099 Berlin
Diplomarbeit
Wissenserwerb für ressourcenorientiertes
Konfigurieren
vorgelegt von: Andreas Kuntzagk
Betreuer:
Prof. Dr. Joachim Fischer
Martin von Löwis of Menar
Berlin, 13. März 2001
Inhaltsverzeichnis
Einleitung
Inhalt der Arbeit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1
1
1 Modellieren und Konfigurieren modularer technischer Systeme
1.1 Einführung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1.2 Strukturorientiertes Konfigurieren . . . . . . . . . . . . . . . . . . . . .
1.3 Ressourcenorientiertes Modellieren / Konfigurieren . . . . . . . . . . .
2
2
4
7
2 Das Konfigurationssystem des SCO-Projektes
2.1 Konfigurationsaufgabe . . . . . . . . . . . . . . . . . . .
2.2 Das zugrunde liegende Metamodell . . . . . . . . . . . .
2.3 Aufbau des Konfigurationssystems . . . . . . . . . . . .
2.4 Die Komponentenbeschreibungssprache . . . . . . . . .
2.5 Bisheriges Modellierungsverfahren . . . . . . . . . . . .
2.6 Darstellung des Komponentenkatalogs als HTML-Seite
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
14
14
16
19
19
22
22
3 Das Werkzeug zum Wissenserwerb
3.1 Alternative Komponentenkataloge . . . . . . . . . . . .
3.2 Techniken für Benutzerschnittstellen . . . . . . . . . .
3.3 Aufbau des Werkzeuges . . . . . . . . . . . . . . . . . .
3.4 Implementierung des Katalogzugriffs . . . . . . . . . .
3.5 Implementierung der grafischen Benutzerschnittstelle
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
24
24
34
37
38
45
4 Ausblick
57
A Benutzerhandbuch des Wissenserwerb-Werkzeuges
A.1 Das Hauptfenster . . . . . . . . . . . . . . . . . .
A.2 Das Fenster zum Ändern von Komponenten . . .
A.3 Die Liste der Ressourcen . . . . . . . . . . . . . .
A.4 Ändern von Ressourcen . . . . . . . . . . . . . . .
60
60
62
64
65
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
B Ausgewählte Dateien
66
B.1 Dateien aus dem Projekt Service Composition . . . . . . . . . . . . . . 66
B.2 Mögliche XML-Darstellung des Komponentenkatalogs (Ausschnitt) . . 76
Abkürzungsverzeichnis
78
Literaturverzeichnis
79
i
Abbildungsverzeichnis
1.1
1.2
1.3
1.4
1.5
1.6
1.7
1.8
Eine Zerlegungshierarchie (Ausschnitt nach [CGS91]) . . . . . . . . . . 5
Ausschnitt aus einer Spezialisierungshierarchie . . . . . . . . . . . . . 6
Einschränkung von Eigenschaften durch Spezialisierung . . . . . . . . 6
Komponentenkatalog nach dem Ressourcenmodell . . . . . . . . . . . . 8
Konfigurationsaufgabe beim ressourcenorientierten Ansatz . . . . . . 8
Lösung der Aufgabe von Abbildung 1.5 . . . . . . . . . . . . . . . . . . . 9
Beispiel für auseinanderlaufende Ressourcenforderungen nach [BR96] 11
Änderung der Konfiguration aus Abbildung 1.7 unter Verwendung
zusammengesetzter Ressourcen . . . . . . . . . . . . . . . . . . . . . . . 12
2.1 Komponenten eines TINA-Systems (Ausschnitt) nach [AFG+ 98] . . . . 15
2.2 Das Ressourcenmodell in SCO . . . . . . . . . . . . . . . . . . . . . . . . 16
2.3 Konfigurationssystem und WWW-Darstellung . . . . . . . . . . . . . . 23
3.1
3.2
3.3
3.4
3.5
3.6
3.7
.
.
.
.
.
.
.
37
38
48
48
48
48
52
Das Hauptfenster des Werkzeuges mit einer selektierten Komponente
Das Katalog-Menü . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Einblenden der Ressourcen . . . . . . . . . . . . . . . . . . . . . . . . .
Anlegen einer neuen Komponente . . . . . . . . . . . . . . . . . . . . .
Kopieren einer Komponente . . . . . . . . . . . . . . . . . . . . . . . . .
In diesem Fenster werden die Eigenschaften von Komponenten verändert . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
A.7 Parameter einer Ressource . . . . . . . . . . . . . . . . . . . . . . . . . .
A.8 Liste der Ressourcen . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
A.9 Fenster zum Ändern der Eigenschaften einer Ressource . . . . . . . . .
60
61
61
61
62
A.1
A.2
A.3
A.4
A.5
A.6
ii
Die Katalog-Schnittstelle . . . . . . . . . . . .
Integration eines CORBA-basierten Katalogs
Konstruiertes Fenster . . . . . . . . . . . . .
Widget-Palette von Glade . . . . . . . . . . .
Widget-Baum . . . . . . . . . . . . . . . . . .
Widget-Eigenschaften . . . . . . . . . . . . . .
Beispiel von CheckListWindow . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
63
63
64
65
Einleitung
Im Rahmen eines Forschungsprojektes (S ERVICE C OMPOSITION – SCO) wurde von
der GMD F ORSCHUNGSZENTRUM I NFORMATIONSTECHNIK G MB H und der H UM BOLDT -U NIVERSITÄT ZU B ERLIN ein Expertensystem für die Konfiguration von
modularen technischen Systemen entwickelt [vLSN99]. Dieses Konfigurationssystem arbeitet nach einem Verfahren, das ressourcenorientiertes Konfigurieren genannt wird [Hei93]. Geplantes Anwendungsgebiet ist der Entwurf von Telekommunikations- und Multimediadiensten, die auf einer Architektur für offene verteilte
Systeme basieren. Die Erfassung des Wissens, mit dem das Expertensystem arbeitet, erfolgte durch das Erstellen von Quelltexten der Programmiersprache Python.
Während diese Vorgehensweise in einem Forschungsprojekt ausreichend ist, erfordert die praktische Arbeit mit dem Konfigurationssystem Werkzeugunterstützung
bei der Wissenseingabe.
Ziel der vorliegenden Arbeit ist die Entwicklung eines Werkzeuges zur Wissenserfassung für das Konfigurationssystem. Dieses soll die Erfassung des Wissens
gegenüber der bisherigen Vorgehensweise vereinfachen und – in Grenzen – auch
unerfahrenen Nutzern möglich machen. Die Funktion des Konfigurationssystems
soll durch das zu erstellende Werkzeug nicht beschränkt werden.
Inhalt der Arbeit
Zu Beginn der Arbeit wird eine kurze Einführung in die Modellierung und Konfigurierung technischer Systeme gegeben. Dabei werden verschiedene Begriffe aus
diesem Bereich erläutert. Danach werden die beiden wichtigsten Ansätze bei der
Entwicklung von Konfigurationssystemen näher betrachtet. Im zweiten Teil wird
das Konfigurationssystem des Forschungsprojektes S ERVICE C OMPOSITION erläutert. Dabei wird auf das Anwendungsgebiet des Konfigurationssystems eingegangen sowie auf das Metamodell, nach dem das Wissen modelliert wird und auf den
Aufbau des Systems. Im dritten und letzten Teil steht das Werkzeug für den Wissenserwerb im Vordergrund. Dabei werden die Entscheidungen bezüglich des Speicherformats für das Wissen und der Benutzerschnittstelle erklärt. Danach wird die
Implementierung des Werkzeuges beschrieben. Im Anhang befindet sich ein kurzes
Nutzerhandbuch für das Werkzeug sowie einige Dateien, die für das Verständnis
dieser Arbeit nützlich sein können.
1
1 Modellieren und Konfigurieren modularer technischer
Systeme
1.1
Einführung
Beim Entwurf von komplexen technischen Systemen, wie z. B. von Telekommunikations- und Softwaresystemen, Fahrzeugen oder automatische Fabrikationsanlagen
werden die Entwürfe oft durch Zusammensetzen vorhandenener Teilentwürfe erzeugt. In der Regel entsprechen diese Teilentwürfe separat produzierbaren Teilen,
die sich dann zum fertigen System zusammensetzen lassen.
Dadurch soll erreicht werden, daß der Zeit- und Geldaufwand für den Entwurf
sinkt. Außerdem ist ein flexibles Eingehen auf Kundenwünsche möglich, ohne den
Vorteil der Serienproduktion zu verlieren [Büt97].
Dieser Vorgang des Zusammensetzens1 wird im allgemeinen als Konfigurieren bezeichnet. So schreibt Michael Heinrich [Hei93]:
„Konfigurieren ist das Entwerfen eines technischen Systems durch
Auswählen, Parametrieren und Zusammenfügen von Exemplaren geeigneter Komponententypen eines vorgegebenen Komponentenkatalogs.“
Mit Komponenten bezeichnet Heinrich die Teile, die zusammengesetzt werden.2
Komponenten gleicher Art werden durch einen Komponententyp3 beschrieben.
Für die Gesamtheit aller erfaßten Komponententypen wird der Begriff Komponentenkatalog verwendet [Hei89]. Das Ergebnis des Konfigurierens, also solch
eine Zusammenstellung von Komponenten, wird als Konfiguration bezeichnet.
Das „Lexikon Informatik und Datenverarbeitung“ [Sch97] beschreibt Konfiguration als:
„[. . . ] eine bestimmte Zusammenstellung datenverarbeitender Peripheriegeräte zur Erfüllung meist unterschiedlicher Funktionen der Datenverarbeitung [. . . ]“
In dieser Arbeit wird der Begriff der Konfiguration ebenso wie der des Konfigurierens nicht auf das Anwendungsgebiet der Datenverarbeitung beschränkt, sondern
1
Mit Begriffen wie Zusammensetzen und Teile usw. ist immer das Zusammensetzen eines Entwurfs
bzw. Teile eines Entwurfs gemeint, da nur der Entwurfsprozeß und nicht der Vorgang des Zusammensetzens des tatsächlichen Systems im Blickpunkt dieser Arbeit steht.
2
Büttner [Büt97] bezeichnet die Komponenten mit dem Begriff „Bausteine“ und ihre Gesamtheit als
„Baukasten“. Hier wird der Bezeichnung Komponente der Vorzug gegeben.
3
In dieser Arbeit wird der Kürze wegen oft „Komponente“ an Stelle von „Komponententyp“ verwendet. Dabei gilt folgende Konvention: bei der Modellierung handelt es sich immer um Komponententypen, die beschrieben werden, bei der Konfigurierung um Exemplare dieser Typen – also
Komponenten.
2
1.1
Einführung
im allgemeineren Sinne für alle zusammengesetzten technische Systeme verwendet.4
Klaus Büttner beschreibt das Konfigurieren als einen Spezialfall des Konstruierens. Beides beschäftigt sich mit dem Entwurf eines neuen Produktes ausgehend
von Anforderungen. Der Unterschied liegt darin, daß beim Konfigurieren nur aus
einer Menge von „weitestgehend vorgegebenen“ Bausteinen ausgewählt wird. Dadurch ist der Ablauf beim Konfigurieren gegenüber dem beim Konstruieren wesentlich vereinfacht [Büt97].
Die theoretischen Grundlagen des Konfigurierens sind ein Schwerpunkt der
Forschung auf dem Gebiet der Künstlichen Intelligenz. Hier sei auf die Berichte
zu dem jährlich stattfindenden Workshop „Planen und Konfigurieren“ verwiesen
[HTH89], [Hor93]. Schwerpunkte dabei sind die Beschreibung der Komponenten
und ihre Beziehungen in Modellen sowie der Entwurf von Konfigurationssystemen
zur Unterstützung bei der Konfigurierung. Ein Konfigurationssystem ist laut
„Lexikon Informatik und Datenverarbeitung“ [Sch97]:
„[. . . ] ein Expertensystem, dessen Anwendungsbereich in der Konfiguration eines komplexen Objektes, z. B. eines Motors oder einer anderen
Maschine besteht. Die Schwierigkeit besteht darin, daß nicht aus einer
vorgegebenen Menge ein Element ausgewählt wird, sondern ein neues
Objekt synthetisiert werden muß.“
Grund für den Entwurf solcher Konfigurationssysteme ist dabei die hohe Zahl von
Freiheitsgraden beim Entwurf der Systeme, die ein Konfigurieren von Hand nur
schwer erlauben und fehlerträchtig machen [Büt97]. Büttner [Büt97] unterscheidet
zwischen interaktiven und automatischen Systemen. Bei interaktiven Systemen
wählt der menschliche Konstrukteur aus den Bausteinen aus, die ihm vom System
vorgeschlagen werden und fügt sie der Teilkonfiguration hinzu. Die Aufgabe des
Konfigurationssystems liegt dann darin, nur Komponenten anzubieten, deren Hinzufügen keine Konflikte mit bestehenden Komponenten erzeugt und zum Lösen der
Konfigurationsaufgabe nützlich sein kann. Nach Heinrich [Hei89] sollen interaktive Systeme auch den Konfigurationsverlauf (vor allem den Grund des Verwerfens
bestimmter Komponenten) erklären.
Automatische Systeme hingegen erarbeiten aus den Anforderungen an das System selbstständig Konfigurationen, die diese erfüllen. Der Anwender hat nur die
Möglichkeit, die gefundenen Lösungen nachzubearbeiten. Dazu ist die Dokumentation der Konfigurationsentscheidungen wesentliche Voraussetzung.
Die einem Konfigurationssystem bekannten Komponenten und ihre Eigenschaften sind durch ein Modell des Anwendungsgebietes beschrieben. Das „Lexikon Informatik und Datenverarbeitung“ [Sch97] definiert den Begriff Modell als:
Idealisierte, vereinfachte, in gewisser Hinsicht ähnliche Darstellung
eines Gegenstandes, Systems oder sonstigen Weltausschnitts, mit dem
4
Das Zusammensetzen chemischer Strukturen, das auch als Konfigurieren bezeichnet wird, liegt
außerhalb der Betrachtung, da es sich, wie Dörner [Dör47] ausführt, deutlich vom Konfigurieren
technischer Systeme unterscheidet.
3
1
Modellieren und Konfigurieren modularer technischer Systeme
Ziel, daran bestimmte Eigenschaften des Vorbilds besser studieren zu
können.
Die Wahl des richtigen Modelltyps (Metamodells) ist dabei wichtig, um zu erreichen, daß das Modell dem Vorbild in genau den Eigenschaften ähnelt, die studiert
werden sollen. Beim Konfigurieren ist der zu betrachtende Weltausschnitt der Anwendungsbereich des Konfigurationssystems. Die zu studierenden Eigenschaften
sind dann die Komponenten, ihre Eigenschaften und ihre Beziehungen.5 Der Komponentenkatalog ist Bestandteil des Modells. Dieses kann aber darüber hinaus
noch andere Informationen, wie z. B. Randbedingungen, enthalten.
Zwei Arten von Metamodellen kommen beim Konfigurieren hauptsächlich zur
Anwendung: der ressourcenorientierte Ansatz (siehe Abschnitt 1.3) und der strukturorientierte Ansatz (Abschnitt 1.2) [Hei93], [AW95].
Beide Ansätze haben, wie im folgenden gezeigt wird, ihre Vor- und Nachteile,
wobei einige Autoren auch eine Verbindung der Ansätze vorschlagen [AW95].
1.2
Strukturorientiertes Konfigurieren
Der strukturorientierte Ansatz ist mit einer Vielzahl von Veröffentlichungen (z. B.
in [HTH89], [Hor93]) und existierenden Konfigurationssystemen [CGS91], [Büt97],
[GKK99], [KG91] am weitesten verbreitet.
Beim strukturorientierten Konfigurieren steht – der Name sagt es bereits –
die Struktur der Komponenten im Vordergrund.6 Diese Struktur der Komponenten wird durch die Has-Parts- („besteht aus“) oder Part-of- („Teil von“) Eigenschaft
der Komponententypen beschrieben. Dadurch wird eine Zerlegungshierarchie
wie in Abbildung 1.1 erzeugt.
Neben der Zerlegungshierarchie werden die Komponententypen in der Regel
auch in eine Spezialisierungshierarchie (taxonomische Hierarchie) eingeordnet.
In den allgemeineren Komponententypen sind die gemeinsamen Eigenschaften ihrer Spezialisierungen zusammengefaßt, wie Bild 1.2 verdeutlicht.
Diese Hierarchie hat üblicherweise eine Baumform, d. h. ein Komponententyp
kann nicht gleichzeitig Spezialisierung mehrerer anderer sein (keine Mehrfachvererbung). Um diese Eigenschaft ausdrücken zu können, werden Sichten auf die Objekte eingeführt [CGS91]. Innerhalb jeder Sicht kann dann eine eigene Spezialisierungshierarchie bestehen.
Jeder Komponententyp hat über die Einordnung in die Hierarchien hinaus noch
weitere Eigenschaften. Diese können mit beliebigen Wertebereichen versehen sein.
Für Spezialisierungen kann dann der Wertebereich weiter eingeengt werden (Abbildung 1.3).
5
In der KI-Forschung werden die Modelle meist als Wissensbasis oder Wissen bezeichnet. Die Art
des Modells wird dann Wissensrepräsentation genannt. In dieser Arbeit wird der Begriff des Modells verwendet, da er besser verdeutlicht, daß es sich um eine vereinfachte Wiedergabe der Realität
handelt.
6
Eine andere gebräuchliche Bezeichnung ist die des Constraints-basierten Konfigurierens. Der Be-
4
1.2
Strukturorientiertes Konfigurieren
Auto
Fahrgestell
Achse
Rad
Felge
Motor
Turbolader
Karosserie
Zylinder
Tür
Reifen
Abbildung 1.1: Eine Zerlegungshierarchie (Ausschnitt nach [CGS91])
Die Abhängigkeiten zwischen den Komponenten werden durch Beschränkungen, sogenannte Constraints, dargestellt. Sie beschreiben Randbedingungen der
Beziehungen zwischen den Komponenten. Constraints dienen sowohl zur Ermittlung oder Einengung von noch unbekannten Eigenschaften von Komponenten als
auch zur Validierung einer (Teil-) Konfiguration. Werden Constraints miteinander
verknüpft, die gemeinsame Variablen haben, so ergibt sich ein Netz. Wird eine Eigenschaft, die im Constraints-Netz vorkommt, mit einem Wert belegt, so ergibt sich
durch Anwendung des Netzes u. U. eine Vielzahl von Einschränkungen des Wertebereichs anderer Eigenschaften.
Ausgangspunkt des Konfigurationsvorganges (die Konfigurationsaufgabe) ist
die Vorgabe von Komponenten, für die einige Eigenschaften festgelegt und andere noch variabel sind. Dadurch wird eine abstrakte Konfiguration vorgegeben, die
die zu lösende Aufgabe erfüllt. Im Verlauf des Konfigurationsverfahrens wird diese
allgemeine Konfiguration konkretisiert. Ziel ist eine Konfiguration, in der Eigenschaften und Zusammensetzung aller Komponenten bekannt sind und alle Constraints erfüllt werden.7 Das wird durch wiederholtes Anwenden der Aktionen
• Zerlegen einer Komponente in ihre Teile,
• Spezialisieren einer Komponente und damit einhergehend Einschränken von
Eigenschaften,
7
griff der Constraints wird später erläutert.
Neben den hier betrachteten sogenannten harten Constraints, die für eine korrekte Konfiguration
erfüllt sein müssen, gibt es noch weiche Constraints, durch die optimale Konfigurationen bestimmt
werden. Durch Lockern dieser Constraints können eventuelle Konflikte gelöst werden [CGS91].
5
1
Modellieren und Konfigurieren modularer technischer Systeme
Konstruktionsobjekt
Autoteil
Auto
PKW
Motor
Fahrwerkteil
Achse
Reifen
Rad
Abbildung 1.2: Ausschnitt aus einer Spezialisierungshierarchie
Auto
+Höchstgeschwindigkeit: [0 km/h - 300 km/h]
+Farbe: {rot gruen blau schwarz}
+Hersteller: Autofirma
Porsche
+Höchstgeschwindigkeit: [200km/h -300km/h]
+Farbe: {rot schwarz}
+Hersteller: = Porsche AG
LKW
+Höchstgeschwindigkeit: [0km/h - 120km/h]
+Hersteller: Lkw-Firma
Abbildung 1.3: Einschränkung von Eigenschaften durch Spezialisierung
• Integrieren von Teilkomponenten zu Zusammensetzungen sowie
• Festlegen von noch unbestimmten Eigenschaften.
erreicht [CGS91]. Sind bei einer erreichten Konfiguration nicht alle Constraints erfüllt, so wird der letzte Schritt rückgängig gemacht und als ungültig gekennzeichnet (Backtracking).8
Die Auswahl des jeweils nächsten Schrittes kann durch verschiedene Verfahren getroffen werden. Möglich sind die Anfrage beim Benutzer, der Vergleich mit
„ähnlichen“ Fällen (fallbasiertes Schließen), das Auswerten von externen Simulationsergebnissen oder das Anwenden der Constraints zur Einengung von Werten
[CGS91], [Pfi93]. Die Strategien dafür sind bestimmend für die Qualität eines Konfigurationssystems. Sie werden unter dem Begriff Kontrollwissen zusammengefaßt.
8
6
In den einzelnen Konfigurationssystemen können darüber hinaus noch andere Verfahren zur Auflösung solcher Konflikte angewendet werden.
1.3
Ressourcenorientiertes Modellieren / Konfigurieren
Für Systeme, in denen die Strukturbeziehungen von Komponenten zum Modellierungszeitpunkt nicht festlegbar sind, ist dieses Verfahren ungeeignet. Ein weiterer Nachteil ist, daß die Eigenschaften der Komponententypen zum Teil von diesen
getrennt in Constraints beschrieben werden. Außerdem ist beim Hinzufügen eines neuen Komponententyps dessen Verträglichkeit mit allen bisher erfaßten zu
überprüfen und durch Constraints zu beschreiben. Das Erfassen und Warten des
Kontrollwissens ist komplex und nur durch Experten möglich.
1.3
1.3.1
Ressourcenorientiertes Modellieren / Konfigurieren
Das einfache Ressourcenmodell
In den Beiträgen zum 3. Workshop „Planen und Konfigurieren“ beschreibt Michael
Heinrich [Hei89] das ressourcenorientierte Konfigurieren. Diesem Konfigurationsverfahren liegt als Metamodell das Ressourcenmodell zugrunde. Wichtigstes Konzept des Ressourcenmodells ist das der Ressource. Ressourcen sind quantitative und qualitative Eigenschaften von Komponenten, aus denen sich die Beziehungen zu anderen Komponenten ergeben [vLSN99], [Hei89]. Jede Komponente stellt
Ressourcen bereit und verbraucht/erfordert Ressourcen. Die Beziehungen zwischen den Komponenten werden allein dadurch ausgedrückt, daß eine Komponente
eine Ressource (Eigenschaft) benötigt, die eine andere bereitstellt [Hei89].
Beim „Benötigen“ einer Ressource durch eine Komponente unterscheidet Heinrich [Hei89] zwischen dem verbrauchen – d. h. diese Ressource steht danach nicht
mehr zur Verfügung und dem erforderlich sein – d. h. mehrere Komponenten
können sich die Ressource teilen. Ressourcen, die verbraucht werden, werden auch
exklusive Ressourcen genannt.
Auch für das ressourcenorientierte Konfigurieren schlägt Heinrich vor, die Komponenten in eine Spezialisierungshierarchie einzuordnen.
Im Gegensatz zur Spezialisierung beim strukturorientierten Ansatz, wo Komponenten abstrakter Typen in Teilkonfigurationen auftreten können und dann später
zu konkreten Komponenten spezialisiert werden, werden beim ressourcenorientierten Ansatz nur die nicht abstrakten Komponenten verwendet.
Beim ressourcenorientierten Konfigurieren werden nach [Hei89] die Anforderungen an das System durch benötigte Ressourcen der Umgebung dargestellt. Vorhandene Voraussetzungen werden dementsprechend durch bereitgestellte Ressourcen abgebildet. Im Verlauf des Konfigurierens werden Komponenten aus dem Katalog hinzugefügt, bis eine korrekte Konfiguration erreicht wird – d. h. alle von
einer Komponente benötigten Ressourcen werden von einer anderen Komponente bereitgestellt und exklusive Ressourcen werden in ausreichender Zahl bereitgestellt. Tritt im Laufe des Konfigurierens die Situation ein, daß eine Ressource gefordert wird, die von keiner Komponente bereitgestellt wird, so sind ein oder mehrere
Auswahl-Entscheidungen rückgängig zu machen (Backtracking).
Das Hinzufügen einer weiteren Komponente gliedert Heinrich in drei Schritte:
1. Auswahl der nächsten nicht befriedigten Ressource der Teilkonfiguration,
7
1
Modellieren und Konfigurieren modularer technischer Systeme
2. Auswahl des bestbewerteten Komponententyps, der diese Ressource bereitstellt und Hinzufügen eines Exemplars dieses Typs zur Konfiguration sowie
3. Abgleich der benötigten und bereitgestellten Ressourcen der neuen Komponente mit dem Rest der Konfiguration [Hei93].
Die Algorithmen zur Auswahl der nächsten Ressource und zur Bewertung der Komponenten sind wieder Bestandteil des Kontrollwissens. Dieses wird oft durch das
Anwendungsgebiet des Konfigurationssystems bestimmt [Hül98] [DKBS96].
Stromversorgung
PC
Internetbenutzung
Modem
Netzwerkverbindung
Ethernetverbindung
Ethernetkarte
Netzwerkverbindung
Stromversorgung
Telefonanschluß
Telefonverbindung
Netzwerkverbindung
Stromversorgung
Telefonverbindung
Modem
Telefonverbindung
Abbildung 1.4: Komponentenkatalog nach dem Ressourcenmodell
Abbildung 1.4 zeigt einen einfachen Komponentenkatalog nach dem Ressourcenmodell, die Abbildungen 1.5 und 1.6 eine Konfigurationsaufgabe und deren
schrittweise Lösung mit diesem Katalog. Die Konfigurationsaufgabe besteht in diesem Beispiel darin, daß ein System entworfen werden soll, daß eine Internetbenutzung ermöglicht. Als Voraussetzung ist nur eine Stromversorgung gegeben.
Internetbenutzung
Systemumgebung
Stromversorgung
Abbildung 1.5: Konfigurationsaufgabe beim ressourcenorientierten Ansatz
8
1.3
Ressourcenorientiertes Modellieren / Konfigurieren
1. Konfigurierungschritt
Systemumgebung
Internetbenutzung
Stromversorgung
PC
Netzwerkverbindung
2. Konfigurierungschritt
Systemumgebung
Internetbenutzung
Stromversorgung
Telefonverbindung
PC
Netzwerkverbindung
Modem
3. Konfigurierungschritt
Systemumgebung
Internetbenutzung
Stromversorgung
Telefonanschluß
PC
Telefonverbindung
Netzwerkverbindung
Modem
Abbildung 1.6: Lösung der Aufgabe von Abbildung 1.5
9
1
Modellieren und Konfigurieren modularer technischer Systeme
• Im ersten Schritt wird eine Komponente gesucht, die die geforderte Ressource „Internetbenutzung“ bereitstellt. Dies ist die Komponente „PC“. Die von
„PC“ geforderte Ressource „Stromversorgung“ wird durch die Systemumgebung bereitgestellt. Die Forderung nach „Netzwerkverbindung“ kann momentan nicht befriedigt werden.
• Um „Netzwerkverbindung“ bereitzustellen, wird die Komponente „Modem“
hinzugefügt.9 Die Forderung nach „Stromversorgung“ wird wieder durch die
Umgebung befriedigt, wohingegen „Telefonverbindung“ als offene Forderung
übrigbleibt.
• Im letzten Schritt wird nach dem Hinzufügen von „Telefonanschluß“ eine korrekte Konfiguration erreicht. Es bestehen keine offenen Ressourcenforderungen mehr.
Während des Konfigurierens werden die von einer Komponente benötigten Ressourcen mit den bereitgestellten Ressourcen der Komponententypen im Katalog
verglichen. In dieser einfachen Ausprägung des Modells stimmen Forderung und
Bereitstellung überein – die bereitgestellte Ressource befriedigt die Forderung –
wenn geforderte und bereitgestellte Ressource von gleicher Art sind. Für die im
folgenden eingeführten Erweiterungen werden unter Umständen neue Vergleichsoperationen nötig.
Im Verlauf des Konfigurierens werden die benötigten Ressourcen jeder Komponente mit Ressourcen, die diesen Bedarf befriedigen, verbunden. Werden diese
Ressourcen verbraucht und nicht nur benötigt, so ist die Bereitstellung dieser Ressource bei der bereitstellenden Komponente entsprechend zu reduzieren. Den Abgleich (das Verbinden) von Forderungen und Bereitstellungen für eine Teilkonfiguration wird Bilanzierung genannt. Auch die Bilanzierung ist bei Erweiterungen
des Ressourcenbegriffs eventuell anzupassen.
1.3.2
Erweiterung des Modells
Strukturbeziehungen im Ressourcenmodell Auch Strukturbeziehungen zwischen
Komponenten („ist Teil von“) lassen sich durch Ressourcen ausdrücken. Dabei werden von den zusammengesetzten Komponenten besondere Ressourcen bereitgestellt, die nur von ihren Teilen verbraucht werden [Hei93]. Es läßt sich allerdings
so nicht ausdrücken, daß die Komponente, die eine Ressourcenforderung befriedigt,
Teil der gleichen Komponente sein muß wie die fordernde Komponente. Dadurch
entsteht, was Börding und Rahmer [BR96] „auseinanderlaufenden Ressourcenforderungen“ nennen. Ein Beispiel für das Problem findet sich in Abbildung 1.7. In
dieser Abbildung fehlt die Systemkomponente. Sie setzt sich aus den Komponenten
9
„Netzwerkverbindung“ wird auch von der Komponente „Ethernetkarte“ bereitgestellt. Wäre diese
anstelle von „Modem“ hinzugefügt worden, so hätte sich eine Sackgasse in der Konfigurierung ergeben, da sie die Ressource „Ethernetverbindung“ fordert, die keine der Komponenten des Katalogs
bereitstellen.
10
1.3
Ressourcenorientiertes Modellieren / Konfigurieren
Bereich Arbeitsplatz 1
Arbeitsplatz
Fernsprechen
Telefonbenutzung
Telefonkomponente
Zugang
Telefonnetz
Anschluß 1
Takt
Gebührenanzeige
Arbeitsplatz
Fernsprechen mit
Gebührenkontrolle
Telefonbenutzung
Gebührenanzeigekomponente
Telefonkomponente
Bereich Arbeitsplatz 2
Zugang
Telefonnetz
Anschluß 2
Takt
Abbildung 1.7: Beispiel für auseinanderlaufende Ressourcenforderungen nach
[BR96]
„Arbeitsplatz Fernsprechen“, „Arbeitsplatz Fernsprechen mit Gebührenkontrolle“,
„Anschluß 1“ und „Anschluß 2“ zusammen.10
Börding und Rahmer schlagen vor, dieses Problem durch zusammengesetzte
Ressourcen zu lösen. Eine zusammengesetzte Ressource ist entweder eine Menge aus anderen zusammengesetzten Ressourcen oder eine atomare Ressource11 .
Der Bedarf nach einer zusammengesetzten (nicht atomaren) Ressource wird durch
eine bereitgestellte befriedigt, wenn die Teilressourcen der geforderten Ressource
wiederum durch Teilressourcen der bereitgestellten Ressource befriedigt werden.
Bei atomaren Ressourcen wird davon ausgegangen, daß eine Vergleichsfunktion
für diese existiert [BR96].
Abbildung 1.8 verdeutlicht die Probleme, die dieser Ansatz aufwirft. Es ist erforderlich, neue Komponenten einzuführen, die die zusammengesetzten Ressourcen bereitstellen. Diese Komponenten sind konzeptionell aus den Komponenten
zusammengesetzt, die die einzelnen Teilressourcen bereitstellen. Diese Zusammensetzung von Komponenten sollte sich auch im Modell (z. B. durch Strukturressourcen) widerspiegeln.12 Der Bedarf einer zusammengesetzten Komponente sind zusammengesetzte Ressourcen, die aus dem Bedarf der Teilkomponenten bestehen.13
In SCO wird das Problem der „auseinanderlaufenden Ressourcenforderungen“
durch den Abgleich von Ressourcen innerhalb einer zusammengesetzten Komponente gelöst (Abschnitt 2.2).
10
In [BR96] fehlt allerdings ein Hinweis auf diese Systemkomponente.
eine Ressource, die denen des einfachen Modells entspricht
12
Börding und Rahmer [BR96] machen keine Aussage über zusammengesetzte Komponenten.
13
Welche Ressourcen aus dem Bedarf der Teilkomponenten jeweils zusammengefaßt werden – also
durch die gleiche Komponente befriedigt werden müssen – ist für jede zusammengesetzte Komponente neu zu bestimmen.
11
11
1
Modellieren und Konfigurieren modularer technischer Systeme
Bereich Arbeitsplatz 1
Arbeitsplatz
Fernsprechen
Telefonbenutzung
Telefonkomponente
Zugang
Telefonnetz,
Takt
Anschluß 1
Bereich Arbeitsplatz 2
Arbeitsplatz
Fernsprechen mit
Gebührenkontrolle
Gebührenanzeige
Telefonbenutzung
Telefon- und
Gebührenanzeige-komponente
Zugang
Telefonnetz,
Takt
Anschluß 2
Abbildung 1.8: Änderung der Konfiguration aus Abbildung 1.7 unter Verwendung
zusammengesetzter Ressourcen
Umwelteigenschaften und Unverträglichkeit Laut Heinrich [Hei89] gibt es einige Komponenteneigenschaften, wie z. B. Umweltbedingungen und Unverträglichkeiten zwischen Komponenten, die sich nicht durch Ressourcen beschreiben lassen. Diese Eigenschaften seien nicht anwendungsspezifisch und könnten deswegen
in das Problemlösungsverfahren fest eingebaut statt durch Ressourcen beschrieben zu werden. Dessenungeachtet lassen sich auch Umweltbedingungen durch Erweiterungen des Ressourcenbegriffs modellieren. Umweltbedingungen sind auch
nur weitere Eigenschaften, die für das Funktionieren der Komponente notwendig
sind. Sie unterscheiden sich von den bisher durch Ressourcen beschriebenen allein
darin, daß sie nur von der jeweiligen Systemumgebung bereitgestellt werden können.14 Umwelteigenschaften wie Temperatur oder Luftfeuchte sind eine Form von
Ressourcen, deren Wert ein Intervall ist. Bei solchen intervallwertigen Ressourcen
wird ein Bedarf dann durch eine Bereitstellung befriedigt, wenn das Intervall der
Bereitstellung das des Bedarfs umschließt.
Die Unverträglichkeit zweier Komponenten ist mit dem Ressourcenmodell nur
schwer zu beschreiben. Eine Möglichkeit wäre, daß beide Komponenten eine exklusive Systemressource verbrauchen. Dadurch wird aber die Eigenschaft, daß sich
die beiden Komponenten nicht vertragen, erst in der Beschreibung des zu konfigurierenden Systems festgelegt. Wenn diese Unverträglichkeit grundsätzlich in jeder
Konfiguration gilt, so sollte sie sich auch schon während der Modellierung ausdrücken lassen.
Eine weitere Möglichkeit, die Unverträglichkeit zweier Komponenten zu beschreiben, besteht nach Ansicht des Autors darin, eine neue Kategorie von Ressourcen einzuführen. Diese seien Ausschlußressourcen genannt. Der Bedarf an einer Ausschlußressource sei befriedigt, wenn keine Komponente sie bereitstellt. Eine
der unverträglichen Komponenten stellt die Ausschlußressource bereit, die andere
14
Es ist durchaus vorstellbar, daß später dem Katalog z. B. eine Komponente „Klimaanlage“ hinzugefügt wird, die diese Eigenschaften bereitstellt. Wurden diese Eigenschaften nicht in das Lösungsverfahren eingebaut sondern als Ressourcen modelliert, ist jetzt keine weitere Änderung nötig.
12
1.3
Ressourcenorientiertes Modellieren / Konfigurieren
fordert sie an.15 Die Einführung von Ausschlußressourcen erfordert eine Anpassung des Konfigurationsvorgangs. Die Ausschlußressourcen dürfen nicht als primäres Kriterium bei der Auswahl der hinzuzufügenden Komponente dienen. Vielmehr sind sie eine Randbedingung, um die Auswahl der Komponenten, die eine andere Ressourcen-Forderung erfüllen, einzuengen. Weiterhin ist beim Hinzufügen
einer Komponente, die eine Ausschlußressource fordert, zu überprüfen, ob in der
bestehenden Teilkonfiguration Komponenten vorhanden sind, die diese Ressource
bereitstellen – also sich nicht mit der neuen Komponente vertragen.16
Ðurd̄anović, Kleine Büning und Suermann schlagen vor, zu jeder Komponente eine Liste mit unverträglichen Komponenten zu speichern [DKBS96]. Dadurch
geht allerdings der Vorteil des ressourcenorientierten Konfigurierens verloren, daß
beim Hinzufügen einer neuen Komponente nicht der gesamte Katalog auf eventuelle Änderungen hin zu überprüfen ist. Wird die Unverträglichkeit dagegen in einer
globalen Liste gespeichert, so verliert sich der Vorteil des Ressourcenmodells, daß
alle Informationen, die eine Komponenten betreffen, mit dieser zusammen abgespeichert werden.
Zusammenfassend läßt sich feststellen, daß der ressourcenorientierte Ansatz
für die Konfiguration in schwach strukturierten Anwendungsbereichen gut geeignet ist. Er läßt sich durch die Einführung neuer Ressourcentypen auch an neue
Konfigurationsaufgaben anpassen. In der Praxis existieren einige Konfigurationssysteme, die auf diesem Ansatz basieren, so zum Beispiel zum Konfigurieren von
Telefonanlagen oder von lokalen Netzwerken [DKBS96], [Hei93].
Der Vorteil des ressourcenorientierten Ansatzes gegenüber dem strukturorientierten liegt in der einfachen Erweiterbarkeit des Komponentenkatalogs. Beim Hinzufügen eines neuen Komponententyps ist im Idealfall nur dieser mit seinen Ressourcen zu beschreiben. Die bereits erfaßten Komponenten müssen nicht geändert
werden. Beim Hinzufügen einer neuen Ressource, die bisher nicht betrachtet wurde, ist dagegen eventuell eine Änderung bestehender Komponententypen notwendig. In einigen Fällen, wie der unauflösbaren Unverträglichkeit zweier Komponenten, scheint die Verbindung mit Konzepten aus dem strukturorientierten Ansatz
angebracht.
15
16
Dabei geht aber verloren, daß die Unverträglichkeit eigentlich eine symmetrische Eigenschaft ist.
Die Auflösung eines Konflikts kann sich u. U. als nicht trivial herausstellen, wenn diese Komponente die einzige ist, die eine bestimmte Ressource bereitstellt.
13
2 Das Konfigurationssystem des SCO-Projektes
2.1
Konfigurationsaufgabe
Das Forschungsprojekt SCO beschäftigte sich mit der Konfiguration von TINASystemen. Die
„Telecommunications Information Networking Architecture“
(TINA) hat das Ziel, die Entwicklung neuer Telekommunikationsdienste1 zu erleichtern und die Interoperabilität dieser Dienste zwischen verschiedenen Anbietern zu gewährleisten [TIN01]. Dies wird durch die Standardisierung von Schnittstellen und Abläufen erreicht.
TINA ist eine Spezialisierung des allgemeinen ODP-Referenzmodells [ITU95]
für offene verteilte Systeme. Eine Reihe von Standardisierungsdokumenten
[TIN01] beschreibt die Kommunikationssysteme aus verschiedenen Gesichtspunkten wie Unternehmenssicht (enterprise viewpoint), Informationssicht (information
viewpoint), Funktionale Sicht (computational viewpoint) und Verfahrenssicht (technology viewpoint) .
In „Service Architecture“ [AFF+ 98] und „Service Component Specification“
[AFG+ 98] werden eine Reihe von Software-Komponenten beschrieben, die für das
Funktionieren eines Dienstes in einem TINA-System von Bedeutung sind. In Abbildung 2.1 sind einige dieser Komponenten und ihre Abhängigkeiten dargestellt.2
Einige Komponenten sind beim Kunden angesiedelt während andere sich beim
Dienstanbieter befinden. Dabei sind einige Komponenten dienstspezifisch während
andere von allen Diensten gemeinsam genutzt werden. Ein Beispiel für letztere
sind die Komponenten, die die Berechtigung zur Benutzung des Systems und einzelner Dienste überprüfen.
Beim Entwurf der Architektur stand die Benutzung wiederverwendbarer Softwarekomponenten im Vordergrund, um die Entwicklung neuer Dienste zu beschleunigen. Außer den in den TINA-Dokumenten beschriebenen Komponenten sind noch
weitere für einen funktionierenden Dienst notwendig: die Software-Komponenten
benötigen Hardware, auf der sie ausgeführt werden, sowie ein Betriebssystem. Desweiteren benötigen viele von ihnen weitere Software – wie Datenbanksysteme oder
Programmbibliotheken.
Beim Zusammensetzen eines neuen TINA-Dienstes aus den wiederverwendbaren Softwarekomponenten handelt es sich um eine typische Konfigurierungsaufgabe.3
1
z. B. herkömmliche Telefonie, Videokonferenzen, „Video-on-Demand“, aber auch ManagementDienste wie An- und Abstellen von Leistungsmerkmalen o. ä.
2
Diese Abbildung soll nur einen Eindruck von der Komplexität der Systeme geben. Deswegen wird
hier nicht weiter auf die verwendeten Abkürzungen und ihre Bedeutung eingegangen.
3
Falls neue, dienstspezifische Komponenten benötigt werden, geht das über eine reine Konfigurie-
14
2.1
Nutzerdomäne
Konfigurationsaufgabe
Anbieterdomäne
Sub
asUAP
IA
UAF
UA
PA
SF
ssUAP
Schnittstelle
USM
SSM
Erzeugung einer Komponente
Abbildung 2.1: Komponenten eines TINA-Systems (Ausschnitt) nach [AFG+ 98]
Das Institut „GMD Fokus“ hat u. a. im Auftrag der D EUTSCHEN T ELEKOM viele wesentliche Komponenten für ein TINA-System4 sowie mehrere Beispieldienste
entwickelt [FOK01]. Bei der testweisen Installation der Dienste stellten sich immer wieder eine Reihe von Abhängigkeiten zwischen den Komponenten und verschiedenen Softwarepaketen und -bibliotheken heraus. Das Wissen darüber war
auf verschiedene Entwickler verteilt.
Bei einem kommerziellen Einsatz der TINA-Architektur ist es aber notwendig,
schnell aus den vorgefertigten Teilen neue Dienste erzeugen zu können. Dabei sollen auch die Abhängigkeiten zwischen den Komponenten berücksichtigt werden
und das Konfigurieren Personen möglich sein, die die Interna des Systems nicht
genau kennen (wie z. B. Kundenberater).
Aus diesem Grund wurde das Projekt SCO ins Leben gerufen, das die Entwicklung eines Konfigurationssystems für diesen Anwendungsbereich als Ziel hatte.
rung natürlich hinaus. Dieser Fall wird im weiteren nicht berücksichtigt, sondern nur die Erstellung von Diensten, die eine Kombination von bestehenden darstellen. Nach der Erstellung neuer,
dienstspezifischer Komponenten ist das Hinzufügen dieser wieder eine Konfigurationsaufgabe.
4
Die Gesamtheit dieser Komponenten wird als TINA-Plattform bezeichnet.
15
2
Das Konfigurationssystem des SCO-Projektes
2.2
Das zugrunde liegende Metamodell
Bei den zu konfigurierenden TINA-Systemen handelt es sich um stark modulare
technische Systeme. An vielen Stellen läßt sich eine Komponente oder eine Gruppe
von Komponenten durch andere ersetzen. Feste Strukturbeziehungen sind dagegen
nur wenige vorhanden. Daher wurde in SCO als Grundlage des Konfigurationssystems ein ressourcenorientiertes Modell gewählt [vLSN99].
Neben den allgemeinen Abhängigkeiten zwischen Komponenten spielen auch
Strukturbeziehungen eine Rolle. Durch die TINA-Architektur wird bereits vorgegeben, daß sich bestimmte Komponenten beim Kunden und andere beim Anbieter befinden (in TINA-Termini: innerhalb der Kundendomäne bzw. innerhalb der
Anbieterdomäne). Weiterhin müssen sich bestimmte Software-Komponenten innerhalb des gleichen Computers befinden. Eine weitere strukturelle Beziehung besteht
darin, daß für bestimmte Dienste besondere Hardware innerhalb eines Computers
erforderlich ist. Diese Strukturbeziehungen lassen sich mit dem in 1.3.1 beschriebenen einfachen Modell nicht ausdrücken. Deshalb wurden neben der Spezialisierungshierarchie5 nach Heinrich [Hei89] auch Strukturbeziehungen, durch Strukturressourcen beschrieben, in das Modell aufgenommen (siehe Abschnitt 1.3.2). Eine Komponente, die andere enthält, wird in SCO Container genannt.
Darüberhinaus bietet das Ressourcenmodell von SCO die Möglichkeit auszudrücken, daß Bedarf und Angebot einer Ressource nicht nur global, sondern auch
innerhalb eines bestimmten Containers ausgeglichen sein müssen.
Neben den Ressourcen werden die Komponenten noch durch weitere Eigenschaften beschrieben. Diese dienen der Darstellung im Konfigurationswerkzeug
oder beinhalten Installationsanweisungen für die Softwarekomponenten. Abbildung
2.2 illustriert das Metamodell aus SCO.
Komponententyp
+GUI-Attribute: text
+name: text
+Installationsanweisungen: text
Container
0..1
benötigt
stellt bereit
*
*
Ressourcentyp
auszugleichen innerhalb
Abbildung 2.2: Das Ressourcenmodell in SCO
Die Ressourcen werden in SCO folgendermaßen klassifiziert:
5
Bestimmte übergeordnete Komponententypen in der Spezialisierungshierarchie werden in SCO als
Komponentenkategorien bezeichnet. Exemplare dieser abstrakten Komponententypen können
nicht in Konfigurationen erscheinen. Andere Komponententypen, von denen auch Spezialisierungen bestehen, können, im Gegensatz zum Ansatz von Heinrich [Hei89], durchaus in Konfigurationen verwendet werden.
16
2.2
Das zugrunde liegende Metamodell
• Strukturressourcen bilden das Enthaltensein einer Komponente in einer
anderen ab. Sie werden von der Komponente bereitgestellt, die andere Komponenten enthält und von den enthaltenen Teilkomponenten verbraucht.Ein
Beispiel dafür sind die Steckplätze für Erweiterungen innerhalb eines PCs.
• Flußressourcen repräsentieren Schnittstellen für den Informations-, Energie- und Materialfluß. Beispiele sind die Schnittstellen der TINA-Komponenten.
• Umgebungsressourcen und Spezifikationsressourcen werden durch die
zu lösende Konfigurierungsaufgabe bestimmt. Die Einordnung von Ressourcen in diese Klasse ist zum Modellierungszeitpunkt nicht möglich. Ressourcen, die in einer Konfigurierungsaufgabe vom System gefordert werden, können in einer andere Aufgabe auch als benötigte Ressourcen einer Komponente
auftreten. Ebenso können Ressourcen in einer Konfiguration von der Systemumgebung und in einer anderen von Komponenten bereitgestellt werden.
Die Ressourcen können desweiteren nach ihrem Datentyp unterschieden werden. Danach entscheidet sich auch, wie Bereitstellung und Bedarf dieser Ressourcen verglichen wird und wie der Verbrauch einer Ressource durch eine Komponente
erfolgt.
• Atomare Ressourcen entsprechen den Ressourcen, die schon von Heinrich
[Hei89] eingeführt wurden. Eine Bereitstellung ist mit einer Forderung verträglich, wenn sie vom gleichen Typ oder eine Spezialisierung der geforderten
ist. Atomare Ressourcen werden in den SCO-Dokumenten nicht explizit erwähnt, werden aber benutzt. So sind die verschiedenen Strukturressourcen
hier einzuordnen.
• Numerische Ressourcen sind eine Verallgemeinerung der exklusiven Ressourcen bei Heinrich. Eine bereitgestellte Ressource kann eine Forderung befriedigen, wenn ihr Wert größer oder gleich dem geforderten Wert ist. Beim
Verbrauch wird dann der Wert um den der Forderung reduziert. Numerische
Ressourcen sind erschöpft, wenn ihr Wert auf Null sinkt. Sie können dann
keinen Bedarf mehr befriedigen.
• Intervallressourcen haben als Wert ein Intervall. Sie sind ausgeglichen,
wenn das benötigte Intervall innerhalb des bereitgestellten liegt. Die Versionen von Softwareprodukten stellen solche Intervallressourcen bereit.
• Eigenschaftsbeschreibungen werden Ressourcen genannt, die eine Menge von Eigenschaften der Komponenten zusammenfassen. Bei ihnen muß der
Verbrauch eine Teilmenge der Bereitstellung sein. Da auch andere Ressourcen Eigenschaften von Komponenten beschreiben, ist der Begriff mengenwertige Ressourcen als Bezeichnung prägnanter. Im Unterschied zu den in
[BR96] eingeführten zusammengesetzten Ressourcen sind die Elemente der
Menge keine Ressourcen.
17
2
Das Konfigurationssystem des SCO-Projektes
Ein Spezialfall der mengenwertigen Ressourcen sind Ressourcen, bei denen
die Menge nur ein Element enthalten kann. Diese könnten für jeden der möglichen Werte auch als separate atomare Ressource modelliert werden, was die
Zahl der Ressourcen im Modell aber wesentlich erhöhen würde.
Für die Ressourcen wurde ebenfalls eine Vererbungshierarchie eingeführt, was
es erlaubt, die Zuordnung zu einer der vorgenannten Kategorien durch Vererbung
zu modellieren. Alle Strukturressourcen erben z. B. von der abstrakten Ressource
„StructureResource“, Intervallressourcen von „Counted“.
Neben den Ressourcen und Komponenten gibt es noch Dienstmuster. Sie stellen Systemkomponenten dar, die zur Spezifikation der Konfigurationsaufgabe beim
ressourcenorientierten Konfigurieren benutzt werden. Beschrieben werden sie
durch Listen von initialen Ressourcenforderungen für die Kunden- bzw. Anbieterdomäne, die Bereitstellung von Ressourcen durch das System unterstützen sie jedoch nicht. Es lassen sich also aus den Dienstmustern nur Konfigurationen erstellen, die keine Ressourcen von der Systemumgebung benötigen. Die Einordnung der
Dienstmuster in Kategorien erfolgt nur zur besseren Präsentation gegenüber den
Nutzern des Konfigurationssystems [vLSN99].
Bei dem in SCO entwickelten Konfigurationssystem handelt es sich um ein interaktives System. Das System ermittelt zu einer Teilkonfiguration alle möglichen
Vervollständigungen. Aus der Menge aller darin enthaltenen Komponenten kann
der Nutzer die nächste hinzuzufügende Komponente auswählen.
Das Verfahren zur Bestimmung der möglichen Vervollständigungen ist eine an
die Erweiterungen des Modells angepaßte Form des in Abschnitt 1.3.1 vorgestellten
Konfigurationsalgorithmus. Dieser wird in [vLSN99] so zusammengefaßt:
1. Ermittlung der aktuellen Bilanz
2. Auswahl einer unausgeglichenen Ressource
3. Auswahl einer Komponente, die diese Ressource bereitstellt
4. Auswahl eines Containers für die neue Komponente (anhand von Strukturressourcen)
5. Einfügen der Komponente in den Container
6. Falls kein Container gefunden werden kann: Fortsetzen mit 3
7. Aktualisierung der Bilanz
8. Falls es noch unausgeglichene Ressourcen gibt, fortsetzen mit 1
9. Ansonsten: Vollständige Konfiguration merken, Alternativen probieren
10. Dazu: Letzte eingefügte Komponente wieder entfernen, fortsetzen mit 4
11. Falls es keine alternativen Container mehr gibt: Letzte eingefügte Komponente wieder entfernen, fortsetzen mit 3
18
2.3
Aufbau des Konfigurationssystems
Die Ermittlung der Bilanz erfolgt entlang der Zerlegungshierarchie. Bei der Bilanzierung eines Containers werden erst die enthaltenen Komponenten bilanziert.
Danach werden die bereitgestellten und benötigten Ressourcen dieser Komponenten soweit möglich miteinander abgeglichen. Verbleiben nach diesem Containerinternen Abgleich noch offene Forderungen von Ressourcen, die nicht innerhalb
dieses Containers ausgeglichen sein müssen (siehe oben), so werden diese den vom
Container benötigten hinzugefügt und mit der Bilanzierung des übergeordneten
Containers fortgefahren. Offene Forderungen von Ressourcen, die innerhalb des
Containers auszugleichen sind, führen zu einem Konflikt, der durch das Hinzufügen von Komponenten in diesen Container eventuell noch zu lösen ist.
2.3
Aufbau des Konfigurationssystems
Das Konfigurationssystem besteht aus zwei wesentlichen Teilen6 :
• der grafischen Benutzeroberfläche, die die Darstellung der aktuellen (Teil-)
Konfiguration übernimmt und die Benutzereingaben verarbeitet und
• einem Konfigurationsserver, der den Katalog der Komponenten beinhaltet,
die Bilanzierung der Ressourcen für die aktuelle Konfiguration durchführt
und mögliche Vervollständigungen ermittelt sowie Installationsskripte erstellt.
Der Konfigurationsserver implementiert dazu eine Reihe von CORBA-Schnittstellen. Wesentlich dabei sind die Schnittstelle „ComponentRepository“, die den Zugang zum Konfigurationssystem ermöglicht, und „Configuration“, die die Bearbeitung einer Konfiguration gestattet. Für die Details der Schnittstelle sei auf die
IDL-Datei „composer.idl“ im Anhang B.1.1 verwiesen.
2.4
Die Komponentenbeschreibungssprache
2.4.1 Anforderungen
In Konfigurationssystemen werden die Komponenten und ihre Beziehungen in der
Regel durch spezielle Sprachen beschrieben. Für die Auswahl einer Komponentenbeschreibungssprache wurden im Projekt SCO eine Reihe von Kriterien festgelegt.
Sie wurden in funktionale und nicht funktionale Aspekte gegliedert. Zu den funktionalen Aspekten wurden folgende Anforderungen gezählt:
• Die Komponenten und Ressourcen sollen separate Konstrukte sein.
• Die Spezialisierung von Komponenten und Ressourcen muß sich ausdrücken
lassen.
6
In SCO wurde neben der hier beschriebenen Version auch eine TINA-Variante des Systems erzeugt.
Diese wurde als ein TINA-Dienst mit den dazugehörigen zusätzliche Komponenten implementiert
[vLSN99].
19
2
Das Konfigurationssystem des SCO-Projektes
• Die Definition von zusätzlichen Attributen zu den Komponenten muß möglich
sein. Dabei handelt es sich um die Attribute für die Benutzerschnittstelle und
die Installationsanweisungen.
• Die Beschreibung des Bilanzierungs- und Verbrauchsverhalten von verschiedenen Ressourcentypen muß möglich sein. Vor allem sollen sich nachträglich noch Ressourcen hinzufügen lassen, die neue Beziehungen zwischen den
Komponenten beschreiben.
Als nichtfunktionale Anforderungen wurden identifiziert:
• die leichte Erlernbarkeit der Notation,
• die direkte Erkennbarkeit der Relationen zwischen Komponenten und Ressourcen in der textuellen Darstellung,
• die Beschreibung der verbrauchten und bereitgestellten Ressourcen einer Komponente mit geringem Aufwand und
• die Möglichkeit der dynamischen Verarbeitung der Beschreibungen durch das
Konfigurationssystem.
2.4.2
Python als Beschreibungssprache
Aus der Forderung, daß sich nicht weiter eingegrenztes Verhalten von Ressourcen
in der Beschreibungssprache ausdrücken lassen soll, wird in [vLSN99] gefolgert,
daß nur Programmiersprachen zur Beschreibung in Frage kommen. Die Wahl einer Programmiersprache wurde außerdem damit begründet, daß sich die Installationsanweisungen der Komponenten als Algorithmen in der Sprache ausdrücken
lassen sollen [vLSN99]. Davon wurde aber kein Gebrauch gemacht, sondern diese
Anweisungen als reine Zeichenketten abgelegt. In diesen Zeichenketten liegen die
Installationsanleitungen in einer XML-ähnlichen Notation vor.
Eine Folgerung, die in [vLSN99] aus der Forderung, daß Spezialisierung beschreibbar ist, getroffen wurde, ist, daß es sich um eine objektorientierte Sprache
handeln muß. Die Spezialisierung ließe sich zwar auch mit anderen Sprachen darstellen, jedoch die Benutzung einer objektorientierten Sprache und der sprachenspezifischen Darstellung der Spezialisierung gewährleistet, daß die Vererbung von
Attributen und Verhalten durch die Sprachimplementation erfolgt und nicht für
das Konfigurationssystem realisiert werden muß.
Aus der Forderung nach dynamischem Laden der Komponenten- und Ressourcenbeschreibungen wird gefolgert, daß nur interpretierte Sprachen geeignet sind.
Gegen die Definition einer neuen und für die Verwendung einer bestehenden Sprache wird ausgeführt, daß eine neue Sprachdefinition sich am Anfang als nicht stabil
erweisen würde und Anwendern garantiert unbekannt wäre [vLSN99]. Aus diesen
Erwägungen heraus wurde in SCO als Beschreibungssprache Python gewählt. Dabei wurde die Sprache mit anderen weitverbreiteten Programmiersprachen verglichen.
20
2.4
Die Komponentenbeschreibungssprache
Das Ressourcenmodell des Konfigurationsservers ist in zwei Pythondateien abgespeichert: eine für die Komponenten und eine für die Ressourcen. Die Datei „components.py“ beinhaltet die Komponenten. Jede Komponente wird durch eine eigene
Python-Klasse repräsentiert. Die Vererbung von Komponenten spiegelt sich in der
Vererbungsrelation zwischen den einzelnen Klassen wieder. Basis aller Komponentenklassen ist die Klasse Component, die in der Datei „SCOSupport.py“ definiert
ist. Verbrauchte und bereitgestellte Ressourcen werden in Listen von RessourcenInstanzen abgespeichert. Auch die Eigenschaft, ob es sich um eine abstrakte Komponente handelt, ist als Attribut innerhalb der Klasse definiert. Das gleiche gilt
für mögliche weitere Eigenschaften der Komponente, die für das eigentliche Modell
nicht von Bedeutung sind.7
Als Beispiel sei hier die Beschreibung der Komponente TTest1 SF angeführt:
class TTest1 SF(Service):
info
= "resources/empty.txt"
icon48 = "images/java-floppy.gif"
name
= "TTest1 Service Factory"
provides = [CorbaService("TTest1SF")]
consumes = [ProviderSide(),Java((1,1,5)),DPEBootstrap(),DPE()]
Diese Komponente ist eine Spezialisierung der Service-Komponente und verbraucht
die Ressourcen ProviderSide, Java, DPEBootstrap und DPE. Die Ressource Java
wird mit dem Wert (1,1,5) verbraucht. Bereitgestellt wird CorbaService mit
dem Wert "TTest1SF". Wäre die Komponente TTest1 SF abstrakt8 , so wäre noch
ein Eintrag abstract=1 vorhanden. Die Reihenfolge der einzelnen Attribute ist
nicht festgelegt.
Während in den Komponentenklassen keinerlei Verhalten beschrieben wird, ist
das bei den Ressourcen nicht der Fall. Diese sind in der Datei „resources.py“ definiert. Auch für jede Ressource existiert eine eigene Klasse, Vererbung wird wiederum durch Vererbung der Pythonklassen beschrieben. Alle Ressourcen sind Spezialisierung der Klasse Resource aus „SCOSupport.py“. Dort ist ebenfalls die Ressource StructureResource definiert, die die Basisklasse für alle Strukturressourcen
bildet. Feste Attribute wie bei den Komponenten gibt es bei den Ressourcen nicht.9
Statt dessen werden für einige der Ressourcen Funktionen definiert:
init (self) initialisiert gegebenenfalls die Instanzen des Ressourcentyps.
must balance at(self,component) gibt an, innerhalb welcher Komponenten
dieser Ressourcentyp ausgeglichen sein muß.
7
Dabei handelt es sich um Informationen, die die Darstellung in der grafischen Benutzeroberfläche
beeinflussen bzw. der Erstellung von Installationspaketen der fertigen Konfiguration dienen.
8
also eine Komponentenkategorie, siehe Abschnitt 2.2
9
Klassenattribute können jedoch auftauchen, falls sie für die im folgenden beschriebenen Funktionen benötigt werden.
21
2
Das Konfigurationssystem des SCO-Projektes
provider for(self,consumed) berechnet, ob die übergebene Ressource durch
diese Ressource bereitgestellt werden kann. Hier findet bei versionsbehafteten oder gezählten Ressourcen (Siehe 2.2) der Vergleich zwischen Verbrauch
und Bedarf statt.
consume(self,resource) zeigt der Ressourceninstanz an, daß sie durch den
übergebenen Bedarf verbraucht wird.
unconsume(self,resource) macht consume(self, resource) wieder rückgängig.
exhausted(self) überprüft, ob die Instanz noch weiterhin einen Bedarf befriedigen kann oder erschöpft ist.
Diese Funktionen werden in Ressourcen wie z. B. BalanceAtBasicHardware,
BalanceAtDomain, ABI und VersionedSoftware benutzt. Sie bilden die Basis
für die verschiedenen Arten von Bilanzierung und werden selbst nicht als verbrauchte oder bereitgestellte Ressource in einer der Komponenten auftauchen. Hier
die Definition von VersionedSoftware als ein Beispiel.
class VersionedSoftware(Resource,BalanceAtBasicHardware):
def init (self,version):
self.version = version
def provider for(self,consumed):
return isinstance(consumed,self. class ) and \
self.version >= consumed.version
2.5
Bisheriges Modellierungsverfahren
Bisher wurde der Komponentenkatalog durch Verändern der entsprechenden Pythondateien von Hand erstellt. Das Wissen über die Komponenten und ihre Beziehungen stammte dabei aus Befragungen von Programmierern einzelner Bestandteile der TINA-Plattform und der Beispieldienste sowie von Personen, die Erfahrungen bei der Installation dieser gewonnen haben, durch den Entwickler des Konfigurationssystems.
Nachteilig bei dieser Vorgehensweise ist, daß neue Komponenten und Ressourcen nur von Personen hinzugefügt werden können, die über die Struktur besagter
Dateien und über die Syntax der Programmiersprache Python Kenntnis haben.
2.6
Darstellung des Komponentenkatalogs als HTML-Seite
In einer Studienarbeit wurde vom Autor die dynamische Darstellung der Komponenten des Katalogs in einer HTML-Seite beschrieben [Kun00]. Das Ziel dabei war,
eine Übersicht über die Komponenten und ihre Eigenschaften zu Informations- und
Werbezwecken zu ermöglichen.
22
2.6
Darstellung des Komponentenkatalogs als HTML-Seite
Um Informationen über die im Katalog vorhandenen Komponenten zu erhalten, werden dabei die CORBA-Schnittstellen zwischen dem Konfigurationssystem
und dessen Benutzerschnittstelle benutzt (Abschnitt 2.3 und Anhang B.1.1). Diese ermöglicht es, die Eigenschaften einer namentlich bekannten Komponente zu
ermitteln. Eine Liste aller Komponentennamen kann durch Abschreiten des Spezialisierungsbaumes ausgehend von einem bekannten Namen ermittelt werden.
Aus dieser Liste aller Komponenten werden bestimmte Komponenten herausgefiltert, die nicht angezeigt werden sollen. Auch bietet der Filter die Möglichkeit, die Auswahl der angezeigten Komponenten durch den Benutzer weiter
einzuschränken. Auf diesen Filter greift über eine weitere CORBA-Schnittstelle
der HTML-Generator zu. Dieser generiert aus den erhaltenen Komponentenlisten
dann HTML-Seiten. Abbildung 2.3 verdeutlicht die Beziehungen zwischen den Bestandteilen des Konfigurationssystems und dem HTML-Generator.
WWW-Info::Filter
Konfigurationsserver
ComponentDesc
WWW-Info::HTML-Generator
ComponentRepository
Composition
Benutzeroberfläche
Abbildung 2.3: Konfigurationssystem und WWW-Darstellung
Die zur Informationsgewinnung benutzte CORBA-Schnittstelle zwischen dem
Konfigurationssystem und dessen Benutzeroberfläche ist für die Wissenserfassung
nicht geeignet. Sie bietet keine direkten Informationen über die Ressourcen und
deren Bilanzierungsverhalten. Weiterhin ist kein schreibender Zugriff auf den Katalog möglich.
Für die WWW-Darstellung wurden zusätzliche Eigenschaften von Komponenten in den Katalog eingetragen. Dies beeinträchtigt nicht die Funktion des Konfigurationssystems. Solch zusätzliche Eigenschaften sollten bei der Bearbeitung des
Katalogs durch ein Werkzeug zum Wissenserwerb erhalten bleiben.
23
3 Das Werkzeug zum Wissenserwerb
3.1
Alternative Komponentenkataloge
Wissenserwerb bedeutet, daß der Katalog mit den Komponenten und Ressourcen
zu verändern oder neu zu erstellen ist. Daraus ergibt sich, daß die Funktion des
Werkzeugs für den Wissenserwerb eng an die Implementierung des Katalogs gebunden ist. In der Regel wird das Modellierungswerkzeug parallel zu dem Konfigurationssystem entwickelt, so daß gewährleistet ist, daß beide mit dem Katalog
funktionieren. Im Projekt SCO war die Werkzeugunstützung beim Wissenserwerb
nicht vorgesehen [vLSN99]. Deswegen wurden bei der Wahl der Programmiersprache Python als Komponentenkatalog die Erfordernisse des werkzeugunterstützten
Wissenserwerbs nicht berücksichtigt.
Bei der Erstellung des Werkzeuges ist deshalb die Frage zu behandeln, ob die
bestehende Form des Katalogs weiterhin verwendet werden kann oder ob eine andere Form benötigt wird und welche anderen Formate sinnvoll wären.
Für die Bewertung der verschiedenen Möglichkeiten werden folgende Kriterien
benutzt:
• Kriterien, die unbedingt zu erfüllen sind:
– Der Komponentenkatalog muß in das Konfigurationssystem integrierbar
sein.
– Das Format muß das Ressourcenmodell mit den Erweiterungen von SCO
widerspiegeln.
– Die Bearbeitung des Katalogs durch das Modellierungswerkzeug muß
möglich sein.
– Die Erweiterung um neue Ressourcentypen mit eigenem Bilanzierungsverhalten muß möglich sein. Die Verhaltensbeschreibung muß dabei anzeigbar und veränderbar sein.
• Kriterien zur Beurteilung von Lösungen, die die vorherigen Kriterien erfüllen:
– Die Erweiterung der Komponenten um neue Eigenschaften (z. B. die in
2.6 erwähnten) muß möglich sein.
– Die Integration in das bestehende Konfigurationssystem soll mit geringem Aufwand verbunden sein.
– Die Anforderungen des Komponentenkatalogs an die Hardware-Ausstattung sollten gering sein.
24
3.1
Alternative Komponentenkataloge
– Der Aufwand zur Installation und Pflege der zur Laufzeit benötigten
Technologien sollte gering sein.
– Die Erfassung der Komponenten durch verschiedene Anwender an verschiedenen Arbeitsplätzen sollte möglich sein.
Im folgenden werden mehrere Lösungen näher beschrieben: die Benutzung eines
relationalen Datenbanksystems (3.1.2), die Verwendung einer Datei-basierten Lösung mit einer anderen Beschreibungssprache (3.1.3) und die Beibehaltung der bisherigen Speicherlösung (3.1.4). Vorher werden einige generelle Ausführungen zur
Integration neuer Komponentenkataloge in das Konfigurationssystem gemacht.
3.1.1 Integration neuer Kataloge in das Konfigurationssystem
Beim Einsatz einer neuen Lösung für den Komponentenkatalog ergeben sich zwei
generelle Probleme: die Integration in das Konfigurationssystem und die Umwandlung bestehender Kataloge.
Um einen neuen Katalog im Konfigurationssystem verwenden zu können, muß
der Mechanismus, mit dem die Komponenten und Ressourcen dynamisch geladen
werden, so verändert werden, daß die Informationen aus dem neuen Katalog gewonnen werden.
Durch den Aufruf der folgenden Funktion wird der Katalog vom Konfigurationssystem gelesen:
def load(self, module):
import types
d = {}
exec "import "+module in d
m = d[module]
.
.
.
Die übergebene Variable module enthält den Namen des zu ladenden Moduls.
Daraus wird zur Laufzeit eine import-Anweisung mit dem Modulnamen konstruiert und diese Abweisung dann ausgeführt. Danach enthält das assoziative Feld d
die im Verlauf der Anweisung belegten Namen. Mit dem Modulnamen als Schlüssel
ist dabei eine Variable vom Typ ModuleType1 enthalten. Im weiteren Verlauf der
load()-Funktion werden dann aus dieser Modul-Variablen alle Klassen-Variablen,
die von den Basisklasssen Resource bzw Component abgeleitet sind, ermittelt und
zur späteren Verarbeitung abgespeichert.
Um ohne Änderung des Konfigurationssystems einen neuen Komponentenkatalog zu verwenden, wäre es notwendig, bei einem import der Dateien „resources.py“
und „components.py“ aus dem Katalog den Quelltext für die Klassen für Komponenten und Ressourcen zu erzeugen, diesen zu interpretieren und das Ergebnis
dem Namensraum des zu importierenden Moduls hinzuzufügen.
1
Ein Python-interner Datentyp, der Module der Sprache repräsentiert. In Python sind Module, Klassen und Funktionen wiederum Objekte, die sich an Variablen zuweisen lassen.
25
3
Das Werkzeug zum Wissenserwerb
Die Erzeugung von Python-Quelltext ist von der Art des Katalogs abhängig und wird in dem jeweiligen Abschnitt diskutiert. Durch die Verwendung der
exec-Anweisung kann dieser dann interpretiert werden. Falls für die QuelltextGenerierung andere Module geladen werden oder Klassen, Funktionen oder Variablen benutzt werden, die außerhalb des Moduls nicht gesehen werden sollen,
so können sie nach Benutzung mit del wieder gelöscht werden. Tiefergehende Informationen zur Arbeitsweise von import sowie zum dynamischen Ausführen von
Anweisungen mit exec finden sich im Buch „Python 2“ [vLF00] sowie im „Python
Reference Manual“ [vR00].
Neben den Klassendefinitionen steht in den Dateien „resources.py“ und „components.py“ nur jeweils eine import-Anweisung in der ersten Zeile. Der Komponentenkatalog sollte diese Anweisungen vor dem Laden auch ausführen, um die
Funktion des bisherigen Katalogs zu simulieren. Besser noch wäre es, wenn jedweder Quelltext außerhalb der Klassendefinitionen erhalten bliebe und beim import
an der „richtigen“ Stelle2 ausgeführt würde.
Die Einbindung eines neuen Katalogs ist somit ohne Änderung des Konfigurationssystems möglich, wenn sich aus diesem dynamisch der Python-Quelltext erzeugen läßt, der der alten Katalogform entspricht. Unter anderem ist es wichtig, daß
die Beschreibung der Eigenschaften in dem neuen Katalog sich in Python überführen läßt.3
Das zweite Problem, das bei jedem Wechsel des Katalogs zu beachten ist, ist die
Umwandlung des alten Katalogformats in das neue Format. Der Beispiel-Katalog,
der in SCO verwendet wurde, enthält nur wenige Komponenten und Ressourcen (41
bzw. 31). Diese könnten mit dem zu entwickelnden Modellierungswerkzeug in den
neuen Katalog eingefügt werden. Bei einem größeren Katalog wäre das aufwendig
und fehleranfällig. Dort wäre eine automatische Konvertierung wünschenswert.
Dazu müßten die Informationen aus dem bestehenden Katalog extrahiert werden,
was bedeutet, daß das Extrahieren der Daten aus dem bestehenden Katalog implementiert werden müßte. Dies entspricht schon der Lösung einer wesentlichen
Teilaufgabe bei der Verarbeitung des bestehenden Katalogs.
3.1.2
Relationale Datenbank Management Systeme
Für die dauerhafte Speicherung großer, gut strukturierter Datenmengen werden
oft Relationale Datenbanksysteme eingesetzt. Relationale Datenbank Management
Systeme (RDBMS) basieren auf dem relationalen Datenmodell. Nach diesem Modell werden alle Daten durch Relationen dargestellt. Relationen sind Mengen von
Tupeln, die einem Relationenschema genügen. Nach „Relationale Datenbanken
und SQL“ [MU97] ist
[. . . ] ein Relationenschema s [. . . ] gegeben durch eine (endliche)
2
Die Ermittlung dieser Stelle ist nicht immer trivial, da sich im Laufe des Wissenserwerbs die Reihenfolge der Klassen ändern kann.
3
z. B. nur erlaubte Zeichen für Bezeichner
26
3.1
Alternative Komponentenkataloge
Menge A von Bezeichnern (Attribut-Bezeichner) und einer Zuordnung, die jedem Attributbezeichner aus A eine Domäne s(a) zuordnet.
Mit Domänen werden die Wertebereiche für die Attribute bezeichnet. Ein Tupel
ist eine Menge von Paaren aus Attributbezeichnern und Werten. Es genügt genau
dann einem Schema, wenn es nur Attributbezeichner des Schemas enthält und die
jeweiligen Werte aus der für diesen Bezeichner im Schema festgelegten Domäne
stammen. Die Tupel werden durch die Werte ihrer Attribute identifiziert. Da Relationen Mengen sind, spielt die Reihenfolge der Tupel keine Rolle. Eine Teilmenge
der Attribute, durch die jedes Tupel der Relation eindeutig identifiziert wird, wird
Schlüssel genannt.
Beziehungen zwischen verschiedenen Relationen werden durch das Einfügen
von Fremdschlüsseln in einer Relation ausgedrückt. Das sind Attribute, deren
Domäne die Menge aller Schlüssel einer anderen Relation sind, zu der diese Relation in Beziehung steht.
Die Darstellung der Relationen erfolgt in der Regel in Form von Tabellen mit
den Attributbezeichnern als Spaltenüberschrift. Die Zeilen der Tabelle entsprechen
den Tupeln mit den Attributwerten in den durch die Bezeichner bestimmten Spalten.
Die Bestandteile des Komponentenkatalogs lassen sich folgendermaßen in das
relationale Datenmodell abbilden:
• Je eine Relation für die Komponenten und Ressourcen mit ihren elementaren
Eigenschaften. Als Schlüssel dient der Name.
• Eine Relation, die Komponentennamen zusammen mit den Namen der verbrauchten Ressourcen dieser Komponente und dem eventuellen Wert enthält.
• Eine weitere Relation für die Bereitstellung von Ressourcen.
• Um Mehrfachvererbung darstellen zu können, ist es erforderlich, eine separate Tabelle anzulegen, in der vererbende und erbende Klasse gegenübergestellt
werden.4
• Zusätzliche Eigenschaften lassen sich durch die Erweiterung der Relationen
um neue Attribute darstellen.
In den Tabellen 3.1, 3.2 und 3.3 wird die Modellierung in Relationen für einige
Komponenten angedeutet.
Die Vererbung wird vom relationalen Datenmodell nicht unterstützt, d. h. die
erbende Klasse hat nicht automatisch die Eigenschaften ihrer Basisklasse. Dies
sicherzustellen ist Aufgabe des Konfigurationssystems. Die Erweiterung der Komponenten um neue Eigenschaften kann entweder durch Hinzufügen von Spalten in
der Komponentenrelation oder durch Anlegen neuer Relationen erfolgen.
4
Die Zergliederung des Katalogs in viele verschiedene Relationen ergibt sich aus der Normalisierung
der Relationen. Dies ist eine zentrale Forderung bei Relationalen Datenbanksystemen [MU97]
27
3
Das Werkzeug zum Wissenserwerb
Klassenname
Langer Name
abstrakt
Infotext
Software
TestJar
PAJar
NULL
Java Test Services
Java Provider Agent
Y
N
N
NULL
resources/testServices.txt
resources/pa.txt
Tabelle 3.1: Komponenteneigenschaften als Relation
Komponente
Ressource
Wert
Komponente
erbt von
Software
PAJar
PAJar
TestJar
TestJar
TestJar
InComputer
Java
CorbaJava
TinaJava
Java
Swing
NULL
(1,1,5)
„VisiBroker“
NULL
(1,1,5)
(1,0,1)
TTest1_SF
TestJar
PAJar
Software
Product
OperatingSystem
Service
Service
ServiceSurround
Component
Software
Software
Tabelle 3.2: Ressourcenverbrauch
Tabelle 3.3: Komponentenvererbung
Auf die Daten einer Datenbank wird üblicherweise mit einer Datenmanipulationssprache zugegriffen. Bei den relationalen Datenbanken hat sich die Sprache SQL als Standard etabliert [MU97]. SQL erlaubt sowohl die Definition und
Manipulation von Relationenschemata als auch die Abfrage und Veränderung der
Daten in den Relationen. Für die verschiedenen Datenbanksysteme existieren Bibliotheken um aus Programmen bestimmter Programmiersprachen heraus SQLAnfragen an das Datenbanksystem zu stellen. Auch für Python bestehen einige
solcher Bibliotheken zur Datenbankanbindung [PyD01].
Das Bilanzierungsverhalten läßt sich mit den Mitteln relationaler Datenbanken nicht ohne weiteres darstellen. Eine mögliche Lösung wäre es, das Verhalten
in einer Programmiersprache auszudrücken und in Datentypen des RDBMS (z. B.
Zeichenketten) abzulegen. Für die Interpretation dieser Daten als Verhaltensbeschreibung ist der Mechanismus zum Laden der Komponenten und Ressourcen aus
dem Katalog verantwortlich. Die Wahl von Python als Programmiersprache ist hier
naheliegend.
Wird das Verhalten in Python beschrieben, so ist die Generierung des PythonQuelltextes, der dem alten Katalog entspricht (siehe Abschnitt 3.1.1), trivial: für
jede Komponente bzw. Ressource wird eine Klassendefinition konstruiert, in die
Zuweisungen für die Eigenschaften und Funktionsdefinitionen für das Verhalten
eingefügt werden.
Die Benutzung einer relationalen Datenbank durch das in Python geschriebene Konfigurationssystem wäre also prinzipiell möglich. Auch der Zugriff durch ein
Wissenserwerb-Werkzeug ist durch die vorgenannten Programmbibliotheken realisierbar.
28
3.1
Alternative Komponentenkataloge
Der parallele Zugriff auf RDBMS wird in der Regel durch sogenannte Sperren
abgesichert. Dabei wird beim lesenden Zugriff auf ein Datum dieses für Veränderungen gesperrt. Soll das Datum durch eine Operation verändert werden, so wird
es auch für den lesenden Zugriff gesperrt. Nach Ausführung der Aktion wird die
Sperre wieder entfernt. Die Details der Behandlung von Sperren, wie Granularität
(Tabelle, Spalte), implizites oder explizites Sperren und Auflösung von Verklemmungen (Deadlocks) sind für die einzelnen RDBMS unterschiedlich [MU97]. Auch
für den Netzwerkzugriff bieten die verschiedenen RDBMS Lösungen an.
RDBMS sind komplexe Produkte, die u. U. hohe Anforderungen an die Hardware stellen5 und deren Installation und Wartung umfangreiche Kenntnisse erfordern.
3.1.3 Eine andere Beschreibungssprache
Neben dem Verwenden von Datenbanken ist die Ablage des Katalogs in Dateien
möglich, die in einer bestimmten Beschreibungssprache formuliert sind. Aufgrund
der Anforderung, Verhalten zu beschreiben, wurde in SCO die Verwendung einer
Programmiersprache beschlossen. Dabei wurde die Sprache Python gegenüber anderen Programmiersprachen vorgezogen (Abschnitt 2.4).
Eine andere Programmiersprache wäre aus Sicht des Modellierungswerkzeuges
zu erwägen, wenn deren Verarbeitung wesentlich einfacher wäre und diese sich im
Konfigurationssystem mit wenig Änderungen verwenden ließe. Um aus Dateien einer Programmiersprache Informationen über ihren Inhalt zu erhalten, ist es erforderlich, sie in die Syntaxkonstrukte der Sprache zu zerlegen. Dieser Vorgang wird
allgemein Parsen genannt. Parser sind Bestandteile aller Compiler und Interpreter [ASU92].
Neben von Hand erzeugten Parsern gibt es auch Parser-Generatoren, die aus
einer Beschreibung der Syntax (der Grammatik) einen Parser für die Sprache erzeugen. Dieser läßt sich dann in andere Programme einbinden. Prominenteste Vertreter dieser Parser-Generatoren sind die Programme YACC bzw. BISON.
Parser liefern als Ergebnis Baumstrukturen, die die Zerlegung der Eingabe in
die in der Grammatik der Sprache definierten Teile widergeben. Die benötigten
Informationen müssen dann aus diesen Bäumen heraus gesammelt werden. Das
Programm KIMWITU [vEB00] generiert C-Programme, die Operationen auf solchen
Bäumen ausführen.
Zum Abspeichern des veränderten Kataloges ist auch die Erzeugung von Quelltext in der Beschreibungssprache notwendig. Eine der Operationen, die mit KIMWI TU erzeugte Programme ermöglichen, ist der entgegengesetzte Vorgang zum Parsen
– das Unparsen. Beim Unparsen wird der Syntax-Baum wieder in seine textuelle
Repräsentation überführt. Ebenso wie das Parsen läßt sich das Unparsen auch ohne den Einsatz von durch Generatoren erzeugten Programmen realisieren. Dabei
5
Für das RDBMS Oracle8i wird als Mindestvoraussetzung 128MB Hauptspeicher, 400MB Auslagerungsspeicher und 600MB Plattenplatz angegeben. Dabei ist der Bedarf für die eigentlichen Daten
noch nicht berücksichtigt.
29
3
Das Werkzeug zum Wissenserwerb
muß der Syntax-Baum komplett abgegangen werden und für jeden Knoten (der ein
Syntax-Konstrukt beschreibt) die Text-Repräsentation ausgegeben werden.
Ob eine Erweiterung um neue Komponenteneigenschaften möglich ist, hängt
von der gewählten Sprache ab. Objektorientierte Sprachen, die nach SCO besonders für die Beschreibung des Modells geeignet sind [vLSN99], bieten die Möglichkeit, diese als neue Klassenattribute einzuführen.
Wird für die Komponentenbeschreibung eine andere Programmiersprache als
Python benutzt, so ist die Frage zu lösen, wie das Verhalten der Ressourcen ausgedrückt werden soll. Wird es in Programmfragmenten der neuen Programmiersprache beschrieben, ist daraus beim Laden automatisch Python-Quelltext zu erzeugen, der dann interpretiert werden kann.6 Eine solche automatische Übersetzung
ist nur bei einer Sprache, deren Struktur Python ähnelt, möglich.
Die Alternative wäre es, das Verhalten als Python-Quelltext in Zeichenketten
oder anderen Datentypen der Programmiersprache zu speichern. Damit würden
eventuelle Vorteile des Sprachwechsels wieder verloren gehen, da zur Beschreibung des Verhaltens wieder nur Python zur Verfügung steht. Für die Beschreibung
der statischen Eigenschaften bietet Python für jedes Konstrukt des erweiterten
Ressourcenmodells ausreichende Ausdrucksmöglichkeiten [vLSN99]. Deswegen ist
der Wechsel zu einer anderen Programmiersprache nicht sinnvoll.
Falls eine andere Beschreibungssprache als eine Programmiersprache gewählt
wird, so ist das Verhalten ebenfalls durch Code-Fragmente innerhalb dieser zu beschreiben. Das hat ebenfalls die oben erwähnten Nachteile. Auch hier ist die Zerlegung der Beschreibung in die syntaktische Struktur notwendig. Das Parsen könnte
u. U. einfacher sein, da nicht die komplexen Strukturen einer Programmiersprache
verarbeitet werden müßten.
Eine in Frage kommende Sprache ist die „Extensible Markup Language“ (XML)
[XML01]. Diese Sprache ist vom „World Wide Web Consortium“ standardisiert und
dient dem Austausch von strukturierten Daten. Es gibt zwei Arten von XMLDokumenten: zum einen Dokumente, deren mögliche Struktur in einer „Document
Type Declaration“ (DTD) festgelegt ist. Diese Dokumente werden als valid (gültig)
bezeichnet. XML-Dokumente, deren Struktur nicht näher beschränkt ist, die aber
dem XML-Standard genügen, heißen well-formed (wohlgeformt).
XML kennt keine Verhaltensbeschreibungen und keine Datentypen. Alles, was
nicht die Struktur beschreibt, wird als Text interpretiert. Der Anwendung obliegt
es, diesen Text zu interpretieren. Für das Speichern der Verhaltensbeschreibungen
ergeben sich dann die gleichen Probleme wie bei der Verwendung von Datenbanken.
Für das Verarbeiten von XML-Dokumenten steht eine Reihe von Werkzeugen
zur Verfügung. Dabei existieren zwei Ansätze:
SAX (Simple API for XML) liest das XML-Dokument und generiert beim Auffinden
6
Die Änderung des Konfigurationssystems dahingehend, daß es intern eine andere Beschreibungssprache verwendet, würde einen unvertretbar hohen Aufwand erfordern. Außerdem sind die Argumente gegen andere Sprachen, die in [vLSN99] dargelegt wurden, zu berücksichtigen.
30
3.1
Alternative Komponentenkataloge
von Strukturelementen Ereignisse, die über eine Schnittstelle an ein externes
Programm gesendet werden können. Dieses kann dann diese Signale weiterverarbeiten.
DOM (Document Object Model) ist eine abstrakte Schnittstelle, um Syntax-Bäume
von XML-Dokumenten zu erzeugen und auf diesen Operationen durchzuführen [ABC+ 98]. Es existieren verschiedene Implementierungen dieser Schnittstelle.
Die Verarbeitung von XML-Dokumenten durch das Wissenserwerb-Werkzeug ist
also möglich. Wie einfach die Generierung des Python-Code ist, hängt davon ab, wie
die Struktur des XML-Dokumentes gestaltet ist. Im Abschnitt B.2 wird ein Beispiel
für einen Komponentenkatalog als wohlgeformtes XML-Dokument gegeben, dessen
Struktur sehr eng an die der originalen Pythondateien angelehnt ist. Dieses Beispiel zeigt auch, daß die Erweiterung von Komponenten um neue Eigenschaften
möglich ist.
Wird für den Katalog eine Datei-basierte Lösung gewählt, so ist die Konsistenz
beim gleichzeitigen Verändern der Dateien durch verschiedene Nutzer erst einmal
nicht gewährleistet. Ist dies erwünscht, so wäre dies durch das Werkzeug zur Wissenserfassung zu verwirklichen. Ein Teil der möglichen Probleme ließe sich auch
durch die Verwendung einer Versionsverwaltungsoftware wie CVS vermeiden.7 Der
Zugriff auf den Katalog von verschiedenen Arbeitsplätzen läßt sich durch die Trennung des Wissenserwerbs in eine zentrale Katalog-Komponente und verteilte Benutzerschnittstellen ermöglichen.
3.1.4 Beibehaltung des bestehenden Katalogs
Wird die bestehende Form des Komponentenkatalogs beibehalten, so entfällt die
Integration in das Konfigurationssystem. Diese Form wurde in SCO gerade deswegen gewählt, da sie sehr gut das Ressourcenmodell widerspiegelt und sich das
Bilanzierungsverhalten ausdrücken läßt.
Zwei Möglichkeiten, durch das Wissenserwerb-Werkzeug auf den bestehenden
Katalog zuzugreifen, sind denkbar: das Importieren der Dateien in ein PythonProgramm und das Parsen der Dateien.
Import der Dateien Die erste Variante, das Importieren der Dateien in ein
Python-Programm, wäre analog zur Ladeoperation in SCO (siehe 3.1.1). Danach
wären die in den Dateien definierten Klassen in einem assoziativen Feld enthalten. Über die darin gespeicherten Klassen-wertigen Objekten wären Informationen
über die jeweiligen Basisklassen (<Klassenobjekt>. bases ) und die in der
7
Die Benutzer würden dann lokale Kopien des Katalogs bearbeiten und diese danach in die Versionsverwaltung einbringen. Dabei würden sie auf gleichzeitig erfolgte Änderungen durch andere
Nutzer aufmerksam gemacht werden. Die Auflösung der Konflikte müßte jedoch per Hand erfolgen
und würde wieder Wissen über die Dateistruktur und Pythonsyntax erfordern.
31
3
Das Werkzeug zum Wissenserwerb
Klasse definierten Variablen und deren Werte (<Klassenobjekt>. dict ) ermittelbar.
Im Komponentenkatalog existieren in den verschiedenen Klassendefinitionen
unterschiedliche Arten der Festlegung von Klassen-Variablen. Zum einen werden
den Variablen Konstanten von elementaren Datentypen (in der Regel Zeichenketten) zugewiesen. Dabei handelt es sich um die Attribute, die zur Darstellung in der
Benutzerschnittstelle des Konfigurationssystems bzw. zum Erzeugen von Installationsanweisungen benötigt werden. Auch zusätzliche Eigenschaften von Komponenten würden so eingetragen werden. Der Wert dieser Variablen läßt sich leicht
durch <Klassenobjekt>.<Variable> ermitteln.
Zum anderen kommen als Klassenvariablen Listen von Instanzen anderer
Klassen vor. Das sind die Listen mit verbrauchten und bereitgestellten Ressourcen. Um welche Klassen es sich dabei jeweils handelt, ist ermittelbar
(<Instanz>. class ). Allerdings ist es nicht möglich, zu ermitteln, mit welchen Parametern diese Instanzen erzeugt wurden. Parameter werden z. B. bei der
Instantiierung von Numerischen Ressourcen (die Anzahl) sowie von Intervallressourcen benutzt. In diesen Fällen werden die Parameter nur in Variablen der Instanz abgelegt, aus denen sie sich ermitteln lassen. Es kann aber generell nicht
ausgeschlossen werden, daß später Ressourcen hinzugefügt werden, deren Instanzen auch parametrisiert werden. Um auch bei Instanzen dieser neuen Ressourcen
später feststellen zu können, mit welchen Werten sie erzeugt wurden, wäre eine
Konvention notwendig, nach der sich die Initialisierungsparameter ermitteln lassen. Es ist in Python üblich, die Klassenfunktion repr () so zu definieren, daß
sie einen Ausdruck zurückgibt, dessen Ausführung als Ergebnis eine Kopie der
Instanz liefern würde. Wenn für alle Ressourcen des Katalogs diese Funktion so
definiert wurde, lassen sich mit repr(<Instanz>) die Initialisierungsparameter
ermitteln.
Die Klassen für die Ressourcen haben weiterhin Variablen, die die MemberFunktionen der Klasse (das Bilanzierungsverhalten) beinhalten. Das Verhalten
dieser Funktionen wird in einer internen Darstellung, dem Bytecode, abgespeichert. Das Programm DECOMPYLE [Goe01] ist in der Lage, aus dem Bytecode wieder Quelltext zu generieren. Vom Autor wird das Programm allerdings als „work
in progress“ eingestuft. Versuche mit dem Bytecode, der aus den Dateien „resources.py“ und „components.py“ erzeugt wurde, liefern korrekten und mit dem
ursprünglichen Quelltext in der Funktion gleichenden Quelltext. Es wäre also möglich, den Quelltext zu den Klassenfunktionen innerhalb des Modellierungswerkzeuges zu erhalten.
Die in 3.1.1 angesprochenen Anweisungen, die außerhalb der Klassendefinitionen stehen können, werden beim Importieren ausgeführt. Ihr Quelltext läßt
sich auf diesem Weg nicht ermitteln und somit beim Abspeichern auch nicht wieder herstellen. Außerdem können diese Anweisungen Seiteneffekte haben, die das
Wissenserwerb-Werkzeug beeinflussen können.
Einer dieser Seiteneffekte ist, daß auch die von „ressources.py“ und „components.py“ importierten Module sowie alle davon abhängenden installiert sein
32
3.1
Alternative Komponentenkataloge
müssen. Für die Modellierung sind diese Module aber unerheblich und sollten nicht
benötigt werden.
Parsen der Katalogdateien Die andere Möglichkeit, aus dem WissenserwerbWerkzeug auf den bestehenden Katalog zuzugreifen, ist die des Parsens der Dateien. Hierfür gilt generell, was schon zum Parsen anderer Programmiersprachen
gesagt wird (Abschnitt 3.1.3).
3.1.5 Fazit
Alle der betrachteten Möglichkeiten erfüllen die in Abschnitt 3.1 angegeben harten
Kriterien. Sie lassen sich in das Konfigurationssystem integrieren, sie spiegeln das
Ressourcenmodell wider, die Bearbeitung durch ein Modellierungswerkzeug und
das Hinzufügen neuer Ressourcentypen ist möglich.8
RDBMS erlauben durch den intelligenten Einsatz von Sperrmechanismen die
parallele Wissenserfassung durch mehrere Anwender und den gleichzeitige Zugriff
durch Wissenserwerb und Konfigurationssystem auf den Katalog ohne zusätzlichen
Aufwand. Da in der Regel der Netzwerkzugriff auf RDBMS möglich ist, können die
Anwender auch von verschiedenen Rechnern aus die Wissenseingabe durchführen.
Die Erweiterung der Komponenten um neue Eigenschaften ist möglich.
RDBMS haben vergleichsweise hohe Anforderungen an die Hardwareausstattung und die Pflege und Installation. Der Aufwand zur Integration in das Konfigurationssystem läßt sich erst nach einer prototypischen Lösung abschließend beurteilen. Aufgrund der bestehenden Programmbibliotheken scheint er jedoch gering.
Die Vorteile eines RDBMS-basierten Katalogs wiegen die Nachteile nur für große
Kataloge mit vielen Komponenten auf, die häufig von verschiedenen Anwendern
gleichzeitig verändert werden sollen.
Die Verwendung einer anderen Beschreibungssprache stellt nur geringen Aufwand an die Hardwareausstattung, es werden zur Laufzeit keine zusätzlichen
Technologien benötigt. Die Erweiterbarkeit der Komponenten um neue Eigenschaften ist abhängig von der Sprache, ist aber bei geeigneter Wahl möglich. Die parallele Wissenserfassung wird nicht unterstützt und wäre durch das ModellierungsWerkzeug zu ermöglichen. Der Aufwand zur Integration in das Konfigurationssystem ist beim Einsatz von Parser-/Unparser-Generatoren gering.
Die Verwendung einer anderen Beschreibungssprache bietet allerdings keine
Vorteile gegenüber der bisherigen Lösung. Allein XML könnte, durch die Festlegung einer geeigneten DTD, zum Datentransfer zwischen verschiedenen (ressourcenorientierten) Konfigurationssystemen benutzt werden. Sollen auch Informationen über das Bilanzierungsverhalten von Ressourcen ausgetauscht werden, so ist
eine neutrale Notation dafür zu finden.
8
Für die Verhaltensbeschreibung der Ressourcen muß dabei u. U. auf eine Programmiersprache
zurückgegriffen werden.
33
3
Das Werkzeug zum Wissenserwerb
Wird der bestehende Katalog weiterverwendet, so entfällt der Aufwand für die
Integration in das Konfigurationssystem und die Umwandlung des Katalogs in ein
neues Format. Die Erweiterung von Komponenten um neue Eigenschaften ist in
diesem Katalog ohne weiteres möglich [Kun00]. Zur Laufzeit sind, außer einer
Python-Installation, keine weiteren Technologien notwendig, die Anforderungen an
die Hardware sind gering. Die Erfassung der Komponenten durch verschiedene Anwender an verschiedenen Arbeitsplätzen wäre bei dieser Katalogform gesondert zu
implementieren.
Sowohl die Verwendung eines RDBMS als auch des bestehenden KatalogFormates haben Vor- und Nachteile. Aufgrund des Aufwandes für die Installation
eines RDBMS wurde für den Prototypen des Werkzeugs die bestehende Katalogform weiterverwendet. Dabei wurde die Parser-Lösung verwendet, da auf dem anderen Weg nicht alle Informationen ermittelbar sind. Die Implementierung ist in
Abschnitt 3.4 beschrieben.
3.2
3.2.1
Techniken für Benutzerschnittstellen
Arten der Mensch-Rechner-Interaktion
Bei der Wissenserfassung durch das Werkzeug sind eine Reihe von Interaktionen
zwischen Nutzer und Programm notwendig. Dabei ist zu beachten, daß die Gestaltung dieser Interaktionen für den Benutzer nachvollziehbar ist. Die Gesamtheit
der möglichen Interaktionen wird Benutzungs- oder Benutzerschnittstelle genannt.
Theoretische Betrachtungen der Mensch-Rechner-Interaktionen sind ein Teilgebiet
der Forschung zu Mensch-Maschine-Systemen.
In der Literatur werden verschieden Arten von Mensch-Rechner-Interaktionen
betrachtet [BHO+ 88]:
Kommandotechnik Die Kommandotechnik erlaubt es dem Benutzer, Bearbeitungsfolgen aus einer Reihe von elementaren Kommandos zusammenzusetzen. Die
Kommandotechnik ist sehr flexibel und erlaubt gegebenenfalls Interaktionen, die
bei der Erstellung der Benutzungsschnittstelle nicht vorgesehen waren. Sie ist besonders für unstrukturierte Aufgaben geeignet. Falls der Benutzer die Kommandos im Gedächtnis gespeichert hat, ist der Zeitaufwand für das Ausführen einer
Aufgabe gering, da das Suchen auf dem Bildschirm nach der richtigen Interaktion
entfällt. Dagegen ist der Lern- und Gedächtnisaufwand sehr hoch. Das Erkennen
neuer Interaktionsmöglichkeiten (d. h. unbekannter Kommandos) ist nur schwer
möglich. Deshalb ist diese Interaktionsform nur für Experten und routinierte Benutzer angemessen. Die Wissenserfassung soll aber gerade auch Nichtexperten und
unerfahrenen Benutzern möglich sein. Aus diesem Grund ist diese Art der Benutzerinteraktion nicht oder nur als Ergänzung zu den anderen Interaktionsformen
für den Wissenserwerb geeignet.
34
3.2
Techniken für Benutzerschnittstellen
Menütechnik Bei der Menütechnik werden dem Benutzer Menüs mit Symbolen
oder Beschreibungen möglicher Aktionen angeboten, aus denen er auswählt. Vorteil der Menütechnik ist, daß das Gedächtnis im Vergleich zur Kommandotechnik
entlastet wird. Das Erkennen der möglichen Interaktionen ist sehr einfach. Durch
die Verwendung von z. B. Tastaturkürzeln ist eine Kombination mit der Kommandotechnik gut möglich. Ein Nachteil der Menütechnik ist, ein hoher Platzbedarf, da
alle möglichen Aktionen angezeigt werden müssen. Zur Anwendung kommt diese
Interaktionsart oft als Ersatz für die Kommandotechnik, wenn die Aktionen sich
vorher bestimmen lassen und ihre Zahl klein ist. Solche Aktionen sind in dem hier
betrachteten Anwendungsgebiet das Laden und Speichern des Modells, die Auswahl einer Komponente oder Ressource und der darauf auszuführenden Aktion
(Löschen, Kopieren usw.) sowie das Beenden der Arbeit mit dem Werkzeug.
Formulartechnik Die Formulartechnik ist Papierformularen nachempfunden. Der
Benutzer trägt in ihm dargebotene Formulare bestimmte Werte ein. Sie wird besonders dort eingesetzt, wo strukturierte Daten zu erfassen sind. Bei geeigneter
Gestaltung der Formulare bietet sie eine gute Benutzerführung und ist selbstbeschreibend. Bei der Wissenserfassung stellen die Namen der Komponenten und
Ressourcen solche strukturierten Daten dar. Für ihre Bearbeitung ist die Formulartechnik geeignet.
Direktmanipulation Mit Direktmanipulation werden Interaktionsformen bezeichnet, bei denen Benutzeraktionen direkte Veränderungen von Objekten auf dem
Bildschirm bewirken (z. B. Verschieben von Objekten mit einer Maus9 ). Die Direktmanipulation wird u. a. eingesetzt, wenn numerische Werte eingestellt werden
sollen (z. B. durch Darstellung als Schieberegler) oder sich die Veränderung von
Objekteigenschaften gut darstellen lassen. Auch das Auslösen von Aktionen durch
Ziehen von Objekten mit der Maus in vordefinierte Regionen – sogenanntes Drag
& Drop – ist eine Form der Direktmanipulation.
Da jede dieser Techniken ihre Vor- und Nachteile hat, treten in Programmen in
der Regel Kombinationen von ihnen auf [BHO+ 88].
3.2.2 Technische Möglichkeiten der Umsetzung
Bei Benutzerschnittstellen von Programmen, die auf Standard-PC’s arbeiten sollen, werden häufig die folgenden Techniken für Benutzerschnittstellen verwendet:
Textbasierte Benutzerschnittstellen Dies ist eine der ältesten Techniken für Benutzerschnittstellen. Hier erfolgt die Darbietung der Informationen durch das Programm ausschließlich in Form von Texten. Die Benutzerinteraktionen werden mittels Buchstabeneingabe auf einer Tastatur gesteuert. Diese Schnittstellen stellen
9
Streng betrachtet ist bei der Interaktion mit der Maus auch mindestens eine Indirektion vorhanden, da gedanklich die Mausbewegungen in die Ebene des Bildschirms projiziert werden müssen.
35
3
Das Werkzeug zum Wissenserwerb
geringe Anforderungen an die Hardware. Sie eignen sich gut für die Kommandotechnik. Auch die Menütechnik und Formulartechnik lassen sich einsetzen, wenn
mehrzeiliger Text möglich ist. Dagegen läßt sich Direktmanipulation nur schwer
umsetzen, da die Darstellung der zu manipulierenden Objekte schwierig ist.
Textbasierte Schnittstellen werden von vielen Benutzern als „veraltet“ empfunden.
Grafische Benutzerschnittstellen Unter diesem Begriff werden alle Benutzerschnittstellen zusammengefaßt, die außer Text noch weitere (grafische) Elemente
zur Darstellung nutzen. Neben der Tastatur kommt als Eingabegerät vor allem die
Maus zum Einsatz, durch die sich ein grafisches Zeiger-Objekt (der Mauszeiger)
mittels Direktmanipulation auf dem Bildschirm bewegen läßt. Aktionen werden in
der Regel durch Betätigen von Schaltern auf der Maus oder durch die Tastatur ausgelöst, wobei die Aktion oft von der Position des Mauszeigers mitbestimmt wird (d.
h. sie sind kontextsensitiv).
Zur Umsetzung solcher Benutzerschnittstellen existiert eine Vielzahl von
Programmbibliotheken, die verschiedene vordefinierte grafische Elemente zeichnen, die Mausbewegungen durch Bewegungen des Mauszeigers anzeigen sowie
Möglichkeiten der Verarbeitung von Eingaben durch Tastatur und Maus bieten.
Solche Programmbibliotheken sind bereits Teil einiger moderner Betriebssysteme,
bei anderen sind sie zusätzlich zu installieren.
WWW-basierte Schnittstellen So werden Benutzerschnittstellen bezeichnet, die
die Hypertext Markup Language (HTML) und das Hypertext Transfer Protocol (HTTP) benutzen. HTTP ist dabei das Netzwerkprotokoll, mit dem HTMLDokumente von einem Klienten (HTTP-Client) bei einem Anbieter (HTTP-Server)
angefordert und dann übermittelt werden. HTML erlaubt die Definition von Struktur und Inhalt von Textdokumenten, die Definition von Verweisen auf andere Dokumente sowie das Einbetten von Multimedia-Inhalten in die Dokumente. Die Darstellung der so definierten Inhalte übernehmen spezielle Programme – sogenannte
Browser. Neben der reinen Strukturbeschreibung bietet HTML auch Elemente, mit
denen sich die Darstellung bestimmen läßt. Dabei ist die Interpretation dieser Elemente dem Browser überlassen. Die Möglichkeiten der Benutzerinteraktion, die
mit HTML beschreibbar sind, sind das Verfolgen von Verweisen auf andere Dokumente und das Ausfüllen und Absenden von Formularen. Wie diese Interaktionen
ausgeführt werden, ist Browser-abhängig. Dabei können alle vier Techniken zum
Einsatz kommen.
Neben der Anzeige statischer Dokumente kann HTML auch dynamisch erzeugt
werden. Dabei werden die in Formularen eingetragenen Daten per HTTP übermittelt und bei der Erzeugung von HTML-Dokumenten benutzt. Dadurch kann eine
Benutzerschnittstelle in Formulartechnik mittels HTML erzeugt werden. Das in
Abschnitt 2.6 beschriebene System benutzt diesen Weg. Der Vorteil von HTMLbasierten Benutzerschnittstellen ist die Möglichkeit, aus einer Vielzahl von Be-
36
3.3
Aufbau des Werkzeuges
triebssystemen über das Internet die Anwendung benutzen zu können. Nachteil
ist, daß Direktmanipulation und Kommandotechnik nur begrenzt realisierbar sind.
Die Darstellung der HTML-Dokumente und damit der Benutzerschnittstelle variiert je nach Browser und Betriebssystem sehr stark. Außerdem existiert neben der
Benutzerschnittstelle der Anwendung immer auch die Benutzerschnittstelle des
Browsers, die in der Regel in ihrer Gestaltung zu ersterer nicht konsistent ist.
Es gibt Methoden, die Beschränkungen bezüglich der möglichen Benutzerinteraktionen zu durchbrechen. Das wird durch in das HTML-Dokument eingebettete
Programme erreicht, die auf Bibliotheken für grafische Benutzerschnittstellen zugreifen. Es gilt hier, was bereits zu grafischen Benutzerschnittstellen gesagt wurde.
Der Vorteil neben der Freiheit bei der Ausgestaltung der Benutzerschnittstelle ist
auch hier die Möglichkeit, das Programm aus der Ferne zu nutzen. Entscheidende
Nachteile sind die langen Wartezeiten bei schlechter Internetanbindung sowie der
Verlust von Betriebssystem- und Browserunabhängigkeit10 .
Beide Möglichkeiten für WWW-basierte Schnittstellen sind mit den genannten
Einschränkungen für den Wissenserwerb nur bedingt geeignet.
3.3
Aufbau des Werkzeuges
Sowohl bei den Betrachtungen zum Format des Komponentenkatalogs (3.1.5) als
auch zu den Benutzerschnittstellen (3.2.1) wurden mehrere mögliche Varianten erkannt. Davon wird jeweils eine in einem Prototyp des Wissenserwerb-Werkzeuges
umgesetzt. Um eine spätere Einbindung anderer Varianten zu ermöglichen, ist die
Entkoppelung von Katalogzugriff und Benutzerschnittstelle sinnvoll.
Für jeden Katalog müssen sowohl die Lade- als auch die Speicheroperation implementiert werden. Deshalb wurde eine von der Katalogform unabhängige Schnittstelle für diese Operationen definiert (Abbildung 3.1). Dabei wird eine
von der Katalogform unabhängige Beschreibung der Komponenten und Ressourcen durch die Klassen „Component“ und „Resource“ benutzt.
«interface»
Component
+name: string
+abstract: boolean
+provided: [Resource,string]
+consumed: [Resource,string]
+pythonCode: string
+bases: [Component]
Resource
ModelStore
+laden(): [Resource],[Component]
+speichern(ResList:[Resource],CompList:[Component])
PythonStore
Benutzerschnittstelle
+name: string
+bases: [Resource]
+pythonCode: string
Abbildung 3.1: Die Katalog-Schnittstelle
10
Viele dieser Programmpakete sind nicht für alle Browser vorhanden oder unterschiedlich umgesetzt. Andere müssen erst vom Benutzer heruntergeladen und installiert werden.
37
3
Das Werkzeug zum Wissenserwerb
Zwischen dem Laden und Speichern werden die Veränderungen des Katalogs
auf einer Arbeitskopie ausgeführt.11 Diese Operationen werden in dieser Abbildung der Benutzerschnittstelle zugeordnet. Bei näherer Betrachtung der Implementierung (3.5) läßt sich feststellen, daß innerhalb dieser „Benutzerschnittstelle“
nochmal eine Trennung zwischen den Operationen auf den Daten und deren Darstellung besteht.
Die Schnittstelle zwischen Katalog-Komponente und Benutzerschnittstelle wurde im Prototypen als Python-Klasse (ModelStore) realisiert, da beide Teile auch
in Python geschrieben wurden. Die Klasse PythonStore, in der der eigentliche
Zugriff auf den bestehenden Katalog umgesetzt wird, ist eine Spezialisierung von
ModelStore.
«interface»
ModelStore
+laden(): [Resource],[Component]
+speichern(ResList:[Resource],CompList:[Component])
CORBAStore
PythonStore
Benutzerschnittstelle
Katalog
CORBA-Katalog
Abbildung 3.2: Integration eines CORBA-basierten Katalogs
Soll der Katalogzugriff in einer anderen Programmiersprache umgesetzt werden oder ist die Verteilung von Katalog und Benutzerschnittstelle auf verschiedene
Rechner gewünscht, so ist die Verwendung einer CORBA-Schnittstelle zwischen
Benutzerschnittstelle und Katalog sinnvoll. Dazu würde eine Python-Klasse, die
Spezialisierung von ModelStore ist, die CORBA-Schnittstelle kapseln. In Abbildung 3.2 ist diese Klasse mit CORBAStore bezeichnet.
3.4 Implementierung des Katalogzugriffs
Als Programmiersprache für den Katalogzugriff wird Python [vR00] benutzt. Python ist eine objektorientierte Skriptsprache, mit der eine Reihe von Bibliotheken
(Module) für verschiedene Aufgaben mitgeliefert werden. Die schnelle Implementierung von Prototypen war eines der Hauptziele beim Entwurf der Sprache. Diese
Sprache hat den Vorteil, das bereits ein Parser-Modul existiert, das Syntax-Bäume
aus Python-Quelltext generiert. In den folgenden beiden Abschnitten werden die
Details der Informationsgewinnung aus den Pythondateien des Katalogs und die
Generierung von Python-Quelltext näher beschrieben.
11
Das entspricht auch der Arbeitsweise anderer gängiger Programme, z. B. von Office-Paketen.
38
3.4
Implementierung des Katalogzugriffs
3.4.1 Informationsgewinnung aus den Pythondateien
Die Verarbeitung des Komponentenkatalogs erfolgt durch die Python-Klasse
PythonStore, die die ModelStore-Schnittstelle implementiert (Abschnitt 3.3).
Um aus den Pythondateien die Informationen über den Komponentenkatalog zu gewinnen, wird das Python-Modul parser benutzt. Dieses gehört zu jeder Standardinstallation von Python und bietet eine Schnittstelle zum Python-internen Parser,
der in C implementiert ist.12
Die beim Parsen erzeugten Objekte vom Typ ASTType lassen sich in eine Listenoder Tupelrepräsentation umwandeln. Die Listenrepräsentation eines SyntaxBaumes (ebenso die eines Teilbaumes) beginnt mit einer numerischen Konstante,
die den Typ des Wurzelknotens beschreibt, sowie den Listenrepräsentationen der
Teilbäume. Auf diese Weise werden die Syntax-Bäume als vielfach verschachtelte
Listen widergegeben. Die Blätter des Baums bestehen aus Konstanten für den Typ
der Terminale sowie einer Zeichenkette13 . Die Lexik und Syntax von Python ist
im „Python Reference Manual“ [vR00] beschrieben. Die folgende Liste enthält als
Beispiel den Syntaxbaum der Anweisung print ’a’.14
[file input, [stmt, [simple stmt, [small stmt, [print stmt,
[NAME, ’print’], [test, [and test, [not test, [comparison,
[expr, [xor expr, [and expr, [shift expr, [arith expr,
[term, [factor, [power, [atom, [STRING, "’a’"]]]]]]]]]]]]]]]],
[NEWLINE, ’’]]], [ENDMARKER, ’’]]
Die Klasse PythonStore verarbeitet diese Listenrepräsentation der geparsten Pythondateien. Daraus werden in der Funktion reduce() die Informationen über den Katalog gesammelt. Das soll am Beispiel von findCompDef()
erläutert werden. Die Funktion findCompDef() sucht in einem Syntaxbaum
nach Teilbäumen mit Klassendefinitionen. Jeder dieser Teilbäume beginnt mit:
[stmt, [compound stmt, [classdef,. . .
Wird in findCompDef() festgestellt, daß die übergebene Liste diesem Muster genügt, so wird der Teilbaum, der mit [classdef, beginnt, an die Funktion addComponent() übergeben.15 Diese ermittelt daraus die Eigenschaften einer
Komponente. Anstelle dieses Teilbaums wird ein Platzhalter eingefügt, der später
12
Einige Informationen zu der Verwendung des Moduls findet sich in der „Python Library Reference“
[vRDJ00].
13
z. B. dem Namen eines Bezeichners
14
Die numerischen Werte der Konstanten wurden durch ihre symbolischen Namen aus den PythonModulen „symbol“ und „token“ ersetzt.
15
Es wäre ausreichend, im Syntaxbaum nach [classdef. . . zu suchen, was aber eine höhere Zahl
von Rekursionen erfordern würde.
39
3
Das Werkzeug zum Wissenserwerb
beim Wiederherstellen der Pythondateien benutzt wird.
def findCompDef(self, List):
if type(List) == ListType:
if len(List) > 1 \
and List[0] == symbol.stmt \
and List[1][0]== symbol.compound stmt \
and List[1][1][0] == symbol.classdef:
self. addComponent(List[1][1])
return 1,List
else:
for i in range (1, len(List)):
(a, s) = self. findCompDef(List[i])
if a:
List[i] = comp def
else:
List[i] =s
return 0,List
return 0,List
Beginnt die momentan bearbeitete Liste nicht mit [stmt, [compound stmt,
[classdef, so wird findCompDef() rekursiv auf die Elemente der Liste angewendet. Auf diese Weise wird der gesamte Syntaxbaum abgeschritten. Dieser
Aufwand ließe sich reduzieren, wenn Einschränkungen bezüglich der Struktur der
Datei „components.py“ gemacht würden.
Die Funktion addComponent ermittelt die Basisklassen der Komponente. Hier
wird von der Annahme ausgegangen, daß dort nur ein Tupel von Bezeichnern
steht. Python erlaubt aber an dieser Stelle beliebige Ausdrücke, die als Ergebnis
Klassen-Objekte liefern [vR00]. Soll dies unterstützt werden, so ist die Funktion
findbasesComp() entsprechend anzupassen.
def addComponent(self, Tuple):
.
.
.
if Tuple[4][0] == symbol.testlist:
bases = self. findbasesComp(Tuple[4])
i = 7
else: i = 4
if Tuple[i][0]== symbol.suite :
abstract,provided,consumed,Tuple[i]=self. findconsumed2(Tuple[i])
Die weiteren Eigenschaften der Komponente werden in der Funktion
findconsumed2() ermittelt. Dies geschieht wieder durch rekursives Abgehen des Syntaxbaumes und Suchen nach der für Zuweisungen typischen Struktur
[stmt, [simple stmt, [small stmt, [expr stmt . . .
Die gefundenen Zuweisungen werden dann dahingehend untersucht, ob es
sich um Zuweisungen an die bekannten Eigenschaften von Komponenten handelt
40
3.4
Implementierung des Katalogzugriffs
(consumes, provides, abstract). Je nach Eigenschaft wird dann der Syntaxbaum, der die rechte Seite der Zuweisung beschreibt, ausgewertet. Dabei werden
folgende vereinfachende Annahmen über die Klassendefinitionen in der Komponentendatei getroffen16 :
1. Auf der linken Seite der Zuweisungen stehen nur die Bezeichner.
2. Auf der rechten Seite von provides= und consumes= steht eine Liste der
Art
[<Ressourcenname>,("<Wert>")].
3. Auf der rechten Seite von abstract= steht der Wert 1, falls die Komponente
abstrakt ist oder ein anderer Wert falls nicht.
Die Teile des Syntaxbaumes, die diesen Zuweisungen entsprechen, werden entfernt.
Was nach der Abarbeitung von findconsumed2() in dem Syntaxbaum noch
vorhanden ist, enthält allen zusätzlichen Quelltext innerhalb der Klassendefinition. Er wird durch den Unparser, der in 3.4.2 beschrieben ist, wieder in seine
textuelle Repräsentation umgewandelt. Abschließend wird eine Instanz der Klasse
Datatypes.Component erzeugt, in der die gewonnenen Daten gespeichert werden.
t = Tuple[i][3:−1]
Code =""
for t2 in t:
u = unparser.Unparser()
s = u.astlist2str(t2)
Code = Code + s
comp = Component(name, bases, provided, consumed, abstract,Code)
self.Components[name]=comp
Die Ermittlung der Ressourcen und ihrer Eigenschaften aus dem Syntaxbaum
der Datei „resources.py“ geschieht auf vergleichbare Weise durch die Funktionen
findResDef(), addResource() und findbasesRes(). Hierbei wird der gesamte Quelltextblock innerhalb der Klassendefinition wieder in seine Textrepräsentation umgewandelt.17
3.4.2 Erzeugung der Pythondateien des Katalogs
Die Erzeugung der Pythondateien geschieht in zwei Schritten. Zuerst werden zwei
Syntaxbäume generiert, die diesen Dateien entsprechen. Danach werden diese
Bäume durch einen Unparser in Quelltext umgewandelt und in die Dateien geschrieben.
16
17
Diese Annahmen treffen für den Beispielkatalog von SCO zu.
Denkbar ist, den Quelltext in die Definitionen der Funktionen init (), must balance at(),
provider for(), consume(), unconsume() und exhausted(), die in Abschnitt 2.4 beschrieben
sind, zu zerlegen.
41
3
Das Werkzeug zum Wissenserwerb
Erzeugung der Syntaxbäume
Die Erzeugung der Syntaxbäume erfolgt in der Funktion expand() der Klasse
PythonStore. Dabei werden die durch reduce() um die Klassendefinitionen reduzierten Syntaxbäume wieder erweitert. Als erstes wird nach der Stelle in den
Syntaxbäumen gesucht, an welcher der von reduce() eingetragene Platzhalter
erstmalig auftritt. Dieser erste Platzhalter wird durch einen Teilbaum ersetzt,
der durch die Funktionen getCompList() bzw. getResList() erzeugt wird.
Alle weiteren Platzhalter werden entfernt. Die eingehängten Teilbäume entsprechen der Folge von Klassendefinitionen in den Pythondateien „components.py“ bzw.
„resources.py“. Die Erzeugung dieser Teilbäume soll hier anhand der Funktion
getResList() kurz aufgezeigt werden. Diese Funktion ist für den Teilbaum mit
den Klassendefinitionen der Ressourcen zuständig.
Zuerst werden die Ressourcen, die in einem assoziativen Feld gespeichert sind,
so sortiert, daß die Basisklassen vor den von ihnen erbenden stehen.18
def getResList(self):
.
.
.
sorted res=self.order Resources()
Für jede Ressource der sortierten Liste wird ein Teilbaum generiert, der einer Python-Klassendefinition entspricht.
for res in sorted res:
res tree = [symbol.stmt,
[symbol.compound stmt,
[symbol.classdef,
[token.NAME, "class"],
[token.NAME, res.name]]]]
Falls die Ressource Basisklassen hat, so wird ein Teilbaum für die Notation dieser
durch get bases() erzeugt und dem Ergebnisbaum hinzugefügt.
bases = get bases(res)
if bases :
for b in bases: res tree[1][1].append(b)
Falls kein Python-Quelltext für die Ressource definiert ist, wird ein Syntaxbaum
eingefügt, der der Python-Anweisung pass, die leere Quelltextblöcke kennzeichnet,
18
Zyklen werden dabei nicht erkannt und führen zu Fehlverhalten des Programms.
42
3.4
Implementierung des Katalogzugriffs
entspricht.
if not (res.pythonCode):
res tree[1][1].append([symbol.suite,
[token.NEWLINE, ’’],
[token.INDENT, ’’],
[symbol.stmt,
[symbol.simple stmt,
[symbol.small stmt,
[symbol.pass stmt,
[token.NAME, ’pass’]]],
[token.NEWLINE, ’’]]],
[token.DEDENT, ’’]])
result.append(res tree)
Wenn dagegen Quelltext existiert, so wird dieser geparst (mit Hilfe des parserModuls) und das Ergebnis benutzt. Dieses wird mit [suite, [NEWLINE,’’],
[INDENT,’’]. . . [DEDENT,’’]] umgeben, da der Quelltext innerhalb einer Klassendefinition stehen soll.
else:
tree2 = [symbol.suite,
[token.NEWLINE, ’’],
[token.INDENT, ’’]]
tree2.append( get Code(res.pythonCode))
tree2.append([token.DEDENT, ’’])
res tree[1][1].append(tree2)
result.append(res tree)
Die Erzeugung des Syntaxbaumes für die Komponentendefinitionen verläuft
analog.
Der Unparser
Nach dem die Syntaxbäume generiert wurden, werden diese in Quelltext umgewandelt. Dazu wurde ein allgemeiner Unparser für Python-Syntaxbäume19 entwickelt.
Dessen Funktionsweise soll im folgenden umrissen werden.
Bei der Quelltextgenerierung wird die Tatsache genutzt, daß zu jedem Terminal
im Baum auch eine Zeichenkettenrepräsentation abgelegt ist. Eine Aneinanderreihung dieser Zeichenketten ergibt einen dem Original sehr ähnlichen Text, wenn für
das Terminal NEWLINE ein Zeilenumbruch erzeugt wird.
Problematisch ist die Einrückung der Zeilenanfänge. Diese sind in Python signifikant, da Anweisungen durch die Tiefe ihrer Einrückung gruppiert werden: alle
Anweisungen eines Blockes haben die gleiche Einrückungstiefe. Daher ist es beim
Unparsen wichtig, die Hierarchie der Einrückungen wiederherzustellen.
19
Syntaxbäume, die den vom Parser-Modul gelieferten entsprechen
43
3
Das Werkzeug zum Wissenserwerb
Der Beginn eines neuen Blocks wird im Syntaxbaum durch das Terminal INDENT angezeigt, das Ende durch DEDENT. Die naheliegende Lösung, beim Auftreten eines INDENT einen Zähler zu erhöhen, bei DEDENT diesen wieder zu verringern und nach jedem Zeilenumbruch dem Zähler entsprechend einzurücken20 ,
ist nicht ausreichend. Grund dafür ist, daß am Ende eines Blockes erst das NEWLINE auftritt und dann das DEDENT, wodurch die nächste Anweisung, die schon
nicht mehr zum Block gehört, wie der Block – also falsch – eingerückt wird.
Im Unparser wird dieses Problem gelöst, indem neben den Blättern (den Terminalen) auch die Struktur des Baumes berücksichtigt wird. Dabei wird der gesamte
Baum abgeschritten.
def unparse(self, List):
if isinstance(List, ListType):
if sym name.has key(List[0]):
if List[0] == stmt:
s= "\n" + " " *self.indent + self. unparse(List[1])
return s
Vor jeder Python-Anweisung wird ein Zeilenumbruch und die Einrückung ausgegeben. Wenn direkt zuvor ein Block endete, ist die Einrückung hier korrekt, da das
DEDENT schon verarbeitet wurde.
elif List[0] == suite:
sl = map(self. unparse, List[1:])
return string.join(sl,’’)+"\n"+" "*self.indent
else:
sl = map(self. unparse, List[1:])
return string.join(sl,’’)
Bei einem anderem Nichtterminal wird die Funktion unparse() rekursiv aufgerufen. NEWLINE wird ignoriert, da der Zeilenumbruch schon behandelt wird.
Ist ein Terminalsymbol ein Bezeichner (NAME), so wird nach dem Namen noch
ein Leerzeichen ausgegeben, um zu verhindern, daß aufeinanderfolgende Bezeichner ohne Trennzeichen aufeinanderfolgen. Von allen anderen Terminalen wird die
Zeichenkette ausgegeben (z. B. Klammern, Operatoren usw. ).
else:
if tok name.has key(List[0]):
if List[0] == NEWLINE:
return ’’
elif List[0] == DEDENT:
self.indent = self.indent − 1
return ’’
20
Diese Idee entstammt einer Nachricht in der Newsgroup „comp.lang.python“.
44
3.5
Implementierung der grafischen Benutzerschnittstelle
elif List[0] == INDENT:
self.indent = self.indent + 1
return ’’
elif List[0] ==NAME:
return List[1]+’ ’
return List[1]
3.5
3.5.1
Implementierung der grafischen Benutzerschnittstelle
Die Schnittstellenbibliothek GTK+
Die Auswahl von Bibliotheken zur Erstellung von grafischen Benutzerschnittstellen ist groß. Für das Modellierungswerkzeug fiel die Entscheidung zugunsten der
Bibliothek GTK+.21 Dabei waren folgende Eigenschaften ausschlaggebend:
• GTK+-Programme lassen sich durch entsprechende Erweiterungen in einer
Vielzahl von Programmiersprachen erstellen. So z. B. ADA95, C++, Dylan,
Eiffel, Guile, Haskell, JavaScript, Objective C, Pascal, Perl und Python
[GTK00].22 Besonders letzteres ist hier von Interesse, da bereits andere Faktoren für die Verwendung von Python sprachen. (siehe 3.4)
• GTK+ existiert für eine Vielzahl von UNIX-Systemen sowie MS W INDOWS.
Portierungen nach MacOS [Mac00] und BeOS [BeO00] sind im Entstehen.
• Die Darstellung aller GTK+-Programme auf einem Rechner ist einheitlich.
Durch das Verwenden sogenannter Themen („Themes“) kann es an die Benutzerwünsche angepaßt werden.
• Die Lizenz von GTK+ (GNU LGPL) erlaubt die kostenlose Entwicklung und
Verbreitung von GTK+-Programmen. Die Quelltexte sind offen zugänglich
und erlauben so guten Einblick in die interne Arbeitsweise der Bibliothek.
GTK+ beinhaltet eine Reihe von Fenster-Elementen (sogenannten Widgets), die
zur Erzeugung von grafischen Benutzerschnittstellen nützlich sind. Das reicht von
einfachen Widgets wie Beschriftungen, Schaltern oder Trennstrichen bis zu komplexen wie Fenstern für die Farb- oder Dateiauswahl.
Wenn hier von GTK+ die Rede ist, so ist eigentlich die Kombination von drei
Software-Bibliotheken gemeint:
21
Das Kürzel GTK steht für „GIMP Toolkit“, da die Bibliothek ursprünglich für das Programm GIMP
(Gnu Image Manipulation Program), ein Open-Source Bildbearbeitungsprogramm, entwickelt wurde. GTK+ wird aber in zunehmendem Maße auch für andere Softwareprojekte und Programme benutzt. Als größtes dieser Projekte ist die Entwicklung der Desktop-Umgebung GNOME [GNO00]
zu nennen.
22
Ein Ansatz zur Verwendung von GTK+ in Java-Programmen ist in iX 1/2001 [Lud01] beschrieben.
45
3
Das Werkzeug zum Wissenserwerb
GLib (G Library) ist eine Bibliothek, die verbesserte und sicherere Alternativen zu
einigen Systemrufen, einige Datentypen, wie doppelt verkettete Listen oder
Zeitnehmer, sowie Funktionen zum Speichermanagement und zur Fehlerbehandlung bereitstellt. Obwohl diese Bibliothek zusammen mit GTK+ entwickelt wurde, ist sie inzwischen auch ohne GTK+ einsetzbar.
GDK Die Bibliothek GDK (GIMP Drawing Kit) kapselt alle Aufrufe von Funktionen
der XLib des X Window Systems aus der GTK+-Bibliothek.23
GTK Die eigentliche GTK+-Bibliothek: In ihr sind alle Widgets sowie Funktionen
zur Behandlung von Ereignissen wie z. B. Benutzereingaben enthalten. Auf
sie wird im Anschluß noch näher eingegangen.
Bei der Entwicklung von GTK+ wurde ein objektorientierter Ansatz verfolgt.
Da für die Implementierung die Programmiersprache C24 verwendet wurde, die ursprünglich keine Mittel für objektorientiertes Programmieren bereitstellt, werden
einige Hilfskonstrukte benutzt. So wird für jedes Widget sowohl eine Datenstruktur für die jeweilige Klasse als auch für die Instanzen definiert. Die Benennung der
Klassenstruktur folgt dem Muster: Gtk<WidgetName>Class, die der Instanzen
Gtk<WidgetName>. Erster Bestandteil der Datenstruktur ist immer die Struktur der Basisklasse (die Klasse, deren Spezialisierung diese Klasse ist), bzw. der
dazugehörigen Instanz. Dadurch wird eine Vererbung der Datenstruktur von der
Basisklasse auf die abgeleitete Klasse erreicht.
Auch die Eigenschaft der Polymorphie wird damit gewährleistet, d.h. ein Zeiger auf eine Instanz einer abgeleiteten Klasse kann anstelle eines Zeigers auf die
Instanz einer Basisklasse verwendet werden.25 Danach folgen die Attribute der
Klasse bzw. der Instanzen.
Die Zuordnung von Funktionen zu Widgetklassen erfolgt nur über den Namen.
Dabei wird folgendes Schema benutzt: gtk <widgetname> <funktionsname().
Handelt es sich um eine Funktion, die auf einer Instanz der Klasse arbeitet, ist der
erste Parameter immer ein Zeiger auf diese Instanz.26 Auf Grund der oben dargestellten Polymorphie kann es auch ein Zeiger auf eine Instanz einer abgeleiteten
Klasse sein. Dadurch wird die Vererbung von Funktionen erreicht [Pen99].
Zu jeder Klasse existiert mindestens ein Konstruktor (mit dem Namen
gtk <widgetname> new()), eine Funktion, die Instanzen dieser Klasse erzeugt.
Zu einigen Widgets sind auch parametrisierte Konstruktoren vorhanden.
23
Das gilt natürlich nur für Systeme, die das X Window System benutzen. Auf anderen Plattformen,
wie MS-Windows oder BeOS, werden die vergleichbaren Bibliotheken gekapselt.
24
Die Entscheidung gegen C++ zugunsten von C wurde laut Havoc Pennington [Pen99] aus einer Vielzahl von Gründen getroffen, u.a. Vorliebe der Autoren, bessere Standardisierung und Verbreitung
von C im UNIX-Umfeld.
25
Wie Rolf Herzog [Her98] anführt, gilt dies nur, wenn der Compiler die Elemente in der Reihenfolge
im Speicher ablegt, in der sie deklariert werden.
26
Zur Laufzeit wird überprüft, ob die übergebenen Instanz einer Klasse angehört, für die die Funktion definiert ist.
46
3.5
Implementierung der grafischen Benutzerschnittstelle
Ein weiteres wichtiges Konzept von GTK+ ist das der Ereignisse27 . Durch Ereignisse wird ein GTK+-Programm über Benutzerinteraktionen informiert. Nach
dem Aufruf von gtk main() durchläuft das Programm eine Schleife, die erst durch
gtk mainquit() wieder beendet wird. Innerhalb dieser Schleife wird jedesmal,
wenn eine Benutzereingabe (per Maus oder Tastatur) erfolgt, ein Ereignis ausgelöst. Wenn vom Programmierer mittels gtk signal connect() Funktionen (sogenannte Callback-Funktionen) mit dem Ereignis verbunden wurden, so werden
diese jetzt aufgerufen.
Außer durch Benutzerinteraktionen können Ereignisse auch durch das Programm selber erzeugt werden und so die Kommunikation zwischen Programmteilen ermöglichen. Das geschieht durch Aufruf von gtk signal emit().
3.5.2 GTK+ -Programme mit Glade
Die Erstellung von komplexen Oberflächen ist oft sehr aufwendig, da eine Vielzahl
von Widgets erstellt und initialisiert werden und in die sie umgebenden Widgets
eingebettet werden muß.28 Besonders das Festlegen von Eigenschaften der Widgets, wie z.B. Größe oder Positionierung, erfordert wiederholtes Testen.
Um dieses Problem zu umgehen, wurden spezielle Werkzeuge entwickelt, sogenannte GUI-Builder. Mit ihnen lassen sich grafische Benutzeroberflächen leicht erzeugen. Dabei wird das spätere Aussehen der Oberfläche mit der Maus konstruiert.
In der Regel wird dann daraus Quelltext einer Ziel-Programmiersprache und ZielOberflächenbibliothek generiert, dessen Ausführung eine Oberfläche genau diesen
Aussehens erzeugt. Außerdem werden oft auch Programmfragmente für das Verhalten bei Benutzerinteraktionen erzeugt. Diese müssen dann vom Programmierer
ausgefüllt werden. Es existiert eine Vielzahl solcher Werkzeuge für verschiedene
Oberflächenbibliotheken und Programmiersprachen.
Auch für GTK+ gibt es mehrere solcher Werkzeuge [GTK00]. Von diesen wurde Glade [GLA] ausgewählt, da es den ausgereiftesten Eindruck machte und keine
Abhängigkeiten von anderen Technologien vorhanden sind. Glade bietet neben der
Ansicht der Ziel-Oberfläche (Abbildung 3.3) und einer Palette von Widgets (Abbildung 3.4), wie sie typisch für Werkzeuge dieser Art sind, noch eine Baumansicht
der Widgets (3.5) und einen Editor für die Widget-Eigenschaften (Abbildung 3.6).
Neben der Generierung von Quelltexten für verschiedene Programmiersprachen (C, C++, ADA95, Perl und Eiffel) gibt es noch eine weitere Möglichkeit, mit
Glade erzeugte Oberflächen in Programme einzufügen: das Initialisieren von Oberflächen aus den sie beschreibenden Projektdateien des Glade-Werkzeuges29 durch
die Bibliothek libglade [Hen00a]. Auf die einzelnen Widgets kann über Namen,
27
In Dokumentationen zu GTK+ ist in diesem Zusammenhang oft von Signalen die Rede. Um diese
vom Konzept der Signale von Unix-Betriebssystemen zu unterscheiden, wird in dieser Arbeit statt
dessen der Begriff Ereignisse verwendet.
28
Auch bei den Widgets eines GTK+-Programms besteht eine Enthaltensein-Hierarchie.
29
Diese sind wohlgeformte XML-Dokumente (Abschnitt 3.1.3) und deshalb u. U. auch von Hand zu
erzeugen und zu bearbeiten.
47
3
Das Werkzeug zum Wissenserwerb
Abbildung 3.3: Konstruiertes Fenster
Abbildung 3.4: Widget-Palette von Glade
Abbildung 3.5: Widget-Baum
Abbildung 3.6: Widget-Eigenschaften
die ihnen mit dem Glade-Werkzeug verliehen wurden, zugegriffen werden. Danach
können diese ebenso benutzt und verändert werden, wie andere GTK+-Widgets
auch.
3.5.3
Grafische Benutzerschnittstellen mit PyGtk
PyGTK [Hen00b] ermöglicht die Verwendung von GTK+ in Python-Programmen.
Dabei werden die GTK+-Konstrukte und -Konzepte in die entsprechenden Pythonkonzepte abgebildet. Jedes Widget wird durch eine eigene Python-Klasse repräsentiert. Dabei werden die Namen in der Form Gtk<WidgetName> beibehalten.
Python ermöglicht als objektorientierte Sprache die direkte Zuordnung von Funktionen zu Klassen. Deshalb entfällt der Präfix der Funktionsnamen, der in GTK+
den Namen der Klasse repräsentiert.
48
3.5
Implementierung der grafischen Benutzerschnittstelle
Die Klassen und ihre Funktionen sind in der Datei „gtk.py“30 definiert. In
„GTK.py“ und „GDK.py“ sind diverse numerische Konstanten festgelegt, die auch
mit ähnlichen Namen (mit Präfix GTK bzw. GDK) auch in GTK+ und GDK definiert
sind.
Auch die Verwendung von Glade-generierten Oberflächen ist mittels PyGTK
möglich. Dazu wird der Weg der Generierung der Oberflächen mit libglade benutzt. Die Erzeugung von Python-Quelltext aus Gladedateien war zu dem Zeitpunkt, als es für diese Arbeit benötigt wurde, noch nicht möglich.31 Um libglade zu
benutzen, muß die Datei „libglade.py“ importiert werden. In ihr werden die Klasse
GladeXML sowie einige Hilfsfunktionen definiert.
Mittels g=libglade.GladeXML(Gladedatei) werden alle Widgets, die in
der Glade-Datei beschrieben sind, initialisiert. Widgets, die mit dem GladeWerkzeug „sichtbar“ gesetzt wurden, werden jetzt angezeigt. Beim Aufruf
von g=libglade.GladeXML(Gladedatei,Widgetname) wird nur der Teil des
Widget-Baumes erzeugt, dessen Wurzel das übergebene Widget ist.32 Durch den
Aufruf von g.get widget(Widgetname) kann jetzt auf die verschiedenen Widgetinstanzen zugegriffen und diese benutzt werden.
3.5.4
Implementierungsdetails der Benutzerschnittstelle
Die Benutzerschnittstelle des Modellierungswerkzeuges setzt sich aus mehreren
Fenstern für verschiedene Aufgaben zusammen. Bis auf eine Ausnahme, auf die
später noch eingegangen wird, wird für alle Fenster libglade benutzt. Dabei wird
für jedes Fenster eine separate Glade-Datei verwendet. Neben den Klassen für die
benötigten Fenster existiert eine weitere Klasse, die die gesamte WissenserwerbAnwendung repräsentiert. Letztere benutzt Instanzen der Fensterklassen und
führt alle Operationen durch, die Veränderungen des Komponentenkatalogs verursachen. Die Eigenschaften der Klassen sind im folgenden näher beschrieben.
Die Klasse CompModel
Dies ist die Anwendungsklasse, sie beinhaltet jeweils eine Instanz der Fensterklassen:
• ResListWindow: die Liste der Ressourcen,
• CompListWindow: die Liste der Komponenten,
• ResEditWindow: zum Editieren einer Ressource und
30
Die Datei „GTKinter.py“, auf die in der Literatur [vLF00] verwiesen wird, existiert nur noch aus
Gründen der Kompatibilität mit älteren Versionen. Bei einem Import wird eine Warnung ausgegeben, die auf „gtk.py“ verweist.
31
Inzwischen ist mit GladePyC [Gla00] auch diese Möglichkeit vorhanden.
32
Widgetname ist der Name des Widgets, der mit Glade festgelegt wurde, nicht der Name der Widgetklasse.
49
3
Das Werkzeug zum Wissenserwerb
• CompEditWindow: zum Editieren einer Komponente.
Die Klasse CompModel erwartet bei der Initialisierung eine Implementierung der
ModelStore-Schnittstelle (Abschnitt 3.3). Über diese wird dann auf einen Komponentenkatalog zugegriffen. Da in der Modellierungsanwendung oft Komponenten und Ressourcen über ihre Namen referenziert werden, werden zum Speichern
dieser zwei assoziative Felder verwendet, die die Namen der jeweiligen Ressource/Komponente als Zugriffsschlüssel haben. Zu diesen Schlüsseln ist das zugehörige Objekt der Klasse Component bzw. Resource, die in Abschnitt 3.3 beschrieben
wurden, abgespeichert.
Neben den Fensterinstanzen und Datenfeldern bietet diese Klasse noch Funktionen, die Veränderungen des Modells ermöglichen. Zu diesen Veränderungen
zählt das Laden bzw. Speichern des Modells sowie das Löschen, Editieren, Erzeugen und Kopieren von Ressourcen und Komponenten. Die Funktionen zum Laden
und Speichern des Modells (load() und store()) rufen die entsprechenden Funktionen der ModelStore-Instanz auf.
Ein Problem, das bei der Arbeit mit GTK+ oft auftritt, ist, daß nach dem Anzeigen eines Fensters der Programmfluß unterbrochen werden soll, bis das Fenster geschlossen wird.33 Wird ein Fenster innerhalb einer Funktion erzeugt, so gibt GTK+
nach dem Anzeigen des Fensters die Kontrolle an das erzeugende Programm zurück. Dieses fährt dann sofort an der Stelle im Programm fort, an der das Fenster
erzeugt wurde. Soll die Ausführung unterbrochen werden, ist nach der Erzeugung
des Fensters die Kontrolle explizit an GTK+ zu übergeben. Das geschieht entweder,
in dem ein Ruf von gtk.mainloop() erfolgt, der durch gtk.mainquit() zu beenden ist, der die Callback-Funktion, mit deren Ausführung das Programm gerade
beschäftigt ist, beendet wird. Um an der gewünschten Stelle in der Programmlogik fortzufahren, sind geeignete Callbacks für das Schließen des neuen Fensters
notwendig. Sollen andere Fenster in der Zwischenzeit nicht auf Eingaben reagieren, so ist das neue Fenster als „modal“ einzustellen. (Durch Glade oder Aufruf von
GTKWindow.set modal(GTK.true))
Ein Beispiel, wo dieses Verfahren zur Anwendung kommt, ist das Kopieren von
Komponenten. Wenn der Benutzer das Kopieren einer Komponente in dem Fenster der Klasse CompListWindow auswählt, so wird in der zugehörigen CallbackFunktion die Funktion copy comp() der Klasse CompModel gerufen.
Zuerst wird die Komponente mit dem übergebenen Namen aus dem Feld aller
Komponenten gesucht, eine Kopie angelegt und diese in das Feld eingefügt:
def copy comp(self,CompName):
OldComp = self.CompList[CompName]
NewCompName = "Kopie_von_" + CompName
NewComp = Component(NewCompName,OldComp.bases, OldComp.provided, \
OldComp.consumed,OldComp.abstract, OldComp.pythonCode)
self.CompList[NewCompName]=NewComp
33
GNOME erlaubt es, dies mit relativ einfachen Mitteln zu erreichen. Im Rahmen dieser Arbeit wird
jedoch darauf verzichtet, um keine weitere Technologie-Abhängigkeit einzuführen [GNO00].
50
3.5
Implementierung der grafischen Benutzerschnittstelle
Jetzt werden alle Komponenten ausgewählt, die Spezialisierungen der Ursprungskomponente waren. Wenn diese Liste nicht leer ist, soll ein Fenster mit einer Checkliste angezeigt werden. In dieser kann der Benutzer auswählen, welche Komponenten nunmehr Spezialisierung der neuen Komponente sein sollen. Bei der Initialisierung des Fensters wird die Funktion für die zweite Phase des Kopierens
übergeben. Näheres zu diesem Fenster findet sich im Abschnitt über die Klasse
CheckListWindow. An dieser Stelle ist nur von Bedeutung, daß beim Schließen
des Auswahlfensters die hier übergebene Funktion aufgerufen wird.
List=[ ]
for c in self.CompList.values():
if CompName in c.bases:
List.append(c.name)
if List:
Text = "Welche der Komponenten soll Spezialisierung der " + \
"neuen Komponente sein statt wie bisher von " + CompName
CheckWin=CheckListWindow(Text,"Kopie einer Komponente",
List,self.copy comp stage2,NewCompName,CompName)
else:
self.copy comp stage2([ ],(NewCompName,CompName))
Falls die Liste nicht leer ist, übernimmt GTK+ nach Ende der Funktion
copy comp() die Kontrolle und zeigt jetzt das Auswahlfenster an.34 Ist die Liste
leer, wird gleich mit der zweiten Phase fortgefahren.
In der zweiten Phase des Kopierens (copy comp stage2) werden für die Komponenten, die im Fenster ausgewählt wurden, die zu kopierende Komponente als
Basisklasse aus- und die Kopie eingetragen. Danach wird das Fenster zum Editieren der kopierten Komponente angezeigt.
def copy comp stage2(self, List, args):
NewCompName= args[0]
CompName = args[1]
for n in List:
c = self.CompList[n]
c.bases.remove(CompName)
c.bases.append(NewCompName)
self.edit comp(NewCompName)
Das Kopieren von Ressourcen funktioniert auf ähnliche Weise, erfordert jedoch
zusätzliche Phasen, da noch zwei weitere Fenster angezeigt werden. In diesen kann
jeweils aus der Liste der Komponenten, die die kopierte Ressource verbrauchen
bzw. bereitstellen, ausgewählt werden.
Auch das Löschen von Ressourcen und Komponenten erfolgt in zwei Phasen,
wobei in der ersten ein Bestätigungsfenster erzeugt wird und in der zweiten die
eigentliche Löschung erfolgt.
34
Das gilt nur unter der Voraussetzung, daß mit dem Ende dieser Funktion auch die übergeordnete
Callback-Funktion beendet wird. Ansonsten wird erst mit dieser fortgefahren.
51
3
Das Werkzeug zum Wissenserwerb
Mit edit res() und edit comp() wird das Fenster zum Ändern der Ressource bzw. Komponente geöffnet und die übergebene Ressource/Komponente hineingeladen. Wurden die Eigenschaften einer Komponente in diesem Fenster geändert,
so wird von dort edit comp ok() aufgerufen. Dadurch werden die Änderungen
dann in die lokale Kopie des Katalogs übernommen. Falls der Name geändert wurde, werden alle Referenzen auf den alten Namen in anderen Komponenten in den
neuen geändert. Bei einer Namensänderung einer Ressource muß zusätzlich für alle Komponenten, die diese Ressource bereitstellen oder verbrauchen, die Referenz
geändert werden.
Die Klasse CheckListWindow
An mehreren Stellen des Werkzeuges werden Fenster benötigt, in denen eine Entscheidungsfrage für mehrere gleichartige Objekte gestellt wird. Solche Fenster werden durch die Klasse CheckListWindow realisiert. Ein Fenster dieser Klasse besteht aus dem Text der Frage und einer Folge von Schaltern mit Beschriftungen.
Mit diesen Schaltern läßt sich vom Benutzer dann einstellen, ob die Frage für die
Beschriftung gilt.35 Abbildung 3.7 zeigt ein Beispiel für dieses Fenster.
Abbildung 3.7: Beispiel von CheckListWindow
Zur Initialisierung der Fenster (durch Aufruf von init ()) werden der Text
der Abfrage, der Titel des Fensters, eine Liste der Beschriftungen für die Schalter, eine Funktion, die nach Schließen des Fensters abgearbeitet werden soll, sowie
zusätzliche Argumente für diese Funktion übergeben.
def
init (self,Text,Title,CheckLabelList,Func,*Args):
self.Win=gtk.GtkWindow(gtk.WINDOW DIALOG,Title)
self.Win.set wmclass("","CompModel")
self.Win.set modal(gtk.TRUE)
self.VBox=gtk.GtkVBox(3)
self.VBox.set homogeneous(gtk.FALSE)
self.Win.add(self.VBox)
35
Dies ist eine Umsetzung der Formulartechnik analog zum Ankreuzen auf Papierformularen.
52
3.5
Implementierung der grafischen Benutzerschnittstelle
self.Label=gtk.GtkLabel(Text)
self.Label.set line wrap(gtk.TRUE)
self.ButtonBox=gtk.GtkVButtonBox()
for label in CheckLabelList:
button = gtk.GtkCheckButton(label)
self.ButtonBox.pack start(button)
self.OkButton=gtk.GtkButton("Ok")
self.VBox.pack start(self.Label)
self.VBox.pack start(self.ButtonBox)
self.VBox.pack start(self.OkButton)
self.OkButton.connect("clicked",self.ok)
Dieses Fenster wird, im Gegensatz zu den anderen der Anwendung, nicht aus
einer Glade-Datei erzeugt, sondern aus den einzelnen Widgets konstruiert. Der
Grund dafür ist, daß sich das Aussehen dieses Fensters zum Teil nicht vorher
festlegen läßt36 . Obwohl es sich um ein relativ einfaches Fenster handelt, ist der
Aufwand dafür schon hoch. Noch größer wäre er, wenn versucht würde, alle Eigenschaften, die mit Glade normalerweise gesetzt werden, anzupassen. Hier wird der
Vorteil der Erzeugung von Oberflächen durch Werkzeuge sichtbar.
Um zu verhindern, daß andere Benutzerinteraktionen in der Zwischenzeit erfolgen, wird das Fenster als „modal“ eingestellt, d. h. alle anderen Fenster der Anwendung reagieren nicht auf Benutzereingaben solange dieses Fenster geöffnet ist.
Nach dem Schließen des Fensters wird die Funktion aufgerufen, die bei der Initialisierung übergeben wurde. Sie erhält als erstes Argument eine Liste der Beschriftungen von denjenigen Schaltern, die eingeschaltet wurden. Weitere Argumente
werden übergeben, sofern diese bei der Initialisierung des Fensters verwendet wurden.
Die Klasse ResListWindow
Die Fenster dieser Klasse zeigen die Liste aller bekannten Ressourcen an.37 Außerdem sind Knöpfe zum Hinzufügen, Editieren, Kopieren und Löschen von Ressourcen vorhanden. Eine Abbildung dieses Fensters befindet sich im Anhang A.3 auf
Seite 64.
Für die Initialisierung wird die Instanz von CompModel übergeben, die dieses Fenster erzeugt hat. Dies ist notwendig, da die Datenhaltung von der Klasse
36
Mit einem Kunstgriff ließe sich auch dieses Fenster mit Glade erzeugen: An der Stelle, an der
die Liste von Schaltern im Fenster stehen soll, wird eine Liste mit einem unsichtbaren Schalter
eingefügt. Später werden dann die eigentlichen Schalter hinzugefügt.
37
Die Ressourcen, die in CompModel.toHide eingetragen sind, werden nicht mit angezeigt. Hintergrund ist, daß dies die Basistypen für die gezählten Ressourcen, Strukturressourcen usw. sind. Sollen diese auch von Benutzern verändert werden können, so ist CompModel.toHide entsprechend
zu ändern.
53
3
Das Werkzeug zum Wissenserwerb
CompModel übernommen wird und alle Aktionen, die sich auf das Modell auswirken, dort erfolgen.
Die Funktion row select() dient als Callback für das Selektieren eines Eintrags in der Liste. Bei einem Doppelklick wird die Ressource editiert, ansonsten
werden die Knöpfe zum Kopieren, Editieren und Löschen sensitiv d. h. aktivierbar.
def row select(self,*args):
if args[3]:
if args[3].type == gtk.GDK. 2BUTTON PRESS:
text= self.ResList.get text(args[1],0)
self.mainClass.edit res(text)
else:
self.CopyButton.set sensitive(gtk.TRUE)
self.DelButton.set sensitive(gtk.TRUE)
self.EditButton.set sensitive(gtk.TRUE)
Durch row unselect() werden dagegen diese Knöpfe wieder deaktiviert. Erfolgt eine Veränderung der Ressourcen in CompModel, so wird dort die Funktion
refresh list() dieses Fensters aufgerufen und dadurch die Änderungen im Fenster sichtbar.
Fenster der Klasse CompListWindow ähneln in Funktion und Aussehen stark
den Fenstern dieser Klasse. Ihre Benutzung ist im Anhang A.1 beschrieben.
Die Klasse ResEditWindow
Mit dieser Klasse werden Fenster zum Editieren von Ressourcen erzeugt. In diesen Fenstern besteht die Möglichkeit, den Namen der Ressource zu ändern, Ressourcen zur Liste der Basis-Ressourcen hinzuzufügen oder aus dieser zu entfernen
sowie den Python-Quelltext zu ändern. Außerdem werden ein Knopf zur Bestätigung sowie einer zum Zurücksetzen auf die Ausgangswerte angezeigt (Abbildung
A.9 auf Seite 65). Die Gestaltung dieses Fensters ist eine Kombination aus Menüund Formulartechnik. Die Gliederung gleicht einem Papierfomular, der Name und
der Quelltext sind frei änderbar. Das Eintragen der Basisklassen erfolgt dagegen in
Menütechnik, da die Möglichkeiten hier durch die Menge der bekannten Ressourcen beschränkt sind.
Neu gegenüber der bisherigen Vorgehensweise bei der Erzeugung von Fenstern
sind folgende Zeilen:
def
.
.
.
init (self,mainClass):
self.ResBases.connect ("select_row",
self.row select,self.DelBasesButton)
self.ResBases2.connect("select_row",
self.row select,self.AddBasesButton)
54
3.5
Implementierung der grafischen Benutzerschnittstelle
self.ResBases.connect ("unselect_row",
self.row unselect,self.DelBasesButton)
self.ResBases2.connect("unselect_row",
self.row unselect,self.AddBasesButton)
Hier wird bei der Festlegung der Callbacks ein zusätzliches Argument benutzt, das
beim Ruf der Callback-Funktion mit übergeben werden soll. Das erlaubt es, mehrere Callbacks mit gleicher Funktionalität auf unterschiedlichen Daten zusammenzufassen. Am Beispiel von row select() wird das deutlich.
def row select(self,*args):
if args[0].selection:
args[−1].set sensitive(gtk.TRUE)
Der Wert von args[0] ist die Liste38 , in der das Ereignis "select_row" auftrat. Mit args[−1] wird das letzte Argument abgefragt. Dies ist das ButtonWidget, das weiter oben beim Aufruf von connect() benutzt wurde. Dieser Knopf
wird durch row select() aktiviert. Dadurch wird gewährleistet, daß bestimmte
Knöpfe nur benutzbar sind, wenn ein Listeneintrag zur Bearbeitung ausgewählt
wurde.
Die Callback-Funktion hide() versteckt das Fenster, zerstört es aber nicht.
Durch edit res() wird die übergebene Ressource in das Fenster geladen und dieses wieder angezeigt.
def edit res(self,Res):
.
.
.
for r in self.mainClass.AllResList.keys():
if r in Res.bases:
self.ResBases.append([r])
else:
self.ResBases2.append([r])
self.ResCode.freeze()
Der Aufruf von freeze() verhindert, daß der Bereich für den Python-Quellcode
neugezeichnet wird, während er mit Text gefüllt wird. Nach dem Aufruf von
thaw() werden alle Änderungen mit einem Mal sichtbar.
self.ResCode.delete text(0,−1)
self.ResCode.insert defaults(Res.pythonCode)
self.ResCode.thaw()
self.Win.show()
Nach Betätigung des Ok-Knopfes wird die Funktion eval res() aufgerufen.
An dieser Stelle können Plausibilitätüberprüfungen der Eingaben eingefügt werden. Bisher wird nur bei einer Namensänderung eine Bestätigung eingeholt.
Anschließend werden in edit ok() die Eigenschaften der Ressource aus den
einzelnen Teilen des Fensters gewonnen. Diese werden dann dem Aufruf von
CompModel.edit res ok() übergeben.
38
das GTK+-Widget CList
55
3
Das Werkzeug zum Wissenserwerb
Die Klasse CompEditWindow
Das Fenster zum Ändern der Komponenten ähnelt in Aussehen und Verhalten sehr
stark dem zum Ändern von Ressourcen. Zusätzlich vorhanden sind ein Schalter um
festzulegen, ob die Komponente abstrakt ist (siehe 2.2), sowie Listen und Knöpfe
zum Hinzufügen und Entfernen von verbrauchten bzw. bereitgestellten Ressourcen.
Wie schon im Fenster zum Ändern von Ressourcen haben alle ListenWidgets eine gemeinsame Callback-Funktion für das Auswählen von Zeilen:
row select(). Für die Listen mit Ressourcen, die in der aktuellen Einstellung
verbraucht/bereitgestellt werden, existiert eine zweite Callback-Funktion, die bei
einem Doppelklick ein neues Fenster vom Typ ModDialogWindow öffnet. In diesem kann dann der Parameter für die Ressource eingetragen werden.39
Die Callbacks für die Knöpfe zum Hinzufügen/Entfernen haben alle ein ähnliches Verhalten. Der Unterschied beim Hinzufügen von Ressourcen gegenüber dem
von Basiskomponenten ist, daß dieselbe Ressource mehrmals hinzugefügt werden
kann. Hier wäre sicherlich ebenfalls ein Zusammenfassen der Funktionen möglich.
Die Funktionen edit comp(), eval comp() und edit ok() arbeiten auf vergleichbare Weise wie ihre Entsprechungen in der Klasse ResEditWindow.
39
Wünschenswert wäre es, diese Parameter in der Liste direkt einzutragen. Das ließe sich das einfach
realisieren, wenn GTK+ es gestatten würde, in Zellen innerhalb einer Liste (GtkCList) beliebige
andere Widgets (z. B. GtkEntry zum Ändern von einzeiligem Text) einzubetten. Dies ist für spätere
Versionen von GTK+ auch geplant.
56
4 Ausblick
In der vorliegenden Arbeit wird die nachträgliche Erweiterung eines Konfigurationssystems um ein Werkzeug zum Wissenserwerb beschrieben. Dabei lag der
Schwerpunkt darauf, die grundsätzliche Machbarkeit zu zeigen und Lösungsansätze zu zeigen. Bei dem entwickelten Werkzeug handelt es sich darum nur um
einen (funktionsfähigen) Prototypen.
Um vom Prototypen zu einem fertigen Produkt zu kommen, sind weitere Untersuchungen zur Gestaltung der Benutzerschnittstelle durchzuführen. Dabei sind
z. B. die Punkte Aufgabenangemessenheit, Selbstbeschreibungsfähigkeit, Erwartungskonformität, Steuerbarkeit und Fehlerrobustheit zu untersuchen. Besonders
die Fehlerrobustheit wurde im Prototypen wenig berücksichtigt. Es erfolgen nur
wenige Plausibilitätsüberprüfungen der Benutzereingaben. Die Implementierung
des Prototypen erlaubt aber das einfache Einfügen solcher Überprüfungen. Durch
die Verwendung von Glade bei der Konstruktion der Benutzerschnittstelle ist zumindest eine Umgruppierung der Fenster-Bestandteile einfach.
Das Werkzeug erlaubt momentan nicht, den Katalog gleichzeitig durch verschiedene Nutzer zu bearbeiten. Soll dies ermöglicht werden, so ist die Veränderung der
Architektur oder die Verwendung eines Relationalen Datenbank Management Systems zu erwägen.
57
Anhang
58
A Benutzerhandbuch des Wissenserwerb-Werkzeuges
Sehr geehrter Nutzer, bei dem folgenden, kurzen Benutzerhandbuch wird davon
ausgegangen, daß Sie bereits mit den theoretischen Hintergründen des Ressourcenorientierten Konfigurieren vertraut sind. Nähere Informationen finden Sie im
ersten Teil dieser Arbeit (Abschnitt 1.3).
In diesem Teil wird beschrieben, welche Möglichkeiten Sie haben, mit dem
Werkzeug den Komponentenkatalog zu verändern. Die Benutzerschnittstelle des
Modellierungswerkzeuges besteht im wesentlichen aus vier Fenstern. Ihr Aufbau
und ihre Benutzung wird in den folgenden Abschnitten näher erläutert. Das Aussehen der Fenster kann auf Ihrem Rechner von den Abbildungen abweichen.
A.1 Das Hauptfenster
Wenn Sie das Werkzeug zur Wissenserfassung starten, so erscheint als erstes das
Hauptfenster (Abb. A.1). Mit dem Schließen des Fensters wird auch die Anwendung
beendet.
Abbildung A.1: Das Hauptfenster des Werkzeuges mit einer selektierten Komponente
60
A.1
Das Hauptfenster
Dieses Fenster besteht aus einer Menüleiste, einer Leiste mit Schaltern und der
Liste aller im Katalog vorhandenen Komponenten (Abbildung A.1).
Abbildung A.2: Das Katalog-Menü
Abbildung A.3: Einblenden der Ressourcen
Die Menüleiste beherbergt eine Menü mit Aktionen, die den gesamten Komponentenkatalog betreffen (Abb. A.2), sowie ein weiteres, um das Fenster mit den
Ressourcen ein- und auszuschalten (Abb. A.3).
Im Katalog-Menü können Sie den Katalog laden und speichern. In der momentanen Version werden die Dateien „resource.py“ und „component.py“, die im selben
Verzeichnis liegen, in dem das Werkzeug gestartet wurde, als Katalog verwendet.
Die Auswahl anderer Dateien ist momentan nicht möglich. Außerdem können Sie
in diesem Menü auch die Arbeit mit dem Werkzeug beenden. Die Aktionen die im
Katalog-Menü enthalten sind, können Sie auch durch Tastaturkürzel initiieren:
<Strg>l1 zum Laden, <Strg>s zum Speichern und <Strg>q zum Beenden. Diese
Tastaturkürzel funktionieren, solange dieses Fenster den „Tastaturfokus“2 hat.
Unterhalb der Menüleiste finden Sie eine Schalterleiste mit Knöpfen zum Erzeugen einer neuen Komponente und zum Löschen, Ändern und sowie Kopieren
vorhandener Komponenten. Die letzten drei Knöpfe sind nur benutzbar, wenn eine
Komponente aus der Liste ausgewählt ist.
Abbildung A.4: Anlegen einer neuen Komponente
Der Schalter „Neue Komponente“ läßt ein Fenster erscheinen, das Sie nach dem
Namen der Komponente fragt (Abb. A.4). Solange dieses Fenster sichtbar ist, reagieren andere Fenster nicht auf Eingaben. Nach Schließen dieses Fensters mit dem
„Übernehmen“-Knopf erscheint die neue Komponente in der Liste der Komponenten im Hauptfenster.
Sie können mit der Maus eine Komponente aus der Liste auswählen. Wenn Sie
die Eigenschaften der ausgewählten Komponente verändern wollen, so können Sie
1
2
gleichzeitiges Betätigen der „Strg“- bzw. Ctrl“-Taste und des Buchstaben „l“
Das heißt, alle Tastendrücke werden an dieses Fenster gesendet. Das Umschalten des „Tastaturfokus“ ist abhängig von der Umgebung, in der Sie das Werkzeug betreiben
61
A
Benutzerhandbuch des Wissenserwerb-Werkzeuges
das mit dem „Komponente ändern“-Schalter oder einem Doppelklick auf die Komponente. Danach erscheint das Fenster zum Ändern von Komponenten (siehe A.2).
In diesem können dann die Eigenschaften der ausgewählte Komponente verändert
werden.
Durch „Komponente löschen“ wird nach einer Sicherheitsabfrage die ausgewählte Komponente aus dem Katalog entfernt.
Wenn Sie „Komponente kopieren“ auswählen, erscheint das Änderungsfenster
mit einer Kopie der ausgewählten Komponente. Der Name wird nach dem Muster Kopie_von_<alterName>gebildet. Falls andere Komponenten Spezialisierungen der kopierten Komponente sind, wird zuvor ein Fenster angezeigt, in dem ausgewählt werden kann, welche von diesen Komponenten statt dessen Spezialisierung der Kopie sein sollen (Abb. A.5).
Abbildung A.5: Kopieren einer Komponente
A.2 Das Fenster zum Ändern von Komponenten
In diesem Fenster (Abb. A.6) können Sie die Eigenschaften einer Komponenten
verändern.
Oben links befindet sich ein Eingabefeld für den Namen der Komponente. Daneben ist ein Ein-/Aus-Schalter. Wenn der Schalter eingeschaltet ist, bedeutet das,
daß es sich um eine abstrakte Komponente handelt. Abstrakte Komponenten3 können in keiner Konfiguration benutzt werden sondern fassen nur die gemeinsamen
Eigenschaften von einander ähnlichen Komponenten zusammen. Sie können den
Zustand dieses Schalters einfach per Mausklick verändern.
Den Hauptteil des Fensters nehmen drei Reihen mit jeweils zwei Listen und
zwei Schaltern dazwischen ein. Dabei beinhalten die linken Listen die aktuell eingestellten Eigenschaften der Komponente (von oben nach unten: die Basiskomponenten4 , die von der Komponente verbrauchten Ressourcen und die bereitgestellten Ressourcen). In den Listen auf der rechten Seite sind die möglichen Werte für
diese Eigenschaften enthalten. Mit den Schaltern zwischen den Listen können Sie
Einträge aus den rechten zu den linken Listen hinzufügen und wieder entfernen.
3
4
auch Komponentenkategorien genannt
Komponenten, von denen die bearbeitete eine Spezialisierung ist
62
A.2
Das Fenster zum Ändern von Komponenten
Abbildung A.6: In diesem Fenster werden die Eigenschaften von Komponenten verändert
Wenn Sie aus der Liste der möglichen Basiskomponenten eine zu den aktuellen Eigenschaften hinzufügen, wird diese aus der rechten Liste entfernt, da das nochmalige Hinzufügen der selben Komponente zu den Basiskomponenten nicht möglich
ist. Anders hingegen bei den Listen der verbrauchten/bereitgestellten Ressourcen.
Diese können durchaus mehrmals hinzugefügt werden (z. B. mit verschiedenen Parametern).
Abbildung A.7: Parameter einer Ressource
Wenn Sie die Parameter von bereitgestellten oder verbrauchten Ressourcen verändern wollen, so können sie das durch einen Doppelklick auf die Spalte mit der
Ressource in der entsprechenden Liste auf der linken Seite erreichen. Dadurch wird
ein separates Fenster geöffnet, in dem dieser Parameter eingegeben werden kann
(Abb. A.7). Welche Werte dabei sinnvoll sind, hängt von der Art der Ressource ab.
Momentan erfolgt keine Überprüfung der Werte.
Im unteren Teil des Änderungsfensters wird Ihnen eventueller zusätzlicher
Python-Quelltext zu der Komponente angezeigt. Dazu gehören z. B. die Festlegung
weiterer Eigenschaften der Komponente. Diesen Quelltext sollten Sie nur ändern,
63
A
Benutzerhandbuch des Wissenserwerb-Werkzeuges
wenn Sie mit der Programmiersprache Python sowie der Arbeitsweise des Konfigurationssystems vertraut sind. Das Kapitel 2 gibt eine kleine Einführung in letzteres.
Sind Sie mit den Veränderungen der Komponente zufrieden, so können Sie diese
mit einem Knopfdruck („Ok“) in den Katalog übernehmen.5 Mit dem „Rückgängig“Knopf stellen Sie den Ausgangszustand beim Öffnen des Fensters wieder her.
A.3 Die Liste der Ressourcen
Abbildung A.8: Liste der Ressourcen
Dieses Fenster (Abb. A.8) ähnelt in seinem Aufbau dem Hauptfenster (Abschnitt
A.1). Unter einer Leiste mit vier Schaltern wird Ihnen die Liste der Ressourcen angezeigt. Auch die Aktionen, die Sie mit den Knöpfen aktivieren, gleichen denen des
Hauptfensters. Statt Komponenten werden hier nur Ressourcen erzeugt, gelöscht,
kopiert oder verändert.
Wenn Sie eine Ressource kopieren, so sucht das Werkzeug alle Komponenten
heraus, die diese Ressource verbrauchen oder bereitstellen. Es fragt Sie dann danach, welche dieser Komponenten statt dessen die Kopie verwenden sollen.
Sie können das Fenster mit der Ressourcenliste jederzeit mit dem Knopf am
unteren Rand schließen.
5
Bei einer Umbenennung der Komponente erfolgt noch eine Sicherheitsabfrage.
64
A.4
A.4
Ändern von Ressourcen
Ändern von Ressourcen
Die Eigenschaften einer Ressource können Sie in diesem Fenster bearbeiten. Ein
großer Teil dieser Eigenschaften wird durch den Python-Quelltext im unteren Teil
des Fenster bestimmt. Dieser sollten Sie allerdings nur verändern, wenn Sie sich
über die Funktionsweise des Konfigurationssystems im klaren sind. Ansonsten
können Sie nur den Namen der Ressource verändern und festlegen, von welchen
Ressourcen diese eine Spezialisierung sein soll. Durch das Betätigen des „Ok“Knopfes übernehmen Sie die Veränderungen.
Abbildung A.9: Fenster zum Ändern der Eigenschaften einer Ressource
65
B Ausgewählte Dateien
B.1 Dateien aus dem Projekt Service Composition
B.1.1
Schnittstelle des Konfigurationssystem – composer.idl
#pragma prefix "hu-berlin.de"
module SCO {
//Component category names
const string OperatingSystem = "OperatingSystem";
const string Hardware = "Hardware";
const string BasicHardware = "BasicHardware";
const string ExternHardware = "ExternHardware";
const string Service = "Service";
const string Software = "Software";
const string RuntimeEnvironment = "RuntimeEnvironment";
const string ServiceSurround = "ServiceSurround";
const string Product = "Product";
// Domain container component names
const string Provider = "Provider";
const string CPE = "CPE";
// Component container
const string Computer = "Computer";
};
module Composer{
interface
interface
interface
interface
typedef
typedef
typedef
typedef
typedef
Component;
ComponentDesc;
Configuration;
ServiceTemplate;
sequence<Component> ComponentList;
sequence<ComponentDesc> CDList;
sequence<ServiceTemplate> STList;
sequence<string> StringList;
unsigned long ComponentID;
exception UnknownComponent{};
exception Unresolvable {
};
exception NotExisting{};
exception NotEmpty{};
exception Unsortable{
ComponentList best effort;
};
interface Description{
string describe(in string what)
raises(NotExisting);
66
B.1
Dateien aus dem Projekt Service Composition
};
//A ComponentDesc describes similar components
interface ComponentDesc:Description {
string name();
string gui definition();
ComponentDesc super ();
CDList variants();
Component create();
};
//A Component represents an instance of a component description.
interface Component:Description{
ComponentDesc description ();
ComponentID instance();
Component container();
ComponentList contained();
ComponentList sorted contained()raises(Unsortable);
void add( in Component comp )raises(Unresolvable);
// Remove component from container. Returns true on success
boolean remove( in ComponentID comp );
// Return a list of all components that could fit into this component
// without conflict, and can be used to satisfy required resources in
// for the named service template
CDList components for template ();
};
// A service template serves as a starting point for a new
// configuration
interface ServiceTemplate:Description{
string name();
string gui definition();
};
//The repository knows all components providing a certain
//resource, and can create instances of a named component.
interface ComponentRepository{
Configuration new configuration();
Configuration configuration for template(in ServiceTemplate template);
Configuration load configuration(in string category, in string config);
ComponentDesc find component(in string name)raises(UnknownComponent);
void debug(in string message);
long debug level(in long newlevel); // returns old debugging level
// Return a list of service template category names
StringList service categories();
// Return a list of service templates per category
STList service templates(in string category);
// Return a list of categories
StringList configuration categories ();
// Return a list of configurations in a category
StringList configurations (in string config category);
// Delete existing configurations
void delete configuration( in string category, in string toBeDeleted )
raises(NotExisting);
void delete category( in string categoryName )
raises(NotEmpty, NotExisting);
};
67
B
Ausgewählte Dateien
//A configuration is a set of components.
interface Configuration{
ComponentList selected();
Component root();
void add(in Component new)raises(Unresolvable);
void remove(in ComponentID old);
ComponentList unbalanced components();
// Filtering not needed anymore
// CDList proposed components( in ComponentDesc filter );
// CDList needed components( in ComponentDesc filter );
void save(in string category, in string config);
// Return a list of configuration names under which the components
// in this configuration have been collectively tested
StringList tested in ();
// Return the template that the configuration is based on
ServiceTemplate template();
};
// GUI callback
interface Terminate{
oneway void endSession();
};
interface TINARepository:ComponentRepository, Terminate{
void register callback(in Terminate cb);
};
// Factory callback
interface TINACallback:Terminate{
void callback (in ComponentRepository repo,
in Object session);
string user();
};
};
B.1.2
Pythondateien des Komponentenkatalogs
components.py
Um eine übersichtlichere und kürzere Darstellung zu erreichen, wurden die Installationsanweisungen der meisten nun folgenden Komponenten entfernt.
# $Id: components.py,v 1.16 1999/11/26 16:39:41 loewis Exp $
from SCOSupport import *
from resources import *
# Categories
class Software(Component):
consumes = [InComputer()]
abstract = 1
class OperatingSystem (Software):
abstract = 1
class Hardware(Component):
abstract = 1
68
B.1
Dateien aus dem Projekt Service Composition
class BasicHardware (Hardware):
provides = [InComputer()]
consumes = [InDomain()]
abstract = 1
class Service (Component):
consumes = [InComputer()]
abstract = 1
class ServiceSurround(Component):
consumes = [InComputer()]
abstract = 1
class RuntimeEnvironment(Component):
consumes = [InComputer()]
abstract = 1
class Product(Software):
abstract = 1
class Domain(Component):
provides = [InDomain()]
abstract = 1
# Domains
class Provider(Domain):
info = "resources/provider.txt"
icon48 = "images/NeXT-WS.gif"
provides = [ProviderSide()]
class CPE(Domain):
info = "resources/cpe.txt"
icon48 = "images/Workstation.gif"
provides = [CustomerSide()]
# Network nodes
# Even though this does not consume anything,
# it is intended to go into Domains only
class Computer(BasicHardware):
icon48 = "images/Workstation.gif"
info = "resources/computer.txt"
provides = [Processor()]
# Operating systems
class WindowsNT (OperatingSystem):
icon48 = "images/nt-floppy.gif"
info = "resources/winnt.txt"
name = "Windows NT"
provides = [Win32()]
consumes = [Processor()]
class Windows98 (OperatingSystem):
icon48 = "images/98-floppy.gif"
info = "resources/win98.txt"
name = "MS Windows 98"
provides = [Win32()]
consumes = [Processor()]
class MacOS (OperatingSystem):
69
B
Ausgewählte Dateien
name = "MacOS 8.5"
info = "resources/macos85.txt"
icon48 = "images/mac-floppy.gif"
provides = [MacABI()]
consumes = [Processor()]
class Solaris (OperatingSystem):
name = "Sun Solaris"
consumes = [Processor()]
class Solaris25 (Solaris):
name = "Sun Solaris 2.5.1"
info = "resources/empty.txt"
icon48 = "images/sun-floppy.gif"
provides = [SolarisABI25()]
class Solaris26 (Solaris):
name = "Solaris 2.6"
info = "resources/empty.txt"
icon48 = "images/sun-floppy.gif"
provides = [SolarisABI26()]
# XXX MvL: Sollte gtar/gzip nicht Teil des Installationsprozesses
# selbst sein?
install = """
<component name="OS">
<location format="dir">/vobs/Tina/tina96/installer/repository/sunos-5.6</location>
<packagedir>sunos</packagedir>
</component>
<component name="Gzip">
<location format="dir">/vobs/Tina/tina96/installer/repository/gzip-sol26</location>
<packagedir>gzip</packagedir>
</component>
"""
#Runtime Environment, CPE side
class TestJar (Service):
icon48 = "images/java-floppy.gif"
name = "Java Test Services"
info = "resources/testServices.txt"
provides = [TTest1()]
consumes = [TinaJava(), Java((1,1,5)), Swing((1,0,1))]
install = """
"""
class PAJar (ServiceSurround):
name = "Java Provider Agent"
info = "resources/pa.txt"
icon48 = "images/pa-floppy.gif"
provides = [TinaJava()]
consumes = [Java((1,1,5)), CorbaJava("VisiBroker")]
class ProductsJar (Product):
info = "resources/javaProducts.txt"
icon48 = "images/java-floppy.gif"
name = "Java Products Package"
provides = [CorbaJava("VisiBroker"), Swing((1,0,1))]
consumes = [Java((1,1,5))]
# Runtime Environment, Provider Side
70
B.1
Dateien aus dem Projekt Service Composition
class DPEComponent Sol26(RuntimeEnvironment):
consumes = [ProviderSide(), CorbaService("osagent"),
CorbaService("Naming"),SolarisABI26(),DPEBootstrap()]
class FokusPlatform(RuntimeEnvironment):
name = "Platform"
provides = [DPE()]
consumes = [CorbaService("TheServer"), CorbaService("V-Sub-Server"),
CorbaService("V-Ass-Server"),CorbaService("V-TM-Server"),
CorbaService("OLS-Server"),CorbaService("PRF-Server"),
CorbaService("CF-Server")]
class DPECore(RuntimeEnvironment):
name = "Misc. Platform Support"
consumes = [ProviderSide(),SolarisABI26(),CorbaService("Versant")]
provides = [DPEBootstrap()]
install = """
<component name="MWP base">
<location format="dir">/vobs/Tina/tina96/installer/repository/mwp-base</location>
<packagedir>mwp-base</packagedir>
</component>
<component name="launcher">
<location format="dir3>/vobs/Tina/tina96/installer/repository/perl-launcher</location>
<packagedir>perl-launcher</packagedir>
</component>
<component name="config">
<location format="dir">/vobs/Tina/tina96/installer/repository/perl-config</location>
<packagedir>config</packagedir>
</component>
"""
class TheServer Sol26 (DPEComponent Sol26):
name = "Access Session for Solaris 2.6"
provides = [CorbaService("TheServer")]
class Accounting (RuntimeEnvironment):
name = "Accounting"
provides = [CorbaService("Accounting")]
consumes = [DPEBootstrap()]
class OnlineSubscription (DPEComponent Sol26):
name = "Online Subscription"
provides = [CorbaService("Online Subscription")]
consumes = [DPEBootstrap()]
install = """
<component name="Online Subscription3>
<location format="dir3>/vobs/Tina/tina96/installer/repository/ols-sol26</location>
<packagedir>ols</packagedir>
</component>
"""
class V Sub Server Sol26 (DPEComponent Sol26):
name = "Subscription Server for Solaris 2.6"
provides = [CorbaService("V-Sub-Server")]
consumes = [CorbaService("Versant")]
class V Ass Server Sol26 (DPEComponent Sol26):
name = "Access Database for Solaris 2.6"
provides = [CorbaService("V-Ass-Server")]
consumes = [CorbaService("Versant")]
71
B
Ausgewählte Dateien
class V TM Server Sol26 (DPEComponent Sol26):
name = "Type Manager for Solaris 2.6"
provides = [CorbaService("V-TM-Server")]
consumes = [CorbaService("Versant")]
class OLS Server Sol26 (DPEComponent Sol26):
name = "Online Subscribption for Solaris 2.6"
provides = [CorbaService("OLS-Server")]
class PRF Server Sol26 (DPEComponent Sol26):
name = "Profiling for Solaris 2.6"
provides = [CorbaService("PRF-Server")]
class CF Server Sol26 (DPEComponent Sol26):
name = "Capsule Finder for Solaris 2.6"
provides = [CorbaService("CF-Server")]
# TTest1
class TTest1 SF (Service):
info = "resources/empty.txt"
icon48 = "images/java-floppy.gif"
name = "TTest1 Service Factory"
provides = [CorbaService("TTest1SF")]
consumes = [ProviderSide(),Java((1,1,5)), DPEBootstrap(), DPE()]
class TTest1 Service (Service):
info = "resources/empty.txt"
icon48 = "images/java-floppy.gif"
name = "TTest1 Service Implementation"
# requires bootstrap services through service factory
provides = [TTest1Provider()]
consumes = [ProviderSide(), Java((1,1,5)), CorbaService("TTest1SF"),
CorbaService("Accounting"), CorbaService("Online Subscription")]
#Product
class JDK115 (Product):
info = "resources/jdk115.txt"
name = "JDK 1.1.5 (Win32)"
icon48 = "images/jdk-floppy-pure.gif"
url = "http://www.sun.com/"
provides = [Java((1,1,5))]
consumes = [Win32()]
class JDK115Sparc (Product):
info = "resources/jdk115.txt"
name = "JDK 1.1.5 (Solaris)"
icon48 = "images/jdk-floppy-pure.gif"
url = "http://www.sun.com/"
provides = [Java((1,1,5))]
consumes = [SolarisABI26()]
class MRJ20 (Product):
info = "resources/mrj20.txt"
name = "MRJ 2.0"
icon48 = "images/mrj-floppy.gif"
provides = [Java((1,1,6))]
consumes = [MacABI()]
class Visigenic Nameservice Sol26(RuntimeEnvironment):
72
B.1
Dateien aus dem Projekt Service Composition
info = "resources/empty.txt"
icon48 = "images/java-floppy.gif"
name = "VisiBroker 3.1 Nameservice for Solaris 2.6"
consumes = [SolarisABI26(),DPEBootstrap()]
provides = [CorbaService("Naming")]
class Visigenic osagent Sol26(RuntimeEnvironment):
info = "resources/empty.txt"
icon48 = "images/java-floppy.gif"
name = "VisiBroker 3.1 osagent for Solaris 2.6"
consumes = [SolarisABI26(),DPEBootstrap()]
provides = [CorbaService("osagent")]
class Versant Sol26 (RuntimeEnvironment):
name = "Versant for Solaris 2.6"
consumes = [SolarisABI26()]
provides = [CorbaService("Versant")]
resources.py
# $Id: resources.py,v 1.12 1999/11/24 18:54:00 loewis Exp $
from SCOSupport import *
#balancing levels
class BalanceAtBasicHardware:
#If resource is not present at the PC level, it can’t be provided from
#somewhere else. Still, not having it balanced is temporarily OK
def must balance at(self, component):
from components import BasicHardware
return issubclass(component.desc.kl, BasicHardware)
class BalanceAtDomain:
def must balance at(self, component):
from components import Domain
return issubclass(component.desc.kl, Domain)
# Component structure
class InDomain(StructureResource):
pass
class InComputer(StructureResource):
pass
#ABI Variants
class ABI(Resource, BalanceAtBasicHardware):
def provider for (self, consumed):
return isinstance(consumed,self. class )
class i486(ABI):
pass
class MacABI(ABI):
pass
class SolarisABI25(ABI):
pass
class SolarisABI26(ABI):
73
B
Ausgewählte Dateien
pass
class Win32(ABI):
pass
#Versioned Software:
class VersionedSoftware(Resource,BalanceAtBasicHardware):
def init (self,version):
self.version = version
def provider for(self,consumed):
return isinstance(consumed,self. class ) and \
self.version >= consumed.version
class Java(VersionedSoftware):
pass
class Swing(VersionedSoftware):
pass
#Counted resources
class Counted(Resource):
def init (self,max):
self.max=max
self.current=0
def provider for(self,r):
if self. class != r. class :
return 0
if self.current+r.max<self.max:
return 0
return 1
def consume(self,r):
if not self.provider for(r):
return 0
self.current = self.current−r.max
self.consumers.append(r)
return 1
def unconsume(self,r):
self.consumers.remove(r)
self.current = self.current + r.max
def
str (self):
return "%s(%d)" % (self. class . name ,self.max)
def exhausted(self):
return self.current == self.max
class VideoIn(Counted, BalanceAtBasicHardware):
pass
class VideoOut(Counted, BalanceAtBasicHardware):
pass
class SoundOut(Counted, BalanceAtBasicHardware):
pass
class Processor(Counted):
def init (self):
74
B.1
Dateien aus dem Projekt Service Composition
Counted. init (self,1)
def must balance at(self, component):
from components import BasicHardware
return self.fail if not balanced at(component,BasicHardware)
#Exact match resources
class ExactMatch(Resource):
def init (self, variant = None):
self.variant = variant
def provider for(self,consumed):
return self. class == consumed. class
self.variant == consumed.variant
def
and \
str (self):
if self.variant:
return "%s(%s)" % (self. class . name , self.variant)
else:
return self. class . name
class ProviderSide(ExactMatch):
# If a component requires to be on the provider side, grouping it
# elsewhere won’t work
def must balance at(self, component):
from components import Domain
return self.fail if not balanced at(component,Domain)
class CustomerSide(ExactMatch):
def must balance at(self, component):
from components import Domain
return self.fail if not balanced at(component,Domain)
class TTest1(ExactMatch):
pass
class TTest1Provider(ExactMatch):
pass
class PA(ExactMatch, BalanceAtBasicHardware):
pass
class TinaJava(ExactMatch, BalanceAtBasicHardware):
pass
class CorbaJava(ExactMatch, BalanceAtBasicHardware):
pass
class CorbaService(ExactMatch, BalanceAtDomain):
pass
class DPE(ExactMatch, BalanceAtDomain):
pass
class DPEBootstrap(ExactMatch, BalanceAtDomain):
pass
class Webview(ExactMatch, BalanceAtBasicHardware):
pass
75
B
Ausgewählte Dateien
class Driver(ExactMatch, BalanceAtBasicHardware):
pass
B.2 Mögliche XML-Darstellung des Komponentenkatalogs (Ausschnitt)
<?xml version="1.0" standalone="yes" encoding="ISO-8859-1"?>
<katalog>
<komponente>
<name>Software</name>
<basisklasse>Component</basisklasse>
<abstrakt/>
<verbraucht>
<ressourcen name> InComputer</ressourcen name>
</verbraucht>
</komponente>
<komponente>
<name>TestJar</name>
<basisklasse>Service</basisklasse>
<stellt bereit>
<ressourcen name>TTest1</ressourcen name>
</stellt bereit>
<verbraucht>
<ressourcen name>TinaJava</ressourcen name>
</verbraucht>
<verbraucht>
<ressourcen name>Java</ressourcen name>
<ressourcen parameter>(1,1,5)</ressourcen parameter>
</verbraucht>
<verbraucht>
<ressourcen name>Swing</ressourcen name>
<ressourcen parameter>(1,0,1)</ressourcen parameter>
</verbraucht>
<eigenschaft>
<eigenschaft name>icon48</eigenschaft name>
<eigenschaft wert>images/java−floppy.gif</eigenschaft wert>
</eigenschaft>
<eigenschaft>
<eigenschaft name>name</eigenschaft name>
<eigenschaft wert>Java Test Services</eigenschaft wert>
</eigenschaft>
<eigenschaft>
<eigenschaft name>info</eigenschaft name>
<eigenschaft wert>resources/testServices.txt</eigenschaft wert>
</eigenschaft>
</komponente>
<ressource>
<name>ExactMatch</name>
<basisklasse>Resource</basisklasse>
<funktion>
<funk name>provider for</funk name>
<parameter>consumed</parameter>
<code>
<![CDATA[return self. class ==consumed. class and self.variant ==consumed.variant]]>
</code>
</funktion>
</ressource>
</katalog>
76
B.2
Mögliche XML-Darstellung des Komponentenkatalogs (Ausschnitt)
77
Abkürzungsverzeichnis
CORBA Common Object Request Broker Architecture
CVS Concurrent Versions System, Versionsverwaltungssystem
DOM Document Object
Dokumenten
Model,
Schnittstelle
zur
Verarbeitung
von
XML-
DTD Document Type Declaration, definiert die Struktur von XML-Dokumenten
GDK GIMP Drawing Kit
GMD Fokus Institut für Offene Kommunikationssysteme der GMD - Forschungszentrum
Informationstechnik GmbH
GNOME GNU Network Object Model Environment, OpenSource Arbeitsumgebung
GNU LGPL GNU Library General Public License
GTK+ GIMP Toolkit, Bibliothek für grafische Benutzerschnittstellen
HTML Hypertext Markup Language
HTTP Hypertext Transfer Protocol
ODP Open Distributed Processing
RDBMS Relationales Datenbank Management System
SAX Simple API for XML, Schnittstelle zur Verarbeitung von XML-Dokumenten
SCO Service Composition, Projekt zur werkzeugunterstützten Konfigurierung von
TINA-Systemen
SQL Structed Query Language, Datenmanipulationssprache
TINA Telecommunications Information Networking Architecture, Architektur für
verteilte Telekommunikationssysteme
XML Extensible Markup Language
78
Literaturverzeichnis
[ABC+ 98] A PPARAO, V IDUR, S TEVE B YRNE, M IKE C HAMPION, S COTT I SAACS,
I AN J ACOBS, A RNAUD L E H ORS, G AVIN N ICOL, J ONATHAN R OBIE,
R OBERT S UTOR, C HRIS W ILSON und L AUREN W OOD: Document Object Model (DOM) Level 1 Specification. Technischer Bericht, W3C, 1998.
http://www.w3.org/TR/REC-DOM-Level-1.
[AFF+ 98] A BARCA , C., P. FARLEY, J. F ORSLÖW, J. C. G ARCÍA, T. H AMADA, P. F.
H ANSEN, S. H OGG, H. K AMATA, L. K RISTIANSEN, C. A. L ICCIAR DI , H.M ULDER , E. U TSUNOMIYA und M. YATES : Service Architecture.
Technischer Bericht, TINA-C, 1998.
[AFG+ 98] A BARCA , C., P. FARLEY, J. C. G ARCÍA, T. H AMADA, P. F. H ANSEN,
P. H ELLEMANS, C. A. L ICCIARDI, K. N AKASHIRO und M. YATES: Service Component Specification. Technischer Bericht, TINA-C, 1998.
[ASU92]
A HO, A LFRED V., R AVI S ETHI und J EFFREY D. U LLMAN: Compilerbau.
Addison–Wesley, 1992.
[AW95]
A BECKER , A NDREAS und H OLGER WACHE: Constraint-Processing in
der Konfiguration. Technischer Bericht, DFKI GmbH Kaiserslautern,
1995.
[BeO00]
GTK+ for BeOS. http://www.gtk.org/beos, 2000.
[BHO+ 88] B ALZERT, H ELMUT, H EINZ U. H OPPE, R EINHARD O PPERMANN, H EL MUT P ESCHKE , G ABRIELE R OHR und N ORBERT A. S TREITZ (Herausgeber): Einführung in die Software-Ergonomie, Band 1 der Reihe
Mensch Computer Kommunikation : Grundwissen. de Gruyter, 1988.
[BR96]
B ÖRDING, J OSEF und J ÖRG R AHMER: Abgleich komplexer Ressourcen
beim ressourcenorientierten Konfigurieren. In: Beiträge zum 10. Workshop Planen und Konfigurieren, 1996.
[Büt97]
B ÜTTNER , K LAUS: Rechnerunterstütztes Konfigurieren von Baukastenprodukten. Nummer 246 in Fortschrittberichte VDI Reihe 20. VDI Verlag, Düsseldorf, 1997.
[CGS91]
C UNIS, R OMAN, A NDREAS G ÜNTER und H ELMUT S TRECKER (Herausgeber): Das PLAKON-Buch. Nummer 266 in Informatik-Fachberichte.
Springer-Verlag, 1991.
79
Literaturverzeichnis
[DKBS96] Ð URÐANOVI Ć , I GOR, H ANS K LEINE B ÜNING und M ICHAEL S UER MANN : New Aspects and Applications of Resource-based Configuration.
Technischer Bericht, Universität Paderborn und NEC Research Institute, 1996.
[Dör47]
D ÖRNER , H ARTMUT: Modelle für wissensbasiertes Konfigurieren. Doktorarbeit, Martin-Luther-Universität Halle-Wittenberg, 1947.
[FOK01]
GMD FOKUS – R & D – Competence Centers – PLATIN. http://www.
fokus.gmd.de/research/cc/platin/content.html, 2001.
[GKK99]
G ÜNTER , A NDREAS, I NGO K RENZ und C HRISTIAN K ÜHN: Kommerzielle Software-Werkzeuge für die Konfigurierung technischer Systeme.
Künstliche Intelligenz, (3), 99.
[GLA]
GLADE GTK+ User Interface Builder. http://glade.pn.org/.
[Gla00]
GladePyC. http://www.fcoutant.freesurf.fr/gladepyc.html,
2000.
[GNO00]
GNOME. http://www.gnome.org, 2000.
[Goe01]
G OEBEL , H ARTMUT: decompyle – A Python byte-code reverter. http:
//goebel-consult.de/decompyle/, 2001.
[GTK00]
Gtk+ - The Gimp Toolkit. http://www.gtk.org, 2000.
[Hei89]
H EINRICH , M ICHAEL: Ein generisches Modell zur Konfiguration technischer Systeme aus modularen Komponenten. In: H EIN, M ANFRED et al.
[HTH89], Seiten 49–58.
[Hei93]
H EINRICH , M ICHAEL: Ressourcenorientiertes Konfigurieren. Künstliche
Intelligenz, (1), 1993.
[Hen00a]
H ENSTRIDGE , J AMES: Libglade. http://www.daa.com.au/~james/
gnome/#libglade, 2000.
[Hen00b]
H ENSTRIDGE , J AMES: PyGTK. http://www.daa.com.au/~james/
gnome/#pygtk, 2000.
[Her98]
H ERZOG, R OLF: Signalgeber, Widget-Bibliothek Gtk. iX, Seiten 142–
147, Oktober 1998.
[Hül98]
H ÜLLERMEIER , E IKE: Approximating cost functions in resource-based
configuration. Technischer Bericht, Universität Paderborn, 1998.
[Hor93]
H ORZ , A LEXANDER (Herausgeber): Beiträge zum 7. Workshop Planen
und Konfigurieren, Nummer 723 in Arbeitspapiere der GMD. Gesellschaft für Mathematik und Datenverarbeitung, 1993.
80
[HTH89]
H EIN, M ANFRED, W OLFGANG T ANK und J OACHIM H ERZBERG (Herausgeber): Beiträge zum 3. Workshop Planen und Konfigurieren, Nummer 388 in Arbeitspapiere der GMD. Gesellschaft für Mathematik und
Datenverarbeitung, 1989.
[ITU95]
ITU-T: Open Distributed Processing – Reference Model Part1 - Part4,
1995. ITU-T Rec. X.901 - X.904.
[KG91]
K OPISCH , M ANFRED und A NDREAS G ÜNTER: Configuration of a Passenger Aircraft Cabin based on Conceptual Hierarchy, Constraints and
flexible Control. Technischer Bericht, Universität Hamburg, FB Informatik, 1991.
[Kun00]
K UNTZAGK , A NDREAS: WWW-basierte Informationen über eine Komponentendatenbank. Studienarbeit, Humboldt-Universität zu Berlin,
2000.
[Lud01]
L UDWIG, E LMAR: Kanalarbeit, GTK statt AWT/Swing in JavaProgrammen. iX, Seiten 127–130, Januar 2001.
[Mac00]
GTK+ for the MacOS.
gtk-mac, 2000.
[MU97]
M ATTHIESEN, G ÜNTER und M ICHAEL U NTERSTEIN: Relationale Datenbanken und SQL. Addison–Wesley, 1997.
[Pen99]
P ENNINGTON, H AVOC: GTK+ / Gnome Application Development.
New Riders Publishing, 1999. http://developer.gnome.org/doc/
GGAD/.
[Pfi93]
P FITZNER , K AI: Fallbasiertes Konfigurieren technischer Systeme. Doktorarbeit, Universität Hamburg, 1993.
[PyD01]
Python Database Modules.
http://www.python.org/topics/
database/modules.html, 2001.
[Sch97]
S CHNEIDER , H ANS -J OCHEN (Herausgeber): Lexikon Informatik und
Datenverarbeitung. Oldenbourg Verlag, 1997.
[TIN01]
TINA-C. http://www.tinac.com/, 2001.
[vEB00]
E IJK , P ETER VAN und A XEL B ELINFANTE: The Term Processor Kimwitu, Manual and Cookbook. Technischer Bericht, University of Twente,
2000.
[vLF00]
L ÖWIS, M ARTIN VON und N ILS F ISCHBECK: Python 2. Addison–Wesley,
2000.
http://sourceforge.net/projects/
81
Literaturverzeichnis
[vLSN99] L ÖWIS, M ARTIN VON, F RANK S TOINSKI und B ERTRAM N EUBAUER:
Projekt Service Composition, Meilenstein 6. nicht veröffentlicht, Januar
1999.
[vR00]
R OSSUM , G UIDO VAN: Python Reference Manual.
http://www.
python.org/doc/current/ref/ref.html, Oktober 2000.
[vRDJ00] R OSSUM , G UIDO VAN und F RED L. D RAKE J R: Python Library Reference. http://www.python.org/doc/current/lib, Oktober 2000.
[XML01]
82
Extensible Markup Language (XML).
2001.
http://www.w3c.org/xml,
Thesen zur Diplomarbeit
1. Die Methode des ressourcenorientierten Konfigurierens ist geeignet, TINADienste zu erstellen.
2. Die Erweiterung des bestehenden Konfigurationssystems um ein Werkzeug
zum Wissenserwerb ermöglicht auch Nicht-Experten die Erfassung der Komponenten solcher TINA-Dienste.
3. Die Bibliothek GTK+ für grafische Benutzerschnittstellen ist geeignet, ein solches Werkzeug zu erstellen.
4. Die Konstruktion von Benutzerschnittstellen mit dem grafischen Werkzeug
Glade erleichtert die Programmierung mit GTK+.
5. Die Verarbeitung des bestehenden Katalog-Formates als Pythondateien durch
das Wissenserwerb-Werkzeug ist möglich.
Erklärung
Hiermit erkläre ich, daß ich die vorliegende Arbeit selbstständig, ohne fremde
Hilfe und nur unter Nutzung der angegebenen Literatur und Hilfsmittel angefertigt habe.
Ich erkläre mich damit einverstanden, daß meine Diplomarbeit öffentlich in der
Universitätsbibliothek ausgestellt wird.
Berlin, 13. März 2001
Andreas Kuntzagk

Documentos relacionados