Funktionsweise

Das folgende Bild skizziert den Ablauf eine Anfrage durch einen Websurfer. Anschließend werden die einzelnen Schritte und Stationen (in eckigen Klammern angegeben) näher erklärt. Bedingung für den Ablauf ist eine funktionierende InstantWeb-Anwendung. Diese kann mit dem InstantWeb-Generator(Funktionsweise Generator) oder von Hand erzeugt werden.

  1. [Webbrowser] Der Benutzer gibt in seinem Webbrowser eine URL ein, die zu der InstantWeb-Anwendung führt. Die URL könnte z.B. ein Bookmark sein oder ein Link, der auf der Homepage des Unternehmens zu finden ist.
  2. Der Browser überträgt die Anfrage an den JSP-Server (ein evtl. dazwischenliegender Webserver ist hier nicht dargestellt).
  3. Im weiteren Verlauf gehen wir davon aus, dass der Benutzer bereits in der InstantWeb-Anwendung navigiert. Er befindet sich gerade auf einer Seite, wo er Daten eingegeben hat und nun den „Ok“-Knopf betätigt hat.
  4. [JSP-Server] Der JSP-Server übernimmt mehrere Aufgabe: Er generiert aus JSP-Seiten HTML-Seiten (zu dem Punkt kommen wir später) und die darunter liegende Servlet-Engine verwaltet die Sessions und gibt die Kontrolle an das Servlet weiter.
  5. [Struts-Framework] Dieses Servlet ist hier das Struts-Framework. Anhand der URL erkennt Struts, welche Action- und welche Form-Klasse gemeint sind. Nun wird das Form-Bean ([class xxxForm]) mit den Daten gefüllt, die der Benutzer auf der Webseite eingegeben hat. Im nächsten Schritt wird die perform()-Methode der Action-Klasse aufgerufen.
  6. [class xxxAction] Hier wird auf die Aktion des Benutzers reagiert (perform-Methode):


  7. Wie im Punkt 3 angenommen, hat der Benutzer den „Ok“-Knopf gedrückt. Falls keine Interaktion vorliegt (weil der Benutzer die Seite direkt anspringt oder wir von Punkt 8 kommen), geht es weiter mit Punkt 9.
    Die abgeleitete perform()-Methode verarbeitet diese Interaktion:
    1. Nach der Validierung wird ein "drainWindow" durchgeführt. Die Eingaben werden zusammen mit der Nachricht "Ok-Knopf gedrückt" zu einem komprimierten XML-Stream zusammengesetzt (Wap Binary XML) und an den Coordinator gesendet:
      1. CX_Action.drainWindow stellt einen XML-Stream mit allen benötigten Daten zusammen.
      2. CX_Action.fetchXmlStream weist den Request Dispatcher an, diesen Datenstrom zu übertragen (über RequestDispatcher.XMLExportImport und CXRequestDispatcher.acceptWbxmlRequest).
      3. Auf Serverseite nun wird in CXRequestDispatcherImpl.acceptWbxmlRequest dieser Datenstrom geparst und in entsprechend viele Messages aufgeteilt. Diese werden der Reihe nach an die laufende ClassiX®-Instanz gesendet. Abschließend wird die gerade angezeigte Seite im XML-Format angefordert. Dieser XML-Strom wird in einen WBXML-Strom umgewandelt und wieder zurück an CX_Action.fetchXmlStream gegeben.
      4. Diese Antwort (der XML-Strom) wird in der Session-Variable „xmlStream“ gespeichert.
    2. Aus der Antwort wird der Name des gerade angezeigten Fensters herausgelesen. Dieses Fenster ist das Folgefenster, denn es ist das Fenster, was im Browser des Benutzers als nächstes dargestellt werden muss.
  8. Es hängt von der Folgeseite ab, wie nun weiter fortgefahren wird:
    1. Falls die Folgeseite nicht die Seite ist, die gerade dargestellt ist, teilt perform() Struts die neue Seite mit. Anschließend ruft Struts die perform()-Methode der neuen Seite auf. Es geht weiter mit Punkt 7.
    2. Ist die Folgeseite die Seite, die gerade angezeigt wird, wird der Code weiter ausgeführt, es geht weiter mit Punkt 9.
  9. Die letzte Antwort wird aus der Session-Variable „xmlStream“ geholt. Wenn hier keine Antwort gespeichert wurde, so hat der Benutzer offenbar die Seite direkt angewählt. In diesem Fall wird eine Message an den Coordinator gesendet mit der Anweisung, die Seite darzustellen (die Message ist in der Variablen START_MESSAGE abgelegt).
  10. Die Antwort wird verarbeitet, indem das Form-Bean mit den Werten aus der Antwort gefüllt wird.
  11. Trat ein Fehler auf oder wird gerade eine Attention-Meldung angezeigt, so wird der Text in einem gesonderten Property abgelegt. Die JSP-Seite zeigt diesen Text dann an.
  12. Im letzten Schritt springt die Action-Klasse xxxAction zum Struts-Framework zurück und übergibt dabei den Namen der Seite, die als nächstes angezeigt werden soll, nämlich die JSP-Seite dieser Action-Klasse.

Das folgende Bild veranschaulicht das Zusammenspiel zwischen CX_Action und einer abgeleiteten Klasse beim drainWindow (Punkt 7a) und parseXmlStream (Punkt 10):

 

Aufbau Koordinator und Kommunikation mit Struts

Da der Koordinator beliebig viele, beliebig unterschiedliche ClassiX®-Instanzen verwalten kann ist er auf den ersten Blick etwas unübersichtlich.
Warum ist das so?
Der Koordinator kann mehrere CX-Projekte gleichzeitig. Will ein ClassiX®-Kunde also mehrere Webapplikationen(z.B. verschiedene interne Projekte wie Fibu/Lager + externe Projekte Telefonliste/Webshop) anbieteten können diese durch einen einzigen Koordinator gesteuert werden. Außerdem müssen für jedes Projekt die Instanzen verwaltet werden, da für jeden User der eine InstantWebanwendung benutzt ein ClassiX® des jeweiligen Projektes gestartet werden muss.
Da das Starten einer ClassiX®-Instanz ein paar Sekunden dauern kann hält der Koordinator für jedes Projekt(i.F. auch Applikation gennant) ein paar Instanzen auf Halde. Wieviele das mindestenz bzw. höchsten sein müssen/dürfen kann man in der InstantWeb-init.xml bestimmen.

Das nebenstehende Diagramm ist eine starke Vereinfachung der tatsächlichen Beziehungen und soll nur zum verdeutlichen der Grundsätzlichen Zusammenhänge dienen.
Der Koordinator hat eine Map mit ApplicationData-Objekten. Jedes ApplicationData-Objekt entspricht einem CX-Projekt(also einem .cxp).
In einem ApplicationData-Objekt werden zwei Maps geführt.
  • eine mit wartenden Instanzen(unkownProcesse)
  • und eine mit 'beschäftigten' Instanzen(instances)
Besucht eine neuer User eine unserer Applikationen wird
  • aus der unknownProcesses-Map dieser Applikation ein Prozess herausgenommen
  • mit einer ApplicationInstance in ein Containerobjekt gewickelt
  • und in die Liste der Aktiven Instanzen dieser Applikation(ApplicationData.intances) eingefügt.

Jede ApplicationInstance=ClassiX®Web-Objekt hat einen CXRequestDispatcher. Ein CXRequestDispatcher kann die 'nativen' Funktionen des CX-Prozesses aufrufen der zu der gemeinsamen ApplicationInstance gehört. In diesen Funktionen wird die Arbeit an das CX weitergeleitet.

Wie kommen die Daten vom Webserver zur ApplicationInstance?
Die Kommunikation wird über eine Socket/TCP-Verbindung abgewickelt. Damit das nicht 'von-Hand' implementiert werden muss benutzen wir RMI - Remote Method Invocation. Hier wird einem Javaprozess  ein Objekt 'übers Netz' zur Verfügung gestellt(mal ganz platt ausgedrückt).
Die 'xyzWin'Action.Java - Klassen(Struts) holen die Daten aus den Formularen der HTTP-Requests des Browsers. Ihre Aufgabe ist es diese Daten artgerecht aufzubereiten, und sie dem zugehörigen CXRequestdispatcher zukommen zulassen.

Doch wie kommt der ServletContainer an einen CXRequestDispatcher?
In den perform()-Methoden der 'xyzWin'Action.Java - Klassen wird eine Instanz eins ConnectionRequestDispatcher erstellt. Die Klasse erbt von RequestDispatcher - diese beiden Klassen hängen aber nicht von CXRequestDispatcher ab!
Über die Hostadresse, den Hostport (des Koordinators) und den Applikationsnamen kann sich der (Connection-)RequestDispatcher dann einen CXRequestDispatcher einer freien ApplicationInstance vom Koordinator 'geben lassen', dieser wird dann in der Session abgespeichert.

Das ist war nur die grobe Funktionsweise. Tatsählich gibt es noch einige Abhängigkeiten mehr, diese dienen aber hauptsächlich dazu um die Instanzen besser zu verwalten(freigeben, recyclen etc) und um das Ganz Threadsafe zu machen.

Klicken zum vergößern