Universität Paderborn Fakultät für Elektrotechnik, Informatik und Mathematik Diplomarbeit Attributberechnung in abstrakten Website-Strukturen vorgelegt bei: Prof. Dr. Gerd Szwillus Dr. Michael Tauber vorgelegt von: Jan Stulgies Paderborn, Juni 2005 Eidesstattliche Erklärung Hiermit erkläre ich, dass ich die vorliegende Diplomarbeit ohne Hilfe Dritter und ohne Benutzung anderer als den angegebenen Quellen und Hilfsmitteln angefertigt habe. Alle Stellen, die wörtlich der inhaltlich aus veröffentlichten Schriften entnommen sind, habe ich als solche kenntlich gemacht. Diese Arbeit hat in gleicher oder ähnlicher Form noch keiner Prüfungsbehörde vorgelegen. Paderborn, Juni 2005 (Jan Stulgies) Abstract i Abstract Das Internet gewinnt in der heutigen Zeit immer mehr an Bedeutung. Eine Internetpräsenz kann daher, gerade für kleine Unternehmen, ein entschiedener Wettbewerbsvorteil sein. Kleine Unternehmen müssen sich jedoch besonders auf ihr eigentliches Geschäft konzentieren, haben wenig bis gar keine Kompetenz bei der Erstellungen von Web-Anwendungen, oder können sich die kontinuierliche Beauftragung externer Dienstleister nicht leisten. Um dennoch die Vorteile einer Internetpräsenz nutzen zu können, bietet sich für solche Unternehmen ein modellbasierter Ansatz zur Web-Anwendungsentwicklung an. Ein solcher Ansatz wurde von Szwillus/Bomsdorf unter der Bezeichnung Website Management System (WSMS) vorgestellt. Diese Arbeit beschäftigt sich mit der Entwicklung von Konzepten und Vorgehensweisen zur Berechnung einer Attributierung einer AWS, dem so genannten AWS-State. Die entwickelten Konzepte wurden anschließend in einer prototypischen Implementierung umgesetzt. Inhaltsverzeichnis ii Inhaltsverzeichnis 1 Einleitung ...........................................................................................................................1 2 Attributgrammatiken ..........................................................................................................3 3 2.1 Kontextfreie Grammatiken .........................................................................................3 2.2 Attributierung von Grammatiken ...............................................................................4 2.3 Attributauswertung und WOLM ................................................................................7 WOLM/WSMS...................................................................................................................8 3.1 Wolm-WSMS .............................................................................................................8 3.2 Komponenten .............................................................................................................8 4 WOLM-State ....................................................................................................................10 5 AWS .................................................................................................................................11 6 5.1 Überblick ..................................................................................................................11 5.2 Zugriffsregeln ...........................................................................................................12 5.3 Knotentypen .............................................................................................................13 AWS-State ........................................................................................................................19 6.1 Überblick ..................................................................................................................19 6.2 Knotentypen .............................................................................................................20 6.2.1 Project...............................................................................................................20 6.2.2 Page ..................................................................................................................20 6.2.3 Field..................................................................................................................21 6.2.4 Text...................................................................................................................22 6.2.5 Textinput, Hiddentextinput...............................................................................22 6.2.6 Link...................................................................................................................23 6.2.7 Image ................................................................................................................23 6.2.8 Button, Action ..................................................................................................24 6.3 7 Beispiele ...................................................................................................................26 Berechnung des AWS-State .............................................................................................32 7.1 Überblick Berechnungskonzepte..............................................................................32 7.1.1 Berechnungskonzepte als Blackbox .................................................................32 7.1.2 AWS ohne Bezüge ...........................................................................................33 7.1.3 AWS mit AWS-Bezügen..................................................................................34 7.1.4 AWS mit WOLM-Bezügen ..............................................................................39 7.1.5 AWS mit Listenknoten .....................................................................................41 Inhaltsverzeichnis 7.2 Berechnung AWS-State im Detail............................................................................45 7.2.1 Fehlende Informationen bei der AWS-State Berechnung ................................45 7.2.2 Zustandsabhängige Modifikation der AWS .....................................................48 7.2.3 Aufbau Awslink, Wolmpath, Wolmclass .........................................................48 7.2.4 Bezüge ..............................................................................................................50 7.2.5 Abhängigkeiten.................................................................................................52 7.2.6 Entfernen von Knoten, abhängigen Knoten .....................................................55 7.2.7 Rekursion..........................................................................................................55 7.2.8 BerechneAwslink..............................................................................................56 7.2.9 BerechneWolmpath ..........................................................................................58 7.2.10 BerechneBezug.................................................................................................59 7.2.11 BerechneObjectselection ..................................................................................65 7.3 8 iii Berechnung Knotentypen .........................................................................................69 Prototyp ............................................................................................................................77 Allgemein .................................................................................................................77 8.2 Beispiel 1 ..................................................................................................................78 8.3 Beispiel 2 ..................................................................................................................81 9 8.1 Zusammenfassung ............................................................................................................83 10 Literaturverzeichnis ......................................................................................................84 A Änderung AWS-DTD.......................................................................................................86 A.1 Action-Knoten ......................................................................................................86 A.2 Listofobjectlists-Knoten .......................................................................................87 A.3 Image-Knoten .......................................................................................................87 B WOLM-Definiton.............................................................................................................88 C AWS-State-DTD ..............................................................................................................89 D CD-ROM ..........................................................................................................................91 Tabellenverzeichnis iv Tabellenverzeichnis Tabelle 1: AWS-State Knotentypen .........................................................................................19 Einleitung 1 1 Einleitung Es ist unbestritten, dass das Internet aus unserem heutigen Alltag nicht mehr wegzudenken ist. Dies betrifft sowohl den privaten als auch den geschäftlichen Bereich. War es zu Zeiten des Internetbooms, zu Beginn dieses Jahrtausends, einfach nur „Hip“ als Privatperson eine eigene Homepage zu besitzen, so gibt es heute durchaus sinnvolle Anwendungen für private InternetNutzer. Diese reichen von der privaten Fotosammlung des letzten Familienurlaubs, über Bewerbungsseiten für eine neue Anstellung, bis hin zu den sich momentan stark verbreitenden Blogs. Allen diesen Anwendungen ist gemein, dass sie sich, entweder mit standardisierten Tools oder einfachen HTML-Editoren, vergleichsweise einfach erstellen und betreiben lassen. Auf der anderen Seite wird es für Unternehmen jeder Größe immer wichtiger im Internet vertreten zu sein. Heutzutage sind die meisten der mittleren und großen Unternehmen in Internet präsent. Diese Unternehmen leisten sich zumeist eigene IT-Abteilungen oder zumindest ein festes Budget für die Beauftragung externer Dienstleister. Kleine Unternehmen, wie Bäcker, Handwerker oder Friseure können sich einen solchen Aufwand, verständlicher Weise, nicht leisten. Dennoch könnten sich gerade diese kleinen Unternehmen, durch geeignete Internetangebote, von der Konkurrenz absetzen. Unternehmen, die dies erkannt haben, verfolgen meistens folgenden Ansatz. Sie beauftragen eine Firma mit der Erstellung einer Internetseite. Das Ergebnis sind zumeist statische Webseiten mit einem Minimum an Nutzen für potenzielle Kunden. Interessant wird ein Internetangebot für kleine Unternehmen bzw. deren Kunden, erst durch ständige Aktualisierung und Pflege der enthaltenen Inhalte. Mit dem zuvor gewählten Ansatz würde dies eine ständige Kommunikation zwischen beiden Unternehmen erfordern. Dies ist aufwändig und kostspielig, aber notwendig, da ein kleines Unternehmens in den meisten Fällen nicht über die Kompetenz verfügt, Änderungen an Webseiten selbst vorzunehmen. An dieser Stelle setzt das von Szwillus/Bomsdorf vorgestellte Website Management System (WSMS) an. Es ermöglicht die selbständige Änderung und Aktualisierung einer einmalig professionell erstellten Website mit geringem Aufwand und geringsten EDV-Kenntnissen. In den folgenden Kapiteln werden die einzelnen Komponenten des WSMS kurz vorgestellt. Es folgt eine Einführung in die wichtigsten Konzepte der AWS. Anschließend folgt der Hauptteil dieser Arbeit mit der Konkretisierung der AWS-State-Definition, sowie der Entwicklung von Konzepten und Vorgehensweisen zur Berechnung eines AWS-State aus Einleitung 2 einem gegebenen WOLM-State und zugehöriger AWS. Der letzte Teil beschäftigt sich mit der Vorstellung einer prototypischen Implementierung der vorgestellten Berechnungskonzepte, die im Rahmen dieser Arbeit entwickelt wurde. Attributgrammatiken 3 2 Attributgrammatiken Attributgrammatiken stellen eine Möglichkeit der formalen Definition von Sprachen dar. Sie basieren auf kontextfreien Grammatiken, die um einen Attributierungsteil erweitert sind. Eine starke Verbreitung erfahren Attributgrammatiken im Bereich Compiler- und Übersetzerbau. Im Folgenden wird in das Konzept der kontextfreien Grammatiken eingeführt bevor eine Betrachtung von Attributgrammatiken anhand von zwei Beispielen erfolgt. Abschließend findet eine Beurteilung über den Einsatz von Attributgrammatiken im WOLM, bzw. bei der Berechnung einer Attributierung einer AWS, statt. 2.1 Kontextfreie Grammatiken Eine kontextfreie Grammatik besteht aus einer Menge von Terminalsymbolen (Terminale) T, einer Menge von Nichtterminalsymbolen (Nichtterminale) N, einer Menge von Produktionen P und einem Startsymbol S. In einer Art Ersetzungssystem lassen sich mit einer kontextfreien Grammatik unterschiedlichste Strukturen beschreiben. Dies können beispielsweise Programme von Programmiersprachen oder auch Datenaustauschformate wie XML sein. Anhand eines einfachen Beispiels erfolgt die Beschreibung einer einfachen Struktur zur Speicherung von Wahlergebnissen in XML. Dokumente sollen folgenden Aufbau aufweisen. <wahl> <stimme>cdu</stimme> <stimme>spd</stimme> <stimme>cdu</stimme> </wahl> Die vier Bestandteile einer kontextfreien Grammatik, für die oben angegebene Struktur, könnten wie folgt aussehen. Terminale T = {'<wahl>', '</wahl>', '<stimme>', '</stimme>', 'spd', 'cdu'} Nichtterminale N = {ergebnis, stimmen, stimme, partei} Startsymbol S = ergebnis Produktionen ergebnis stimmen stimme partei partei ::= ::= ::= ::= ::= '<wahl>'stimmen'</wahl>' stimme * '<stimme>'partei'</item>' 'cdu' 'spd' Der Inhalt eines XML-Dokuments dieser kontextfreien Grammatik wird durch die sechs Terminale bestimmt. Die Struktur wird durch die Produktionen vorgegeben. Eine einzelne Attributgrammatiken 4 Produktion legt für ein bestimmtes Nichtterminal die möglichen Ersetzungen durch Terminale und oder Nichtterminale fest. Der linke Teil der Produktion gibt das Terminal an, der rechte Teil seine erlaubte Ersetzung. Mehrere Produktionen für ein Nichtterminal sind möglich (siehe: „partei“). Der Ausdruck „stimme *“ gibt an, dass das Nichtterminal „stimmen“ durch ein oder mehrere „stimme“-Terminale ersetzt werden darf. Das Startsymbol gibt das Nichtterminal an, mit dem die Ersetzung begonnen werden muss. Ohne weitere Ersetzung würde das Startsymbol folgenden Ableitungsbaum sowie das zugehörige XML-Dokument erzeugen. XML-Dokument: ergebnis <wahl></wahl> „<wahl>“ stimmen „</wahl>“ Wird das Nichtterminal „stimmen“ gemäß der obigen Produktionen durch weitere Nichtterminale und Terminale ersetzt, so erhält man einen komplexeren Ableitungsbaum, der ein Dokument der oben vorgestellten Struktur beschreibt. ergebnis „<wahl>“ stimmen „</wahl>“ „<stimme>“ partei stimme … stimme stimme „</stimme>“ „cdu“ „<stimme>“ partei „</stimme>“ „spd“ 2.2 Attributierung von Grammatiken Mit Hilfe kontextfreier Grammatiken lassen sich sehr komplexe Strukturen beschreiben. Ein Informationstransport zwischen einzelnen Knoten eines Ableitungsbaums ist jedoch nicht möglich. Attributgrammatiken erlauben genau dies. Informationen können von einem Knoten des Ableitungsbaums zu einem anderen Knoten transportiert und mit den dort vorliegenden Informationen verknüpft werden. Bevor darauf eingegangen wird, wie eine kontextfreie Attributgrammatiken 5 Grammatik um eine solche Attributierung erweitert wird, sei ein weiteres Beispiel eines Ableitungsbaums mit einer kontextfreien Grammatik gegeben. S 3 A B len a A 3 len 2 b B len a 2 len 1 A b B len a 1 len b Terminale T = {a, b} Nichtterminale N = {S, A, B} Startsymbol S = S Produktionen (1) (2) (3) (4) (5) S A A B B ::= ::= ::= ::= ::= AB aA a bB b Wie bereits im Beispiel zu kontextfreien Grammatiken gesehen, kann mittels der gegebenen Produktionen, Terminalen, Nichtterminalen und dem Startsymbol eine Struktur aufgebaut werden. Bei der Struktur soll es sich um Folgen der Buchstaben a und b handeln. Dabei soll sichergestellt sein, dass zunächst eine beliebige Anzahl an Buchstaben a erzeugt wird, der dann dieselbe Anzahl an Buchstaben b folgt. Beispiele wären „aaabbb“ oder „aabb“. Eine kontextfreie Grammatik kann diese Bedingung nicht sicherstellen. Sie muss zuvor um eine Attributierung ergänzt werden. Hierzu wird zunächst den beiden Nichtterminalen A und B jeweils ein Attribut mit der Bezeichnung len zugeordnet. Der Wert des Attributs len eines Knoten A soll stets die Anzahl der unter diesem Knoten angehängten Knoten mit der Beschriftung a enthalten. Gleiches gilt für Knoten mit der Beschriftung B. Einhalten lässt sich Attributgrammatiken 6 diese Forderung durch die Definition einer semantischen Regel für die zweite und vierte der oben aufgeführten Produktionen. Aufgrund des doppelten Vorkommens der Nichtterminale A und B innerhalb der beiden Produktionen, werden die Nichtterminale von links nach rechts durchnummeriert. Produktion (2) A1 B1 A ::= aA len len Produktion (4) a A2 len B ::= bB b B2 len Die semantischen Regeln für die zweite und vierte Produktion lauten wie folgt. A1.len = A2.len + 1 B1.len = B2.len + 1 Diese beiden Definitionen ermöglichen einen Informationstransport von Knoten im Ableitungsbaum zu höher gelegenen Knoten. Die Definition von zwei weiteren semantischen Regeln für die dritte und fünfte Produktion vervollständigen die Attributierung. A 1 len Produktion (3) B A ::= a 1 len Produktion (5) a B ::= b b A.len = 1 B.len = 1 Der Informationstransport von den Blättern des Ableitungsbaums bis hin zu den Knoten unterhalb des Wurzelknotens ist somit gewährleistet. Abschließend erfolgt die Definition einer semantischen Bedingung, die der ersten Produktion zugeordnet wird. check(A.len, B.len) Bei dem Ausdruck check handelt es sich um ein Prädikat für das gilt: check(n1, n2) ist wahr falls n1 = n2 Eine Überprüfung der Werte der Attribute len für die Knoten direkt unterhalb der Wurzel auf Gleichheit, stellt somit die eingangs geforderte Form der Ausdrücke („aaabbb“) sicher. In diesem Beispiel, dass sich an ein Beispiel aus [Kühnem] anlehnt, werden Informationen zwischen Knoten nur in Richtung Wurzelknoten ausgetauscht. Solche Attribute werden als Attributgrammatiken 7 synthetische Attribute bezeichnet. Das Gegenstück, die inheriten Attribute, ermöglichen einen Informationsaustausch zwischen Knoten aus Richtung Wurzelknoten in Richtung der Blätter. Beide Arten von Attributen lassen sich kombinieren. Weitere ausführliche Beispiele, die auch gleichzeitig Gebrauch von synthetischen und inheriten Attributen machen, können [Kühnem] und [Schütte] entnommen werden. 2.3 Attributauswertung und WOLM Das erste Beispiel hat gezeigt, dass sich kontextfreie Grammatiken zur Definition von XMLStrukturen einsetzen lassen. Wird eine solche Grammatik um eine Attributierung erweitert, so lassen sich Informationen zwischen Knoten des Ableitungsbaums austauschen. Der Austausch der Attributwerte kann sowohl in Richtung der Blätter als auch in Richtung des Wurzelknoten erfolgen. Werden beide Richtungen kombiniert, so lassen sich beispielsweise kleine Programmiersprachen definieren (vgl. [Kühnem], [Schütte]), die die Deklariertheit von in Zuweisungen verwendeten Variablen überprüfen. Die Definition einer AWS, sowie der in ihr enthaltenen Attributabhängigkeiten, verwenden ähnliche Konzepte (XML-Definition, Überprüfung auf existente Knoten). Eine komplette formale Definition der AWS zur Berechnung eines AWS-State würde den Rahmen dieser Arbeit sprengen. WOLM/WSMS 8 3 WOLM/WSMS 3.1 Wolm-WSMS Ziel des Website Management System (WSMS) ist es, den Anwender beim Betrieb einer Website zu unterstützen. Dabei werden auf Seiten des Anwenders nur geringste Computerkenntnisse vorausgesetzt. Der Anwender wird nicht mit technischen Begriffen, die mit dem Betrieb einer Website und den zugrunde liegenden Internettechnologien in Verbindung stehen, konfrontiert. Erreicht werden diese Ziele durch den Einsatz eines Modells, dem Web Object Life Cycle Model, kurz WOLM. Dieses Modell enthält Informationen zu Daten und Prozessen der abzubildenden Realität, die in Form von Web-Objekten gespeichert werden. So lassen sich beispielsweise alle für die Erstellung und den Betrieb einer Website relevanten Abläufe, innerhalb eines kleinen Unternehmens, in diesem Modell abbilden. Ein solches Modell wird zu Beginn einmalig von einer professionellen Kraft in Zusammenarbeit mit dem Unternehmen erstellt. Nach dieser einmaligen Erstellung, kann der Anwender seine Website selbständig aktualisieren und dabei indirekt die Zustände der einzelnen Web-Objekte ändern. Der Anwender wird mit Hilfe einer Reihe von Fragen durch die anstehenden Änderungen der Website geführt („Möchten Sie ein neues Angebot erstellen? Möchten Sie Kundendaten ändern?“). Nach Beantwortung dieser Fragen und der evtl. Eingabe von Daten, werden intern die Zustände der Web-Objekte geändert, Web-Objekte werden gelöscht oder neue hinzugefügt. Das WOLM geht in einen neuen Zustand über. Die Website wird automatisch aktualisiert. Die Arbeit des Anwenders beschränkt sich auf die Beantwortung von Fragen und die Eingabe von Daten. 3.2 Komponenten Den Ausgangspunkt für die spätere Website bildet das WOLM. Dieses Model beschreibt alle für eine Website relevanten Prozesse und Funktionen eines Unternehmens. Der WOLM-State enthält einen konkreten Zustand dieses Modells zu einem bestimmten Zeitpunkt (1). Für die strukturelle Darstellung des WOLM in einer Website ist die AWS verantwortlich. Sie wird stets einem WOLM zugeordnet. Eine initiale AWS lässt sich automatisch aus einem WOLM berechnen (2). Diese initiale AWS muss in den meisten Fällen manuell nachbearbeitet und oder ergänzt werden um eine sinnvolle Darstellung der späteren Website zu gewährleisten. Dies kann mittels eines speziellen AWS-Editors (6) geschehen, aber theoretisch auch mit jedem beliebigen Text-Editor. Als Gegenstück zum WOLM-State gibt es den AWS-State, welcher ebenfalls einen konkreten Zustand repräsentiert. Der AWS-State füllt die durch die WOLM/WSMS 9 AWS festgelegte Struktur mit konkreten Daten aus dem WOLM-State (3). Somit sind im AWS-State sowohl die Struktur als auch alle vorhandenen Daten einer Website gespeichert. Der AWS-State macht jedoch keinerlei Aussagen über das Aussehen der Website bzw. der in ihr enthaltenen Seiten und deren Elemente. Ausgehend vom AWS-State muss daher zunächst, mit Hilfe eines Website-Templates, die finale Website generiert werden (4). Hierbei kann das Website-Template, und somit auch die finale Website, beispielsweise aus HTML-Code bestehen. Ein Website-Template beschreibt das Layout der finalen Website. 5 AdminSeiten 7 WOLM 1 WOLM-State Website 3 2 AWS AWS-State 4 4 3 AWSEditor 6 WebsiteTemplate Innerhalb der finalen Website ist es durch Benutzerinteraktion möglich Methoden innerhalb des WOLM aufzurufen, und somit den Zustand des Models zu verändern, was einen veränderten WOLM-State zur Folge hat (5). Veränderter WOLM-State und AWS ergeben einen neuen AWS-State und schließlich eine neue finale Website. Die Zustandsänderung des WOLM kann alternativ auch über die Admin-Seiten erfolgen (7). Die Auswirkungen auf WOLM-State, AWS-State und finale Website bleiben die gleichen wie bei der durch Benutzerinteraktion verursachten Änderungen. Die Komponenten WOLM, WOLM-State sowie Admin-Seiten wurden in den Arbeiten [Minßen] und [Köpke] entwickelt und beschrieben. Der Schritt zur Berechnung einer initalen AWS in der Arbeit von [Langer] erarbeitet. Die vorliegende Arbeit beschäftigt sich mit der Berechnung eines AWS-State aus WOLM-State und AWS. Konzepte zum Website-Template und finaler Website, sowie zum AWS-Editor werden zum Zeitpunkt der Erstellung dieser Arbeit in weiteren Arbeiten untersucht und umgesetzt, weswegen detaillierte Aussagen zu diesen Schritten noch nicht möglich sind. WOLM-State 10 4 WOLM-State Ein WOLM-State betrachtet alle in einem WOLM vorhandenen Objekte zu einem festen Zeitpunkt. Dabei werden alle zu diesem Zeitpunkt existenten Objekte, inklusive ihrer Attributbezeichnungen sowie der aktuellen Attributwerte, in einer Datei festgehalten. Bei dieser Datei handelt es sich um eine XML-Datei. Da schon die Darstellung kleinerer XMLDateien sehr viel Platz beansprucht und zudem schnell unübersichtlich wird, wird eine vereinfachte Notation eingeführt. Ziel ist es, die wesentlichen Eigenschaften einer WOLMState-Datei abzubilden damit, im weiteren Verlauf dieser Arbeit, Beispiele zu konkreten WOLM-State übersichtlicher dargestellt werden können. Die vereinfachte Notation folgt folgendem Schema. Klassenname : id (Attributname = Attributwert, ...) Klassenname ist die Bezeichnung der WOLM-Klasse des jeweiligen Objekts. Weiterhin ist jedes Objekt im WOLM-State durch eine eindeutige Bezeichnung identifizierbar (id). Abschließend folgt die Auflistung sämtlicher Attribute mit den momentanen Werten des jeweiligen Objekts. Bei den Attributen wird zwischen den drei im WOLM zulässigen Arten unterschieden. Die Werte einfacher Attribute mit atomaren Attributwerten vom Typ int, string, boolean werden in Anführungszeichen geschrieben. Bei Attributen, die als Wert eine Referenz auf ein anderes Objekt des WOLM enthalten, wird als Attributwert die eindeutige id des referenzierten Objekts angegeben. Auto : a1 (typ=”VW”, ps=60, km=80.000, besitzer=p2) Person : p2 (name=”Hans”) Im obigen Beispiel eines WOLM-State erwartet das Attribut besitzer eine Referenz auf ein Objekt vom Typ Person. Die dritte Art von Attributen betrifft Attribute, die eine Liste von Referenzen auf andere WOLM-Objekte als Wert haben. Im folgenden Beispiel ist dies das Attribut studenten. Lehrstuhl : l1 (studenten=[s1,s3]) Student: s1 (name=”Hans”) Student: s3 (name=”Paul”) Mehrere Objektreferenzen werden in eckigen Klammern und durch Kommata getrennt geschrieben. AWS 11 5 AWS 5.1 Überblick Die AWS bildet mit Hilfe einer Hierarchie von Knoten die Struktur einer Website ab. Dabei hat jeder Knoten in dieser Hierarchie einen bestimmten Typ. Die zur Verfügung stehenden Knotentypen sind: Project, Page, Field, Pagelist, Fieldlist, Text, Textinput, Hiddentextinput, Image, Link, Button, Action, Object, Objectlist, Listofobjectlists Dem Knotentyp Project kommt hierbei eine besondere Bedeutung zu. Er darf nur genau einmal in der AWS vorkommen, hat selbst keine Vorgängerknoten und bildet somit den Wurzelknoten der AWS. Die gesamte Website wird durch diesen einen Knoten repräsentiert. Durch Einfügen weiterer Knoten, der oben aufgelisteten Knotentypen, unterhalb des ProjectKnotens werden alle weiteren Elemente der Website definiert. Diese übrigen Knotentypen können durch eine beliebige Anzahl an Knoten vertreten sein. Sie haben jeweils einen direkten Vorgängerknoten und sind ggf. selbst Vorgänger für weitere Knoten in der AWS. Durch Strukturregeln für jeden einzelnen Knotentyp wird weiterhin festgelegt, welche Knotentypen als Nachfolgeknoten erlaubt sind. Zudem kann eine Begrenzung in der Anzahl der zulässigen Nachfolgeknoten bestehen. So darf beispielsweise ein Knoten vom Typ Image nur genau einen oder keinen Knoten vom Typ Link als Nachfolgeknoten enthalten. Der Project-Knoten darf hingegen beliebig viele Knoten vom Typ Link enthalten. Eine AWS wird stets in Form einer XML-Datei gespeichert. Eine zugehörige AWS-DTD legt den Aufbau der XML-Datei fest, gewährleistet das Einhalten der Strukturregeln und stellt sicher, dass Knoten der verschiedenen Knotentypen stets in der richtigen Kardinalität vorhanden sind. Detaillierte Ausführungen zum Aufbau der AWS-DTD sowie eine genaue Beschreibung der einzelnen AWS-Konzepte können [SZW AWS] und [Langer] entnommen werden. Für das Verständnis des Hauptteils der vorliegenden Arbeit (AWS-State, Berechnung AWSState), ist jedoch ein grundlegendes Verständnis der wichtigsten AWS-Konzepte erforderlich. Aus diesem Grund wird im Folgenden kurz auf die wichtigsten AWS-Konzepte eingegangen. Zu einem besseren Verständnis der AWS können die beiden oben genannten Quellen herangezogen werden. Zudem wird im weiteren Verlauf dieser Arbeit an verschiedenen Stellen auf weitere Konzepte eingegangen bzw. diese vertieft, soweit dies erforderlich ist. Alle AWS oder AWS 12 Ausschnitte von AWS, die im Rahmen von Beispielen verwendet werden, werden in der vereinfachten Notation (vgl. [Langer]) der AWS angegeben. Diese vereinfachte Notation lehnt sich an die XML-Notation an. Mit ihr lässt sich eine AWS kompakter darstellen. Eine Darstellung der vollständigen XML-Notation wäre schon für kleine Beispiele zu unübersichtlich. 5.2 Zugriffsregeln Jeder Knoten in der AWS kann mit einem Attribut ausgezeichnet werden, welches dem Knoten einen Namen zuweist. Somit sind solche Knoten in der AWS unter einem Namen bekannt. Andere Knoten in der AWS können bei Bedarf einen Bezug zu einem solchen benannten Knoten herstellen. Der Name eines einzelnen Knoten kann mehrfach in der AWS verwendet werden. Die Eindeutigkeit eines Zugriffs wird dabei durch folgende drei Zugriffsregeln gesichert. 1. Jeder Knoten kann auf sich selbst direkt zugreifen. 2. Jeder Knoten kann auf seinen Vorfahren und dessen Vorfahren (...) direkt zugreifen. 3. Jeder Knoten kann auf seine Geschwisterknoten direkt zugreifen. Ein Beispiel verdeutlicht die verschiedenen Zugriffsmöglichkeiten. A B C E D Knoten C kann nach Regel 1 auf sich selbst, nach Regel 2 auf Knoten B und A und nach Regel 3 auf Knoten D jeweils direkt zugreifen. Knoten A kann nur auf sich selbst direkt zugreifen (Regel 1). Ausgehend von direkt erreichbaren Knoten kann, unter Angabe eines Pfades, auf weitere Knoten zugegriffen werden. Somit sind für den Knoten A (direkter Zugriff auf A) die Zugriffe A.B, A.B.C, A.B.D und A.E möglich. Entsprechendes gilt für alle anderen Knoten. Besitzen Geschwisterknoten den gleichen Namen ist ein Zugriff nicht mehr eindeutig AWS 13 möglich. Der Ausdruck A.B ermöglicht auf Grund der Namensgleichheit der Geschwisterknoten keinen qualifizierten Zugriff. A B B Ein weiteres Problem stellen rekursive Bezüge dar. Greift der Knoten B auf C, C auf D und dieser wiederum auf B zu, so entsteht ein rekursiver Bezug. A B C D Sowohl die Namensgleichheit von Geschwisterknoten als auch rekursive Bezüge lassen sich nicht durch die Definition innerhalb der AWS-DTD verhindern. Die Erkennung dieser Probleme muss optimalerweise bereits bei der Erstellung einer AWS im AWS-Editor erfolgen, und dem Anwender des Editors mitgeteilt werden. Werden diese Probleme nicht erkannt bzw. wird kein Editor verwendet, so sollte bei der Berechnung des AWS-State zumindest die Erkennung von rekursiven Bezügen gewährleistet sein, und die Berechnung abgebrochen werden. 5.3 Knotentypen Die unterschiedlichen Knotentypen der AWS lassen sich in unterschiedliche Klassen einteilen. Im Folgenden wird anhand dieser Einteilung ein kurzer Überblick über die verschiedenen AWS-Knotentypen sowie deren Funktion gegeben. Wurzelknoten Der Wurzelknoten der AWS ist stets vom Typ Project. Er hat selbst keine Darstellung in der Website. Er repräsentiert vielmehr die gesamte Website. Alle weiteren Knoten der AWS haben diesen Knoten als direkten bzw. indirekten Vorgänger. Eine weitere Aufgabe besteht in der Festlegung der so genannten Startpage. Hierbei handelt es sich um eine einzelne Seite der Website, die als Einstiegspunkt für den Besucher der Website dient und angezeigt wird, wenn der Besucher die Website betritt. AWS 14 Webseite Eine Website kann in beliebig viele Seiten aufgeteilt werden. Dabei wird jede einzelne Seite durch einen Knoten vom Typ Page repräsentiert. Page-Knoten können nur direkt unterhalb des Project-Knotens aufgehängt sein. Eine besondere Funktion haben Page-Knoten nicht. Sie dienen lediglich der Aufteilung der Website in einzelne Seiten, sowie der Aufnahme weiterer AWS-Knoten. Informationstragende Knoten Diese Art von Knoten repräsentiert die eigentlichen Inhalte der Webseiten. Zu diesen Knoten zählen Knoten vom Typ Text, Image und Link. Sie sorgen für die Darstellung von Inhalten in Form von Texten und Bildern und ermöglichen somit die Gestaltung einer Seite. Ein LinkKnoten, für sich alleine betrachtet, führt nicht zu einer Darstellung auf der Seite. Knoten dieses Typs müssen einem Text- oder Image-Knoten zugeordnet sein um eine Darstellung zu erzielen. Der Aufbau der AWS könnte bislang wie folgt aussehen. Project P Page A Page B Text T Image I Link L Gruppierung von Knoten Mittels Knoten des Typs Field lassen sich Inhalte einer Seite gruppieren. So lassen sich beispielsweise Texte und Bilder zu Informationseinheiten zusammenfassen und an unterschiedlichen Positionen der Seite darstellen. Diese Funktion von Field-Knoten dient hauptsächlich einer übersichtlicheren Darstellung von Inhalten. Darüber hinaus lassen sich Gruppen mit Bedingungen verknüpfen. Ist die Bedingung nicht erfüllt, so wird die Gruppe samt all ihrer enthaltenen Knoten aus der AWS ausgeblendet, was letzten Endes dazu führt, dass diese Informationen nicht mehr in der späteren Website enthalten sind. Anwendung für eine solche Funktion wäre beispielsweise die Personalisierung einzelner Seiten der Website. So können, abhängig vom jeweiligen Besucher, unterschiedliche Teile der AWS ein- bzw. ausgeblendet werden. AWS 15 Interaktionsknoten Ähnlich zu den informationstragenden Knoten verursacht diese Art von Knoten eine Darstellung auf einer Seite der Website. Anstelle von Texten oder Bildern werden dem Besucher jedoch Steuerelemente präsentiert, in die er Informationen eintragen, oder mit denen er Aktionen auslösen, kann. Knoten zur Eingabe von Informationen können entweder vom Typ Textinput oder Hiddentextinput sein. Bei beiden Knotentypen handelt es sich um ein Eingabefeld, in das der Besucher einen Text eingeben kann. Bei einem HiddentextinputKnoten erfolgt die Darstellung der Benutzereingabe auf dem Bildschirm des Benutzers in Form von Sternchen, und eignet sich daher besonders für die Eingabe von Passwörtern. Mit Hilfe von Knoten vom Typ Button kann der Besucher Aktionen auslösen. Bei diesen Aktionen handelt es sich meistens um die Übernahme von Informationen aus Eingabefeldern kombiniert mit dem Aufruf von Methoden des WOLM. So lassen sich Zustandsänderungen im WOLM herbeiführen, was sich letzten Endes in Änderungen der Website auswirkt. Objektknoten Objektknoten stellen die Verbindung zwischen AWS und WOLM her. Ein Objektknoten ermöglicht den Zugriff auf ein oder mehrere Objekte des WOLM, die entsprechend des aktuellen WOLM-State verfügbar sind. Die Objektknoten stellen lediglich die Verbindung zum WOLM her und halten die konkreten Daten der Objekte vor. Sie verursachen selbst jedoch keine Ausgabe in der AWS. Die drei Knotentypen object, objectlist und listofobjectlists unterscheiden sich jeweils in der Anzahl der referenzierten Objekte. Ein Knoten vom Typ object enthält als Wert stets die Referenz auf genau ein WOLM-Objekt oder nimmt den Wert null an. Objectlist-Knoten enthalten als Wert eine Liste von Referenzen auf WOLM-Objekte. Dabei kann die Liste auch leer sein. Um eine Zuordnung der gewünschten Referenzen zu den entsprechenden Objektknoten zu gewährleisten, gibt es eine Reihe von Selektionsmöglichkeiten, die einer Query-Sprache ähneln. So lassen sich beispielsweise mit dem folgenden Ausdruck, alle Objekte der WOLM-Klasse Person, dessen Attribut alter einen Wert größer 17 aufweist, selektieren und einem Objectlist-Knoten zuweisen. Objectlist OL = Person [ alter > 17 ] Es gibt viele weitere Selektionsmöglichkeiten auf die auch im späteren Verlauf dieser Arbeit, bei der Berechnung des AWS-State, noch einmal eingegangen wird. Der Zugriff auf ein Element einer Objektliste erfolgt über einen Index. Zusätzlich besitzt jede Objektliste eine Eigenschaft size, welche die Anzahl der in der Objektliste enthaltenen Elemente angibt. OL[3] OL.size // drittes Element der Objektliste // Anzahl Elemente der Objektliste AWS 16 Listofobjectlists-Knoten lassen sich am ehesten mit einem zweidimensionalem Array vergleichen. Sie können mehrere Objektlisten aufnehmen, die sich jedoch nicht aus beliebigen Objektreferenzen zusammensetzen dürfen. Die Referenzen müssen in einem Zusammenhang stehen, was folgendes Beispiel verdeutlicht. WOLM Klasse: WOLM Klasse: class Film { Darsteller* dst; ... } class Darsteller { String name; ... } Objekte der Klasse Film enthalten ein Attribut das eine Menge von Objektreferenzen definiert. Existiert nun eine Menge von Objekten des Typs Film, so enthält wiederum jedes Element dieser Menge eine Menge von Objektreferenzen (vom Typ Darsteller). 1 D1 1,1 F1 D3 1,2 2,1 2 2,2 F2 D2 D4 2,3 Obiges Beispiel enthält zwei Objekte des Typs Film sowie vier Objekte des Typs Darsteller, die in dem angegebenen Zusammenhang stehen. Auf einen Listofobjectlists-Knoten, der diesen Zusammenhang abbildet, lässt sich wie folgt zugreifen. Ein direkter Zugriff auf die Objekte des Typs Film ist nicht möglich. LOOL[1,1] LOOL[2,1] LOOL[2,3] // Objekt D1 // Objekt D1 // Objekt D4 Analog zum Objectlist-Knoten besitzt der Listofobjectlists-Knoten ebenfalls eine Eigenschaft, die die Anzahl der Elemente einer Liste angibt. LOOL.size LOOL.size(1) LOOL.size(2) // 2 // 2 // 3 Der Ausdruck size ohne Angabe eines Parameters bezieht sich auf die äußere Liste. Mit Hilfe des Parameters lässt sich die Anzahl der jeweiligen inneren Listen abfragen. AWS 17 Listenknoten Listenknoten sind Knoten der Typen Pagelist sowie Fieldlist. Sie unterscheiden sich in besonderer Weise von den restlichen Knotentypen. Grundlegend entsprechen diese beiden Knotentypen den Page- bzw. Field-Knoten. Die Besonderheit besteht darin, dass eine Pagelist eine Reihe von Page-Knoten und eine Fieldlist eine Reihe von Field-Knoten in der AWS definiert. Die Vervielfachung der Knoten wird dabei durch einen Knoten vom Typ Objectlist gesteuert, der einem Listenknoten zugeordnet wird. Im Falle einer Pagelist wird für jedes Objekt, der dieser Pagelist zugeordneten Objektliste, ein neuer Page-Knoten in der AWS definiert. Project P Objectlist A Pagelist B Text T Image I Link L Alle Knoten die unterhalb des Pagelist-Knotens hängen werden unter die neuen Page-Knoten angehängt, so dass folgendes Bild entsteht. Project P Objectlist A Page B[1] Text T Page B[2] Image I Link L Text T Page B[3] Image I … … Link L Das zur Vervielfachung verwendete Objekt der Objektliste ist im Folgenden innerhalb des Page-Knoten, sowie all seiner Unterknoten, über den Ausdruck object bekannt. Alternativ lässt sich mittels object[index] auf das gleiche Objekt zugreifen. Index gibt dabei die Position innerhalb der Pagelist an. Durch zusätzliche Rechenoperationen lassen sich, ausgehend von der aktuellen Position, andere Objekte derselben Objektliste erreichen AWS 18 (object[index+1], object[index-1]). Ebenfalls möglich ist ein direkter Zugriff auf ein bestimmtes Objekt (object[7]). Die Ausführungen für Pagelist-Knoten gelten analog für Knoten vom Typ Fieldlist. Knoten des Typs Pagelist kann, alternativ zu einem ObjectlistKnoten, auch ein Listofobjectlists-Knoten zugeordnet sein. Die Objekte, die in einem solchen Fall zur Vervielfachung verwendet werden, werden aus allen inneren Listen der Listofobjectlists bezogen. Der Zugriff auf die jeweiligen Objekte ist, innerhalb einer Page, weiterhin mit Hilfe des Ausdrucks object möglich. Indizierte Zugriffe müssen unter Angabe beider Indizes erfolgen (object[index,index2], object[2,3]). AWS-State 19 6 AWS-State 6.1 Überblick Ein AWS-State enthält eine Teilmenge der zur Definition einer AWS eingeführten Knotentypen. Die Hierarchie zwischen den einzelnen Knotentypen in der AWS bleibt im AWS-State erhalten. Bei der Berechnung eines AWS-State wird eine AWS mit konkreten Werten aus dem aktuellen WOLM-State, des zur AWS gehörigen WOLM, gefüllt. Knotentypen, welche im AWS einen WOLM-Bezug hergestellt haben (object, objectlist, listofobjectlists), werden nicht in den AWS-State übernommen. Knoten vom Typ Pagelist und Fieldlist werden ebenfalls nicht übernommen. Sie werden im AWS-State durch eine entsprechende Anzahl an Page bzw. Field-Knoten ersetzt. Alle anderen Knotentypen finden sich auch im AWS-State wieder. Zu beachten sind jedoch kleinere Änderungen innerhalb der Strukturregeln der einzelnen Knotentypen. So darf ein Text-Knoten beispielsweise nicht mehr unterhalb des Project-Knoten existieren. Eine Auflistung der möglichen Knotentypen im AWS-State, sowie deren mögliche Nachfolger, kann der folgenden Tabelle entnommen werden. Knoten im AWS-State Mögliche Nachfolgeknoten Project Page Page Field, Text, Image, Textinput, Hiddentextinput, Button Field Field, Text, Image, Textinput, Hiddentextinput, Button Text, Image Link Button Action, Link Link, Textinput, Keiner dieser Knoten hat Nachfolgeknoten im AWS-State Hiddentextinput, Action Tabelle 1: AWS-State Knotentypen Dies sind alle Knotentypen, die in einem AWS-State vorkommen können. Die Hierarchie der einzelnen Knoten beschreibt, genau wie die AWS, die Struktur der späteren Website. Im Gegensatz zur AWS, enthält der AWS-State jedoch weder WOLM- noch AWS-Bezüge. Sämtliche Bezüge sind aufgelöst. Das Ergebnis der Berechnung ist eine vollständige, zur AWS kompatible, Struktur der gesamten Website. Der AWS-State enthält keine Informationen über das Layout der späteren Website. Die Festlegung des Layouts sowie die Generierung der finalen Website, in einer für den Benutzer lesbaren Form, müssen in einem AWS-State 20 separaten Vorgang erfolgen. Gespeichert wird der AWS-State, wie das WOLM, der WOLMState und die AWS, in einer XML-Datei. Eine zugehörige AWS-State-DTD sorgt für die Einhaltung der Strukturregeln, definiert Attribute für die einzelnen Knotentypen und stellt die Kardinalitäten von Nachfolgeknoten sicher. Anhand der AWS-State-DTD werden im Folgenden alle Knotentypen und evtl. zu beachtende Besonderheiten erläutert. 6.2 Knotentypen Jeder Knoten innerhalb des AWS-State besitzt ein Attribut mit der Bezeichnung id. Es handelt sich hierbei um eine innerhalb des AWS-State eindeutige ID, genannt AWS-State-ID. Der Wert für dieses Attribut muss für jeden Knoten gesetzt sein. Durch die AWS-State-ID ist jeder Knoten innerhalb des AWS-State eindeutig identifizierbar. 6.2.1 Project Der Project-Knoten hat die gleiche Aufgabe wie in der AWS. Er dient als Wurzelknoten für die Hierarchie von Knoten, welche die Struktur der späteren Website beschreibt. Der Knoten hat selbst keine konkrete Darstellung in der späteren Website, enthält jedoch alle weiteren Knoten. Der Project-Knoten darf als Kindknoten nur Knoten vom Typ Page enthalten, diese jedoch in beliebiger Anzahl. Zusätzlich besitzt der Project-Knoten zwei Attribute. Bei dem ersten Attribut mit der Bezeichnung id handelt es sich um die eingangs erwähnte AWS-StateID, die jeden Knoten innerhalb des AWS-State eindeutig identifiziert. Da jeder Knotentyp innerhalb des AWS-State dieses Attribut besitzt, und seine Bedeutung nun bekannt ist, wird in den Ausführungen zu den übrigen Knotentypen nicht mehr explizit auf dieses Attribut eingegangen. Das zweite Attribut des Project-Knoten ist das Attribut startpage. Als Wert enthält dieses Attribut eine AWS-State-ID eines Page-Knoten des AWS-State, und gibt somit den Einstiegssprung, die Startseite, für die spätere Website an. <!ELEMENT project (page)*> <!ATTLIST project id CDATA #REQUIRED startpage CDATA #REQUIRED > 6.2.2 Page Der Page-Knoten beschreibt eine konkrete Seite der späteren Website und kann selbst eine beliebige Anzahl weiterer Knoten vom Typ Field, Text, Image, Textinput, Hiddentextinput sowie Button enthalten. Zudem kann der Page-Knoten ein Attribut mit der Bezeichnung listid AWS-State 21 enthalten. Listid identifiziert eine Pagelist der AWS eindeutig. Die Bezeichnung #IMPLIED in der AWS-State-DTD gibt an, dass dieses Attribut optional ist. Ein Page-Knoten besitzt dieses Attribut lediglich dann, wenn er aus einer Pagelist hervorgegangen ist. <!ELEMENT page (field | text | image | textinput | hiddentextinput | button)*> <!ATTLIST page id CDATA #REQUIRED listid CDATA #IMPLIED > Jede Pagelist innerhalb der AWS wird im AWS-State durch eine entsprechende Anzahl an Page-Knoten ersetzt, vorausgesetzt die zur Pagelist gehörige Objektliste weist eine entsprechende Anzahl an Elementen auf. Ohne Angabe der listid ließen sich die einzelnen Page-Knoten innerhalb des AWS-State keiner Pagelist der AWS mehr zuordnen. AWS listid: PL1 ... listid: PL1 Pagelist A Text t1 AWS-State Text t2 Page #1 Text #3 Text #4 ... listid: PL1 Page #2 Text #5 ... Text #6 Anhand dieser listid ist es möglich Gruppen von Page-Knoten innerhalb des AWS-State zu identifizieren. Jede dieser Gruppen entstand aus einer Pagelist. Die Zuordnung der PageKnoten innerhalb des AWS-State zu ihrer gemeinsamen Ursprungs-Pagelist, ist dann erforderlich und von Vorteil, wenn ein Page-Knoten in der Website dargestellt werden soll. Auf Grund der Strukturgleichheit von Page-Knoten einer Pagelist ist beispielsweise die Transformation in eine HTML-Darstellung nur einmal nötig. Für alle folgenden Page-Knoten bleibt die Struktur gleich. Lediglich die enthaltenen Werte ändern sich. 6.2.3 Field Die Definition des Field-Knoten in der AWS-State-DTD ist identisch mit der des PageKnoten. Die möglichen Knoten die ein Field-Knoten enthalten kann sind, ebenso wie die AWS-State 22 Attribute und deren Bedeutung, gleich zu denen des Page-Knoten. Ebenso wie bei einer Pagelist wird eine Fieldlist im AWS-State durch eine Reihe von Field-Knoten ersetzt. <!ELEMENT field (field | text | image | textinput | hiddentextinput | button)*> <!ATTLIST field id CDATA #REQUIRED listid CDATA #IMPLIED > 6.2.4 Text Ein Text-Knoten hat außer dem Attribut id, für die AWS-State-ID, keine weiteren Attribute. Er kann genau einen oder keinen weiteren Knoten vom Typ Link enthalten. Der Knoten const enthält den konkreten Inhaltswert des Text-Knoten. <!ELEMENT text (const, link?)> <!ATTLIST text id CDATA #REQUIRED > Ein Text-Knoten im AWS-State mit dem Inhaltswert “Hallo” hätte somit folgende XMLDarstellung. <text id=”#1”><const>Inhalt</const></text> 6.2.5 Textinput, Hiddentextinput Diese beiden Knotentypen sind sowohl vom Aufbau als auch von ihrer Bedeutung her nahezu identisch. Ein Textinput-Knoten steht für ein Eingabefeld in das der Benutzer der Website einen Text eingeben kann. Beim Hiddentextinput-Knoten handelt es sich ebenfalls um ein Eingabefeld in das der Benutzer einen Text eingeben kann. Der eingegebene Text ist jedoch nicht auf dem Bildschirm sichtbar und wird beispielsweise nur durch Sternchen angedeutet. Dieser Knotentyp eignet sich somit für die Eingabe von sicherheitsrelevanten Daten (z.Bsp. Passwörter), die nicht für Dritte am Bildschirm ablesbar sein sollen. AWS-State 23 <!ELEMENT textinput (const)> <!ATTLIST textinput id CDATA #REQUIRED > <!ELEMENT hiddentextinput (const)> <!ATTLIST hiddentextinput id CDATA #REQUIRED > Die Definition in der AWS zeigt, dass die konkreten Inhaltswerte der einzelnen Knoten wiederum in einem const-Knoten dargestellt werden. Die Inhaltswerte können in beiden Fällen vom Benutzer oder durch eine Vorbelegung der Eingabefelder mit bestimmten Werten stammen. 6.2.6 Link Ein Knoten vom Typ Link kann keine weiteren Knoten enthalten. Die Information steht bei diesem Knoten direkt innerhalb des Link-Xml-Tags: <link id=“#4“>INHALT</link> Dies wird in der AWS-State-DTD durch den Ausdruck #PCDATA dargestellt. Als Information enthält ein Link-Knoten eine AWS-State-ID zur Identifizierung des AWS-StateKnotens auf den der Link-Knoten verweisen soll. Ein Link im AWS-State kann auf Knoten der folgenden Typen verweisen: Page, Field, Text, Textinput, Hiddentextinput, Image, Button. <!ELEMENT link (#PCDATA)> <!ATTLIST link id CDATA #REQUIRED > Der folgende XML-Ausdruck, innerhalb einer AWS-State-Datei, würde beispielsweise einen Link auf den Knoten mit der AWS-State-ID „#23“ entsprechen. <link id=“#4“>#23</link> 6.2.7 Image Ein Image-Knoten im AWS-State beschreibt ein Bild auf der späteren Website. Alle benötigten Informationen werden als String in einem Const-Knoten innerhalb des ImageKnoten definiert. AWS-State 24 <!ELEMENT image (const, link?)> <!ATTLIST image id CDATA #REQUIRED > Dieser String enthält Angaben zum Dateinamen (File) der Breite (Width) und Höhe (Height) des Bildes. Die Angabe von Width und Height ist optional. Die einzelnen Angaben werden durch Kommata getrennt. Im Folgenden sind zwei Beispiele für Image-Knoten innerhalb eines AWS-State dargestellt. <image id=”#123”> <const>File=bild.jpg,Width=160,Height=80</const> </image> <image id=”#123”> <const>File=bild.jpg</const> </image> 6.2.8 Button, Action Der Button-Knoten beschreibt eine Schaltfläche auf der Website, welche durch einen Benutzer betätigt werden kann. Nach der Betätigung einer solchen Schaltfläche sind unterschiedliche Aktionen möglich. Im einfachsten Fall wird lediglich eine beschriftete Schaltfläche ohne jegliche Funktion angezeigt (const: Beschriftung der Schaltfläche). <!ELEMENT button (const, action*, link?)> <!ATTLIST button id CDATA #REQUIRED > Darüber hinaus ist es möglich einen Knoten der Website anzugeben (link), der nach Betätigung der Schaltfläche angesprungen werden soll, beispielsweise eine andere Seite. Diese Angabe ist optional. Wird ein solcher Zielknoten nicht angegeben, so wird nach Betätigen der Schaltfläche die gleiche Seite erneut angezeigt. Die letzte Möglichkeit besteht im Aufruf einer oder mehrerer Methoden des WOLM, welche zu einem veränderten WOLMState, verändertem AWS-State und letztlich neuen Website führt (action). Die aufzurufenden Methoden des WOLM werden jeweils durch einen Knoten vom Typ Action repräsentiert. Die DTD-Definition eines Action-Knotens wurde nahezu unverändert AWS-State 25 aus der DTD-Definition der AWS übernommen. Lediglich das Attribut name wurde durch das Attribut id (AWS-State-ID) ersetzt. <!ELEMENT action (params?)> <!ATTLIST action id CDATA #REQUIRED precedence CDATA #IMPLIED wolmobject CDATA #REQUIRED method CDATA #REQUIRED > <!ELEMENT params ((const | cvalue)+)> Ein Button könnte im AWS-State somit folgende Form haben. <button id="#1"> <const>Klick mich</const> <action id="#2" wolmobject="42" method="doIt"> <params> <const>12</const> <cvalue>#3</cvalue> // #3 AWS-State-ID </params> </action> </button> Die Beschriftung des Buttons ist mit „Klick mich“ angegeben. Nach Betätigen des Buttons soll die Methode mit dem Namen „doIt“ auf dem WOLM-Objekt mit der id 42 aufgerufen werden. Jedes WOLM-Objekt innerhalb des WOLM-State besitzt eine eindeutige id. Das in diesem Beispiel nicht angegebene optionale Attribut precedence legt bei mehreren vorhandenen Action-Knoten innerhalb eines Button-Knotens die Reihenfolge fest, in der die einzelnen Methoden aufgerufen werden. Fehlt diese Angabe, so werden die Methoden der Reihe nach aufgerufen. Parameter, die dem Methodenaufruf übergeben werden, können auf zwei unterschiedliche Arten angegeben werden. Erfolgt die Angabe des Parameters innerhalb eines const-Knotens, so handelt es sich bei dem Parameter um einen konstanten Wert. Die Angabe innerhalb eines cvalue-Knotens deutet an, dass es sich bei dem Parameter um einen clientseitigen Wert innerhalb der finalen Website handelt. Dies können Werte sein, die in Knoten der Typen Textinput oder Hiddentextinput durch den Benutzer eingegeben und bei Betätigen eines Buttons verfügbar wurden. Der Bezug zu den Eingabefeldern erfolgt dabei durch Angabe der AWS-State-ID des entsprechenden Eingabefeldes. Nähere Informationen zum Ablauf des Aufrufs von Methoden im WOLM aus einer fertigen Website heraus, sind zum Erstellungszeitpunkt dieser Arbeit noch nicht vorhanden. Es ist AWS-State 26 somit möglich, dass zu einem späteren Zeitpunkt Änderungen und oder Ergänzungen an den Knotentypen Button und Action erforderlich werden. Die komplette zusammenhängende AWS-State-DTD kann dem Anhang entnommen werden. 6.3 Beispiele Der theoretischen Betrachtung aller möglichen Knotentypen eines AWS-State folgen nun einige Beispiele konkreter AWS-State. Dabei werden nicht nur die fertigen, berechneten AWS-State betrachtet, sondern das gesamte WOLM, inklusive WOLM-State und AWS. Alle Beispiele wurden aus Gründen der Übersichtlichkeit so einfach wie möglich gehalten. Aus demselben Grund, wird die vereinfachte Notation, bei der Darstellung von WOLM-State, AWS und AWS-State, anstelle der XML-Darstellung verwendet. Da sich ein AWS-State immer direkt aus einem WOLM-State und einer zugehörigen AWS zusammensetzt, wird zunächst ein simples WOLM eingeführt. WOLM class Auto { String typ int ps int km } class Geschäft { String name int umsatz } class User { String name setName(String n) } Das WOLM, welches für die folgenden Beispiele Verwendung findet, besteht aus drei Klassen. Die einzelnen Klassen enthalten jeweils unterschiedliche Attribute vom Typ string oder int. Die Klasse User enthält des Weiteren eine Methode, die dazu verwendet werden kann dem Attribut name selbiger Klasse einen neuen Wert zuzuweisen. Dem ersten Beispiel eines AWS-State liegt folgender WOLM-State zu Grunde. WOLM-State (1) Auto:a1 (typ=”VW”, ps=60, km=80.000) Der WOLM-State enthält genau ein Objekt der Klasse Auto, mit den obigen Ausprägungen der drei Attributwerte typ, ps und km. Neben dem WOLM-State wird eine AWS benötigt, welche die Werte des WOLM-State in einer Website-Struktur darstellt. Eine mögliche AWS AWS-State 27 für das zugrunde liegende WOLM, sowie den konkreten WOLM-State, könnte wie folgt aussehen. AWS (1) Project P = A Object obj = Auto Page A Text = P.obj.typ + “,” P.obj.ps + “,” + P.obj.km Die AWS stellt über den Object-Knoten obj eine Verbindung zum WOLM-State her. Der Knoten obj enthält im aktuellen Beispiel eine Referenz auf das einzige Objekt des WOLMState, das Objekt a1 der Klasse Auto. Anschließend kann innerhalb des Text-Knoten über die Objekt-Referenz obj auf die Attributwerte des Auto-Objekts zugegriffen werden. Alle Attributwerte des Objekts sollen in der späteren Website durch Kommata getrennt dargestellt werden. Mit den nun vorliegenden Informationen (WOLM-State, AWS) kann der AWS-State berechnet werden. Die Berechnung ist trivial und führt zu folgendem AWS-State. AWS-State (1) Project #1 = #2 Page #2 Text #3 = “VW,60,80.000” Die fertige Website besteht somit aus einer Seite. Die Seite enthält als einzige Information die aktuellen Attributwerte des Auto-Objekts aus dem WOLM-State. Im zweiten Beispiel enthält der WOLM-State mehrere Objekte der Klasse Auto mit entsprechenden Attributwerten. WOLM-State (2) Auto:a1 (typ=”VW”, ps=60, km=80.000) Auto:a2 (typ=”VW”, ps=40, km=60.000) Auto:a3 (typ=”OPEL”, ps=160, km=20.000) Eine zugehörige AWS soll ähnlich zum ersten Beispiel die Attributwerte eines Auto-Objektes auf einer Seite darstellen. Jedes Objekt des WOLM-State soll jedoch auf einer eigenen Seite dargestellt werden. Zudem sollen die einzelnen Seiten, über entsprechende „next“ und „prev“ Links, auf die nächste bzw. vorherige Seite, untereinander verbunden sein. Eine AWS, die dies gewährleistet könnte wie folgt aussehen. AWS-State 28 AWS (2) Project P = A[first] Objectlist olist = Auto Pagelist A = olist Text = object.typ + “,” object.ps + “,” + object.km Text = “Next” Link = A[index+1] Text = “Prev” Link = A[index-1] Es wird im Folgenden darauf verzichtet die AWS im Detail zu erläutern. Detaillierte Informationen können bei Bedarf dem Kapitel AWS bzw. den im Anhang erwähnten Quellen entnommen werden. Der aus WOLM-State und der AWS resultierende AWS-State sieht wie folgt aus. Page #2 AWS-State (2) Project #1 = #2 Page #2 Text #3 = “VW,60,80.000” Text #4 = “Next“ Link #5 = #6 Page #6 Text #7 = “VW,40,60.000” Text #8 = “Next“ Link #9 = #12 Text #10 = “Prev“ Link #11 = #2 Page #12 Text #13 = “OPEL,160,20.000” Text #14 = “Prev“ Link #15 = #6 VW, 60, 80.000 next Page #6 VW, 40, 60.000 prev next Page #12 OPEL, 160, 20.000 prev Wie gefordert, werden die Attributinformationen der einzelnen Objekte des WOLM-State jeweils in einer eigenen Seite dargestellt. Zu beachten ist im obigen Beispiel, dass die drei im AWS-State vorhandenen Seiten alle die gleiche Struktur aufweisen, da sie alle aus der gleichen Pagelist (in der AWS) entstanden sind. Ein letztes, etwas komplexeres Beispiel zeigt die Berechnung des AWS-State in Abhängigkeit vom WOLM-State. Zudem wird das Vorgehen zur Modifikation des WOLM bei durch AWS-State 29 den Benutzer der Website ausgelösten Aktionen erläutert. Der initiale WOLM-State enthält zwei Objekte mit entsprechenden Attributwerten. Der Wert des Attributs name des UserObjekts u1 ist zunächst leer bzw. undefiniert. WOLM-State (3-1) Geschäft:gs1 (bez=”VW-ULI”, umsatz=250) User:u1 (name=““) Folgende zugehörige AWS definiert für die fertige Website zwei Seiten. Auf der ersten Seite soll die Bezeichnung des Unternehmens dargestellt werden. Zudem wird, abhängig von einer Bedingung, ein weiterer Text auf der gleichen Seite dargestellt. Der Umsatz des Unternehmens. Ist die Bedingung hingegen nicht erfüllt, so wird ein Link mit der Bezeichnung „Login“ dargestellt, welcher auf die zweite Seite der Website verweist. AWS (3-1) Project P = A Object obj_gs = Geschäft Object obj_u = User Page A Text = P.obj_gs.bez Field ? P.obj_u[name = ”ULI”] // Bedingung 1 Text = “Umsatz:” + P.obj_gs.umsatz Field ? P.obj_u[name != “ULI”] // Bedingung 2 Text = ”Login” Link = P.B Page B Textinput ti = ”” Button = ”Login” Action = P.obj_u:setName(ti) Link = P.A Im hier verwendeten WOLM-State ist der Wert des Attributs name des User-Objektes nicht definiert. Er ist somit ungleich „ULI“. Bedingung 1 des Field-Knoten ist somit nicht erfüllt. Die Knoten, die sich unterhalb dieses Field-Knoten befinden werden nicht in den AWS-State übernommen. Folglich ist in diesem Beispiel Bedingung 2 erfüllt, und alle Knoten unterhalb des zweiten Field-Knoten werden in den AWS-State übernommen. Die zweite Seite (Page B) enthält ein Text-Eingabefeld sowie einen Button zur Bestätigung der Eingabe. Nach betätigen des Buttons durch den Benutzer der Website, wird eine Methode AWS-State 30 „setName(…)“ auf dem User-Objekt aufgerufen. Als Parameter wird hierbei der Eingabewert des Text-Eingabefeldes (ti) übergeben. Nach Ausführung dieses Aufrufs soll dem Benutzer wieder die erste Seite der Website angezeigt werden. Dies wird durch den Link mit dem Ziel P.A (erste Seite) gewährleistet. Folgende Abbildung zeigt den berechneten AWS-State sowie eine schematische Darstellung der fertigen Website zu oben gegebenem WOLM-State und AWS. Page #2 AWS-State (3-1) Project #1 = #2 VW-ULI Page #2 Text #3 = “VW-ULI” Field #4 Text #5 = “Login” Link #6 = #7 Page #7 Textinput Button #9 Action = Link #10 #8 = “” = “Login” P.obj_u:setName(#8) = #2 Field #4 Login Page #7 Login Der Benutzer befindet sich zu Beginn auf der ersten Seite. Der Umsatz des Geschäfts wird nicht angezeigt. Gelangt der Benutzer über den Link „Login“ zur zweiten Seite der Website, kann er dort einen Namen in das Text-Eingabefeld eingeben und den Button „Login“ betätigen. Ein Betätigen des Buttons führt zum Aufruf der Methode setName() im WOLM, welche dem Attribut name des User-Objekts den übergebenen neuen Wert zuweist. Hat der Benutzer den Namen „ULI“ eingegeben, so führt dies zu folgendem verändertem WOLMState. WOLM-State (3-2) Geschäft:gs1 (bez=”VW-ULI”, umsatz=250) User:u1 (name=“ULI“) AWS-State 31 Das Attribut name des User-Objekts besitzt nun den Wert „ULI“. Unter Zuhilfenahme der bereits bekannten AWS kann mit dem veränderten WOLM-State ein neuer AWS-State berechnet werden. Der so neu berechnete AWS-State enthält wiederum zwei Seiten. Die zweite Seite ist unverändert gegenüber AWS-State (3-1). Auf der ersten Seite wird nun allerdings der Umsatz des Geschäfts angezeigt, da jetzt, durch den veränderten WOLM-State, die Bedingung des ersten Field-Knoten erfüllt ist. AWS-State (3-2) Page #2 Project #1 = #2 VW-ULI Page #2 Text #3 = “VW-ULI” Field #4 Text #5 = “Umsatz: 250” Field #4 Umsatz: 250 Page #6 Textinput #7 = „“ Button #8 = „Login“ Action = P.obj_u:setName(#8) Page #7 Link #9 = #2 Login Berechnung des AWS-State 32 7 Berechnung des AWS-State Die Berechnung des AWS-State ist ein komplexer Vorgang. Hierdurch wird auch die Beschreibung der verwendeten Konzepte und Vorgehensweise, in einer für Dritte, die sich noch nicht intensiv mit der Materie beschäftigt haben, leicht verständlichen Form, erschwert. Aus diesem Grund beginnt dieses Kapitel mit einer kompakten Darstellung aller wesentlichen Konzepte zur Berechnung eines AWS-State. Im darauf folgenden Kapitel (7.2) werden diese Konzepte vertieft sowie weitere Konzepte eingeführt. Die in diesen beiden Kapiteln erarbeiteten und vorgestellten Konzepte, ermöglichen dann eine vergleichsweise einfache Betrachtung der Berechnung jedes einzelnen AWS-Knotentyps (7.3). 7.1 Überblick Berechnungskonzepte Einige Vorbemerkungen zum Vorgehen bei der Berechnung. Die Berechnung des AWS-State erfolgt zunächst innerhalb der gegebenen Hierarchie von AWS-Knoten. AWS-Knotentypen werden nach erfolgter Berechnung in AWS-State-Knotentypen überführt. Erst nach Berechnung sämtlicher Knoten, werden alle gültigen Knoten in eine AWS-State-Hierarchie überführt. Dies beinhaltet das Entfernen von Knotentypen, die nicht in einem AWS-State vorkommen (Pagelist, Fieldlist, Object,…). Ein undefinierter oder ungültiger Knoten ist ein Knoten, für den keine AWS-State Repräsentation existiert, beispielsweise aufgrund eines Bezugfehlers. Ein berechneter Knoten befindet sich in seiner AWS-State Repräsentation. 7.1.1 Berechnungskonzepte als Blackbox Die Berechnung eines AWS-State, aus einem gegebenen WOLM-State sowie einer AWS, lässt sich mit Hilfe einer einzigen rekursiv definierten Funktion beschreiben. BerechneKnoten(Knoten, true|false) Die Funktion erhält als ersten Parameter eine Referenz auf einen Knoten innerhalb der AWS. Aufgabe der Funktion ist die Berechnung des referenzierten AWS-Knotens. Hat der zweite Parameter den Wert true, so werden alle Kindknoten des aktuellen Knotens, soweit vorhanden, ebenfalls berechnet. Dies geschieht jeweils durch einen erneuten Aufruf von BerechneKnoten(), mit dem entsprechenden Kindknoten als Parameter. Die Berechnung des kompletten AWS-State könnte damit wie folgt aussehen. Berechnung des AWS-State 33 refAWS = … // Referenz auf den Wurzelknoten der AWS BerechneKnoten(refAWS, true) Betrachtet man folgende Baumdarstellung einer AWS, so würde mit den beiden oben stehenden Zeilen somit zunächst die Berechnung des Wurzelknotens (Project) angestoßen. Da auch alle vorhandenen Kindknoten berechnet werden sollen, folgt ein Aufruf auf dem Knoten Page, welcher wiederum die Berechnung seiner Kindknoten veranlasst. Project Page Text … … ... Dies geschieht solange bis alle Knoten in der AWS erreicht wurden. Nach der Abarbeitung aller Aufrufe ist ein vollständiger AWS-State berechnet. Dieser Ansatz zur Berechnung ist recht trivial. Die konkrete Umsetzung der Funktion BerechneKnoten(), kann für praxisrelevante AWS jedoch sehr schnell zu einem komplexen Vorgang werden. Allen weiteren Betrachtungen liegt jedoch die oben beschriebene rekursive Vorgehensweise zugrunde. Im Folgenden werden, anhand von zunächst einfachen Beispielen, die notwendigen Vorgehensweisen und Konzepte Schritt für Schritt erläutert. 7.1.2 AWS ohne Bezüge Betrachtet man eine AWS, welche weder AWS-Bezüge noch WOLM-Bezüge enthält, so lässt sich die vollständige Berechnung des AWS-State sehr leicht durchführen. In der praktischen Anwendung werden allerdings in nahezu jeder AWS Bezüge sowohl zwischen Knoten innerhalb der AWS, als auch Bezüge zu Objektknoten, die eine Verbindung zum WOLM herstellen, vorhanden sein. Diese Bezüge stellen einen zentralen Bestandteil der AWS dar, erschweren aber zugleich die Berechnung des AWS-State. Aus diesem Grund wird zunächst eine AWS ohne Bezüge betrachtet, anhand derer die Schritte zur Berechnung des AWS-State gut beschrieben werden können. Trotz der Vereinfachung ist die untenstehende AWS dennoch selbstverständlich eine gültige AWS. Berechnung des AWS-State AWS Project P = A Page A Text T1 = "Hallo" Text T2 = "abc" 34 AWS-State Project #1 = #2 Page #2 Text #3 = "Hallo" Text #4 = "abc" Anhand der gegebenen AWS lässt sich die Aufrufreihenfolge der einzelnen BerechneKnoten Funktionen aufstellen. BerechneKnoten(P, true) BerechneKnoten(A, true) BerechneKnoten(T1, true) BerechneKnoten(T2, true) Innerhalb der Funktionen geschieht nun folgendes. Jeder Knoten bekommt eine eindeutige AWS-State-ID zugewiesen. Da die beiden Text-Knoten keine Kindknoten haben und auch keine AWS bzw. WOLM-Bezüge vorhandnen sind, sind die Text-Knoten hiermit vollständig berechnet. Die Funktion zur Berechnung des Page-Knoten erfordert ebenfalls keine weiteren Berechnungen. Es muss lediglich sichergestellt sein, dass die Berechnung der Kindknoten (hier T1, T2) angestoßen wird. Gleiches gilt für den Project-Knoten. Nachdem alle Knoten berechnet sind, muss der Project-Knoten jedoch noch den Wert seiner Startseite anpassen. Die Startseite verweist in diesem Fall auf die AWS-State-ID der Page A der AWS (hier: #2). Der AWS-State ist somit berechnet und hat die oben abgebildete Darstellung. Alle gültigen AWS, die ebenfalls keine Bezüge enthalten, lassen sich auf die gleiche Weise berechnen. Darüber hinaus lassen sich auch alle anderen AWS mit derselben Vorgehensweise berechnen. Es müssen jedoch weitere Punkte beachtet werden, welche in den nächsten Kapiteln erläutert werden. 7.1.3 AWS mit AWS-Bezügen Durch die Verwendung von AWS-Bezügen ist es einem AWS-Knoten möglich einen Bezug zu einem anderen Knoten innerhalb der AWS herzustellen. So kann zum Beispiel der Inhaltswert eines Text-Knotens aus dem Inhaltswert eines anderen Text-Knotens bestimmt werden. Es gibt viele weitere Anwendungsmöglichkeiten von AWS-Bezügen. Die grundlegende Vorgehensweise ist jedoch immer gleich, weshalb an dieser Stelle zunächst wiederum nicht auf alle Details eingegangen wird. Dies wird jedoch in den folgenden Kapiteln nachgeholt. Berechnung des AWS-State 35 Das Konstrukt zur Herstellung von AWS-Bezügen ist der Awslink. Der Awslink gehört nicht direkt zu den AWS-Knotentypen, wie sie in Kap. AWS beschrieben sind, und ist daher auch in der bislang verwendeten Baumdarstellung einer AWS nicht zu erkennen. In der vereinfachten Notation ist der Awslink ebenfalls nicht direkt zu erkennen und es muss aus dem Zusammenhang auf ihn geschlossen bzw. dieser explizit, zum Beispiel durch einen Kommentar, ausgezeichnet werden. Page A Text T1 = F.T2 // awslink Field F Text T2 = „xy“ Page A Text T1 Field F Text T2 awslink AWS-State: Page #1 Text #2 = “xy” Field #3 Text #4 = „xy“ Die notwendigen Aufgaben zur Berechnung eines Awslink werden in einer neuen Funktion gekapselt. BerechneAwslink(Knoten, awslink) Die Funktion bekommt als ersten Parameter eine Referenz auf einen in der AWS befindlichen Knoten (hier: T1) übergeben. Als zweiter Parameter wird der im Awslink gespeicherte Pfad angegeben (hier „F.T2“). Die Aufgabe der Funktion besteht nun darin, ausgehend vom übergebenen Knoten, gemäß der Pfadangabe des Awslinks, einen Zugriff auf den referenzierten Knoten herzustellen. Dies geschieht anhand der Zugriffsregeln innerhalb der AWS. Der Knoten T1 kann zunächst direkt auf seinen Geschwisterknoten F und von dort aus auf den Knoten T2 zugreifen. Ein so referenzierter Knoten kann dann für weitere Berechnungen verwendet werden. Die im vorangegangenen Kapitel verwendete Vorgehensweise zur Berechnung des AWSState würde für den obigen Ausschnitt einer AWS zu folgender Berechnungsreihenfolge führen. BerechneKnoten(A, true) BerechneKnoten(T1, true) BerechneKnoten(F, true) BerechneKnoten(T2, true) Berechnung des AWS-State 36 Die Existenz des Awslink im Text-Knoten T1 hat aber zur Folge, dass der Knoten T1 nicht vollständig berechnet werden kann, bevor nicht der Knoten T2 berechnet wurde. Die Berechnung des Knotens T2 müsste also vor der Berechnung des Knotens T1 erfolgen. Dies hätte wiederum die vorherige Berechnung des Knotens F zur Folge. Ein möglicher Ansatz wäre also die Berechnung des rechten Teilbaums von Page A im ersten Schritt und folglich die Berechnung des linken Teilbaums im zweiten Schritt. BerechneKnoten(A, true) BerechneKnoten(F, true) BerechneKnoten(T2, true) BerechneKnoten(T1, true) Somit wäre sichergestellt, dass der Knoten T2 berechnet ist, bevor der Knoten T1 auf selbigen zugreift. In diesem konkreten Beispiel mit lediglich einem Awslink wäre diese Vorgehensweise denkbar. Sobald eine AWS jedoch mehr als einen Awslink enthält, ist diese Vorgehensweise unter Umständen nicht mehr möglich, was im Folgenden anhand eines Beispiels gezeigt wird. Page A Text T1 Page B Text T2 awslink Project P = Page A Text T1 Text T2 Page B Text T3 Text T4 P.A = P.B.T3 = „XYZ“ = „ABC“ = P.A.T2 Text T3 Text T4 awslink BerechneKnoten(A, true) BerechneKnoten(T1, true) BerechneKnoten(T2, true) BerechneKnoten(B, true) BerechneKnoten(T3, true) BerechneKnoten(T4, true) Der linke Teilbaum enthält in diesem Beispiel einen Knoten mit einem Awslink auf einen Knoten im rechten Teilbaum und umgekehrt. Ein Austausch der Berechnungsreihenfolge der Berechnung des AWS-State 37 beiden Teilbäume ist somit nicht mehr möglich. Dennoch muss der Knoten T3 vor dem Knoten T1, sowie der Knoten T2 vor dem Knoten T4 berechnet werden. Um trotzdem einen AWS-State berechnen zu können muss also anders vorgegangen werden. Die grundlegende Vorgehensweise bleibt dabei dieselbe wie im vorigen Kapitel, was die bekannte Aufrufreihenfolge der BerechneKnoten Funktionen zur Folge hat (siehe obige Abbildung). Innerhalb der einzelnen BerechneKnoten Funktionen kommt dabei der neuen Funktion BerechneAwslink eine bedeutende Rolle zu. Solange die zu berechnenden Knoten keinen Awslink enthalten erfolgt die Berechnung wie gehabt. Ist dies nicht der Fall, so wird wie folgt vorgegangen. Innerhalb der Funktion BerechneKnoten wird die Funktion BerechneAwslink aufgerufen. Wie eingangs erwähnt sucht diese Funktion zunächst den referenzierten Knoten. Ist der Bezug zu diesem Knoten hergestellt kann allerdings, wie im obigen Beispiel der Fall eintreten, dass dieser Knoten zwar innerhalb der AWS existiert, er jedoch noch nicht berechnet ist. Sollte dies der Fall sein, so wird der Knoten einfach an dieser Stelle berechnet, jedoch ohne evtl. vorhandene Kindknoten zu berechnen (angedeutet durch „false“). BerechneAwslink(Knoten, awslink) { Zielknoten = … // suche Zielknoten in AWS BerechneKnoten(Zielknoten, false) } Anhand des Beispiels von Knoten T1 wird die Reihenfolge der Aufrufe deutlich. BerechneKnoten(A, true) BerechneKnoten(T1, true) BerechneAwslink(T1, „P.B.T3“) BerechneKnoten(T3, false) BerechneKnoten(T2, true) BerechneKnoten(B, true) BerechneKnoten(T3, true) BerechneKnoten(T4, true) Der erneute Aufruf zur Berechnung des Knotens T3 im rechten Teilbaum würde in diesem Fall nicht zu einer erneuten Berechnung von T3 führen, da dieser Knoten bereits innerhalb der Funktion zur Berechnung des Awslink berechnet wurde. Nur evtl. vorhandene Kindknoten von T3 müssen ggf. an dieser Stelle noch berechnet werden. Durch diese vorzeitige Berechnung von Knoten, die gemäß der Aufrufreihenfolge erst später hätten berechnet werden sollen, können alle Awslink innerhalb der AWS aufgelöst und somit alle Knoten Berechnung des AWS-State 38 innerhalb der AWS berechnet werden. Obwohl sich mit dieser Vorgehensweise zu allen bislang beschriebenen Arten von AWS ein AWS-State berechnen lässt, kann es bei der Berechnung des AWS-State durch die Verwendung von Bezügen zu Situationen kommen, in denen weitere Betrachtungen notwendig sind. Auf diese Situationen wird im Folgenden kurz eingegangen. Eine detailliere Betrachtung erfolgt innerhalb des Kapitels 7.2 „Berechnung AWS-State im Detail“. Das erste und offensichtlichste Problemfeld stellt die Gefahr von Zyklen innerhalb der AWS dar. Einfachstes Beispiel für einen Zyklus innerhalb einer AWS ist der Selbstbezug eines Knoten. Knoten1 awslink In einem solchen Fall, in dem ein Knoten innerhalb der AWS über einen Awslink einen Bezug zu sich selbst herstellt, ist die Berechnung eines AWS-State nicht mehr möglich. Ein Zyklus kann auch indirekt über mehrere Knoten entstehen. Sobald eine AWS einen Zyklus enthält ist sie ungültig. Es muss also bestenfalls schon zum Zeitpunkt der Erstellung der AWS, zum Beispiel in einem AWS-Editor, sichergestellt sein, dass eine AWS keine Zyklen enthält. Enthält eine AWS trotzdem einen Zyklus, würde die Berechnung des AWS-State in eine Endlosschleife laufen. Es ist also ratsam, eine Zykluserkennung in die Berechnung des AWS-State zu integrieren. Wird während der Berechnung des AWS-State ein Zyklus erkannt, so muss die Berechnung abgebrochen werden. Die AWS ist ungültig. Dies ist die einzige Stelle, an der die Berechnung eines AWS-State abgebrochen werden muss. Alle anderen Berechnungen führen stets zu einem gültigen, wenn auch möglicherweise leerem, AWS-State. Knoten1 Knoten2 awslink Knoten3 awslink awslink Ein weiteres Problem stellen Zugriffe auf ungültige Knoten innerhalb der AWS dar. Ist ein Knoten in einem vorriegen Berechnungsschritt als ungültig gekennzeichnet worden, weil während der Berechnung ein Fehler aufgetreten ist, so wird dieser ungültige Knoten nicht in den AWS-State übernommen. Ein Awslink auf einen solchen Knoten führ somit zwangsweise dazu, dass auch der bezugnehmende Knoten ungültig wird. Möglich ist allerdings auch, dass ein referenzierter Knoten erst zu einem späteren Zeitpunkt der Berechnung des AWS-State Berechnung des AWS-State 39 ungültig wird, der Bezug aber auf den, zu dem Zeitpunkt noch gültigen Knoten erfolgte. Der untere Ausschnitt einer AWS verdeutlicht diesen Zusammenhang. Die Funktion zur Berechnung des Knotens T1 erfordert die vorzeitige Berechnung des Knotens T2. Treten keine Fehler auf, so sind T1 und T2 berechnet und gültige Knoten, die in den AWS-State übernommen werden. Kommt es in der nun folgenden Berechnung des Knotens F sowie seiner Kindknoten zu einem Fehler, so kann dadurch möglicherweise auch der schon berechnete Knoten T2 ungültig werden. Dies alleine würde lediglich dazu führen, dass der Knoten T2 nicht im AWS-State vorhanden ist. Dadurch, dass der Knoten T1 aber von der Existenz des Knotens T2 abhängig ist, würde dieser Knoten ebenfalls ungültig und aus dem AWS-State ausgeblendet. Sowohl die Aufzeichnung von Abhängigkeiten zwischen Knoten, als auch das Deaktivieren von Knoten, sowie von abhängigen Knoten, im Fehlerfall, muss gewährleistet sein. Details hierzu können ebenfalls innerhalb des Kapitels 7.2 „Berechnung AWS-State im Detail“ nachgelesen werden. . Page A Text T1 Field F Text T2 … möglicher Fehler … awslink 7.1.4 AWS mit WOLM-Bezügen Alle bislang beschriebenen AWS haben zu keinem Zeitpunkt einen Bezug auf konkrete Daten des WOLM genommen. Sämtliche Informationen lagen statisch in der AWS vor und Bezüge beschränkten sich auf Knoten innerhalb der AWS. Interessant wir die Verwendung der AWS jedoch erst, wenn auch auf konkrete Daten des WOLM, zugegriffen werden kann. Um eine solche Verbindung herzustellen gibt es in der AWS drei Typen von Knoten: Object, Objectlist und Listofobjectlists. Eine detaillierte Betrachtung der Berechnung selbiger Knoten soll an dieser Stelle nicht erfolgen. Das Hauptaugenmerk liegt hier auf der Betrachtung des Wolmpath-Ausdrucks. Berechnung des AWS-State 40 AWS Project P = A Object obj = Person Page A Text T1 = P.obj.name AWS-State Project #1 = #2 Page #2 Text #3 = "Franz" In der obigen vereinfachten Notation der AWS unterscheidet sich der Wolmpath-Ausdruck („P.obj.name“) nicht von einem Awslink. Auf einen Wolmpath muss hier aus dem Zusammenhang geschlossen werden. In der XML-Definition der AWS erfolgt eine explizite Auszeichnung. Die Vorgehensweise zur Berechnung eines Wolmpath ähnelt jedoch sehr stark der Vorgehensweise zur Berechnung eines Awslink. Bei einem Awslink besteht der Pfad aus einer Reihe von Knoten innerhalb der AWS. Bei einem Wolmpath hingegen muss der Pfad in zwei Teile unterteilt werden. Der erste Teil besteht aus AWS-Knoten und endet mit einem Knoten vom Typ object, objectlist oder listofobjectlists. Im obigen Beispiel ist dies der Teil „P.obj“. Der darauf folgende Pfad bezieht sich nicht mehr auf die AWS, sondern auf ein Objekt des WOLM. BerechneWolmpathWert(Knoten, wolmpath) { Zielknoten = … // suche Zielknoten in AWS BerechneKnoten(Zielknoten, false) Wert = … // bestimme Wert aus WOLM-Objekt return Wert } Es wird zunächst wieder ausgehend vom aktuellen Knoten (hier: T1) mit Hilfe der Pfadangabe innerhalb des Wolmpath der Zielknoten des WOLM-Bezugs bestimmt. In obiger AWS ist dies der Knoten mit der Bezeichnung obj, bei dem es sich um einen Knoten vom Typ Object handelt. Ist dieser Knoten berechnet, so erhält er als Wert eine Referenz auf ein Objekt des WOLM. Auf dieses referenzierte Objekt wird dann der zweite Teil des Wolmpath Ausdrucks angewandt, wodurch letztlich der Wert des Wolmpath-Ausdrucks bestimmt wird. Auf den ersten Blick wirkt die Berechnung eines Wolmpath im Vergleich zu der eines Awslink sehr viel einfacher. Da für die Berechnung eines Wolmpath jedoch auch immer die Berechnung eines Knoten vom Typ object, objectlist oder listofobjectlists erforderlich ist, können die gleichen Probleme wie bei der Berechnung eines Awslink (Rekursion, Abhängigkeiten) auftreten. Berechnung des AWS-State 41 Object obj objectselection awslink: “P.OL“ constraint awslink: “X.A“ wolmpath: “P.O.name“ Dies liegt am internen Aufbau der Objektknoten, welche zur Selektion ihrer referenzierten WOLM-Objekte bzw. WOLM-Objektmengen wiederum Awslink und oder Wolmpath Ausdrücke verwenden können, um Bezüge zu anderen Knoten der AWS herzustellen bzw. konkrete Werte des WOLM abzufragen. 7.1.5 AWS mit Listenknoten Alle bislang betrachteten AWS enthielten stets eine konstante feste Anzahl an Knoten. Awslink- und Wolmpath-Ausdrücke konnten Bezüge herstellen und somit über Pfade innerhalb der AWS andere Knoten erreichen. Wird die Betrachtung um Knoten der Typen Pagelist und Fieldlist erweitert, so gibt es bei der Berechnung des AWS-State weitere Punkte zu beachten. Die einem Listenknoten zugeordnete Objektliste bestimmt, durch die Anzahl ihrer Elemente, die Anzahl der Page- bzw. Field-Knoten in der AWS. In der AWS selbst sind als Knoten jedoch lediglich Knoten vom Typ Pagelist bzw. Fieldlist existent. Project P = P.A[1] Objectlist OL = Person Pagelist A = OL Text T1 = object.name Die einzelnen Page-Knoten, die beispielsweise aus der obigen Definition einer Pagelist hervorgehen, sind nicht als Knoten in der AWS vorhanden. Es ist somit nicht möglich eine Referenz auf einen solchen Knoten zu erhalten. Ebenso sind die unterhalb des PagelistKnoten angehängten Knoten, die auf jeder neu erzeugten Page vorhanden sind, nicht in der AWS existent. Die zu Beginn eingeführte Funktion BerechneKnoten verlangt als Parameter jedoch eine Referenz auf einen Knoten der AWS. Eine separate Berechnung der einzelnen Page-Knoten einer Pagelist ist somit nicht möglich. Im obigen Beispiel könnte dieses Problem Berechnung des AWS-State 42 dadurch umgangen werden, dass der Funktion BerechneKnoten eine Referenz auf den Pagelist-Knoten übergeben würde. Die Behandlung der Berechnung eines Knotens vom Typ Pagelist müsste dann in einem Schritt erfolgen. In einer Schleife würde für jedes Objekt der zum Pagelist-Knoten gehörigen Objektliste ein neuer Page-Knoten für den AWS-State angelegt. Zusätzlich würden für jede Page der Reihe nach alle Unterknoten berechnet. Der berechnete AWS-State könnte somit wie folgt aussehen. Project #1 = #2 Page #2 Text #3 = „Name Person 1“ Page #4 Text #5 = “Name Person 2“ Dieses Vorgehen wird jedoch unmöglich, wenn die AWS zusätzlich einen Knoten enthält der über einen Awslink einen Bezug zu einem Knoten innerhalb einer Pagelist/Fieldlist herstellt, bzw. wenn innerhalb eines Listenknotens Bezüge zu Knoten außerhalb der eigenen Liste hergestellt werden. Ersteren Fall verdeutlicht folgende AWS. Project P Objectlist OL Text T1 awslink Pagelist A Text T2 ? P.A[2].T2 Der Knoten T1 möchte einen Bezug zu Knoten T2 auf der zweiten Page einer Pagelist mit dem Namen A herstellen („P.A[2].T2“). Dieser Knoten existiert aber zu diesem Zeitpunkt noch nicht in der AWS, da die entsprechende Pagelist noch nicht berechnet wurde. Ein Vorziehen der kompletten Berechnung der Pagelist, wie zuvor beschrieben, wäre in diesem Fall möglich, führt jedoch bei komplexeren AWS wieder zu den gleichen Problemen, wie sie bereits im Kapitel zur Berechnung von AWS-Bezügen erläutert wurden. Dadurch, dass die Knoten innerhalb der Pagelist wieder Bezüge zu anderen Knoten und auch zu Knoten in anderen Listen enthalten können, ist das Vorziehen einer vollständigen Berechnung einer Liste in vielen AWS unmöglich. Um dieses Problem zu lösen, wird eine Pagelist bzw. Fieldlist zunächst „berechnet“ ohne jedoch die in ihr enthaltenen Knoten zu berechnen. In der Berechnung des AWS-State 43 obenstehenden AWS würde ein Aufruf der Funktion BerechneKnoten(A, false) zunächst die zu dieser Pagelist gehörige Objektliste bestimmen. Danach wird für jedes Objekt der Objektliste ein neuer Page-Knoten in der AWS erzeugt. Jeder Page-Knoten erhält als Kindknoten die jeweiligen Kindknoten der zugehörigen Pagelist. Diese Knoten werden einfach unter die jeweiligen Page-Knoten angehängt, aber zu diesem Zeitpunkt noch nicht berechnet. Project P Objectlist OL Text T1 awslink Pagelist A Page A[1] Page A[2] Text T2 Text T2 Text T2 P.A[2].T2 Diese Vorgehensweise hat den Vorteil, dass nun alle Knoten in der AWS existieren. Der Awslink auf den Knoten T2 der zweiten Page A verweist somit auf einen in der AWS existenten Knoten und kann wie gehabt berechnet werden. Der Ablauf der Berechnung des TextKnotens T1 läuft somit wie folgt ab. BerechneKnoten(T1, true) BerechneAwslink(T1, „P.A[2].T2“) BerechneKnoten(A, false) BerechneKnoten(P.A[2].T2, false) Bevor die Berechnung des Awslink abgeschlossen werden kann, wird zunächst die Pagelist A berechnet, bzw. präziser gesagt in ihre Page-Knoten aufgelöst, was schließlich die Berechnung des referenzierten Knotens T2 ermöglicht. Durch das Auflösen einer Pagelist, oder auch Fieldlist, in ihre einzelnen Elemente gehen jedoch Informationen verloren, die unter Umständen zu einem späteren Zeitpunkt der Berechnung des AWS-State wieder benötigt werden. Der Informationsverlust kommt dadurch zu Stande, dass die in der Liste enthaltenen Knoten lediglich in die neu entstehenden Pagebzw. Field-Knoten kopiert werden, aber erst zu einem späteren Zeitpunkt berechnet werden. Zu diesem späteren Zeitpunkt ist es nicht mehr ohne weiteres möglich auf die der ursprünglichen Liste zugrunde liegende Objektliste, sowie auf den jeweiligen Index innerhalb der Liste zu schließen. Berechnung des AWS-State 44 Project P = P.A[1] Objectlist OL = Person Pagelist A = OL Text T1 = object[index+1].name // wolmpath Der Text-Knoten T1 in obiger AWS bestimmt seinen Inhaltswert über einen WolmpathAusdruck. Die AWS mit der aufgelösten Pagelist enthält zwei neue Page-Knoten, die jeweils den Inhalt der ursprünglichen Pagelist kopiert haben. Project P = P.A[1] Objectlist OL = Person Page A[1] Text T1 = object[index+1].name // wolmpath Page A[2] Text T1 = object[index+1].name // wolmpath Den Text-Knoten T1 innerhalb der neuen Page-Knoten fehlt nun allerdings die Verbindung zur Objektliste der ursprünglichen Pagelist. Ein Zugriff auf WOLM-Objekte innerhalb ihrer Wolpmpath-Ausdrücke ist somit nicht mehr möglich. Zudem lassen sich Bezeichner wie index (index gibt die Position in einer Liste an) nicht mehr bestimmen. Zur Lösung dieses Problems werden alle Kindknoten eines Page- bzw. Field-Knoten zum Zeitpunkt der Auflösung ihrer zugehörigen Liste mit drei zusätzlichen Attributen versehen. Diese Attribute sind: oid, index und index2. oid stellt den Bezug zur Objektliste her, index und index2 geben die Position in einer Objectlist bzw. Listofobjectlists an. oid: 1 Obectlist Pagelist A B Page A[1] C Page A[2] … B C B C oid: 1 oid: 1 oid: 1 oid: 1 index: 1 index: 1 index: 2 index: 2 Die so gekennzeichneten Knoten können somit zu einem späteren Zeitpunkt der Berechnung des AWS-State direkt und ohne Probleme auf die entsprechenden Listenobjekte zugreifen, sowie ihre Position in der ursprünglichen Pagelist bestimmen, und somit berechnet werden. Berechnung des AWS-State 45 Project P = P.A[1] Objectlist OL = Person // oid = 1 Page A[1] Text T1 = object[index+1].name // oid = 1, index = 1 Page A[2] Text T1 = object[index+1].name // oid = 1, index = 2 Angewandt auf die konkrete AWS, weiß nun der Text-Knoten T1 in der Page A[1], dass er auf das zweite Element der Objectlist OL zugreifen soll (index+1). Mit dieser zusätzlichen Attributierung von AWS-Knoten, die ursprünglich in einer Pagelist bzw. Fieldlist enthalten waren, ist nunmehr kein Unterschied zu Knoten zu erkennen, die bereits zum Zeitpunkt der Definition der AWS als konkrete Knoten in der AWS existierten. Somit lassen sich auch die in den bisherigen Kapiteln beschriebenen Berechnungskonzepte weiterhin anwenden. 7.2 Berechnung AWS-State im Detail Nach der Betrachtung der grundlegenden Konzepte und Vorgehensweise bei der Berechnung eines AWS-State im vorangegangenen Kapitel, werden diese im Folgenden vertieft. Der Schwerpunkt liegt dabei auf der Betrachtung der unterschiedlichen Arten von AWS- und WOLM-Bezügen sowie deren Behandlung. Die Berechnung von Bezügen nimmt einen wesentlichen Teil der Berechnung eines AWS-State ein. 7.2.1 Fehlende Informationen bei der AWS-State Berechnung Es gibt verschiedene Situationen in denen ein WOLM-State nicht alle von einer AWS geforderten Informationen enthält. So können beispielsweise Bezüge auf undefinierte WOLMObjekte, Bezüge auf undefinierte Attribute eines WOLM-Objekts oder ungültige Pfade innerhalb eines Bezugs, zu einem AWS-Bezugsfehler führen. Auch wenn sie als Bezugsfehler bezeichnet werden, so verursachen solche Situationen bei der Berechnung des AWS-State keine Fehlermeldungen. Knoten, die auf fehlende Informationen zugreifen und somit einen AWS-Bezugsfehler verursachen, werden allerdings nicht in den AWS-State übernommen. Der folgende Ausschnitt einer AWS enthält einen Knoten vom Typ Link, der auf die siebte Seite einer Pagelist verweist. Für den Fall, dass die zur Pagelist gehörige Objectlist keine oder weniger als sieben Elemente aufweist, wäre die siebte Seite der Pagelist nicht vorhanden. Der Link L wäre undefiniert. Text T = „Person 7“ Link L = PL[7] Berechnung des AWS-State 46 Auch wenn der Text-Knoten T korrekt definiert ist, wäre es in einem solchen Fall von Vorteil, wenn der Text-Knoten trotzdem nicht in den AWS-State übernommen würde. Da der Link undefiniert ist, gibt es für den Text in der späteren Website keine sinnvolle Verwendung mehr. Bei einem auftretenden Bezugsfehler erscheint es somit sinnvoll, Knoten, die in einem gewissen Bereich um den bezugsfehlerverursachenden Knoten liegen, ebenfalls nicht in den AWS-State zu übernehmen. Als Grundregel sei definiert, dass ein Knoten, der einen Bezugsfehler auslöst, zur kompletten Ausblendung der „kleinsten Gruppe“ (Umgebung) in der er liegt führt. Als „kleinste Gruppe“ oder Umgebung wird die engste Schachtelung durch eine Field-/Fieldlist-Definition definiert. Existiert eine solche Definition nicht wird die engste Page-/Pagelist-Definition verwendet. Liegt der auslösende Knoten direkt unterhalb des Project-Knoten, so ist das gesamte Project undefiniert. Das Resultat ist ein leerer AWS-State und somit eine leere Website. Mit dem Einsatz von Gruppen in der AWS können die Auswirkungen auftretender Fehler, aufgrund fehlender Informationen, gesteuert werden. Page A Object O = Person Text = O.Wohnort // weitere Knoten ... Der Text-Knoten im obigen Beispiel könnte aufgrund eines nicht definierten WOLM-Objekts (O), oder eines nicht definierten Attributs (Wohnort), einen AWS-Bezugsfehler auslösen. Als Folge würde die komplette Page A ausgeblendet werden, da es sich bei ihr in diesem Fall, bezogen auf den Text-Knoten, um die „kleinste Gruppe“ handelt. Durch den Einsatz eines Page A Field F Object O = Person Text = O.Wohnort // weitere Knoten ... Field-Knoten, lässt sich der betroffene Bereich verkleinern. In diesem Fall würden nur noch Knoten, die sich innerhalb des Field-Knoten befinden ausgeblendet. Die Page A wäre damit im schlimmsten Fall leer, aber immer noch definiert und im AWS-State vorhanden. Eine Ausnahme bilden die Listenknoten Pagelist und Fieldlist. Project P Objectlist ST = Studenten Pagelist PL = ST Text = object.Vorname Text = object[index+1].Vorname Berechnung des AWS-State 47 Verursacht ein Knoten, der sich innerhalb einer Liste befindet, einen Bezugsfehler, so wird nicht die komplette Liste, sondern nur das jeweils betroffene Element der Liste ausgeblendet. Die restlichen Elemente der Liste existieren weiterhin. Obiges Beispiel macht dies deutlich. Jede Seite der Pagelist enthält zwei Text-Knoten die ihre Inhaltswerte zum einen aus dem aktuellen und zum anderen aus dem darauf folgenden Objekt der Pagelist bestimmen. Für die letzte Seite der Pagelist ist der Ausdruck index+1 größer als die Anzahl der Elemente der Pagelist, welche der Anzahl der zur Pagelist gehörigen Objectlist entspricht. Der letzte TextKnoten der Pagelist ist damit undefiniert. Als Folge wird die komplette letzte Seite nicht in den AWS-State übernommen. Alle übrigen Seiten der Pagelist werden übernommen. Das Ausblenden einer einzelnen Komponente der AWS kann in einer Kettenreaktion das Ausblenden weiterer Komponenten der AWS auslösen. Im schlimmsten Fall kann ein Bezugsfehler das komplette Project ungültig machen. Ein Beispiel für eine solche Kettenreaktion stellt eine verkette Pagelist dar. Jede Seite der Pagelist ist jeweils mit der vorherigen und nächsten Seite der Pagelist über einen Link verknüpft. Project P Objectlist ST = Studenten Pagelist PL = ST Text = object.Vorname Text = “vorheriger Student” Link = PL[index-1] Text = “nächster Student” Link = PL[index+1] Auf der ersten Seite ist ein Link auf die vorherige Seite (Seite 0) nicht möglich, da diese Seite nicht existiert. Auf der letzten Seite ist ein Link auf die nächste Seite (n+1) nicht möglich, da diese Seite ebenfalls nicht existiert. Als Folge werden die erste und letzte Seite der Pagelist nicht in den AWS-State übernommen. Dies wiederum verursacht Bezugsfehler auf der ursprünglich zweiten und vorletzten Seite der Pagelist, da deren Vorgänger bzw. Nachfolger nicht mehr definiert sind. Das Ergebnis ist die Ausblendung sämtlicher Seiten der Pagelist. Verhindern lässt sich dies im vorliegenden Beispiel durch eine Einbettung der Link-Knoten in Field-Knoten. Berechnung des AWS-State 48 Project P Objectlist ST = Studenten Pagelist PL = ST Text = object.Vorname Field Text = “vorheriger Student” Link = PL[index-1] Field Text = “nächster Student” Link = PL[index+1] Mit einer solchen Definition der AWS resultieren aus Bezugsfehlern, in Folge von Verweisen auf nicht existente Seiten einer Pagelist, lediglich die Ausblendungen der betroffenen FieldKnoten mit deren enthaltenen Knoten. Im Beispiel würde jeweils ein Link der ersten sowie letzten Seite der Pagelist ausgeblendet. Alle Seiten der Pagelist würden in den AWS-State übernommen werden. 7.2.2 Zustandsabhängige Modifikation der AWS Eine weitere Möglichkeit Teile der AWS auszublenden, dass heißt nicht in den AWS-State zu übernehmen, besteht in der Definition von Gruppen in Abhängigkeit von WOLM-Objekt Zuständen. Dazu wird einem Field-Knoten ein ihm bekanntes WOLM-Objekt zugeordnet. In Kombination mit Abfragen (vgl. Kap. 7.2.11 „BerechneObjectselection“) an dieses WOLMObjekt wird über den Status des Field-Knoten im AWS-State entschieden. Object obj = Person [ id = 5 ] Field F ? obj [ alter >= 18 ] Text = “...” Ist die obige Bedingung nicht erfüllt, hat das Attribut alter, des durch obj referenzierten WOLM-Objekts, also nicht einen Attributwert >=18, so wird der Field-Knoten nicht in den AWS-State übernommen. Eine Abfrage darf sich jeweils nur an ein einziges WOLM-Objekt richten. 7.2.3 Aufbau Awslink, Wolmpath, Wolmclass Knoten der Typen Awslink, Wolmpath, Wolmclass zählen nicht zu den AWS-Knotentypen. Eine Reihe der AWS-Knotentypen verwendet jedoch Knoten dieser Typen, als Bestandteil der eigenen Definition, um Bezüge zu anderen Knoten der AWS herzustellen oder auf konkrete Daten des WOLM zuzugreifen. Ein Awslink-Knoten enthält als einzige Information einen Pfad-Ausdruck in Form eines Strings. Ein solcher Pfad besteht aus einer Reihe benannter AWS-Knoten, die jeweils durch einen Punkt voneinander getrennt sind. Ausgehend von dem Berechnung des AWS-State 49 AWS-Knoten, der einen solchen Awslink-Knoten enthält, wird der Pfad gemäß der AWSZugriffsregeln abgearbeitet, bis der Zielknoten erreicht ist. Die folgenden Beispiele zeigen den prinzipiellen Aufbau solcher Pfade. // Bezug auf Text-Knoten Proj.PageX.Text2 // Bezug auf Image in Field-Knoten Proj.PageX.Field3.Image // Bezug auf erste Seite einer Pagelist PL[first] // Bezug auf Text-Knoten, PL = Pagelist, FL = Fieldlist Proj.PL[3].FL[2].Text4 // Bezüge auf Objektknoten vom Typ Objectlist und Object Proj.ObjList Proj.Obj Ziel eines solchen Pfads ist stets ein in der AWS existenter Knoten. Knoten des Typs Wolmpath enthalten ebenfalls einen Pfadausdruck. Der Aufbau des Pfads kann dabei zunächst dem eines Awslink-Ausdrucks entsprechen. Es wird somit zunächst ein Pfad aus in der AWS befindlichen Knoten verfolgt. Jedoch nur solange bis ein Objektknoten erreicht ist. // Obj = Object-Knoten Proj.PageB.Obj.Vorname Der weitere Teil des Pfads bezieht sich dann nicht mehr auf Knoten der AWS, sondern auf das durch den Objektknoten referenzierte WOLM-Objekt. Im obigen Beispiel wird das Attribut Vorname des referenzierten WOLM-Objekts angesprochen. Ein Wolmpath liefert immer einen atomaren Wert vom Typ int, string oder boolean. Der Pfad hinter dem Objektknoten kann auch aus mehr als einem Teil bestehen. // Obj = Object-Knoten Proj.PageB.Obj.Adr.Strasse In einem solchen Fall handelt es sich bei dem durch den Object-Knoten referenziertem WOLM-Objekt um ein Objekt welches ein Attribut besitzt, das als Wert eine Referenz auf ein weiteres WOLM-Objekt speichert. Folgende WOLM-Klassen Konstruktion wäre in einem solchen Fall denkbar. Berechnung des AWS-State class Person { Adresse Adr Freund* Freunde } 50 class Adresse { String Strasse ... } Komplexere Pfadangaben sind ebenso möglich. // PL = Pagelist, FL = Fieldlist Proj.PL[3].FL[2].Obj.Vorname Auch der dritte Knotentyp, Wolmclass, enthält einen Pfadausdruck. Die erste Möglichkeit für einen solchen Ausdruck unterscheidet sich grundlegend von denen des Awslink bzw. Wolmpath. // Klassenname Person Der Ausdruck besteht in einem solchen Fall lediglich aus der Angabe eines Klassennamens einer im WOLM enthaltenen Klasse. Mit der Angabe im obigen Beispiel werden daraufhin alle aktuellen im WOLM vorhandenen Objektinstanzen dieses Klassentyps selektiert. Ein Wolmclass-Ausdruck liefert somit eine Liste von Referenzen auf WOLM-Objekte. Diese Liste kann leer sein oder beliebig viele Elemente enthalten. Alternativ lässt sich der Pfad innerhalb eines Wolmclass-Ausdrucks in einer zum Wolmpath ähnlichen Form angeben. // Obj_Person = Object-Knoten, Referenz auf ein WOLM-Objekt PageX.Obj_Person.Adr Obj_Person.Freunde Es wird zunächst identisch zum Wolmpath ein Bezug zu einem Objektknoten innerhalb der AWS hergestellt (Knoten Obj_Person). Der Unterschied zum Wolmpath besteht in dem auf diesen Objektknoten folgenden Teil der Pfadangabe. Es wird nicht, wie beim Wolmpath, ein Attribut des WOLM-Objekts vom Typ int, string oder boolean angesprochen, sondern ein Attribut, das als Wert eine Referenz auf ein WOLM-Objekt bzw. eine Menge von Referenzen auf WOLM-Objekte enthält. Ein Wolmclass-Ausdruck selektiert somit eine Menge von Referenzen auf WOLM-Objekte. 7.2.4 Bezüge In den bisherigen Kapiteln wurde bereits auf AWS- sowie WOLM-Bezüge eingegangen. Die Funktionen BerechneAwslink und BerechneWolmpath zur Behandlung der jeweiligen Bezüge Berechnung des AWS-State 51 wurden eingeführt. Das vorliegende Kapitel, sowie einige weitere, gehen im Folgenden detaillierter auf die beiden Funktionen, ihren Zusammenhang mit der BerechneKnoten Funktion sowie auf die Besonderheiten und Probleme, die bei der Berechnung auftreten können, ein. In unten stehender Abbildung ist ersichtlich, dass die Funktionen BerechneAwslink sowie BerechneWolmpath innerhalb der BerechneKnoten Funktion aufgerufen werden können und selbst erneut die Funktion BerechneKnoten aufrufen können. Beliebig tiefe Verschachtelungen sind denkbar. Auf Grund dieser Verschachtelungen kommt es zum einen zu Abhängigkeiten in der Berechung zwischen verschiedenen Knoten der AWS. BerechneKnoten BerechneAwslink BerechneKnoten … BerechneWolmpath … … Abhängigkeiten Rekursions- zwichen Knoten gefahr Die Aufzeichnung dieser Abhängigkeiten sowie die korrekte Behandlung der Abhängigkeiten in unterschiedlichen Situationen der Berechnung des AWS-State werden im Folgenden erläutert. Neben den zwangsweise entstehende Abhängigkeiten, bei ausreichen komplexen AWS, kann es zum anderen zu einer Rekursion in der Berechnung kommen, die ebenfalls erkannt und behandelt werden muss. Im folgenden Beispiel einer AWS soll der Text-Knoten t1 berechnet werden. Project P = A Page A Text t1 = P.B.t2 Page B Object obj = Person Text t2 = obj.name // awslink // wolmpath Die Aufrufreihenfolge der einzelnen beteiligten Funktionen kann untenstehendem PseudoCode entnommen werden. In Zeile 3 erfolgt der Aufruf zur Berechnung des im Text-Knoten enthaltenen Awslink. Als Ergebnis erhält die Funktion BerechneAwslink eine Referenz auf einen berechneten Knoten, den Knoten, auf den Bezug genommen wurde. Gespeichert wird Berechnung des AWS-State 52 diese Referenz in der Variablen k. In Zeile 20 erfolgt über die so erhaltene Referenz ein Zugriff auf den Wert des Text-Knotens t2. Der Wert wird im Knoten t1 gespeichert. Der TextKnoten t1 ist berechnet. Die Zeilen 4-19 sind für das Auffinden des Text-Knotens t2, sowie zur Berechnung weiterer abhängiger Knoten zuständig. 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 BerechneKnoten(t1) { k = BerechneAwslink(t1, „P.B.t2“) { t2 = BerechneBezug(„P.B.t2“) k = BerechneKnoten(t2) { s = BerechneWolmpath(t2, „obj.name“) { obj = BerechneBezug(“obj.name”) k = BerechneKnoten(obj) { } ... // Abhängigkeit P#B#t2 Å P#B#obj return k.getAttributWert(„name“) } t2.value = s } ... // Abhängigkeit P#A#t1 Å P#B#t2 return k } t1.value = k.value } 7.2.5 Abhängigkeiten Durch die zuvor beschriebene Berechnung des Text-Knoten t1, sowie durch die Verwendung von AWS- und WOLM-Bezügen, entstehen Abhängigkeiten zwischen Knoten der AWS. Die Berechnung des Knoten t1 erfordert beispielsweise die vorherige Berechnung des Knotens t2. Der Knoten t1 kann somit im späteren AWS-State nur existieren, wenn auch der Knoten t2 existiert. Eine Aussage über die Existenz des Knoten t2 lässt sich jedoch zum Zeitpunkt der Berechnung des Knoten t1 noch nicht machen. Im Laufe der weiteren Berechnung des AWSState könnten Fehler bei der Berechnung von Knoten auftreten. Diese Fehler könnten sich auf andere Knoten, beispielsweise t2, auswirken, da sie innerhalb der gleichen Gruppe liegen und somit ebenfalls ungültig würden. Wäre in einem solchen Fall keine Information über abhängige Knoten gespeichert, so wäre es dem Knoten t2 nicht mehr möglich eine Verbindung zum Knoten t1 herzustellen. Eine solche Verbindung wäre jedoch erforderlich, da der von t2 abhängige Knoten t1 nun ebenfalls ungültig wäre. Berechnung des AWS-State Project P = A Page A Text t1 = P.B.t2 Page B Object obj = Person Text t2 = obj.name ... 53 // awslink // wolmpath // weitere AWS-Knoten Aus diesem Grund ist es erforderlich die Abhängigkeiten zwischen allen Knoten aufzuzeichnen. In der obigen AWS befinden sich zwei Abhängigkeiten. Wie schon erwähnt ist der Knoten t1 von der Existenz des Knoten t2 abhängig. Des Weiteren ist der Knoten t2 von der Existenz des Objektknotens obj abhängig. Würde der Objektknoten beispielsweise keine gültige Referenz auf ein WOLM-Objekt liefern, so wäre auch der Zugriff „obj.name“ innerhalb des Knotens t2 ungültig. Knotentypen welche direkt mittels Awslink oder Wolmpath einen Bezug zu einem anderen Knoten der AWS herstellen, verursachen somit immer eine Abhängigkeit. Darüber hinaus gibt es weitere Knotentypen, welche Abhängigkeiten verursachen. Knoten vom Typ Pagelist und Fiedlist stellen über ihr Attribut sourceobjectlist einen AWS-Bezug zu einem Objectlist-Knoten her. Somit ist jeder Pagelistbzw. Fieldlist-Knoten von der Existenz dieses Objectlist-Knotens abhängig. Pagelist PL = olist // sourceobjectlist Eine weitere Quelle für Knotentypen welche Abhängigkeiten verursachen, stellen Knotentypen dar, welche einen Knoten vom Typ objectselection enthalten können (Object, Objectlist, Fiedlist, Field). Ein solcher objectselection-Knoten kann eine oder mehrere Constraint-Knoten enthalten, welche wiederum einen Bezug zu einem anderen Knoten der AWS herstellen können. Object obj = Person [name = P.B.name] So wird im obigen Object-Knoten beispielsweise die Menge der WOLM-Objekte auf ein Objekt mit einem bestimmten Attributwert eingeschränkt. Der rechte Teil des Vergleichs bezieht sich dabei auf einen Knoten (bsp. Text-Knoten) innerhalb der AWS. Somit verursacht diese Objectselction und somit der ganze Object-Knoten eine Abhängigkeit. Auf die zu Beginn dargestellte AWS, mit ihren zwei Abhängigkeiten übertragen, lassen sich ihre Abhängigkeiten wie folgt darstellen. Berechnung des AWS-State 54 P#A#t1 Å P#B#t2 Lies: Die Existenz des Knoten t1 ist abhängig von der Existenz des Knoten t2 P#B#t2 Å P#B#obj Die zweite Abhängigkeit liest sich entsprechend. Bezeichnungen von abhängigen Knoten werden mit der vollständigen Pfadangabe ausgehend vom Project-Knoten angegeben, um die Knoten eindeutig identifizieren zu können. Unter Einbeziehung der unterschiedlichen Gruppen innerhalb einer AWS, lassen sich die beiden Abhängigkeiten vereinfachen. Die Abhängigkeit des Knoten t1 zum Knoten t2 lässt sich auf eine Abhängigkeit des Knotens t1 auf den Knoten B (Page B) reduzieren. Die kleinste Gruppe, die den Knoten t2 umgibt ist der Knoten B. Wird ein Knoten dieser Gruppe (bsp. t2) ungültig, so wäre die ganze Gruppe und somit auch der Knoten B ungültig. Die zweite Abhängigkeit muss nicht zwingend aufgezeichnet werden, da die Knoten t2 und obj innerhalb der gleichen Gruppe liegen. Wird der Knoten obj ungültig, so wird die ganze Gruppe (Page B) ungültig und somit auch der abhängige Knoten t2. Es bleibt eine Abhängigkeit. P#A#t1 Å P#B Zusammengefasst lässt sich festhalten, dass ein Knoten der AWS, der einen Bezug zu einem anderen Knoten der AWS herstellt, stets eine Abhängigkeit zwischen diesen beiden Knoten erzeugt. Gruppe Abhängigkeit K X Bezug Die Abhängigkeit besteht dann zwischen dem Knoten, der den Bezug hergestellt hat, und der kleinsten Gruppe in der sich der Zielknoten befindet. Berechnung des AWS-State 55 7.2.6 Entfernen von Knoten, abhängigen Knoten Tritt während der Berechnung eines Knotens ein Fehler auf, so wird dieser Knoten als ungültig markiert. In der unten stehenden AWS weist beispielsweise der Knoten t3 einen Bezugsfehler auf. Der Knoten ist daher ungültig und wird nicht in den AWS-State übernommen. Darüber hinaus gibt es zwei weitere Punkte zu beachten. Alle Knoten, die sich in der gleichen kleinsten Gruppe, wie der ungültig gewordene Knoten, befinden, müssen ebenfalls als ungültig markiert werden. Project P = A Page A Text t1 = P.B.t2 Page B Object obj = Person Text t2 = obj.name Text t3 = P.X.z // awslink // wolmpath // awslink, Bezugsfehler In diesem Beispiel wären dies die Knoten t2, obj und B. Weiterhin ist bei jedem Knoten, der als ungültig gekennzeichnet wird, zu beachten, dass evtl. abhängige Knoten ebenfalls als ungültig markiert werden müssen. In obiger AWS existiert die Abhängigkeit P#A#t1 Å P#B. Da der Knoten B bereits ungültig ist, muss auch der Knoten t1 als ungültig markiert werden. Dies wiederum hat zur Folge, dass die kleinste Gruppe, in der sich der Knoten t1 befindet (Page A) ebenfalls ungültig wird. Als Folge eines einzigen Bezugsfehlers (in t3) enthält das Projekt keine einzige Page. Der AWS-State und die Website sind somit leer. 7.2.7 Rekursion Die Möglichkeit der AWS-Knoten Bezüge zu anderen Knoten der AWS herzustellen birgt die Gefahr von rekursiven Bezügen. So kann es bei der Berechnung eines AWS-Knotens zu einem wiederholten Aufruf der BerechneKnoten Funktion auf demselben Knoten kommen, was letzten Endes in einer Endlosschleife endet. Einfachstes Beispiel für eine solche Situation ist der Selbstbezug eines Knoten. Knoten1 Bezug Ein Knoten stellt, beispielsweise über einen Awslink, einen Bezug zu sich selbst her. Ebenso möglich ist das entstehen einer Rekursion über mehrere Knoten hinweg. Berechnung des AWS-State Knoten1 56 Knoten2 Bezug Knoten3 Bezug Bezug Der Aufruf der BerechneKnoten Funktion für Knoten1 würde eine Berechnung von Knoten2 auslösen. Knoten2 erfordert wiederum die Berechnung von Knoten3 und dieser die Berechnung von Knoten1. Um Zyklen dieser Art zu erkennen, muss beim ersten Aufruf der BerechneKnoten Funktion (hier: bei Knoten1), beispielsweise in einer Liste, ein eindeutiger Vermerk auf den aktuellen Knoten gespeichert werden. Ebenso wird für jeden weiteren Aufruf der BerechneKnoten Funktion verfahren, bis entweder der Ausgangsknoten berechnet ist, oder ein Knoten doppelt in der Vermerkliste auftaucht. Im obigen Beispiel wäre das vierte Element einer solchen Liste (K1, K2, K3, K1) wieder ein Vermerk auf den Ausgangsknoten. Für den Fall, dass während der Berechnung eines AWS-Knotens eine Rekursion entdeckt wird, ist die AWS nicht mehr eindeutig definiert. Die Berechnung des AWS-State wird abgebrochen. 7.2.8 BerechneAwslink Jeder in der AWS auftretende Awslink wird durch die Funktion BerechneAwslink() behandelt. Die prinzipielle Vorgehensweise bei der Berechnung eines Awslink lässt sich wie folgt beschreiben. BerechneAwslink(k, awslink) { (1) starte bei Knoten k (2) verfolge von dort den im awslink gegebenen Pfad in der AWS bis der Zielknoten erreicht ist (3) berechneKnoten(Zielknoten) (4) berücksichtige Abhängigkeiten (5) gib eine Referenz auf den berechneten Zielknoten zurück } Ein Awslink stellt immer, ausgehend von einem Knoten der AWS, einen Bezug zu einem anderen Knoten der AWS her. Es lassen sich verschiedene Awslink-Arten unterscheiden. Bei der ersten Art enthält der Pfad des jeweiligen Awslink keine Bezüge zu Knoten einer Pagelist bzw. Fiedlist. Berechnung des AWS-State 57 P.Page_A.Text2 P.Page_B.Link2 P.Object_A P.Objectlist_B Der oben beschriebene Schritt (2), die Verfolgung des Pfads ausgehend vom Startknoten, lässt sich in diesen Fällen leicht verwirklichen. Die einzelnen Knoten des Pfades werden dabei Schritt für Schritt gemäß der Zugriffsregeln der AWS abgearbeitet. Handelte es sich um einen gültigen Pfad, so ist der Zielknoten nach Abarbeitung des Pfades erreicht. Die zweite Art von Awslink-Ausdrücken enthält Bezüge auf Knoten einer Pagelist und oder einer oder mehrerer Fieldlist. P.PL[first].FL[5].Name Der obige Awslink bezieht sich auf einen Knoten mit der Bezeichnung „Name“, der sich im fünften Feld einer Fieldlist befindet, welches sich wiederum auf der ersten Seite einer Pagelist befindet. Sind die jeweiligen Listen noch nicht berechnet, so müssen zunächst diese, ihre zugehörigen Objektlisten, sowie evtl. weitere Knoten berechnet werden, bevor der Zielknoten „Name“ erreicht und eine Referenz auf ihn zurückgegeben werden kann. Da dieses Vorgehen bereits komplizierter ist und es diverse weitere Pfadkonstruktionen gibt, empfiehlt es sich den oben mit (2) gekennzeichneten Schritt in einer eigenen Funktion zu kapseln. Aufgabe dieser Funktion ist es ausgehend von einem Knoten der AWS, mit Hilfe eines gültigen Pfades, einen anderen Knoten der AWS zu erreichen und eine Referenz zurückzugeben. Hinzu kommt, das diese neue Funktion auch für Wolmpath-Pfade, welche in der Funktion BerechneWolmpath verarbeitet werden, sowie für Berechnung weiterer Bezüge in der AWS (z.Bsp: sourceobjectlist) verwendet werden kann. Die Vergleichweise schwierige und vielfältige Behandlung von Pfadangaben innerhalb von Bezügen werden also zentral in der Funktion BerechneBezug behandelt. Zusammengefasst hat die Funktion BerechneAwslink somit folgenden Aufbau. 1 2 3 4 5 6 7 k = BerechneAwslink(t1, „P.A.B“) { r = BerechneBezug(t1, „P.A.B“) k = BerechneKnoten(r) { ... } ... // Abhängigkeiten beachten return k } Berechnung des AWS-State 58 Die Funktion bekommt einen Startknoten (t1) sowie einen Pfad („P.A.B“) übergeben. Anhand dieser beiden Parameter wird eine Referenz auf den Zielknoten („B“) erzeugt. Der Zielknoten wird berechnet. In Zeile 5 wird die Abhängigkeit zwischen Start- und Zielknoten aufgezeichnet. Die Funktion BerechneAwslink liefert, im Erfolgsfall, immer eine Referenz auf einen berechneten Knoten. 7.2.9 BerechneWolmpath Da die Pfadangabe innerhalb eines Wolmpath-Ausdrucks in weiten Teilen denen eines Awslink-Ausdrucks ähnelt, gestaltet sich auch die Berechnung ähnlich zu der eines Awslink. BerechneWolmpath(k, wolmpath) { (1) starte bei Knoten k (2) verfolge von dort den im awslink gegebenen Pfad in der Aws bis der Zielknoten erreicht ist (3) berechneKnoten(Zielknoten) (4) bestimme Wolmpath-Wert anhand Objektreferenz und Pfad (5) berücksichtige Abhängigkeiten (6) gib Wolmpath-Wert zurück } Die Hauptarbeit findet, genau wie bei der Berechnung eines Awslink, in Schritt (2) statt. Die Ermittlung des Zielknotens erfolgt dabei wieder mit Hilfe der Funktion BerechneBezug, wie folgendes Beispiel zeigt. Text t2 = P.A.B[2].Obj.name // Obj = Object-Knoten Die Berechnung des Knoten t2 erfolgt dabei wie folgt. Ein Aufruf der Funktion BerechneBezug bearbeitet den Pfad des Wolmpath-Ausdrucks, und ermittelt eine Referenz auf den im Pfad enthaltenen Objektknoten Obj, dem Zielknoten. Nach erfolgter Berechnung des Zielknotens, wird in Zeile 6 das Attribut name, des durch den Objektknoten Obj, auf den nun eine Referenz vorliegt (k), referenzierten WOLM-Objekts, abgefragt. 1 2 3 4 5 6 7 s = BerechneWolmpath(t2, „P.A.B[2].Obj.name“) { obj = BerechneBezug(t2, “P.A.B[2].Obj.name”) k = BerechneKnoten(obj) { } ... // Abhängigkeiten beachten return k.getAttributWert(„name“) } Berechnung des AWS-State 7.2.10 59 BerechneBezug Die Funktion BerechneBezug ist eine der wichtigsten Funktionen bei der Berechnung des AWS-State. Ihre Aufgabe ist die Ermittlung einer Referenz auf einen Knoten der AWS. Dieser Knoten wird ausgehend von einem anderen Knoten der AWS, mittels eines Pfads, gemäß der Zugriffsregeln der AWS erreicht. Verwendung findet die Funktion bei der Berechnung von Knoten, die einen Bezug zu anderen Knoten der AWS herstellen. Diese Bezüge können beispielsweise mittels eines Awslink oder Wolmpath, aber auch im Rahmen eines sourceobjectlist-Attributs (Pagelist/Fieldlist), des indexof-Operators oder einer Objectselection, hergestellt werden. Auf alle Möglichkeiten wird im Folgenden eingegangen. Die einfachste Form von Bezügen stellen AWS-Bezüge zu anderen Knoten der AWS dar, welche keine Pagelist oder Fieldlist Knoten enthalten. Ein Beispiel ist ein Awslink innerhalb eines Text-Knotens, der einen Bezug zu einem Knoten der AWS mit der Bezeichnung A herstellen möchte. Die Funktion BerechneBezug soll nun eine Referenz auf diesen Knoten A liefern. Text t1 = P.B.A // awslink In einem ersten Schritt werden dazu die einzelnen Bestandteile des Pfads (P.B.A) anhand des Zeichens „.“ separiert. Darauf hin wird untersucht, ob der auf diese Weise erste erhaltene Knoten (P), ausgehend vom bezugnehmenden Knoten (t1), gemäß der AWS Zugriffsregeln erreicht werden kann. Ist dies der Fall, so wird in einem nächsten Schritt ausgehend vom aktuellen Knoten versucht den nächsten Knoten zu erreichen. Dies geschieht solange bis alle Knoten des Pfads abgearbeitet und der Zielknoten erreicht wurde. Ist der Zielknoten erreicht, so gibt die Funktion BerechneBezug eine Referenz auf ihn zurück. Während des gesamten Ablaufs werden keine Knoten berechnet. Es wird lediglich der Pfad in der AWS verfolgt und eine Referenz auf einen Knoten zurückgegeben. Neben der Einhaltung der Zugriffsregeln der AWS, sind zwei weitere Punkte zu beachten. Es ist möglich, dass ein Knoten innerhalb des angegebenen Pfads nicht erreicht werden kann. Denkbar wären eine falsche Bezeichnung, eine Verletzung der Zugriffsregeln oder ein Zugriff auf einen bereits ungültigen Knoten. In allen Fällen kann der Zielknoten nicht erreicht werden. Es kommt zu einem Bezugsfehler, der an die aufrufenden Funktionen weitergegeben wird. Berechnung des AWS-State Text t1 = P.B.O.A 60 // wolmpath, O = Object-Knoten Der obige Pfad (P.B.O.A) unterscheidet sich zunächst nicht von dem vorangegangenen Beispiel. Es handelt sich hierbei jedoch nicht um einen Awslink sondern einen Wolmpath. Das Vorgehen zum Erreichen des Zielknotens ist identisch mit dem zuvor beschriebenen. Bei einer Pfadangabe innerhalb eines Wolmpath-Ausdrucks handelt es sich bei dem letzten durch einen Punkt getrennten Bezeichner (hier: A) jedoch nie um den eigentlichen Zielknoten. Bei dem Zielknoten handelt es sich immer um einen Objektknoten. Einen Knoten vom Typ Object oder Objectlist (hier: O). Der Teil des Pfads hinter dem Objekt-Knoten bezieht sich nicht mehr auf die AWS, sondern auf das durch den Objekt-Knoten referenzierte WOLM-Objekt. Dieser Teil kann aus mehr als einem Bezeichner bestehen. Für die Funktion BerechneBezug endet die Verfolgung des Pfads somit sobald ein Objektknoten erreicht wurde. Eine Referenz auf diesen Objektknoten wird zurückgegeben. Befindet sich innerhalb der Pfadangabe ein Knoten vom Typ Field, welcher wiederum mittels einer Objectselection seine Existenz im AWS-State von einem Zustand des WOLM abhängig macht, so muss dieser Knoten gesondert behandelt werden. Text T1 = A.F.T2 // F = Field-Knoten mit objectselection Page A Text T1 Field F Text T2 awslink Object Obj objectselection Field F ? Obj [x > 3] Ist die Verfolgung des Pfads beim Knoten F angekommen, so muss dieser Knoten zunächst berechnet werden. Der Objectselection-Ausdruck des Field-Knotens wird berechnet. Kommt die Berechnung zu dem Ergebnis, dass der Field-Knoten im AWS-State existiert so kann die Verfolgung des Pfads fortgesetzt werden. Würde der Knoten nicht existieren, so würden auch alle weiteren Knoten unterhalb des Knotens nicht existieren. Eine weitere Verfolgung des Pfads wäre somit überflüssig. Es läge auf jeden Fall ein Bezugsfehler vor. Eine Berechnung des Field-Knotens ist nicht zwingend erforderlich. Würde der Field-Knoten nicht an dieser Berechnung des AWS-State 61 Stelle berechnet und die Verfolgung des Pfads fortgesetzt, so würde die Funktion BerechneBezug zunächst eine gültige Referenz auf den Zielknoten (hier: T2) bestimmen. Mit Hilfe der aufgezeichneten Abhängigkeit zwischen Knoten T1 und T2 kann der Knoten nachträglich als ungültig deklariert werden, falls der Knoten T2 aufgrund eines nicht existenten Field-Knotens F aus dem AWS-State eliminiert würde. Beide Wege sind möglich. Welcher Weg effizienter ist, hängt letzten Ende auch von der jeweiligen AWS ab. Der untenstehende Text-Knoten verwendet wiederum einen Awslink um einen Bezug zu einem Knoten (A) herzustellen. Im Unterschied zu den bisherigen Pfaden enthält dieser Pfad indizierte Zugriffe. In diesem Fall wird auf die dritte Seite eines Pagelist-Knoten zugegriffen. Für den Fall, dass die dritte Seite bereits in der AWS vorhanden ist, unterscheidet sich der Zugriff nicht von dem Zugriff auf einen normalen Page-Knoten, da der Knoten, der die dritte Seite der Pagelist repräsentiert den passenden Namen (PL[3]) besitzt. Im aktuellen Beispiel wird einfach ausgehend vom Knoten P nach einem Knoten mit dem Namen „PL[3]“ gesucht. Text t1 = P.PL[3].A // awslink, PL = Pagelist Sind die entsprechenden einzelnen Page-Knoten der zugehörigen Pagelist noch nicht in der AWS vorhanden, so kann kein Knoten mit dem Namen „PL[3]“ an der passenden Stelle gefunden werden. Ein Bezugsfehler würde ausgelöst. P Knoten PL[3] nicht vorhanden Knoten P vorhanden T1 PL A Damit dies verhindert werden kann, müssen indizierte Teile von Pfadangaben (Teile mit […]) weiter aufgeteilt werden, in einen Namen und einen Index (hier: PL und 3). In einem zweiten Versuch kann dann, ausgehend von Knoten P nach einem Knoten mit dem Namen „PL“ gesucht werden, dem Knoten der Pagelist. Anhand der zur Pagelist gehörigen Objektliste kann die Anzahl der Page-Knoten der Pagelist PL bestimmt werden. Ggf. muss der Objektlistenknoten hierzu zunächst berechnet werden. Für jedes Element der Objektliste wird ein neuer Page-Knoten in die AWS eingefügt (vgl. auch Berechnung Pagelist). Die Page-Knoten sowie die jeweiligen Unterknoten werden nur in die AWS eingefügt, jedoch nicht berechnet. Berechnung des AWS-State 62 Ausgehend vom nun in der AWS vorhandenen Page-Knoten „PL[3]“ kann der Pfad „P.PL[3].A“ weiterverfolgt und schließlich die gewünschte Referenz auf den Zielknoten A P T1 PL Objectlist A PL[1] PL[2] PL[3] A A A awslink: P.PL[3].A ermittelt werden. Für Knoten vom Typ Fieldlist gelten die gleichen Ausführungen wie die obigen für Knoten vom Typ Pagelist, wobei Fieldlist-Knoten beliebig oft in einem Pfadausdruck, Pagelist-Knoten hingegen nur maximal einmal vorkommen können. Text t1 = P.PL[3].FL[5].A // awslink Text t1 = P.PL[3].FL[5].Obj.Name // wolmpath Wie obiges Beispiel zeigt, können die Pfadangaben innerhalb von Awslink- und WolmpathAusdrücken wiederum sehr ähnlich sein. Die unterschiedliche Behandlung erfolgt beim Wolmpath-Ausdruck beim Erreichen des Knoten Obj, der einen Objektknoten vom Typ Object darstellt. Neben dem indizierten Zugriff auf Objekte eines Pagelist- bzw. FieldlistKnoten sind des Weiteren Zugriffe auf Knoten vom Typ Objectlist möglich. Dabei wird ein einzelnes Element der in der Objektliste enthaltenen Elemente ausgewählt. Text t1 = P.B.OL[3].A.B // wolmpath, A.B Pfad im WOLM Bei allen beschriebenen indizierten Zugriffen kann es zu Bezugsfehlern kommen, falls versucht wird über einen ungültigen Index auf ein Element zuzugreifen. Dies ist z.Bsp. dann der Fall, wenn der Index größer ist, als die Anzahl der in der Liste enthaltenen Elemente. Werden in die Betrachtung Knoten vom Typ Listofobjectlists aufgenommen, so ergibt sich eine weitere Art der Indizierung von Elementen einer Liste, die in Pfadangaben eines Bezugs auftreten kann. Der durch das Vorhandensein einer Listofobjectlists notwendige zweite Index wird durch ein Komma vom ersten Index getrennt dargestellt. Dies muss ggf. bei der oben beschriebenen Aufteilung eines solchen Ausdrucks, in Namen und Index, berücksichtigt Berechnung des AWS-State 63 werden. Auftreten können solche doppelten Indizes, bei einem Bezug auf einen Knoten vom Typ Pagelist, welchem eine Objektliste vom Typ Listofobjectlists zugrunde liegt, oder bei einem direkten Zugriff auf einen Knoten vom Typ Listofobjectlists (siehe folgendes Beispiel). // awslink, PL= Pagelist mit Listofobjectlists Text t1 = P.PL[3,1].FL[5].A // wolmpath, LOOL = Listofobjectlists Text t1 = P.B.LOOL[3,1].A.B Neben der direkten Angabe von numerischen Indizes, können in einer Pfadangabe verschiedene Schlüsselwörter auftreten. Diese lauten: index index2 first last // // // // aktuelle Position innerhalb Pagelist/Fieldlist zweiter Index, bei Pagelist mit Listofobjectlists erstes Element = 1 letztes Element einer Page-/Field-/Objectlist // Position des Objekts O in der Objektliste OL indexof O in OL Diese Schlüsselwörter müssen gemäß ihrer Bedeutung ausgewertet werden. Ergebnis dieser Auswertung ist stets ein numerischer Wert. Zusätzlich sind die Operationen „+“ und „-„ auf Indizes erlaubt. Gültige Ausdrücke wären somit beispielsweise [index+1], [first+2], [5-3], usw., welche wiederum zu numerischen Ausdrücken ausgewertet werden müssen. Eine gesonderte Betrachtung bedarf das Schlüsselwort indexof. Am häufigsten Verwendung finden sicherlich Ausdrücke der ersten Form (1). Hierbei ermittelt indexof die Position des aktuellen Objekts (object) eines Listenknotens (Pagelist/Fieldlist) innerhalb einer Objectlist (Objlist). Ein Zugriff auf die beteiligten Knoten ist in einem solchen Fall vergleichsweise einfach möglich. Die Position lässt sich bestimmen, der Ausdruck indexof kann somit einen numerischen Wert bestimmen. (1) [indexof object in Objlist] (2) [indexof P.A.Obj in P.B.Objlist] (3) [indexof P.A.Objlist[3] in P.B.Objlist] Möglich sind aber auch, zumindest theoretisch, Ausdrücke der Formen (2) und (3). Hierbei handelt es sich bei dem ersten Objektknoten nicht um das aktuelle Objekt eines Listenknotens. Stattdessen wird ein Bezug zu einem Objektknoten der AWS hergestellt, welcher Berechnung des AWS-State 64 wiederum zunächst ausgewertet werden muss. Dies beinhaltet die Identifizierung des Knotens in der AWS (BerechneBezug), evtl. Berechnung des Knotens sowie weiterer Knoten, sowie die Gefahr von Rekursion und das Entstehen von Abhängigkeiten. Eine Besonderheit für die Funktion BerechneBezug stellen Pfadangaben der folgenden Form da, wie sie ausschließlich in Knoten vom Typ Wolmpath vorkommen können. Text t1 = object[index].A.B // wolmpath Beginnt eine Pfadangabe mit dem Schlüsselwort object, so ist ein Aufruf der Funktion BerechneBezug nicht erforderlich, da es sich bei dem Zielknoten dieses Bezugs um den aktuellen Objektknoten einer Pagelist/Fieldlist handelt. Der bezugnehmende Knoten t1 befindet sich jedoch in der gleichen Liste, ansonsten wäre eine Verwendung von object nicht möglich. Der Zielknoten ist somit bekannt und eine Ermittlung einer Referenz auf den Zielknoten mittels Aufruf der Funktion BerechneBezug ist nicht erforderlich. Eine weitere Verwendung findet die Funktion BerechneBezug bei der Ermittlung der zu einer Pagelist/Fieldlist gehörigen Objektliste. Das Attribut sourceobjectlist einer Pagelist/Fieldlist stellt dazu einen AWS-Bezug zu einem Knoten vom Typ Objectlist bzw. Listofobjectlist her. In vielen Fällen ist dieser Objektknoten dem zugehörigen Listenknoten direkt bekannt, da sich beide auf der gleichen Ebene befinden, damit Geschwisterknoten sind, und ein direkter Zugriff gemäß der AWS-Zugriffsregeln möglich ist. Objectlist OL = Personen Pagelist PL = OL // sourceobjectlist: OL Denkbar sind aber auch komplexere AWS-Bezüge. Beispielsweise könnte sich die zugehörige Objektliste innerhalb einer anderen Seite, innerhalb eines Fieldlist-Knotens befinden. Pagelist PL = P.A.FL[7].OL // sourceobjectlist: P.A.FL[7].OL Für solche Fälle kann mit der Funktion BerechneBezug einfach eine Referenz auf die entsprechende Objektliste ermittelt werden. Die evtl. Berechnung des so referenzierten Knotens, das Erkennen von Rekursion sowie die Aufzeichnung von Abhängigkeiten sind dann wiederum Aufgaben, die in der Funktion zu Berechnung eines Knotens vom Typ Berechnung des AWS-State 65 Pagelist behandelt werden. Ein letzter Einsatzbereich für die Funktion BerechneBezug stellen Knoten vom Typ objectselection dar. Ein solcher Knoten kann Bezüge zu anderen Knoten der AWS herstellen. Der Knoten in Beispiel (1) schränkt mittels einer objectselection die Menge der Objekte vom Typ „Person“ auf ein Objekt mit dem Attributwert „4“ ein. Bezüge zu anderen AWS-Knoten sind nicht vorhanden. (1) Object O1 = Person [knr = 4] (2) Object O2 = Person [knr = P.PL[4].FL[first].knr] (3) Objectlist OL = O1, O2, P.A.O3 Beispiel (2) zeigt, dass der Wert für den Vergleich innerhalb einer Bedingung auch aus anderen Knoten der AWS stammen kann. Dies kann mittels Awslink oder Wolmpath, mit den für beide typischen und in diesem Kapitel beschriebenen Pfadangaben, geschehen. Mittels eines Awslink innerhalb einer Objectselection ist es zudem möglich auf andere Objektknoten zuzugreifen (3), welche dann die Elemente einer neuen Objektliste bilden. Die Identifizierung sowie Ermittlung der Referenz auf die entsprechenden Knoten ist wiederum Aufgabe der Funktion BerechneBezug. Rekursion und Abhängigkeiten werden innerhalb der bezugnehmenden Knoten bzw. deren Objectselection-Ausdrücken behandelt. Im folgenden Kapitel erfolgt eine detaillierte Betrachtung der Berechnung von Knoten vom Typ Objectselection. 7.2.11 BerechneObjectselection Für die Berechnung eines Objectselection-Ausdrucks ist es zunächst interessant seinen Aufbau und seine Position in der AWS zu betrachten. Knotentypen die einen oder mehrere Objectselection-Ausdrücke enthalten bzw. enthalten können sind zum einen die Objektknoten Object und Objectlist, zum anderen Knoten vom Typ Field bzw. Fieldlist. Auf die genaue Bedeutung und Verwendung eines Objectselection-Ausdrucks innerhalb dieser Knotentypen, wird ausführlicher in der Beschreibung der Berechnung der einzelnen Knotentypen eingegangen. Der prinzipielle Aufbau einer Objectselection kann der folgenden Abbildung entnommen werden. Berechnung des AWS-State 66 Knoten k objectselection objectselection … … awslink / constraint constraint … wolmclass awslink wolmpath … Die Definition in der AWS-DTD legt den genauen Aufbau fest. <!ELEMENT objectselection ((wolmclass | awslink)+, constraint*)> Ein Knoten vom Typ Objectselection enthält zunächst wahlweise einen Knoten vom Typ Wolmclass oder Awslink. Aufgabe dieses Knotens ist die Selektion von WOLM-Objekten. Das „+“-Zeichen in einer DTD hat die Bedeutung, dass der entsprechende Ausdruck (hier: „(wolmclass | awslink)“) mindestens einmal in dem jeweils definierten Knoten vorkommen muss. Somit wären laut DTD-Definition theoretisch mehrere Vorkommen von Awslink bzw. Wolmclass an dieser Stelle des Objectlist-Knotens erlaubt. Die resultierenden AWSDokumente wären laut DTD valide. Eine solche Bedeutung ist jedoch nicht gewünscht. Auf die AWS bezogen muss die Bedeutung an dieser Stelle hingegen „genau einmal“ und nicht „mindestens einmal“ sein. Eine solche Definition ist mit Hilfe einer DTD jedoch nicht möglich. Als weitere Knoten kann ein Objectselection-Knoten optional einen oder mehrere Knoten vom Typ Constraint enthalten. Mit Hilfe dieser Knoten können Bedingungen definiert werden, die die im ersten Schritt ausgewählten WOLM-Objekte weiter einschränken können. Eine genauere Behandlung der Knoten vom Typ Constraint erfolgt in einem späteren Abschnitt. Aus obiger Abbildung ist jedoch schon ersichtlich, dass Knoten diesen Typs wiederum Knoten der Typen Awslink und Wolmpath enthalten können. Das Auftreten von Awslink- und Wolmpath-Knoten an dieser Stelle, sowie an der Stelle der ersten Selektion der WOLM-Objekte, macht deutlich, dass Knoten, die einen Objectselection-Knoten enthalten, über diesen Knoten Bezüge zu anderen Knoten der AWS herstellen können. Dies beinhaltet die bekannten Probleme der Rekursion und Abhängigkeiten zwischen Knoten. Awslink- und Wolmpath-Knoten lassen sich jedoch wie gehabt mit den Funktionen BerechneAwslink und BerechneWolmpath berechnen. Der Startknoten ist hierbei immer der Knoten, der den Objectselection-Knoten enthält. Berechnung des AWS-State 67 Beispiele ohne "constraint" Wie beschrieben, kann die erste Selektion von WOLM-Objekten mittels Wolmclass- oder Awslink-Knoten erfolgen. Mit Hilfe eines Wolmclass-Knotens lässt sich diese Selektion auf die folgenden Arten durchführen. <objectselection> <wolmclass> Lehrstuhl </wolmclass> </objectselection> In obigem Beispiel werden alle Objekte des aktuellen WOLM-State selektiert, die Instanzen der Klasse "Lehrstuhl" sind. Das Ergebnis kann ein oder mehrere WOLM-Objekte umfassen, oder auch leer sein. <objectselection> <wolmclass> Object_Lehrstuhl.diplomanden </wolmclass> </objectselection> In diesem Fall handelt es sich bei dem Knoten Object_Lehrstuhl um einen AWS-Knoten vom Typ Object, der eine Referenz auf ein WOLM-Objekt enthält. Der zweite Teil des obigen Ausdrucks („.diplomanden“) stellt einen Pfad in diesem WOLM-Objekt dar. Für die Berechnung wird zunächst eine Referenz auf den AWS-Knoten ermittelt (mit Hilfe der Funktion BerechneBezug). Anschließend kann über den entsprechenden Pfad (hier: „.diplomanden) auf die jeweiligen WOLM-Objekte des aktuellen WOLM-State zugegriffen werden. Das Ergebnis kann ein oder mehrere WOLM-Objekte umfassen, oder auch leer sein. Die Selektion mittels Awslink-Knoten kann auf die folgenden Arten geschehen. <objectselection> <awslink> Object_Lehrstuhl </awslink> </objectselection> Mit Hilfe des Awslink-Knoten können die bekannten und bislang beschriebenen AWSBezüge zu anderen Knoten hergestellt werden. Aufbau und Berechnung des Awslink sind bekannt. Bei der Verwendung des Awslink im Rahmen einer Objectselection ist zu beachten, dass es sich bei dem Zielknoten um einen Knoten vom Typ Object oder Objectlist handeln muss. Alle in einem solchen Objektknoten referenzierten WOLM-Objkete werden in der Selektion übernommen. Berechnung des AWS-State 68 <objectselection> <awslink> P.A.Objectlist_Diplomanden </awslink> </objectselection> Nach erfolgter Selektion, mittels Wolmclass bzw. Awslink, steht eine Menge von Referenzen auf Objekte des WOLM zu Verfügung. Diese Menge kann in einem zweiten Schritt weiter eingeschränkt werden. Einschränkungen mit "constraint" Die Einschränkungen werden in Knoten vom Typ Constraint definiert. Jede Einschränkung wird auf alle im ersten Schritt selektierten WOLM-Objekte angewandt. Sollten mehrere Constraint-Knoten vorhanden sein, so werden diese UND-verknüpft. <objectselection> ...(awslink|wolmclass) <constraint> <wolmattribute> Bezeichnung </wolmattribute> <binaryoperator operator = "eq"/> <awslink> P.A.X </awslink> </constraint> </objectselection> Es gibt zwei Arten der Definition einer Einschränkung. Obiges Beispiel verwendet einen zweistelligen Operator (binaryopeator). Eine solche Einschränkung bezieht sich immer auf ein Attribut eines WOLM-Objekts. Dabei wird ein ausgewählter Attributwert, hier der Wert des Attributs „Bezeichnung“, mit einem weiteren Wert verglichen. Für diesen Vergleich stehen die Operatoren = , < , > , != , <= , >= bereit, die in der AWS entsprechend benannt sind (eq | lt | gt | neq | lte | gte). Der Wert für den Vergleich kann aus einem Knoten vom Typ Const, Awslink oder Wolmpath stammen (vgl. AWS-DTD). Ist das Ergebnis des Vergleichs negativ, so wird das entsprechende Objekt aus der Objectselection entfernt. Die zweite Möglichkeit besteht in der Verwendung eines einstelligen Operators. Bislang ist in der AWS lediglich ein solcher Operator definiert. Eine spätere Erweiterung wäre jedoch möglich. Der Operator isInstanceOf prüft die Klassenzugehörigkeit eines WOLM-Objekts. Berechnung des AWS-State 69 <objectselection> ...(awslink|wolmclass) <constraint> <singleoperator operator = "isInstanceOf"/> <wolmclass> Lehrstuhl </wolmclass> </constraint> </objectselection> Im vorliegenden Beispiel wird überprüft, ob das WOLM-Objekt eine Instanz der Klasse "Lehrstuhl" ist. Ist dies nicht der Fall so wird dieses Objekt ebenfalls aus der Objectselection entfernt. Ergebnis der Berechnung eines kompletten Objectselection-Knotens ist immer eine Liste von Referenzen auf WOLM-Objekte. Diese Liste kann leer sein oder beliebig viele Elemente enthalten. 7.3 Berechnung Knotentypen Nach der Betrachtung aller zur Berechnung des AWS-State erforderlichen Konzepte, wird in diesem Kapitel die Berechnung der einzelnen AWS-Knotentypen behandelt. Die wichtigsten Konzepte, die für diese Berechnung direkt genutzt werden, sollen noch einmal kurz zusammengefasst werden. Die meisten der AWS-Knotentypen enthalten in ihrer eigenen Definition einen oder mehrere Knoten der Typen Awslink, Wolmpath oder Objectselection. Für jeden dieser drei Typen wurde im vorangegangenen Kapitel eine Berechnungsfunktion vorgestellt. Für jedes Auftreten eines dieser drei Typen innerhalb der Berechnungsfunktion eines AWSKnotens genügt also ein entsprechender Aufruf einer dieser Funktionen. Die eigentlichen Berechnungsfunktionen für die verschiedenen AWS-Knotentypen bleiben dadurch vergleichsweise einfach und übersichtlich. BerechneAwslink liefert dabei eine Referenz auf den Knoten, auf den Bezug genommen wurde. Dieser Knoten ist vollständig berechnet. Innerhalb der BerechneKnoten Funktion wird dann, je nach Knotentyp, über die weitere Verwendung des referenzierten Knoten entschieden. Dies kann beispielsweise die Ermittlung der AWS-State-ID oder des Inhaltswertes sein. BerechneWolmpath liefert einen konkreten Wert aus dem WOLM. Dieser Wert wird ebenfalls, je nach Knotentyp des bezugnehmenden Knotens, weiterverarbeitet. Für die Berechnung von Knoten vom Typ Object, Objectlist oder Field ist die Funktion BerechneObjectselection, welche eine Liste von Referenzen auf WOLM-Objekte liefert, besonders hilfreich, da diese Knotentypen jeweils ein oder mehrere Knoten vom Typ Objectselection enthalten. Berechnung des AWS-State 70 Text Ein Knoten vom Typ Text ist in der AWS wie folgt aufgebaut. Auszug AWS-DTD: <!ELEMENT text ((const | awslink | wolmpath)+, link?)> Er kann seinen Inhaltswert über eine Reihe von konstanten Inhaltswerten (const), AWSBezügen (awslink) und oder WOLM-Bezügen (wolmpath) bestimmen. Die AWS-State Repräsentation eines Text-Knotens enthält lediglich einen konstanten Inhaltswert. Ziel der Berechnung ist also die Auflösung von AWS- und WOLM-Bezügen, sowie die Zusammenführung eventueller Mehrfachvorkommen von const-Ausdrücken. Das prinzipielle Vorgehen bei der Berechnung kann dem untenstehenden Pseudo-Code entnommen werden. Die Darstellung ist stark vereinfacht und berücksichtig evtl. auftretende Fehler nicht. BerechneKnotenText(Knoten) { // für jeden const-Ausdruck Knoten.const += const // für jeden awslink-Ausdruck Ref = BerechneAwslink(Knoten, awslink) Knoten.const += Ref.const // für jeden wolmpath-Ausdruck Knoten.const += BerechneWolmpath(Knoten, wolmpath) return Knoten } Für jedes Vorkommen eines Const-Ausdrucks wird der konstante Wert des Ausdrucks an den Wert des zu berechnenden Knoten angehängt. Für jeden vorhandenen Awslink wird die Funktion BerechneAwslink aufgerufen, welche eine Referenz auf den Knoten im AWS-Bezug zurückgibt. Da dieser referenzierte Knoten stets bereits berechnet ist, kann über „Ref.const“ auf dessen Inhaltswert zugegriffen werden. Zu beachten ist hierbei, dass es sich bei dem Knoten im AWS-Bezug um einen Knoten vom Typ Text, Hiddentextinput oder Textinput handeln Berechnung des AWS-State 71 muss. Bezüge zu anderen Knoten sind nicht erlaubt und auf Grund fehlender Inhaltswerte für einen Text-Knoten auch nicht sinnvoll. Für jedes Vorkommen eines Wolmpath wird die Funktion BerechneWolmpath aufgerufen und der zurückgegebene Wert dem Inhaltswert des zu berechnenden Knotens angehängt. Schließlich sind sämtliche AWS- sowie WOLMBezüge aufgelöst. Der Text-Knoten ist berechnet. Textinput Konten vom Typ Textinput besitzen bis auf den fehlenden optionalen Knoten vom Typ Link die gleiche AWS-Definition. Auszug AWS-DTD: <!ELEMENT textinput ((const | awslink | wolmpath)+)> Die Berechnung kann daher analog zu der Berechnung von Knoten vom Typ Text erfolgen. Hiddentextinput Konten vom Typ Hiddentextinput besitzen bis auf den fehlenden optionalen Knoten vom Typ Link die gleiche AWS-Definition. Auszug AWS-DTD: <!ELEMENT hiddentextinput ((const | awslink | wolmpath)+)> Die Berechnung kann daher analog zu der Berechnung von Knoten vom Typ Text erfolgen. Image Knoten vom Typ Image besitzen eine sehr ähnliche AWS-Definition, wie Knoten vom Typ Text. Auszug AWS-DTD: <!ELEMENT image ((const | awslink | wolmpath), link?)> Der Unterschied besteht darin, dass ein Knoten vom Typ Image lediglich genau ein Vorkommen eines Const-, Awslink- oder Wolmpath-Ausdrucks enthalten darf. Für die Berechnung spielt dies jedoch keine Rolle. Das gleiche Vorgehen wie bei der Berechnung eines Knoten vom Typ Text kann angewandt werden. Zusätzlich sind AWS-Bezüge auf Knoten vom Typ Image erlaubt. In einem solchen Fall wird die Bildinformation aus dem Zielknoten übernommen. Link Der Aufbau von Knoten vom Typ Link ähnelt wieder stark den bislang beschriebenen Knotentypen. Auszug AWS-DTD: Berechnung des AWS-State 72 <!ELEMENT link (const | awslink | wolmpath)> Zu unterscheiden sind externe und interne Links. Bei externen Links handelt es sich bei dem berechneten Wert um eine korrekte Webadresse der Form „http://www.adresse.de“. Dieser Wert kann aus dem Const-Ausdruck, aus dem WOLM (Wolmpath) oder einem anderen LinkKnoten innerhalb der AWS (Awslink) stammen. Interne Links hingegen stellen einen Verweis auf einen anderen Knoten innerhalb der AWS dar. Als Verweisziel sind hierbei alle Knotentypen mit grafischer Repräsentation zulässig. Das heißt, alle Knotentypen, außer Object, Objectlist, Listofobjectlist und Action. Als Wert für den aktuellen Link-Knoten wird dann die AWS-State-ID des Zielknotens gespeichert. Page Knoten vom Typ Page dienen lediglich als Container für weitere Knoten. Neben der Zuweisung der für jeden Knoten erforderlichen AWS-State-ID ist eine weitere Berechnung nicht erforderlich. Project Für Knoten vom Typ Project gilt grundsätzlich das gleiche wie bei Knoten vom Typ Page. Bei einem Project-Knoten muss zusätzlich überprüft werden, ob der im Attribut „startpage“ angegebene Knoten im AWS-State existiert. Ist dies der Fall, so wird dem Attribut „startpage“ die AWS-State-ID selbigen Knotens zugewiesen. Field Die Hauptaufgabe eines Knoten vom Typ Field, ist ähnlich wie bei Knoten vom Typ Project und Page, die Aufnahme weiterer Knoten. Im Gegensatz zu Project- und Page-Knoten kann ein Knoten vom Typ Field zusätzlich einen Objectselection-Ausdruck enthalten. Dieser Ausdruck ermöglicht eine zustandsabhängige Modifikation der AWS, in diesem Fall entscheidet er, ob der jeweilige Field-Knoten, sowie seine enthaltenen Knoten, in den AWS-State übernommen wird oder nicht. <!ELEMENT field (objectselection?, (…weitere Knoten…)*)> Ein dem Field-Knoten bekanntes Objekt (hier: „a“) wird zusammen mit einer Objectselection (hier: „a[preis>5][fsk<18]“) dem Field-Knoten zugeordnet. Berechnung des AWS-State 73 Object a = Videos[id=5] Field F ? a[preis>5][fsk<18] Text t1 = ... Liefert die Funktion BerechneObjectselection genau ein Objekt zurück so wird der FieldKnoten in den AWS-State übernommen. In allen anderen Fällen wird der Field-Knoten, sowie alle an ihm hängenden Unterknoten, aus dem AWS-State ausgeblendet. Object Ein Knoten vom Typ Object enthält als Wert eine Referenz auf genau ein Objekt des WOLM bzw. den Wert null. Ein Object-Knoten besteht aus einem oder mehreren ObjectselectionAusdrücken. Diese Ausdrücke werden jeweils mit der Funktion BerechneObjectselection behandelt. <!ELEMENT object (objectselection+)> Die Funktion BerechneObjectselection gibt eine Liste von Referenzen auf WOLM-Objekte zurück. Enthält eine solche Liste genau ein Element, so wird die Referenz dieses Elements die Referenz des Object-Knotens. Enthält ein Object-Knoten mehrere Objectselection-Ausdrücke, so darf nur einer der Ausdrücke eine einelementige Liste enthalten. Alle anderen Listen müssen leer sein, da sonst die Bedingung, ein Knoten vom Typ Object enthält als Wert eine Referenz auf genau ein Objekt des WOLM, nicht mehr erfüllt wäre. Der Object-Knoten wäre damit ungültig. Objectlist Die Definition für Knoten vom Typ Objectlist in der AWS-DTD, ist identisch mit der Definition von Knoten vom Typ Object. <!ELEMENT objectlist (objectselection+)> Ein Objectlist-Knoten enthält als Wert jedoch eine Liste von Referenzen auf WOLM-Objekte. Die einzelnen Objectselection-Ausdrücke, die analog zum Object-Knoten mit der Funktion BerechneObjectselection behandelt werden, dürfen nun auch mehrelementige Listen zurückliefern. Jede erhaltene Referenz einer Objectselection wird somit in die Liste von Referenzen des Objectlist-Knotens übernommen. Berechnung des AWS-State 74 Listofobjectlists Ein Knoten vom Typ Listofobjectlists hat in der AWS-DTD folgenden Aufbau. <!ELEMENT listofobjectlists ((awslink|wolmclass),wolmpath)> Ein Knoten dieses Typs bestimmt zunächst mittels eines Wolmclass-Knotens, oder eines Awslink-Knotens, der einen Bezug zu einem Objectlist-Knoten herstellt, eine Menge von Referenzen auf WOLM-Objekte. Alle diese Referenzen werden in einer äußeren Liste gespeichert. Jedes der in dieser Liste referenzierten WOLM-Objekte muss mindestens ein Attribut besitzen, welches als Wert selbst eine Referenz auf ein anderes WOLM-Objekt enthält. Folgende Beispiele zweier WOLM-Klassen Definitionen verdeutlichen einen solchen Zusammenhang. WOLM Klasse: WOLM Klasse: class Film { Darsteller* dst; ... } class Darsteller { String name; ... } Enthält die äußere Liste eine Menge von Referenzen auf Objekte der Klasse WOLM, so kann mittels einer Pfadangabe, für jedes Element dieser Liste, eine zweite (innere) Liste erstellt werden, die dann eine Menge von Referenzen auf Objekte der Klasse Darsteller enthält. <listofobjectlists> <awslink> Objlist_Filme </awslink> <wolmpath> dst </wolmpath> </listofobjectlists> // Bezug auf Objectlist-Knoten // Pfad im WOLM Obiges Beispiel einer AWS verdeutlicht die Definition eines Listofobjectlists-Knotens. Der Knoten Wolmpath enthält innerhalb einer Listofobjectlists-Definition stets eine Pfadangabe, die sich auf das WOLM bezieht. Berechnung des AWS-State 75 Pagelist Die Berechnung eines Knoten vom Typ Pagelist ist genau genommen keine Berechnung. Wie bereits in Kapitel 7.1.5 beschrieben, werden alle Page-Knoten, die durch eine Pagelist definiert werden, als neue Page-Knoten in die AWS eingefügt. Die Berechnung der einzelnen Page-Knoten, kann dann wie gewohnt, auch einzeln, erfolgen. Die Schritte zur „Berechnung“ wurden bereits in Kapitel 7.1.5 „AWS mit Listenknoten“ ausführlich beschrieben. Fieldlist Die Berechnung eines Knoten vom Typ Fieldlist erfolgt analog zur Berechnung eines Knoten vom Typ Pagelist. Button Die Berechnung eines Knoten vom Typ Button beschränkt sich wiederum auf das Auflösen der AWS- und WOLM-Bezüge (awslink, wolmpath), sowie das Zusammenführen der ermittelten Werte zu einem Wert für die Beschriftung des Buttons. AWS-DTD: <!ELEMENT button ((const | awslink | wolmpath), action*, link?)> AWS-State-DTD: <!ELEMENT button ((const), action*, link?)> Action Aus der AWS-DTD-Definition eines Action-Knotens wird ersichtlich, welche Schritte zur Berechnung eines solchen Knotens erforderlich sind. <!ELEMENT action (params*)> <!ATTLIST action name CDATA #IMPLIED precedence CDATA #IMPLIED wolmobject CDATA #REQUIRED method CDATA #REQUIRED > <!ELEMENT params (const | awslink | wolmpath)> Das Attribut wolmobject enthält einen Verweis auf ein WOLM-Objekt. Im AWS-State erhält dieses Attribut als Wert die eindeutige WOLM-State-ID dieses WOLM-Objekts. Bei den übrigen Attributwerten handelt es sich um konstante Werte. Eine Berechnung ist somit nicht erforderlich. Berechnung des AWS-State 76 <!ELEMENT action (params*)> <!ATTLIST action id CDATA #IMPLIED precedence CDATA #IMPLIED wolmobject CDATA #REQUIRED method CDATA #REQUIRED > <!ELEMENT params (const | cvalue)> Bei der Angabe der Parameter wird im AWS-State zwischen konstanten Werten und Werten, die aus einer Benutzereingabe (Textfeld) stammen, unterschieden. Parameterwerte, die im AWS mittels Const- oder Wolmpath-Ausdrucks definiert sind, werden im AWS-State als Const-Ausdruck gespeichert. Wird im AWS mittels Awslink ein Bezug zu einem Textinputoder Hiddentextinput-Knoten hergestellt, so wird die AWS-State-ID dieses Eingabe-Knotens im AWS-State innerhalb eines cvalue-Ausdrucks gespeichert (vgl. Kapitel AWS-State). Prototyp 77 8 Prototyp 8.1 Allgemein Der im Rahmen dieser Arbeit entstandene Prototyp, zur Berechnung eines AWS-State, richtet sich bei der Implementierung an den in dieser Arbeit beschriebenen Konzepten und Vorgehensweisen aus. Es wird daher nicht auf die genaue Implementierung eingegangen, sondern die Anwendung des entstandenem Prototypen beschrieben. Klassen, die ihm Rahmen dieser Arbeit entstanden sind, sind in einem Paket mit der Bezeichnung awsstatebuilder zusammengefasst. Für die Behandlung einer WOLM-State-Datei (Einlesen, Parsen) wurden Klassen aus der Arbeit [Minßen] wiederverwendet. Diese Klassen sind im Paket utilwst zusammengefasst und werden vom Paket awsstatebuilder verwendet. Für die Bearbeitung von XML-Strukturen wurde die JDOM-Bibliothek [JDOM] verwendet. import java.io.*; import java.util.Stack; import wolm.awsstatebuilder.*; public class BerechneMich { public static void main( String[] args ) { AwsstateBuilder astb = new AwsstateBuilder(); File aws = new File("bsp2/aws_b2.xml"); File wst = new File("wolmstate/wolmstate_1Ls.xml"); File awsstate = new File("bsp2/awsst.xml"); try { astb.build(aws, wst, true); astb.build(aws, wst, awsstate, false); } catch (AwsCycleException e) { System.out.println("Abbruch, Zyklus:"); Stack cyc = astb.getAwsCycles(); while (!cyc.empty()) { System.out.println((String)cyc.pop()); } } } } Obiges Programm verdeutlicht die Verwendung des Pakets awsstatebuilder. Die Klasse AwsStateBuilder ist für die Berechnung des AWS-State verantwortlich. Ihre Methode build Prototyp 78 startet den Berechnungsvorgang und erwartet wahlweise drei oder vier Parameter. Beim ersten Parameter handelt es sich immer um eine Referenz auf eine AWS-Datei, beim zweiten auf eine WOLM-State-Datei. Bei einem Aufruf mit vier Parametern gibt der dritte Parameter eine Referenz auf eine Datei an, in der der berechnete AWS-State ausgegeben werden soll. Standardmäßig erfolgt die Speicherung des AWS-State in einer Datei mit der Bezeichnung awsstate.xml. Der jeweils letzte Parameter steuert die optionale Ausgabe von Debugginginformationen, auf die im Weiteren noch genauer eingegangen wird. Grundsätzlich treten bei der Berechnung eines AWS-State, vorausgesetzt die AWS ist gültig (keine Zyklen), keine Fehler auf. Es erfolgt immer die Ausgabe eines gültigen AWS-State, auch wenn dieser leer sein kann. Um den einzig möglichen Fehler (Zyklen) behandeln zu können, wird in obigem Beispiel die Ausnahme AwsCycleException abgefangen. Die Berechnung des AWS-State wird in einem solchen Fall stets beendet. Es wird keine AWS-State-Datei angelegt. Alternativ kann die Berechnung über das beiliegende Programm astbcmd von der Kommandozeile aus aufgerufen werden. Dem Aufruf werden dabei die entsprechenden Dateinamen übergeben. Als optionaler letzter Parameter kann der Ausdruck debug angehängt werden, um das Programm im Debug-Modus zu starten. Es ergeben sich vier Aufrufmöglichkeiten. java java java java astbcmd astbcmd astbcmd astbcmd [aws-file] [aws-file] [aws-file] [aws-file] [wolmstate-file] [awsstate-file] [wolmstate-file] [awsstate-file] debug [wolmstate-file] [wolmstate-file] debug Es folgend zwei Beispiele zur AWS-State Berechnung. Das erste Beispiel beschreibt anhand einer komplexen AWS die Verwendung einer großen Zahl von AWS Konzepten. Das zweite Beispiel erläutert die Verwendung des Debug-Modus. Beide Beispiele, sowie weitere Beispiele und das Programm selbst, können der dieser Arbeit beiliegen CD entnommen werden. 8.2 Beispiel 1 Dem Beispiel liegt folgendes WOLM zugrunde. WOLM: class Filmliste { Film* meineFilme } class Film { String titel Darsteller* darsteller } class Darsteller { String name Film* seineFilme } Der WOLM-State für das Beispiel enthält die folgenden WOLM-Objekte. Prototyp 79 WOLM-State: Filmliste : id1 (meineFilme=[2,3]) Film : id2 (titel="Matrix1", darsteller=[4,5]) Film : id3 (titel="Matrix2", darsteller=[4]) Film : id6 (titel="Das Boot", darsteller=[5]) Darsteller : id4 (name="Neo", seineFilme=[2,3]) Darsteller : id5 (name="Triniti", seineFilme=[2,6]) Ziel der Darstellung durch eine AWS ist die untenstehende Struktur einer Website. Page meineListe Page F[1] Matrix1 Darsteller Page DS[1,1] Neo Matrix1 Matrix2 Page F[2] Matrix2 Darsteller Page DS[1,2] Triniti Matrix1 Das Boot Page DS[2,1] Neo Matrix1 Matrix2 Die Startseite „meineListe“ enthält lediglich einen Link auf die erste Seite der Pagelist F. Diese Pagelist enthält alle Film-Objekte, die im Attribut meineFilme des einzigen Objekts der Klasse Filmliste referenziert werden. Dies könnten beispielsweise die Lieblingsfilme einer Person sein. In diesem Beispiel sind dies die Film-Objekte mit den WOLM-State-IDs id2 und id3, also die Filme mit dem Titel „Matrix1“ und „Matrix2“. Der Inhalt einer einzelnen Seite der Pagelist F setzt sich wie folgt zusammen. Neben der Ausgabe des Filmtitels enthält jede Seite einen Link auf eine weitere Pagelist, die die in einem Film mitwirkenden Darsteller beinhaltet. Zudem sind alle Seiten der Pagelist F über Links miteinander verkettet. Der Pagelist DS, zur Darstellung der in einem Film mitwirkenden Darsteller, liegt als Objektliste eine Listofobjectlists zugrunde, die für jedes Film-Objekt die in diesem Objekt referenzierten Darsteller-Objekte enthält, also die Mitwirkenden in einem Film. Für das erste FilmObjekt („Matrix1“) sind im WOLM-State zwei Darsteller-Objekte vorhanden. Für jeden Dar- Prototyp 80 steller eines Films gibt es eine solche Seite der Pagelist DS. Eine einzelne Seite der Pagelist DS enthält den Namen des Darstellers, sowie eine Auflistung aller Filme, in denen dieser Darsteller mitgespielt hat. Diese Filme sind im Attribut „seineFilme“ eines Darsteller-Objekts gespeichert. Auf der Seite dargestellt werden sie durch eine Fieldlist. Zudem enthält jeder Eintrag dieser Fieldlist, also jeder Film, wieder einen Link auf die entsprechende Seite der Pagelist F, die diesen Film darstellt. Die Seite DS[1,2], des Darsteller „Triniti“ stellt hierbei eine Besonderheit dar. Der Darsteller hat in dem Film mit dem Titel „Das Boot“ mitgespielt. Somit müsste dieser Film eigentlich auf der Seite DS[1,2] enthalten sein. Da es aber innerhalb der Pagelist F keinen Eintrag für diesen Film gibt, wird der entsprechende Eintrag auf der Seite DS[1,2] ausgeblendet und nicht in den AWS-State übernommen. Project P1 = P1.meineListe Object Obj_Filmliste = Filmliste Page meineListe Text = "Meine Filmliste" Link = F[first] Objectlist Objectlist_meineFilme = Obj_Filmliste.meineFilme Pagelist F = Objectlist_meineFilme Text = "Titel" + object.titel Text = "Darsteller" Link = DS[index,first] ListOfObjectlists LoolFiDs Objectlist_meineFilme darsteller Pagelist DS = LoolFiDs Text = "Name" + object.name Objectlist F2 = object.seineFilme Fieldlist FL = F2 Text = "Titel" + object.titel Link = F[indexof object in P1.Objectlist_meineFilme] Auf Grund der ohnehin schon aufwendigen Darstellung der AWS wurden die Elemente, die für die Verkettung der einzelnen Seiten der jeweiligen Pagelists verantwortlich sind, nicht aufgeführt. Die komplette AWS, WOLM-State und AWS-State können der dieser Arbeit beiliegenden CD entnommen werden. Prototyp 81 8.3 Beispiel 2 Das zweite Beispiel verwendet folgende AWS. Project P = P.A Object Obj_Diplomand = Diplomand[name="Hansi"] Page A Text T1 = "Diplomand:" + P.B.T2 Page B Text T2 = P.Obj_Diplomand.name Ein Object-Knoten stellt einen Bezug zu einem WOLM-Objekt her. Der Wert eines Attributs (name) dieses Objekts wird in Knoten T2 gespeichert. Der Knoten T1 stellt einen Bezug auf den Knoten T2 her. Der resultierende AWS-State, bei entsprechendem WOLM-State (siehe CD), sieht wie folgt aus. Project #1 = #2 Page #2 Text #3 = "Diplomand: Hansi" Page #5 Text #4 = "Hansi" Ein kleiner Tippfehler bei der Definition der AWS, beispielsweise die Angabe eines falschen Attributnamens, T2 = P.Obj_Diplomand.nome // Attribut nome existiert nicht kann dazu führen, dass die Berechnung einen leeren AWS-State liefert. Durch einen Bezugsfehler in Knoten T2 würden im obigen Beispiel der Reihe nach die Knoten T2, B, T1, A ungültig, und somit das ganze Projekt. Um die Fehlersuche zu erleichtern kann die Berechnung des AWS-State im Debug-Modus gestartet werden. Somit wird zusätzlich zum AWS-State eine zweite Datei mit dem Namen „debug.txt“ erstellt. Für obiges Beispiel einer AWS hat diese Datei folgenden Inhalt, für den Fall, dass der Knoten T2 einen Bezugsfehler verursacht. Abhängigkeiten: #P#B -> #P#A#T1 Hinweise: AccessOnDisabledNode P.B.T2 --<text name="T1" id="#P#A#T1" nid="3" disabled="1"> <const disabled="1">Diplomand:</const> <awslink disabled="1">P.B.T2</awslink> </text> Prototyp 82 Zunächst werden die Abhängigkeiten zwischen den AWS-Knoten angezeigt. Zudem ist ersichtlich, dass der Knoten T1 auf einen ungültigen Knoten T2 (AccessOnDisabledNode) zugegriffen hat. Die Angabe der aktuellen XML-Definition des Knotens T1 erleichtert das Auffinden des Fehlers in der AWS. Neben diesen zusätzlichen Informationen in der externen Datei „debug.txt“, enthält der berechnete AWS-State weitere Informationen. So bleiben alle Objekknoten, Fieldlist- und Pagelist-Knoten im „AWS-State“ erhalten. Zusätzlich kann ein Knoten in dieser Zwischenform die folgenden Attribute enthalten. disabled index index2 id nid = = = = = 1 1…n 1…n #P#A#B 42 // // // // // Knoten ist ungültig index innerhalb Page-/Fieldlist index2 innerhalb Pagelist mit LOOL AWS-State-ID mit vollem Pfad numerische AWS-State-ID Ein solcher „AWS-State“ ist nicht mehr valide gemäß der AWS-State-DTD, erleichtert jedoch das Auffinden von Fehlern in der AWS. Ist der Fehler gefunden, kann die Berechnung eines validen AWS-State durch erneuten Aufruf der Berechnung, ohne Debug-Modus, erfolgen. Zusammenfassung 83 9 Zusammenfassung Wie diese Arbeit zeigt, erfordert die Berechnung einer Attributierung einer AWS, also das Füllen einer AWS mit konkreten Daten des WOLM, eine Reihe von Betrachtungen. Als besonders komplex erwiesen sich dabei Bezüge von Knoten zu anderen Knoten der AWS, sowie der Einsatz der Knotentypen Pagelist und Fieldlist. Durch den Einsatz von Bezügen kommt es zu Abhängigkeiten zwischen Knoten, die in späteren Berechnungsschritten ggf. berücksichtigt werden müssen. Zudem besteht die Gefahr von rekursiven Bezügen. Besonders anspruchsvoll wird das Auflösen von Bezügen, wenn sich die Zielknoten des Bezugs innerhalb eines Listenknotens (Pagelist/Fieldlist) befinden. Im Rahmen dieser Arbeit wurden Konzepte und Vorgehensweisen zur Berechnung eines AWS-State aus einer AWS mit zugehörigem WOLM-State erarbeitet. Die Struktur des AWSState wurde dabei mittels einer AWS-State-DTD festgelegt. Schließlich wurde das Erarbeitete in Form einer prototypischen Implementierung eines Programms zur Berechnung eines AWSState umgesetzt. Mit diesem Programm lässt sich ein AWS-State für komplexe AWSStrukturen (vgl. 8.2, Beispiel 1) berechnen. Bereits kleinste Flüchtigkeitsfehler bei der Definition einer AWS können, ungewollter Weise, zu einem komplett leeren AWS-State führen. Um die Fehlersuche zu erleichtern, wurde der Prototyp mit Funktionen zur Anzeige von DebugInformationen ausgestattet, die die Fehlersuche in einer AWS erleichtern. Auf Konzepte zur Benutzerinteraktion konnte ihm Rahmen dieser Arbeit nur begrenzt eingegangen werden, da entsprechende Konzepte noch nicht konkret umgesetzt wurden, sondern nur theoretische definiert sind. Die Nutzung von Elementen zur Benutzerinteraktion auf der finalen Website ist allerdings auch kein spezielles Problem der Berechnung eines AWS-State. Die in dieser Arbeit vorgestellten Konzepte und Vorgehensweisen lassen sich auf alle Elemente der AWS, auch auf mögliche Erweiterungen, anwenden. In weiteren Arbeiten werden zurzeit Lösungen zur Generierung einer Darstellung der finalen Website aus einem AWS-State erstellt, so dass in absehbarer Zeit die wichtigsten Komponenten des WSMS zur Verfügung stehen. Literaturverzeichnis 84 10 Literaturverzeichnis [Schütte] Schütte, A.: Spezifikation und Generierung von Übersetzern für GraphSprachen durch attributierte Graph-Grammatiken EXpress Edition 1987 [Kühnem] Kühnemann, A.: Attributgrammatiken: eine grundlegende Einführung Vieweg 1997 [Mahn] Mahn, U.: Attributierte Grammatiken und Attributierungsalgorithmen Springer-Verlag 1988 [Kastens] Kastens, U.: Übersetzerbau Oldenbourg-Verlag 1990 [Schmitz] Schmitz, L.: Syntaxbasierte Programmierwerkzeuge Teubner 1995 [SZW 1] Bomsdorf, B., Szwillus, G.: Task-Based Web Modeling (Paper) 2004 [SZW 2] Bomsdorf, B., Szwillus, G.: Task-Object Models for the Development of Interactive Web Sites (Paper) 2004 [SZW 3] Bomsdorf, B., Szwillus, G.: Web Site Management For All (Paper) [SZW 4] Bomsdorf, B., Szwillus, G.: Web Site Management “for Dummies” (Paper) [SZW AWS] Szwillus, G.: AWS (interner Text) [SZW WOLM] Szwillus, G.: WOLM (interner Text) [Langer] Langer, R.: Generierung einer initialen abstrakten Website Struktur aus einem Objektlebenszyklusmodell (Diplomarbeit) 2004 [Köpke] Köpke, C.: Generierung von Webadministrationsseiten aus einem Objektlebenszyklusmodell (Studienarbeit) 2003 Literaturverzeichnis [Minßen] Minßen, A.: Entwicklung und prototypische Implementation eines Simulators für Objektlebenszyklusmodelle (Diplomarbeit) 2003 [Java] Ullenboom, C.: Java ist auch eine Insel Galileo Computing 2003 [JDOM] 85 jdom.org http://www.jdom.org/ Änderung AWS-DTD 86 A Änderung AWS-DTD A.1 Action-Knoten Ein Knoten vom Typ Action war in der AWS bislang wie folgt definiert. <!ELEMENT action EMPTY> <!ATTLIST action name CDATA precedence CDATA wolmobject CDATA method CDATA params CDATA > #IMPLIED #IMPLIED #REQUIRED #REQUIRED #IMPLIED Auf Basis dieser Definition hat ein Action-Knoten folgende XML-Darstellung. <button> <const>Klick mich</const> <action wolmobject="42" method="doIt" params="12"> </action> </button> Von Bedeutung für die Änderung ist im Moment nur das Attribut params, mit dessen Hilfe der jeweiligen Methode Parameter übergeben werden sollen. Die Parameterübergabe mit obiger Definition ist nicht sehr leistungsfähig. Sie ermöglicht keine Angabe von zwei oder mehr Parametern und nur die Angabe von konstanten Werten. Werte für Parameter können nicht aus anderen AWS-Knoten bestimmt werden. Eine veränderte AWS-DTD beseitigt diese Probleme. <!ELEMENT action (params?)> <!ATTLIST action name CDATA #IMPLIED precedence CDATA #IMPLIED wolmobject CDATA #REQUIRED method CDATA #REQUIRED > <!ELEMENT params ((const | awslink | wolmpath)+)> Die XML-Darstellung sieht nun wie folgt aus. Änderung AWS-DTD 87 <button> <const>Klick mich</const> <action wolmobject="42" method="doIt"> <params> <const>12</const> <awslink>P.A.A</awslink> <wolmpath>P.A.O.N</wolmpath> </params> </action> </button> Der Vorteil gegenüber der alten Definition besteht in der Möglichkeit beliebig viele Parameter angeben zu können. Zudem können die Parameter konstant oder Bezüge zu AWSKnoten sein. A.2 Listofobjectlists-Knoten Die bisherige Definition eines Knoten vom Typ Listofobjectlists sah in der AWS-DTD bislang wie folgt aus. <!ELEMENT listofobjectlists ((awslink | wolmpath), wolmpath)> Die neue Definition muss korrekterweise wie folgt lauten. <!ELEMENT listofobjectlists ((awslink | wolmclass), wolmpath)> Der erste Ausdruck, der für die Selektion einer Liste von WOLM-Objekten zuständig ist, muss wahlweise ein Knoten vom Typ Awslink oder Wolmclass sein, jedoch nicht vom Typ Wolmpath. A.3 Image-Knoten Das überflüssige Attribut data wurde entfernt. <!ATTLIST image name CDATA #IMPLIED data CDATA #REQUIRED > WOLM-Definiton 88 B WOLM-Definiton Die Definition einer WOLM-Datei, wie sie bislang in den Arbeiten [Minßen] und [Köpke] verwendet wurde, verwendet für die Bezeichnung von Attributen Ausdrücke der folgenden Form. <attribute name="Diplomand.attribute.name" type="String"/> Dieser Ausdruck wird innerhalb einer WOLM-Datei verwendet, um innerhalb einer Klassendefinition ein Attribut mit der Bezeichnung „Diplomand.attribute.name“ zu definieren. Das Zeichen „.“ wird als Bestandteil des Attributnamens verwendet. Der Grund für die Verwendung einer solchen Bezeichnung liegt in der internen Arbeitsweise des WOLM-Simulators [Minßen] sowie der Admin-Seiten [Köpke]. Bei der Entwicklung des AWS-Builders [Langer], der eine initiale AWS aus einem WOLM berechnet, wurde jedoch von Attributbezeichnungen der folgenden Form ausgegangen. <attribute name="DiplomandName" type="String"/> Das Zeichen “.” wird nicht für die Bezeichnung von Attributen verwendet, da dies innerhalb der AWS zu Mehrdeutigkeiten führen würde. Ein Beispiel soll anhand eines Wolmpath gegeben werden. Text T1 = Obj.Diplomand.attribute.name In der AWS würde der Knoten Obj als Object-Knoten, der eine Referenz auf ein Objekt des WOLM gespeichert hat, erkannt. Der dann folgende Ausdruck „Diplomand.attribute.name“ würde als Pfad auf dem referenzierten WOLM-Objekt gedeutet und nicht als Bezeichnung für ein einziges Attribut erkannt. Um Probleme dieser Art zu umgehen muss bei der Definition eines WOLM zukünftig auf das Zeichen „.“ bei der Attributbezeichnung verzichtet werden. Bei der Erzeugung einiger Beispiel-AWS im Rahmen dieser Arbeit wurde das Zeichen „.“ durch das Zeichen „:“ ersetzt (Beispiele siehe beiliegende CD-ROM). AWS-State-DTD C AWS-State-DTD <?xml version = '1.0' encoding = 'utf-8' ?> <!ELEMENT awsstate (project?)> <!ELEMENT project (page|text|image|link)*> <!ATTLIST project id CDATA #REQUIRED startpage CDATA #REQUIRED > <!ELEMENT page (field|text|image|textinput|hiddentextinput|button)*> <!ATTLIST page id CDATA #REQUIRED listid CDATA #IMPLIED > <!ELEMENT field (field|text|image|textinput|hiddentextinput|button)*> <!ATTLIST field id CDATA #REQUIRED listid CDATA #IMPLIED > <!ELEMENT text (const, link?)> <!ATTLIST text id CDATA #REQUIRED > <!ELEMENT image (const, link?)> <!ATTLIST image id CDATA #REQUIRED > <!ELEMENT textinput (const)> <!ATTLIST textinput id CDATA #REQUIRED > <!ELEMENT hiddentextinput (const)> <!ATTLIST hiddentextinput id CDATA #REQUIRED > <!ELEMENT button (const, action*, link?)> <!ATTLIST button id CDATA #REQUIRED > 89 AWS-State-DTD <!ELEMENT link (#PCDATA)> <!ATTLIST link id CDATA #REQUIRED > <!ELEMENT action (params?)> <!ATTLIST action id CDATA #REQUIRED precedence CDATA #IMPLIED wolmobject CDATA #REQUIRED method CDATA #REQUIRED > <!ELEMENT params ((const | cvalue)+)> <!ELEMENT const (#PCDATA)> <!ELEMENT cvalue (#PCDATA)> 90 CD-ROM 91 D CD-ROM Die beiliegende CD-ROM enthält die vollständige Arbeit in Form einer PDF-Datei, das entwickelte JAVA-Programm, die aktuelle AWS-DTD und AWS-State-DTD, sowie diverse AWS- und WOLM-Beispieldateien.