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:

Übersichtsdiagramm
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.

Prozesse bestehen aus Zuständen und Übergängen
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.

Zusammenhänge zwischen des einzelnen Gates
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.

Prozesse können an Verkaufsständen und als Hintergrundprozesse laufen
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.

Formulare und Menüs verwenden Aktionen, um Benutzereingaben mit Programmreaktionen zu verknüpfen
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:

Kataloge und Bestände
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.

Benutzer haben Fähigkeiten und werden von Benutzermanagern verwaltet.
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.

Tabellen beruhen auf einem Tabellenmodell, das eine Liste von Datensätzen mit Hilfe eines Datensatzschreibers auf Tabellenzeilen projiziert.
Abbildung 6.1: Tabellen beruhen auf einem Tabellenmodell, das eine Liste von Datensätzen mit Hilfe eines Datensatzschreibers auf Tabellenzeilen projiziert.

Eigenschaften von Tabellen

last modified on 24.09.2001
by kk15 and ch17