|
|
Im folgenden wird die technische Realisierung des Frameworks
"SalesPoint" beschrieben. Es sollen
dadurch die Strukur und die Zusammenhänge des Frameworks
verstanden und ein generelles Verständnis im Umgang mit den
bereitgestellten Funktionen entwickelt werden. Es werden wichtige
Begriffe und Konzepte erläutert, die im Framework umgesetzt
werden.
|
|
|
Das Framework gliedert sich physisch in die Pakete
sale , data ,
users , log und
util .
|
|
|
Das Paket sale enthält die zentralen
Klassen des Frameworks, u.a. Shop ,
Gate und Transition .
In sale.stdforms finden sich
Standard-Oberflächen, wie z.B. FormSheets ,
die in allen Anwendungen benutzt werden können.
|
sale
|
|
In data finden sich wichtige Klassen zur
Verwaltung der Daten. Catalog und
Stock sind dort ebenso zu finden wie
DataBasket , MoneyBag und
Currency . Im Paket
data.stdforms findet der Nutzer
vielfältige Möglichkeiten die eben genannten Dinge in
Tabellen u.a. darzustellen.
|
data
|
|
In dem Paket users sind für die
Nutzerverwaltung wichtige Klassen enthalten. Mit deren Hilfe
können Rechte (Capabilities ) vergeben
werden.
|
users
|
|
log ist für das Mitprotokollieren der
Aktionen einer Anwendung verantwortlich. Sehr leicht können
Handlungsabläufe der Nutzer aufgezeichnet und wenn notwendig
abgerufen werden.
|
log
|
|
Von dem Paket util werden einige Hilfsklassen
bereit gestellt.
|
util
|
|
Das folgende statische UML-Diagramm gibt einen
Überblick über die wichtigsten Elemente des
Frameworks. Es zeigt vor allem, wie die Klassen aus den
unterschiedlichen Pakete untereinander zusammenarbeiten:
Abbildung 1.1:
Übersichtsdiagramm
|
|
|
Das Framework zerfällt also in zwei große,
verhältnismäßig unabhängige Bereiche: die
Datenverwaltung (data )und die dynamische
Applikationsverwaltung (sale ).
Außerdem gibt es noch die kleineren Bereiche Benutzermanagement
(user ), Protokollverwaltung
(log ) und GUI. In folgenden werden
wichtige Begriffe und Konzepte aus diesen Bereichen erläutert.
|
Gliederung des Frameworks
|
|
|
Beginnen wir mit dem Bereich der Applikationsverwaltung. Ein wichtiger
Begriff ist hier der des Ladens
(Shop ).
Jede Anwendung auf Basis des Frameworks
"SalesPoint" stellt
im Prinzip einen mehr oder weniger großen Laden dar. Umgekehrt
gibt es in einer Anwendung auch nur genau einen Laden. Ein Laden hat
mindesten einen, möglicherweise mehrere
Verkaufsstände (SalesPoint ).
Ein Verkaufsstand in unserem Sinne ist dabei alles, wo eine
Interaktion
mit der Anwendung stattfindet, also z.B. Kassen, Fleischtheken,
Pfandautomaten, Küche, Werkstatt, usw.
|
Laden und Verkaufsstand
|
|
Alle Interaktionen mit dem Laden finden im Rahmen von
Prozessen (SaleProcess ) statt. Ein
Prozeß ist eine abwechselnde Folge von Kommunikation mit dem
Anwender (z.B. eine Bedienerin an der Fleischtheke will 250g
"Hackepeter") und internen Bearbeitungsvorgängen (z.B.
Entnahme, Abwiegen und Abpacken der gewünschten 250g
"Hackepeter"). Diese wechselnden Vorgänge können
als endliche Automaten interpretiert werden. Die Kommunikation mit dem
Anwender findet in den Zuständen
(Gate ) des Prozesses statt, die interne
Bearbeitung wird in Zustandsübergängen
(Transition ) erledigt. Nachstehendes Diagramm
verdeutlicht diesen Zusammenhang nochmals grafisch.
Abbildung 2.1:
Prozesse bestehen aus Zuständen und Übergängen
|
Prozesse
|
|
Die vom Framework vordefinierten Gates und die Reihenfolge, in der
von einem Gate zum nächsten gegangen wird, zeigt Abbildung
2.2.
Die jeweilige Implementierung schließt die Lücke
vom InitialGate zu einem der Gates, die
letztendlich zum Ende des Prozesses führen.
Abbildung 2.2:
Zusammenhänge zwischen des einzelnen Gates
|
Gates
|
|
Diese explizite Darstellung des Prozeßaufbaus im Objektmodell
hat den zusätzlichen Vorteil, daß Prozesse von der
Anwendung quasi "angefaßt" werden können. Das
heißt, Prozesse können jederzeit in einem definierten
Zustand (nämlich an einem Gate) unterbrochen und später an
der selben Stelle wieder fortgesetzt werden. Befindet sich der
Prozeß zum Zeitpunkt der Unterbrechung gerade in einer
Transition, so wird er einfach am nächsten Gate unterbrochen.
Damit dies aber überhaupt machbar ist, müssen ein paar
Bedingungen eingehalten werden: Da das Unterbrechen von Prozessen
nicht zur Systemblockade führen soll, fordert man, daß
Transitionen verhältnismäßig kurz sind. Insbesondere
dürfen sie keine "potentiell unendlich" andauernden
Aktivitäten umfassen. "Potentiell unendlich" sind dabei
alle Aktivitäten, deren Endtermin nicht vorherbestimmbar ist, zum
Beispiel eine Benutzerkommunikation. Dabei könnte es vorkommen,
daß der Benutzer einfach "vergißt", einen Knopf
zu wählen, was dazu führen würde, daß die
Transition nicht verlassen und damit der Prozeß nicht
unterbrochen werden kann. Deshalb sind Benutzerkommunikation und
ähnliche langandauernde Vorgänge nur an einem Gate erlaubt.
Ein Prozeß darf sich beliebig lange an einem Gate aufhalten,
muß aber sicherstellen, daß er zu jedem Zeitpunkt
unterbrochen werden kann. Im Gegenzug wird einem Prozeß
zugesichert, daß er nie während einer Transition
unterbrochen wird.
|
|
|
Prozesse können auf verschiedene Arten ausgeführt werden.
Zum einen kann an jedem Verkaufsstand zu jedem Zeitpunkt
höchstens ein Prozeß ablaufen. Zum anderen können
Prozesse aber auch als Hintergrundprozesse wichtige Arbeit erledigen.
Um den Prozeß davon abzukoppeln, ob er gerade als
Hintergrundprozeß (background process )
oder als Prozeß an einem Verkaufsstand
abläuft (SalesPoint process ), gibt es das
Konzept der Prozeß-Umgebung
(ProcessContext ). Ein
Prozeß kommuniziert nicht direkt mit dem Verkaufsstand auf dem
er abläuft, oder mit dem Laden, in dem er stattfindet. Aus
Prozeßsicht handelt es sich bei all dem um
Prozeß-Umgebungen, über welche er die von ihm
benötigten Ressourcen erhält bzw. ansteuern kann
In Abbildung 2.3 wird der
Zusammenhang zwischen ProcessContext und
Prozeß noch einmal verdeutlicht.
Abbildung 2.3:
Prozesse können an Verkaufsständen und als Hintergrundprozesse laufen
|
Prozeß-Umgebung
|
|
Wenn man mit dem Anwender kommunizieren will, so braucht man ein
gemeinsames Medium. Im Framework gibt es dafür die
Anzeige (Display ). Über die
Anzeige kommunizieren Anwender und Anwendung miteinander. Für
jeden Verkaufsstand, der im Laden angelegt wird, wird eine solche
Anzeige erzeugt. Die Anzeigen von Verkaufsständen sind als
unabhängige Fenster implementiert. Wird der Verkaufsstand aus dem
Laden entfernt, so wird auch seine Anzeige vernichtet. Auf seiner
Anzeige kann ein Verkaufsstand beispielsweise Menüpunkte und
Knöpfe unterbringen, mit denen der Anwender Prozesse
auslösen kann. Wird ein Prozeß gestartet, so erhält
er die Verantwortung für den Inhalt der Anzeige. Er kann jetzt
alle Formulare und Menüs anzeigen, die für den Prozeß
wichtig sind.
|
Anzeige
|
|
Auf einer Anzeige können Formulare
(FormSheet ) und Menüs
(MenuSheet ) angezeigt werden. Menüs sehen
aus, wie Menüs in anderen Anwendungen auch. Formulare zerfallen
in zwei Bereiche: den Komponentenbereich und die Knopfleiste. Im
Komponentenbereich, der gewöhnlich den oberen Teil der Anzeige
einnimmt, kann jede beliebige Swing-Komponente untergebracht werden.
Hier hat der Anwender die Möglichkeit, Eingaben zu machen, aus
Listen auszuwählen, etc. Gewöhnlich im unteren Bereich der
Anzeige befindet sich die Knopfleiste, eine Zeile, die nur
Schaltflächen enthält. Diese dienen dazu, Aktionen
auszulösen. Obwohl die Formulare beliebige Swing-Komponenten
enthalten können, sind Formulare und Menüs doch im
wesentlichen eine Abstraktion von der konkreten Darstellungsform
und werden deshalb vom Framework unterstützt.
Wenn man als Anwendungsentwickler ein Menü oder Formular
verwendet, braucht man sich nicht darum zu kümmern, wie dieses
letztendlich konkret dargestellt wird. Alles was man tun muß,
ist die richtigen Angaben an der richtigen Stelle einzufügen und
das ganze an die entsprechenden Stellen weiterzuleiten. Die Umsetzung
in eine konkrete Oberfläche ist dann Aufgabe der Anzeige. In der
im Framework enthaltenen Implementation ist dies einmal die
MultiWindow -Oberfläche, die jede
Status-Anzeige eines Verkaufsstandes durch ein Unterfenster eines
großen "Ladenfensters" darstellt und zum anderen die
Umsetzung durch einen JDisplayFrame .
|
Formulare und Menüs
|
|
Im Rahmen des Persistenzmanagements wurde ein weiterer Begriff, der
des Formular-Inhaltserzeugers
(FormSheetContentCreator ), eingeführt.
Da die Swing-Klassen zum Teil erhebliche Schwächen bezüglich
der Serialisierung aufweisen, mußte es vermieden werden,
Swing-Klassen zu serialisieren. Dies wird erreicht, in dem man nur die
Information speichert, die nötig ist, um das GUI wieder zu
regenerieren. Bei Menüs ist diese Information einfach das
MenuSheet selbst (Achtung: nicht die Swing -Komponente!
Das MenuSheet
enthält nur die Information welche Menüknöpfe in
welchem Menü zur Verfügung stehen.), bei Formularen ist es
ein gesondertes Objekt, das die Strategie zur Erzeugung des
Formular-Inhalts kapselt (vgl. Strategy-Muster).
|
FormSheetContentCreator
|
|
Formulare müssen gelegentlich mit ihrer Anzeige kommunizieren,
um sicherzustellen, daß sich Änderungen am Formular auch
sofort
auf die Anzeige auswirken. Wenn beispielsweise ein Formular einen
"Löschen"-Knopf hat, der ein, gerade
in einer Tabelle
ausgewähltes Element löscht, so soll dieser vielleicht
nicht selektierbar sein, wenn kein Eintrag in der Tabelle
ausgewählt ist. Die Anwendung würde also den Zustand des
Knopfes immer dann ändern, wenn sich die Auswahl in der Tabelle
ändert. Um den Zustand des Knopfes zu verändern, verwendet
die Anwendung eine entsprechende logische Operation, ohne sich um die
Umsetzung auf der Ebene von Swing zu
kümmern. Das Formular hat
dann die Aufgabe, dafür zu sorgen, daß die Änderungen
auch auf der Oberfläche sichtbar werden. Um auch hier die
bisherige enge Kopplung zwischen Formular und Oberfläche
aufzuheben wurde der Formular-Container
(FormSheetContainer )
eingeführt. Er stellt ein Objekt dar, das ein Formular anzeigt.
Das Formular erhält die Möglichkeit, den Formular-Container
über Änderungen im Zustand des Formulars zu informieren.
Der Formular-Container stellt gewissermaßen die Sicht des
Formulars auf eine Anzeige dar und bietet dem Formular genau die
begrenzte Schnittstelle, die es benötigt.
|
FomSheetContainer
|
|
Mit den Knöpfen in der Knopfleiste eines Formulars oder in einem
Menü werden Aktionen (Action )
verknüpft, die ausgeführt werden, wenn der entsprechende
Knopf gedrückt wurde.
|
Aktionen
|
|
Jedes Formular oder Menü wird immer in einem gewissen
Kontext dargestellt. Dieser besteht aus dem Laden
in dem es dargestellt wird, gegebenenfalls dem Verkaufsstand an dem
es dargestellt wird und/oder gegebenenfalls dem Prozeß, der es
darstellt. Nur der Laden ist immer vorhanden. Aktionen, die mit
Knöpfen eines Formulars oder Menüs verbunden sind, werden
immer im Kontext dieses Formulars oder Menüs aufgerufen. Dies
geschieht, in dem der entsprechenden Methode der Verkaufsstand und
der Prozeß als Parameter übergeben werden. Der Laden ist
ohnehin bekannt, da es nur einen pro Anwendung gibt. Die folgende
Abbildung verdeutlicht diese Zusammenhänge noch einmal grafisch.
Abbildung 2.4:
Formulare und Menüs verwenden Aktionen, um Benutzereingaben mit Programmreaktionen zu verknüpfen
|
Menü-Kontext
|
|
Zum Abschluß dieses Abschnitts muß noch einmal der Laden
erwähnt werden. Zusätzlich zu den hier geschilderten, eher
konzeptionell begründeten Verantwortungen hat der Laden auch noch
einige andere, eher technischer Natur. Auf abstraktester Ebene
ließen sich diese etwa wie folgt motivieren: "Der Laden
bildet das zentrale Element der Anwendung. Er bündelt
sämtliche Aktivitäten und Verantwortungen." Das
heißt, der Laden ist zentraler Ansprechpartner für alle
Teile der Applikation. Er "kennt", entweder durch direkte
Assoziation oder weil sie ein "Singleton" implementieren,
sämtliche Elemente der Anwendung.
Deshalb ist es nur natürlich, dem Laden auch die Verantwortung
für das Persistenzmanagement (siehe Datenverwaltung)
zuzuordnen. Auf "Knopfdruck", d.h. auf einen einfachen
Methodenaufruf hin, kann der Laden den Zustand der gesamten Anwendung
sichern, bzw. einen früher gespeicherten Zustand wiederherstellen.
|
Der Laden als zentrale Verwaltungseinheit
|
|
|
Ein weiterer, wichtiger und großer Bereich des Frameworks ist
die Datenverwaltung. Diese stellt für Verkaufsanwendungen
typische Datenstrukturen zur Verfügung. Außerdem stellt
sie Mechanismen bereit, die zur Implementation von
Transaktionseigenschaften wie Isolation und Atomizität verwendet
werden können. Es ist mit Hilfe des Frameworks ebenfalls
möglich den Zustand eines Shops
abzuspeichern und wieder zu laden.
|
Datenverwaltung
|
|
Ein Geschäft stellt die angebotenen Waren oder Dienstleistungen
in Form eines oder mehrerer Kataloge
(Catalog ) dar. Ein Katalog ist im wesentlichen eine
Liste von Katalogeinträgen
(CatalogItem ). Jeder Katalogeintrag beschreibt eine Ware
oder Dienstleistung durch ihre Eigenschaften. Alle
Katalogeinträge haben mindestens einen Namen, oder Schlüssel,
und einen Wert. Werte (Value ) sind Objekte,
für die die Operationen Addition, Subtraktion, Multiplikation,
Multiplikation mit Skalar und Division definiert sind. Die Menge aller
Werte eines bestimmten Typs bilden mindestens ein Monoid bzgl.
Addition und Multiplikation. Bzgl. der Multiplikation gibt es
zusätzlich zum neutralen 1-Element noch ein 0-Element. Durch
diese Objektifizierung von Werten wird erreicht, daß man immer
den Typ verwenden kann, der der Anwendung am genauesten entspricht,
dabei aber dennoch die Möglichkeit hat, Algorithmen, die immer
wieder gleich bleiben, im voraus zu formulieren.
|
Kataloge
|
|
Kataloge stellen Listen von potentiell verfügbaren Objekten dar.
Um tatsächlich verfügbare Objekte darzustellen,
benötigt man Bestände. Ein Bestand
(Stock ) bezieht sich auf einen Katalog und
verzeichnet zu jedem Katalogeintrag die Anzahl tatsächlich
verfügbarer Objekte diesen Typs. "Tatsächlich
verfügbar" heißt dabei nicht, daß Bestände
nur verwendet werden können, um Lager- oder Kassenbestände
darzustellen. Auch Bestellungen lassen sich als Bestände
auffassen, wobei "tatsächlich verfügbar" dann
heißt "auf der Bestellung aufgeführt".
|
Bestände
|
|
Es gibt zwei grundlegende Typen von Beständen:
"zählende Bestände"
(CountingStock ) und
"beschreibende Bestände"
(StoringStock ).
Abzählende Bestände speichern zu jedem Katalogeintrag
tatsächlich nur die Anzahl verfügbarer Objekte,
während speichernde Bestände für jedes
tatsächlich verfügbare Objekt einen Bestandseintrag
(StockItem ) speichern. Dadurch ergibt
sich die
Möglichkeit, die einzelnen Objekte zu unterscheiden und ggf. mit
individuellen Merkmalen anzureichern. Z.B. könnte es für
einen Fahrzeughändler interessant sein, für jeden der 50
roten "Peugeot 406 HDI Break", die er auf dem Hof stehen hat,
zusätzlich noch die Fahrgestellnummer, die PIN der Wegfahrsperre
etc. zu speichern. Dennoch sind alle 50 Autos rote "Peugeot 406
HDI Break" und er möchte vermutlich nicht für jedes
einen neuen Katalogeintrag anlegen. Deshalb kann er die
zusätzlichen Informationen in einem Bestandseintrag speichern.
|
Bestandstypen
|
|
Die Abbildung 3.1 stellt diese
Zusammenhänge noch einmal grafisch dar.
Sie zeigt außerdem zwei interessante zusätzliche Elemente:
Kataloge bzw. Bestände sind selbst wieder Katalog- bzw.
Bestandseinträge. Dadurch wird es möglich, auch mit
geschachtelten Katalogen bzw. Beständen zu arbeiten. Diese
können in manchen Anwendungen, die mit sehr komplexen
Beständen arbeiten müssen, recht nützlich sein.
Beispielsweise könnte eine Wechselstube, die Währungen
zwischen denen sie wechseln kann, in einem Katalog anbieten. Die
Währungen selbst sind wieder Kataloge, die die einzelnen
Münzen und Banknoten beschreiben. In Analogie dazu gäbe es
auch einen geschachtelten Bestand, der für jede Währung die
Momentanbestände jedes einzelnen Schalters verwalten könnte.
Werden geschachtelte Bestände verwendet, so müssen immer auch
geschachtelte Kataloge benutzt werden. Der Katalog C, der von einem
Bestand B referenziert wird, muß sich auf der gleichen
Schachtelungsebene befinden wie B. Er muß außerdem im
Katalog des Bestandes enthalten sein, der B enthält. Das
heißt, das Konzept unterstützt die Strukturierung von
Katalogen und Beständen, jedoch nur so lange wie die
Strukturierung nicht in sich selbst informationstragend ist.
|
Schachtelung von Katalogen und Beständen
|
|
Zweitens sieht man in dieser Abbildung, daß die gemeinsame
Eigenschaft, einen Namen zu haben, in dem Begriff des
Benennbaren (Nameable )
zusammengefaßt wurde. Benennbare Objekte haben einen Namen,
welcher sie identifiziert. Dieser Name muß gewissen Regeln
genügen. Die Regeln werden von einem Namenskontext
(NameContext ) festgelegt, welcher dem
benennbaren Objekt zugeordnet werden kann. Vor jeder
Namensänderung wird geprüft, ob der neue Name den Regeln des
Namenskontextes genügt. Ist dem nicht so, so wird der Name nicht
geändert.
Strukturierung nicht in sich selbst informationstragend ist.
|
Benennbare Objekte und Namenskontext
|
|
Die folgende Abbildung zeigt noch einmal die Zusammenhänge
zwischen Cataog und
Stock :
Abbildung 3.1:
Kataloge und Bestände
|
|
|
Um Transaktionseigenschaften, wie Isolation und Atomizität, zu
implementieren, existiert der Datenkorb
(DataBasket ). Im
Abschnitt "Applikationsverwaltung" wurde er bereits unter
dem Namen
Einkaufskorb erwähnt. Datenkörbe arbeiten eng mit
Datencontainern, wie Katalogen und Beständen, zusammen, um
transaktionale Eigenschaften zu implementieren. Man kann sich einen
Datenkorb auf zweierlei Weise vorstellen. Abstrakt ist er eine Art
Transaktionshandle, also eine Struktur, die die aktuelle Transaktion
kennzeichnet, und die an jede Routine, die Datencontainer manipuliert,
übergeben werden muß. Etwas konkreter kann man sich
Datenkörbe durchaus als eine Art Warenkorb vorstellen, in die
beliebige Datenelemente hineingelegt werden können.
|
Datenkorb
|
|
Datenkörbe arbeiten eng mit den entsprechenden Containern
zusammen, um ihre Funktion zu erfüllen. Wenn aus einem Bestand
ein Element entnommen wird, so wird es zunächst in den Datenkorb
eingeordnet. Solange das Element im Datenkorb ist, wird es vom
Bestand als "vorläufig gelöscht" markiert. Erst wenn dem
Datenkorb die Löschung des Elements bestätigt wurde (siehe
unten), wird es endgültig aus dem Bestand gelöscht. Analog
verhält es sich mit dem Hinzufügen von Elementen. Wird ein
Element zum Bestand hinzugefügt, so wird es gleichzeitig in den
entsprechenden Datenkorb eingefügt. Im Bestand wird es
zunächst als "vorläufig hinzugefügt" markiert und steht
anderen Nutzern zunächst nicht zur Verfügung. Erst wenn das
Hinzufügen dem Datenkorb bestätigt wurde, wird das Element
als "tatsächlich enthalten" markiert und wird für andere
Nutzer sichtbar. Die Benutzung von Katalogen verläuft ganz
analog.
|
Elemente des Datenkorbs
|
|
Entsprechend der zwei möglichen Sichtweisen auf Datenkörbe
gibt es auch zwei getrennte Untermengen der Datenkorbschnittstelle.
Die eine bietet Funktionen, mit denen Transaktionseigenschaften
implementiert werden können (Transaktionsschnittstelle), die
andere bietet Funktionen, um den Inhalt des Datenkorbs zu inspizieren
und auszuwerten (Inspektionsschnittstelle).
|
Datenkorbschnittstelle
|
|
Die Transaktionsschnittstelle bietet verschiedene Variationen der
Operationen commit und rollback.
Diese werden verwendet, um Änderungen, die im Datenkorb
registriert sind, zu bestätigen und endgültig
festzuschreiben (commit) oder um sie
rückgängig zu machen (rollback).
Commit bzw. rollback können
unbedingt, also für alle vom Datenkorb beschriebenen Aktionen,
oder nur für eine Auswahl dieser Aktionen durchgeführt
werden. Außerdem ist es möglich, Unterbereiche des
Datenkorbs zu definieren, die ähnlich wie
check points in Transaktionen verwendet werden
können.
|
Commit und Rollback
|
|
Die Inspektionsschnittstelle umfaßt Operationen zum Iterieren
über den Inhalt des Datenkorbs sowie eine Funktion, um den Wert
aller Elemente aufzusummieren, die einer bestimmten Bedingung
genügen.
Außerdem können Datenkörbe gespeichert werden, was
bedeutet, daß auch der Zustand von Transaktionen gesichert
werden kann, so daß diese später wieder fortgesetzt werden
können.
Faßt man die Aufgaben des Datenkorbs nochmals zusammen, so
ergeben sich folgende Verantwortlichkeiten:
Transaktionsschnittstelle |
Ermöglichen von Atomizität durch
commit- und rollback-
Operationen.
|
Isolation |
Ermöglichen von Isolation (bis zu einem gewissen Grad
(im Prinzip SQL Level 2: read committed))
durch Einschränkung der Sichtbarkeit von
Datenelementen.
|
Inspektionsschnittstelle |
Verwendung des Datenkorbs als "Einkaufskorb".
|
|
Datenverwaltung
|
|
Bestände, Kataloge und Datenkörbe können Ereignisse
auslösen, wenn ihr Inhalt geändert wird.
|
|
|
|
Das Framework umfaßt auch einen kleineren Bereich, der sich mit
der Verwaltung von Benutzern beschäftigt. Hier sind die folgenden
Begriffe wichtig.
|
|
|
Benutzer (User ) haben einen Namen,
ein Paßwort sowie eine Liste von Rechten bzw.
Fähigkeiten (Capability ). Die
Fähigkeiten bestimmen, welche
Operationen ein Benutzer ausführen darf und welche ihm nicht
gestattet sind. Der Name und das Paßwort dienen der
Identifikation des Benutzers beim Log in.
|
Benutzer und ihre Rechte
|
|
Benutzer werden von einer Benutzerverwaltung
(UserManager ) verwaltet. Diese kann Benutzer
aufnehmen, löschen und mit Hilfe einer Benutzerfabrik
(UserCreator ) sogar neue Benutzer erzeugen. Neu
erzeugte Benutzer erhalten zunächst einen Satz von
Standardfähigkeiten
(default capabilities).
|
Benutzerverwaltung
|
|
|
Ein kleiner Bereich des Frameworks beschäftigt sich mit dem
Erstellen und Auswerten von Protokollen.
|
|
|
Protokolle (Log ) sind Ströme
von Protokolleinträgen
(LogEntry ). Ein
Protokolleintrag verzeichnet den Zeitpunkt der Protokollierung sowie
einen Text, der den zu protokollierenden Sachverhalt beschreibt. Er
kann jedoch darüber hinaus noch weitere Informationen enthalten,
die für den speziellen Typ von Protokolleintrag wichtig sind.
Protokollierbare Objekte oder Vorgänge
(Loggable ) liefern auf Anfrage einen
Protokolleintrag zurück, der dann ins Protokoll geschrieben wird.
Abbildung 5.1:
Benutzer haben Fähigkeiten und werden von Benutzermanagern verwaltet.
|
Protokolleinträge
|
|
Auf Protokolle besteht nur Schreibzugriff, um Protokollströme zu
lesen und auszuwerten, benötigt man einen
Protokoll-Eingabestrom
(LogInputStream ).
Dieser kann mittels eines Protokollfilters
(LogEntryFilter ) gefiltert werden.
|
Filter
|
|
|
Das Framework enthält bereits einige Standard-GUI-Komponenten.
Neben einfachen Formularen wie MsgForm ,
TextInputForm , etc. gibt es auch Formulare
zum Anzeigen
und Editieren des Inhalts von Datencontainern (siehe Abschnitt
"Datenverwaltung") und Protokoll-Eingabeströmen
(siehe Abschnitt "Protokollverwaltung").
|
|
|
Bei den meisten dieser Formulare werden zunächst die
entsprechenden Swing -Komponenten angeboten, die
anschließend zu
Standard-Formularen zusammengesetzt werden. Das erlaubt einerseits
die flexible Verwendung dieser Komponenten in eigenen Formularen,
bietet aber andererseits auch den Komfort bereits vorgefertigter
Formulare für besondere Anwendungsfälle.
|
Standard-Formulare
|
|
Ein wichtiges Element des Framework-GUI sind Tabellen. Dafür
gibt es ein paar spezielle Komponenten, deren genauere Betrachtung
sich an dieser Stelle lohnt. Die meisten im Rahmen des Frameworks
darzustellenden Daten sind Listen von komplexen, aber gleichartigen
Elementen. Um diese darzustellen, ist im Prinzip nur zu entscheiden,
welche Attribute man darstellen möchte und in welcher Form. Man
kann dann jedem darzustellenden Element eine Zeile und jedem
darzustellenden Attribut eine Spalte einer Tabelle zuordnen.
|
Komponenten von Tabellen
|
|
Für genau diese Art von Darstellung existieren im Framework die
folgenden Konzepte. In Anlehnung an das von Swing verwendete
MVC-Muster gibt es für jede Tabelle ein Modell. Die wesentlichen
Eigenschaften von Tabellen, die Listen von Datensätzen verwalten,
werden im abstrakten Tabellenmodel
(AbstractTableModel ) des Frameworks
zusammengefaßt. Das abstrakte Tabellenmodel kennt eine Liste von
Datensätzen (Record ) und
einen Datensatzbeschreiber
(TableEntryDescriptor ).
Der Datensatzbeschreiber hat die Aufgabe, die darzustellenden
Attribute auszuwählen und ihnen eine Spalte und eine Formatierung
zuzuordnen. Die abstrakte Tabelle
(JAbstractTable ) des Frameworks bindet das ganze dann
wieder zum MVC zusammen. In Abbildung
6.1 sind diese
Zusammenhänge nochmals grafisch dargestellt. Unter diesen
abstrakten Klassen werden dann für jede Situation konkrete
Unterklassen gehängt, die mit der konkreten Art darzustellender
Daten umgehen können.
Abbildung 6.1:
Tabellen beruhen auf einem Tabellenmodell, das eine Liste von Datensätzen mit Hilfe eines Datensatzschreibers auf Tabellenzeilen projiziert.
|
Eigenschaften von Tabellen
|
|