Sachbearbeitergerechte Dialoge mit DHTML und J2EE

Bessere Dialoge

Ralph Graf und Jörg Maurer

Der Trend bei betrieblichen Informationssystemen hat uns von nativen oder Swing-basierenden Clients hin zu HTML geführt, um den Verteilungsaufwand an die Client-Rechner zu minimieren. Dabei werden hohe Anforderungen an die Bedienbarkeit gestellt. Dieser Artikel beschreibt eine Architektur, durch die mit J2EE und DHTML sachbearbeitergerechte Dialoge gebaut werden können, die sich vom Funktionsumfang und Look and Feel kaum von nativen Dialogen unterscheiden.

Dynamic HTML ist der Sammelbegriff für den Einsatz von HTML, Cascading Style Sheets (CSS), JavaScript (JS) und des Document Object Models (DOM). DHTML-basierte Clients haben gegenüber nativen Clients den Vorteil, dass keine anwendungsspezifische Software installiert werden muss. Aufwändige Verteilungsmechanismen entfallen und die Anforderungen an den Client beschränken sich darauf, dass auf diesem ein Browser vorhanden sein muss, der die geforderte DHTML-Version unterstützt. Diesen Vorteilen bei der Softwareverteilung stehen im Allgemeinen Nachteile bei der Bedienbarkeit gegenüber. Standard DHTML-Clients genügen nicht den Anforderungen an sachbearbeitergerechte Dialoge, die sowohl Power-User (Massendatenerfassung) als auch Gelegenheitsnutzer unterstützen sollen.

Mit einer solchen Architektur wurde für ein führendes Unternehmen der Bankenbranche ein betriebliches Informationssystem entwickelt. Es unterstützt die Auftragserfassung und -bearbeitung für einen Kernprozess im Back Office. Das Entwicklungsprojekt für das Dialogsystem lief von Februar 2001 bis Juni 2002 bei einem Umfang von ca. 144 Bearbeitermonaten in einem gemischten Team. Nach einem technischen Durchstich zur Verifikation der Architektur wurden die querschnittlichen technischen Basiskomponenten und anschließend die konkreten Dialoge entwickelt. Das erste Teilprojekt wurde im Sommer 2002 produktiv geschaltet.

Anforderungen an die Benutzeroberfläche

Die Spezifikation der Dialoge erfolgte ursprünglich in der Annahme, dass die Anwendung mit Microsoft-Technologie und einem nativen Windows-Client (Visual Basic) umgesetzt wird. Daher musste der Funktionsumfang und das Look and Feel des DHTML-Clients dem einer nativen Windows-Anwendung entsprechen. Dazu gehörte auch, dass Elemente wie Reiter, editierbare Comboboxen und komplexe Tabellen bereitgestellt werden müssen, die nicht durch den HTML-Standard unterstützt werden.

Das Tabellenelement sollte editier- und sortierbar sein und fixe Zeilen und Spalten darstellen können (Abb. 1). Die Breite der Tabellenspalten mussten durch den Benutzer verändert werden können. Die Zellen der Tabelle sollten andere GUI-Elemente wie z. B. Check- und Comboboxen enthalten können.

Eingabefehler mussten zum frühestmöglichen Zeitpunkt erkannt und dem Benutzer mitgeteilt werden “ im besten Fall nach dem Verlassen eines Feldes. Die Dialoge sollten Mehrsprachigkeit unterstützen und vollständig per Tastatur bedienbar sein. Als Browser sollte der MS Internet Explorer in einer festgelegten Version unterstützt werden, momentan ist dies die Version 6.

Abb. 2: Systemarchitektur

Die Systemarchitektur weist die folgenden Schichten und Komponenten auf (Abb. 2):

  • Präsentationsschicht Client: Der Browser übernimmt die Darstellung der DHTML-Seiten, die vom HTTP-Server beim Response gesendet werden und schickt Requests an das Servlet im HTTP-Server.
  • Präsentationsschicht HTTP-Server: Ein zentrales Servlet nimmt die Requests entgegen und stellt der DialogEngine das auslösende Ereignis und die Parameter des Requests zur Verfügung. Nach jedem Request wird von der zum aktuellen Dialog gehörenden Java Server Page (JSP) eine Antwortseite im DHTML-Format generiert und zum Client als Response geschickt. Dazu greift die JSP auf das DialogModel zu.
  • Dialogschicht: Die DialogEngine hält den Zustand der Benutzersitzung und realisiert unter Verwendung von Hilfsklassen die Dialogsteuerung. Die DialogEngine füllt das DialogModel mit den Benutzereingaben und übergibt es dem DialogActionHandler. Im DialogActionHandler ist die Reaktion auf die im Dialog auszulösenden Ereignisse implementiert.
  • Vorgangsschicht: Die Vorgangsschicht enthält Proxies für die am Host implementierten Module, die die fachlichen Vorgänge abbilden. Fachliche Vorgänge sind vergleichbar mit Use Cases.
  • Host-Zugriffsschicht: Diese Schicht kapselt die Middleware IBM IMS-Connect, die für den Zugriff auf die am Host liegenden Module verwendet wird.
  • Komponenten am HOST: Am Host liegen die Batches, die Vorgangsschicht, der Anwendungskern und die Datenzugriffsschicht. Damit liegt die komplette fachliche Logik sowie die komplette Datenhaltung am Host.

Als HTTP-Server wird der Apache 1.3 und als Applikations-Server wird Weblogic 5.1 eingesetzt.

Abb. 3: Aufbau Client

Die GUI-Bibliothek bietet Methoden zum Erstellen und Manipulieren der grafischen Elemente. Klassischerweise werden die GUI-Elemente auf der HTML-Seite mittels Tags in folgender Form erzeugt:

Danach ist das Element im DOM vorhanden und kann mittels JS manipuliert werden. Es besteht jedoch auch die Möglichkeit, die Elemente mit JS im DOM zu erzeugen:

var obj = document.createElement("");
obj.name = "name";
obj.value = "value";
document.body.appendChild( obj );

Dies hat den Vorteil, dass das Erzeugen von GUI-Elementen in eine JS-Datei ausgelagert und somit gecachet werden kann. Da JS eine interpretierte Sprache ist, können den DOM-Objekten überdies zur Laufzeit Attribute und Methoden zugewiesen

obj.myAttribute = value;

und somit DOM-Objekte um eigene Methoden und Attribute erweitert werden.

Mit diesen Mitteln kann nun für die grafischen Elemente eine Bibliothek aufgebaut werden, und zwar mit Schnittstellen, wie man sie von AWT oder Swing gewohnt ist. Listing 1 zeigt den Code für eine eigene CheckBox und Listing 2 zeigt, wie diese benutzt wird.

Dieser Ansatz erlaubt es, eine GUI-Bibliothek in JS mit einfachen und komfortablen Schnittstellen zu bauen. Es ist nicht nötig, mehrere DOM-Attribute zu ändern, um das gewünschte Ergebnis zu erzielen (so unterstreicht beispielsweise das Setzen des AltKeys auch den entsprechenden Buchstaben auf dem Element). Der Entwickler braucht keine speziellen DHTML-Kenntnisse; es ist für ihn transparent, ob es sich um DOM-Methoden oder um erweiterte Methoden handelt. So kann man den Code kapseln, der nicht auf den W3C-Standards basiert, sondern Browser-spezifisch ist (Crossbrowser-Programmierung). Denn nicht immer lässt sich der erforderliche Funktionsumfang mit den definierten Standards erreichen, Beispiele sind hierfür u.a. komplexere Messageboxen, Tooltips für die Combobox, das Benutzen nicht standardisierter Events oder das Abfangen bestimmter Tastatureingaben.

Auch Vererbung kann mit JS einfach implementiert werden:

this.temp = Parent;
this.temp();
.this.temp = null;

Die Vererbung wirkt sich allerdings negativ auf die Performance aus, sodass sie im Projekt nicht eingesetzt wird. Statt dessen werden dem erbenden Element einzelne Methoden des Vater-Elements zugewiesen (Listing 1).

Listing 1

myCheckBox = new CheckBox("id");

myCheckBox.addEventHandler( "onclick", myEventHandler );
myCheckBox.setChecked ( true );

function myEventHandler() {
alert( "CheckBox clicked");
}

Viele Eigenschaften der Dialogelemente sind statisch und hängen nicht vom aktuellen Dialogzustand ab. Dazu gehören die Position und Größe eines Elements, Beschriftung, Tooltip, AltKeys, die Maximallänge sowie die zugewiesenen Methoden für die Ereignisbehandlung. Diese reiterspezifische Datei enthält eine einzige Methode loadPage() mit dem gesamten Code für den statischen Aufbau des Dialogs.

Durch das Auslagern von statischer Information in CSS- und vor allem in JS- Dateien lassen sich die Daten, die bei jedem Request übertragen werden müssen, minimieren und größtenteils auf die Nutzdaten beschränken. Die CSS- und JS-Dateien lädt der Client nur einmal und benützt anschließend die im Cache gehaltene Version.

JS-Datei für die Ressourcen

Im Gegensatz zu Java unterstützt JS keine Mehrsprachigkeit. Locales oder Resourcebundles sind unbekannt. Um zu vermeiden, dass sprachabhängige Information bei jedem Request vom Server übermittelt werden muss, wird diese in eine dialog- und sprachspezifische JS-Datei ausgelagert. Es existieren somit für jeden Dialog mehrere dieser Dateien, je eine für jede Locale. Die Locale ist Bestandteil des Dateinamens. Die JSP kann somit abhängig von der eingestellten Benutzer-Locale die entsprechende Datei inkludieren. Diese Datei enthält eine Methode getStringForResourceId(id), die für eine ID den Text zurückliefert. Der Entwickler arbeitet im JS-Code nur mit IDs für die Ressourcen. Ähnliches gilt für die AltKeys und die URLs der Feld- und Dialoghilfe, auch sie sind sprachabhängig.

Zudem sind die Muster für Datum- und Zahlendarstellung hinterlegt. Mit Hilfe dieser Muster kann der Client die Benutzereingaben auf syntaktische Korrektheit überprüfen. Die Validierung erfolgt beim Verlassen des Feldes und bevor der Request zum Server gesendet wird. Da auf dem Server mit der sprachenunabhängigen Darstellung der Daten gearbeitet wird, akzeptiert der Server nur syntaktisch korrekte Benutzereingaben.

Die Tabelle

Eine komplexe Tabelle ist das von DTHML zunächst am wenigsten unterstützte GUI-Element. Die gesamte Tastaturbedienbarkeit muss nachprogrammiert werden, angefangen von der Selektion einer oder mehrerer Zeilen, über die Steuerung der Navigation durch die Tastatur mit Pfeiltasten und Tabulator oder dem Nachführen des sichtbaren Bereichs beim Durchwandern der Zeilen. Um die fixen Zeilen und Spalten zu verwirklichen, ist die Tabelle in vier Bereiche unterteilt, die miteinander synchronisiert werden müssen.

Auch für das Requestmapping sind weiterreichende Vereinbarungen zwischen Client und Server notwendig. Grund dafür ist, dass die Tabelle mit großen Treffermengen umgehen können muss, die editierbar und sortierbar sind. Editierbar heißt, dass einzelne Zellen verändert und Zeilen addiert oder gelöscht werden können oder Aktionen ausgeführt werden können, die sich auf die gesamte Treffermenge beziehen. Da der DHTML-Client zustandslos ist, müssen für jede Response die gesamten Daten an den Client gesendet werden. Somit kann am Client nur ein relativ kleiner Ausschnitt (Window) der Treffermenge angezeigt werden, der Benutzer kann jedoch durch die Tabelle blättern (Sliding-Window-Technik). Deshalb wird die gesamte Treffermenge zunächst von der Vorgangsschicht in das serverseitige TabelModel geladen, an den Client wird nur ein kleiner Ausschnitt übermittelt. Da über die gesamte editierbare Treffermenge sortiert wird, muss das Sortieren serverseitig erfolgen.

Der RequestMapper muss nun in der Lage sein, addierte und gelöschte Zeilen zu erkennen und muss den vom Client gesendeten sortierten Ausschnitt richtig in die Gesamtmenge der Daten einfügen. Neben Nutz- und Zustandsdaten der Zeilen muss auch die Breite der Spalte an den Server übermittelt werden, denn der Benutzer möchte nach einem Request die Spalte in der eingestellten Breite wieder sehen.

  • Definition eines Frameworks für webbasierte GUIs.
  • Definition von Java-Basisklassen und JSP-Tags für die GUI-Elemente.
  • Unterstützung der gängigsten GUI-Elemente.
  • Definition eines Standards für die Ereignisbehandlung zwischen Client und Server.
  • Definition einer API für die Eingabevalidierung, einschließlich der Unterstützung für clientseitige Validierung.
  • Unterstützung von Internationalisierung.
  • Automatische Erzeugung von entsprechendem Clientcode abhängig von der Clientkonfiguration, z.B. der Browserversion.

Sun ist sich bewusst, dass die aufgeworfenen Fragestellungen schon von anderen Projekten, z.B. von dem Open Source-Projekt Struts, adressiert worden sind. In erster Linie soll mit JavaServer Faces jedoch das heterogene Umfeld für Web-basierte GUI-Entwicklung standardisiert werden, bereits vorhandene Lösungen sollen in den neuen Standard einfließen. Mit der Standardisierung soll der Einsatz von Tools für die Web-basierte GUI-Entwicklung und das Verwenden fertiger Komponenten vorangetrieben und letztendlich der Unterschied zwischen konventioneller und Web-basierter GUI-Entwicklung verkleinert werden.

Systemarchitektur

Der Einsatz eines Generators für das Erstellen der DHTML-Seiten liegt auf der Hand. Zum einen ist der Code, der individuell erstellt werden muss, auf die Ereignisbehandlung begrenzt. Zum anderen ergibt sich der Einsatz eines Generators aus der Projekthistorie, da die Spezifikation der Dialoge in Visual Basic erfolgte. Der in Java geschriebene Generator wertet die beim Erstellen einer Visual Basic-Maske erzeugte Quelldatei (.CTL) aus und generiert sowohl die JSP als auch die dialogspezifischen JS-Dateien.

Wie Client und Server beim Abarbeiten eines Requests zusammenspielen, verdeutlicht der nächste Abschnitt (Abb. 4). Er zeigt außerdem die notwendigen Schritte, um einen Dialog zu erstellen.

Abb. 4: Zusammenspiel Client – Server

Die Klammer zwischen Client und Server pictureet die eindeutige ID, die jedes GUI-Element besitzt. Diese ID ist ebenfalls in dem zum GUI-Element gehörenden serverseitigen ComponentModel (z.B. CheckBoxModel) hinterlegt. Diese ComponentModels sind Bestandteil des DialogModels.

Sendet der Client einen Request an den Server, nimmt das MainServlet diesen entgegen. Es filtert das gesendete Ereignis heraus und leitet es zusammen mit den Daten an die DialogEngine weiter. Die DialogEngine beauftragt den RequestMapper, die Daten, die der Client in Form von Schlüssel-Wert-Paaren schickt, in die Models zu überführen.

Hierzu iteriert der RequestMapper durch alle ComponentModels eines Dialogs. Mittels der Ids überführt er die Daten aus dem Request in die Models. Ist das DialogModel mit den Benutzereingaben gefüllt, sucht die DialogEngine den zuständigen DialogActionHandler mit Hilfe der vom Client übertragenen Dialog-ID heraus. Im DialogActionHandler ist die Dialog-Aktion ausprogrammiert, gegebenenfalls erfolgt ein Zugriff auf die Vorgangsschicht. Der Entwickler bestimmt hier ebenfalls den aktuellen Zustand des Dialogs. D.h., er bestimmt, ob der Dialog auf dem aktuellen Reiter verbleiben oder z.B. ein anderer Dialog aufgerufen werden soll. Abschließend gibt die DialogEngine die Kontrolle an das Servlet zurück, dass das DialogModel an die zuständige JSP weiterleitet. Die JSP wertet das DialogModel aus und erzeugt zur Laufzeit den JS-Code, um die Nutzdaten und die dynamischen Eigenschaften der GUI-Elemente zu bestimmen.

Die DialogEngine, der DialogActionHandler und der Vorgangs-Proxy sind als Enterprise Java Bean (EJB) realisiert. So können die vom EJB-Server und -Container gelieferten Merkmale benutzt werden, wie z.B. die Verwaltung von Ressourcen und des Beans-Lebenszyklus, Sicherheitsdienst und Sicherstellung der Mehrbenutzerfähigkeit.

Systemarchitektur

Die Ereignisbehandlung setzt Oberflächenereignisse (Klick auf einen Button) in die logischen Ereignisse der Anwendung (Detail anzeigen) um. Ein logisches Ereignis kann durch mehrere Oberflächenereignisse ausgelöst werden (Klick auf den Detailbutton und Doppelklick auf eine Tabelle lösen das Ereignis Detail anzeigen aus). Das Umsetzen der Oberflächenereignisse in logische Ereignisse übernehmen die JS-Elemente, sodass Client und Server nur logische Ereignisse austauschen. Dazu erfolgt das Registrieren eines Eventhandlers beim GUI-Element in der Methode loadPage() zusammen mit dem logischen Event:

obj.addEventHandler("onclick", "DETAIL", handlerDetail);

Bei der Konfiguration eines Dialogs gibt der Entwickler für jedes ComponentModel die möglichen logischen Ereignisse an.

Dieses Vorgehen erlaubt das serverseitige Deaktivieren von logischen Ereignissen abhängig vom Dialogzustand. Ist ein Ereignis deaktiviert, werden automatisch die Oberflächenereignisse auf Clientseite deaktiviert. Denn beim Auswerten der ComponentModels erzeugt die JSP den entsprechenden JS-Code. Abpictureung 5 verdeutlicht diesen Vorgang.

Abb. 5: Ereignisbehandlung

Das Projekt hat gezeigt, dass sich mit DHTML ein Client bauen lässt, dessen Funktionsumfang und Look and Feel mit einem nativen Client vergleichbar ist. Die Antwortzeiten der Dialoge sind für die Massendatenverarbeitung geeignet.

Die wesentliche Limitierung eines DHTML-Clients mit der hier vorgestellten Architektur ist die Zustandslosigkeit des Clients. Alle variablen Informationen müssen bei jedem Response wieder an den Client geliefert werden. Dies bedingt den Einsatz der Sliding-Window-Technik (siehe Kasten Die Tabelle) für die Anzeige großer Treffermengen.

Die Anforderungen an die Benutzeroberfläche konnten mit JavaScript umgesetzt werden. Viele Merkmale, die für native Clients selbstverständlich sind, müssen nachprogrammiert werden. Dazu zählt u.a. die Bedienbarkeit der Tabelle mit der Tastatur oder ein Element wie die editierbare Combobox, das in DHTML überhaupt nicht bekannt ist. Letztlich ist DHTML jedoch so mächtig, dass eine den Anforderungen entsprechende GUI-Bibliothek aufgebaut werden konnte. Nicht immer ist der W3C-Standard ausreichend, um den gewünschten Funktionsumfang zu realisieren. Die optimale Lösung liegt häufig in der Nutzung Browser-spezifischer Erweiterungen.

Eine wichtige Bedingung für das Projekt war die Homogenität der Clientrechner, d.h., es ist ein Browser in einer vorgegebenen Version zu unterstützen. Mehrere Versionen oder gar Browser von verschiedenen Herstellern zu unterstützen ist aus Kosten-Nutzen Sicht nicht vertretbar. Aus technologischer Sicht ist der MS Internet Explorer momentan der einzige Browser, mit dem der volle Funktionsumfang bei vertretbarem Aufwand realisiert werden kann.

Da die JavaScript GUI-Bibliothek allen kritischen Code kapselt, war der im Projektverlauf notwendige Umstieg von IE 5.0 auf IE 5.5 und anschließend auf IE 6 innerhalb weniger Tage erledigt. Der größte Aufwand wurde durch den Re-Test der GUI-Bibliothek verursacht, der sich durch Automatisierung jedoch verringern lässt.

Der Aufwand für die Entwicklung eines Dialogs mit der vorgestellten Umgebung und der Aufwand für die Entwicklung eines Dialogs für einen nativen Client unterscheiden sich nicht. Entwickler ohne OO-, DHTML- oder EJB-Erfahrung konnten sich schnell in die Umgebung einarbeiten.

Geschrieben von
Ralph Graf und Jörg Maurer
Kommentare

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.