|
Die Architektur von InstantView® besteht im wesentlichen aus 3 Schichten. Dem aus Die Instanzen der C++ Klassen
können transient im RAM oder auch persistent in der Datenbank gehalten werden.
Die Runtime Schicht reicht die Daten von der Datenbank bis zur GUI durch, ist
aber auch für den gesamten flow control und den message bus verantwortlich. |
![]() |
![]() |
Die Abtrennung der Visualisierung vom Modell entspricht dem MVC-Konzept, jedoch mit etwas anderen und weitergehenden Zielen: Der Programmcode eines (Modell-)Objekts steht für stabile, in hohem Maße wiederverwendbare Funktionalität, die allgemeingültiges Wissen des Anwendungsgebietes widerspiegelt und nur selten Änderungen unterworfen ist. Im Gegensatz dazu soll das InstantView® Scripting die Besonderheiten einer spezifischen Anwendung beschreiben, damit auf diese Weise individuell angepasste Software aus Standardkomponenten zusammengesetzt werden kann. Ein InstantView® Skript ist nicht nur das User-Interface einer Anwendung, sondern liefert auch die 'Verbindungsstücke' (flexible Relationen zwischen Objekten, Eingabedaten vor Weitergabe an ein Modellobjekt prüfen, ...). InstantView® Skripte können als Module organisiert werden, die gekapselt sind und deren Eigenschaften vererbbar sind. Jedes Modul sollte dabei immer für bestimmte Aufgaben zuständig sein (z.B. Pflege von Kundendaten), stellt für sich also eine Teil-Anwendung dar. Module kommunizieren untereinander über den von der Runtime zur Verfügung gestellten message bus. Die Gesamtheit aller Anwendungsmodule wird als
AppsWarehouse®
bezeichnet, einem Warenhaus von Teilanwendungen, aus dem man sich die
gewünschte Anwendungslösung beliebig zusammenstellen kann. |
InstantView® Skript beschreibt
u.a. Window-Ressourcen, die in
reale Windowobjekte von Windows
transformiert und damit zur Darstellung auf dem Bildschirm gebracht werden. Vom GUI
empfangene Messages werden in logische Events (d.h. in die bei InstantView®
vorgesehenen System-Events) übersetzt. Logische Events
starten die in Aktionslisten beschriebenen Algorithmen.
Wie jedes andere ereignisgesteuerte Programm verweilt InstantView®
in einem Programmzyklus, auf Messages vom Basissystem (MS Windows) wartend.
Sobald der Anwender einen Button drückt, ein Menüitem auswählt oder etwas ähnliches
tut, erhält InstantView® für das betroffene Windowobjekt (den Button, das Menüitem, ...)
eine Message, übersetzt diese in ein logisches (und daher plattformunabhängiges)
Ereignis. Dann wird die Aktionsliste des
Windowobjekts durchsucht.
Gibt es dort eine an das logische Event gebundene
Anweisungsfolge, soll diese natürlich ausgeführt werden. Das geschieht auch, aber nicht
sofort. Unter Umständen könnte jetzt ein zeitaufwendiger Prozess starten - aber
InstantView® beantwortet in diesem Moment eine Message des Basis- Windowsystems! Deshalb
wird die Aktion zeitlich entkoppelt: die InstantView®-Anweisungen passieren eine
Warteschlange. Dieser Umweg ist für den InstantView®-Programmierer
transparent, erlaubt ihm aber, für ein Systemereignis beliebige Aktionen zu definieren
ohne sich dabei um Zeitbedingungen zu kümmern.
Die folgende Abbildung zeigt den
Zusammenhang Message - logisches Ereignis - Aktion für ein Window mit
Button. Wird der Button gedrückt, ändert sich der Titel des Windows, in unserem
einfachen Beispiel wird der Titel "My Window" in Klammern gesetzt:
InstantView® Skript Anweisungen tauschen Parameter und Ergebnisse über
einen Stack aus. Jede Anweisung konsumiert eine exakt definierte Anwahl von
Stackeinträgen und legt anschließend ihre Ergebnisse dort ab. Die folgende Abbildung
zeigt die Stackbelegung für das vorangegangene Beispiel:
InstantView® entfernt automatisch Daten, die von einer durch ein Event getriggerte
Anweisungsfolge auf dem Stack hinterlassen werden. Die Daten, die auf dem Stack liegen
oder von Variablen gehalten werden, belegen Speicher. Dieser Speicher wird frei, sobald
die Einträge vom Stack genommen oder den Variablen andere Werte zugewiesen werden.
InstantView® startet von Zeit zu Zeit einen Garbage-Collection-Prozeß, der solche
Speicherbereiche zurückgewinnt.
Für elementare Datentypen (ganze Zahlen, Zeichenketten,
multiple Zeichenketten, ...) geschieht dies automatisch; es gibt keinen Grund, diesen
Vorgang überhaupt zur Kenntnis zu nehmen. Aber auch der Speicher, den ein transientes
Objekt X einst belegt hat, soll freigegeben werden. Der Garbage-Collection-Algorithmus
kann - zumindest in diesem Release - nicht feststellen, ob X von einem weiteren
(transienten) Objekt Y referenziert wird. Solange X und Y auf dem Stack liegen oder
Variablen zugewiesen sind, ist alles gut. Wird dann nur X frei, enthält Y
nach der nächsten Garbage-Collection eine Referenz auf ein nicht existentes Objekt. Dies
zu verhindern gibt es zwei Möglichkeiten:
Modell-Objekte sind Instanzen in C++ geschriebener Klassen, und daher gibt es keine
inhärente Möglichkeit, zur Laufzeit (mit Nicht-C++-Code) auf Daten und Methoden
zuzugreifen. InstantView® braucht aber genau solch einen Zugang. Deshalb können
Modell-Klassen um ein Data Dictionary (DDI) und ein Method
Dictionary (MDI) erweitert werden.
InstantView® besitzt
Anweisungen, die Daten aus einem Objekt auf den Stack bringen oder umgekehrt Daten vom
Stack in ein Objekt speichern. Das DDI beschreibt, welche
Relationen zwischen Objekten mit InstantView® erzeugbar sind (und garantiert damit
referentielle Integrität). Es ist die Grundlage für das intelligente
Mapping zwischen Modell-Objekt und Windowoberfläche über
Zugriffsausdrücke
(siehe FillWindow und
DrainWindow).
Mit Anweisung Call können Funktionen eines Objektes
aufgerufen werden, wenn sie im MDI eingetragen sind. Das gilt
auch für Funktionsaufrufe innerhalb eines Zugriffsausdrucks.
(Sowohl DDI als auch MDI einer Klasse werden mit Utility GENDDI automatisch
generiert).
Will InstantView® ein persistentes Objekt
erzeugen /
löschen, eine
Query starten usw., so
fordert es diese Dienste nicht direkt von der objektorientierten Datenbank sondern stützt
sich auf den Objektmanager. ClassiX® sieht die Aufteilung der
Datenbank in Layer and
Domains vor,
Objekte können sogar in unterschiedlichen physischen Datenbanken gespeichert sein.
Das
Layout einer Datenbank wird im File CLASSIX.INI beschrieben,
das der Objektmanager in der Initialisierungsphase liest. Nur der
Objektmanager 'weiß', wo ein Objekt einer bestimmten Klasse gespeichert werden muss
und
wo es wiedergefunden werden kann.
Wird (mit SendMsg) eine Message ausgesendet, so durchsucht
InstantView® zuerst die
Aktionslisten aller Module, danach
aller Windowobjekte nach Anweisungen, die mit der ausgesendeten Message verbundenen sind.
Gefundene Anweisungen werden sofort - ohne den Umweg über eine Warteschlange -
ausgeführt. Nur die zur Zeit geöffneten Windows und deren Childobjekte können eine
Message empfangen. Folglich müssen, wenn eine Message ein Window öffnen soll, die
entsprechenden Anweisungen entweder einem Modul oder einem anderen Window, das sich
bereits auf dem Bildschirm befindet, zugeordnet sein. Das eine Message sendende
Windowobjekt kann auch zu den Empfängern dieser Message gehören.
Wie transportiert eine Message weitere Information? Die erste Anweisung einer Folge, die
durch ein System-Ereignis aktiviert wurde, sieht einen leeren
Stack. Das gilt nicht notwendigerweise für die erste der durch eine Message getriggerten
Anweisungen. Bei jedem Empfänger erscheint genau die Stackbelegung, die
SendMsg vorgefunden hat. SendMsg nimmt alle Einträge vom Stack.
Die Empfänger einer Message können mit Anweisung
ReturnValue Werte
von ihrem Stack an den Sender zurückgeben.
Die gleiche Anweisungsfolge kann von System-Ereignissen und Messages getriggert werden.
Wie bei System Events, so dürfen auch die Empfänger einer Message Daten auf dem Stack
hinterlassen (InstantView® entfernt sie automatisch).
SendMsg verteilt seine Message wie ein Rundschreiben. Will man
ein Protokoll aufbauen, wo der Empfänger dem Sender direkt antwortet (unter Ausschaltung
aller anderen potentiellen Mithörer), so muss die primäre Message neben eventuell
anderen Daten auch das sendende Windowobjekt enthalten. Ein Windowobjekt wird mit
Anweisung Widget auf den Stack gebracht. Der Empfänger kann
nun mit ReturnMsg gezielt antworten.