You are on page 1of 82

Implementierung eines Labor Informationsund Managementsystems mittels Google Web Toolkit

Bachelorarbeit

Zur Erlangung des akademischen Grades

Bachelor of Science in Engineering (BSc)

der Fachhochschule FH Campus Wien Bachelorstudiengang: Informationstechnologien und Telekommunikation

Vorgelegt von: Ing. Peter Pratscher

Personenkennzeichen 0710475099

Erstbegutachter: Mag. Dipl.-Ing. Dr.techn. Wolfgang Radinger

Zweitbegutachter: DI (FH) Gerhard Petracek

Eingereicht am: 02. 07. 2010

Erklrung:

Ich erklre, dass die vorliegende Bachelorarbeit von mir selbst verfasst wurde und ich keine anderen als die angefhrten Behelfe verwendet bzw. mich auch sonst keiner unerlaubter Hilfe bedient habe. Ich versichere, dass ich diese Bachelorarbeit bisher weder im In- noch im Ausland (einer Beurteilerin/einem Beurteiler zur Begutachtung) in irgendeiner Form als Prfungsarbeit vorgelegt habe. Weiters versichere ich, dass die von mir eingereichten Exemplare (ausgedruckt und elektronisch) identisch sind.

Datum: 02.07.2010 ............... Unterschrift: ........................................................................................

Danksagung
Hiermit mchte ich mich bei Carmen und meiner Familie fr die Untersttzung whrend des gesamten Studiums bedanken, ohne euch htte ich es wohl nicht geschafft. Weiters mchte ich mich bei meinen Arbeitskollegen im Lafarge European Technical Center bedanken. Ohne die flexible Zeiteinteilung wre mir ein positiver Abschluss des Studiums wohl nicht gelungen. Zu guter Letzt mchte ich mich noch bei meinem Betreuer, Mag. Dipl.-Ing. Dr.techn. Wolfgang Radinger, bedanken welcher mir bei Problemen immer mit Rat und Tat zur Seite stand.

Kurzfassung
Diese Arbeit setzt sich mit der Umsetzung eines Labor Informations- und Managementsystems (LIMS) unter Verwendung des Google Web Toolkits (GWT) auseinander. Basierend auf einer Anforderungsanalyse, welche im ersten Teil dieser Arbeit durchgefhrt wurde, wird eine praktische Implementierung der erarbeiteten Anwendungsflle vorgenommen. Zuerst wird die Applikationsarchitektur nach den derzeit aktuellen Best Practices, unter Verwendung des Model-View-Presenter Models, entworfen und umgesetzt. Dies erfolgt unter Betrachtung der spezifischen Eigenschaften bei Verwendung des Google Web Toolkits. Hierbei werden die Strken und Schwchen dokumentiert und Lsungsvorschlge fr generell auftretende Probleme aufgezeigt. Weiters wird auf die Verwendung der Benutzerkomponenten, insbesondere auf deren Anpassung an die eigenen Bedrfnisse, eingegangen. Dies umfasst auch, die im Mai 2010 neu in den Toolkit eingeflossenen Data Presentation Widgets. Abschlieend wird die praktische Anwendung des Toolkits an der Implementierung einiger ausgewhlter Anwendungsflle demonstriert und gleichzeitig aufgezeigt, dass der Toolkit eine gute Wahl zur Umsetzung einer skalierenden Implementierung von Labor Informations- und Managementsystemen ist. Zusammenfassend zeigt diese Arbeit, dass sich der Google Web Toolkit gut fr die praktische Implementierung von Labor Informations- und Managementsystemen eignet.

ii

Abstract
This thesis deals with the realization of a Laboratory Information- and Management System (LIMS) using the Google Web Toolkit (GWT). Based on the requirement analysis performed in the first part of this thesis a practical implementation of the developed use cases will be performed. At first, the architecture of the application will be designed and realized, according to the current topical best practice using the Model-View-Presenter pattern. This will be done within the context of the specific properties when using the Google Web Toolkit. In this part, the advantages and disadvantages of it are documented and solutions are presented for problems occurring generally. Furthermore a specific focus is put on the usage of the new Data Presentation Widgets, which were introduced to the toolkit in May 2010. In the final part of the thesis, the practical usage of the toolkit is demonstrated on the actual implementation of several selected use cases. It is also shown, that this toolkit is a good choice for implementing scalable Laboratory Information- and Management Systems. Summarizing it can be said, that the Google Web Toolkit is fully applicable for implementing Laboratory Information- and Management Systems.

iii

Abkrzungsverzeichnis
LIMS GWT RPC API IDE JRE SWT DOM mvp4g SQL HQL HTML AJAX XML JDBC JSF Labor Informations- und Management System Google Web Toolkit Remote Procedure Call Application Programming Interface Integrated Development Environment Java Runtime Environment Standard Widget Toolkit Document Object Model Model-View-Presenter for GWT Structured Query Language Hibernate Query Language Hyper Text Markup Language Asynchronous Java Script and XML Extensible Markup Language Java Database Connectivity Java Server Faces

iv

Schlsselbegriffe
Labor Informations- und Management System Google Web Toolkit Web 2.0 AJAX Model View Presenter Informationssystem

Inhaltsverzeichnis
1. EINFHRUNG ................................................................................... 3 2. GOOGLE WEB TOOLKIT .................................................................... 3
2.1. Funktionsweise ......................................................................................... 4 2.1.1. Aufbau eines GWT Projektes ............................................................ 6 2.1.2. Debuggen eines GWT Projektes....................................................... 7 Client Server Kommunikation............................................................... 8 Steuerelemente ....................................................................................... 11 2.3.1. Anpassung von Widgets ................................................................. 15 Data Presentation Widgets .................................................................... 17 2.4.1. Das CellTable Widget ................................................................... 17 Das Model-View-Presenter Entwurfsmuster ........................................ 21 2.5.1. Prinzip ............................................................................................. 21 2.5.2. Die mvp4g Bibliothek .................................................................... 22

2.2. 2.3. 2.4. 2.5.

3. DESIGN EINES LIMS SYSTEMS ........................................................ 25


3.1. 3.2. 3.3. Drei Schichten Architektur .................................................................... 25 Domnenmodel ....................................................................................... 25 Datenzugriffsschicht .............................................................................. 26 3.3.1. Hibernate und GWT ........................................................................ 29 3.3.2. Die Gilead Bibliothek .................................................................... 30 3.4. Serviceschicht ........................................................................................ 34 3.4.1. Datenvalidierung ............................................................................. 36 3.5. Prsentationsschicht ............................................................................. 36 3.5.1. Design der Benutzeroberflche....................................................... 36 3.5.2. Umsetzung des MVP Patterns ........................................................ 40 3.5.3. Applikationsstart.............................................................................. 41 3.5.4. Wechsel des angezeigten Views .................................................... 41

4. IMPLEMENTIERUNG AUSGEWHLTER ANWENDUNGSFLLE ................. 43


4.1. Anwendungsfall Analysen verwalten ................................................. 43 4.1.1. Kurzbeschreibung des Anwendungsfalles ...................................... 43 4.1.2. Umsetzung im Domnenmodell ...................................................... 43 4.1.3. Erstellen des Views ......................................................................... 44

4.1.4. Erstellen des Presenters ................................................................. 49 4.1.5. Validieren und Speichern der Eingaben .......................................... 53 4.2. Anwendungsfall Analysen Planen ..................................................... 55 4.2.1. Kurzbeschreibung des Anwendungsfalles ...................................... 56
1

4.2.2. 4.2.3.

Umsetzung im Domnenmodell ...................................................... 56 Erstellen des Views ......................................................................... 57

4.2.4. Erstellen des Presenters ................................................................. 58 4.3. Anwendungsfall Ergebnisse eingeben .............................................. 61 4.3.1. Kurzbeschreibung des Anwendungsfalles ...................................... 61 4.3.2. Umsetzung im Domnenmodell ...................................................... 61 4.3.3. Erstellen des Views ......................................................................... 62 4.3.4. Erstellen des Presenters ................................................................. 64

5. ZUSAMMENFASSUNG ...................................................................... 65 6. AUSBLICK ..................................................................................... 66 ANHANG ............................................................................................. 67

2.1. Funktionsweise

1. Einfhrung
Im Zuge meiner beruflichen Laufbahn hatte ich bereits die Gelegenheit mit vielen verschiedenen LIMS Systemen zu arbeiten. Angefangen von der Wartung und Weiterentwicklung von Microsoft Access basierenden, selbst entwickelten und ber Jahre gewachsenen Systemen, bis hin zur Implementierung von weltweit eingesetzten Enterprise Applikationen. Obwohl jedes fr sich hinsichtlich seines Einsatzortes durchaus tauglich war, machte ich bei allen Systemen die Erfahrung, dass sich die Anwendung und auch die Wartung als zeitaufwndig und unflexibel gestalteten. Dies wurde teilweise durch die Architektur der Systeme selbst, als auch durch die Limitierungen, welche aufgrund des geschftlichen Umfeldes gegeben waren, verursacht. Aufgrund dessen habe ich seit geraumer Zeit die Idee, ein solches System von Grund auf neu zu entwickeln und es, basierend auf meinen bisherigen Erfahrungen, so benutzerfreundlich und wartbar als mglich zu gestallten. Um dies umzusetzen wurde in der, dieser Arbeit vorhergegangenen Bakkalaureatsarbeit I, ein LIMS System spezifiziert und der Google Web Toolkit als fr die Umsetzung geeignetste Web 2.0 Technologie im Vergleich zu JSF 2.0 ausgewhlt. Ziel dieser Arbeit ist es, das zuvor entworfene LIMS System mittels des Google Web Toolkit anhand der erarbeiteten Spezifikationen zu Implementieren. Hierbei soll gezielt der Fokus auf die Verwendung von Entwurfsmustern und die Anpassung der im Toolkit enthalten Steuerelemente gelegt werden. Weiters sollen die bei der Umsetzung aufgetretenen Probleme dokumentiert, und die Mglichkeiten zu deren Behebung aufgezeigt werden. Am Ende dieser Arbeit soll eine Aussage darber getroffen werden knnen, in wie fern sich der Google Web Toolkit zur Implementierung von Labor Informations- und Managementsystemen eignet. Hierfr wird zuerst auf die generelle Anwendung des Google Web Toolkit eingegangen, sowie die damit verbundenen Entwurfsmuster und externen Programmierbibliotheken diskutiert. Darauf aufbauend wird das in der Bakkalaureatsarbeit I erarbeitete Design eines LIMS Systems in die Praxis umgesetzt und die damit verbundenen Probleme und Herausforderungen aufgezeigt. Abschlieend wird die praktische Umsetzung spezieller Anwendungsflle diskutiert um die Zusammenhnge der einzelnen Komponenten des Toolkit im Zuge der Implementierung von komplexen Ablufen aufzuzeigen.

2. Google Web Toolkit


Der Google Web Toolkit verfolgt einen neuartigen Ansatz zur Entwicklung von Web 2.0 Applikationen. Die Idee dahinter ist, anstatt, wie bei traditionellen AJAX Frameworks, Webanwendungen mittels einer Verbindung von HTML, CSS und Java Script auf der Browser und PHP, Java oder eine andere Programmiersprache auf der Serverseite zu entwickeln, fr den gesamten Prozess nur eine Sprache, und zwar Java, zu verwenden. Der Google Web Toolkit hat dies umgesetzt und erlaubt es, direkt in Java eine komplette Web Applikation, angefangen vom Benutzerinterface bis hin zu einem Datenbank gesttzten Backend, zu implementieren.
3

2.1. Funktionsweise

Um dies umzusetzen, verwendet der Toolkit einen Java-in-JavaScript Compiler welcher in der Lage ist, Java Quelltext nach Java Script zu kompilieren. Damit ist es mglich, dass die komplette Codebasis eines Projekts in Java vorliegt, und bestimmte Teile beim Kompilieren des Projekts nach Java Script bersetzt werden. Die sich daraus ergebenden Vorteile liegen auf der Hand. Zum einen muss sich der Entwickler nicht mit mehreren, durchaus unterschiedlichen, Programmiersprachen auseinander setzten. Zum anderen kann damit das Problem der unterschiedlichen Darstellung einer Website auf verschiedenen Browsern gelst werden, da bei der bersetzung in Java Script fr jeden populren Browser (derzeit Internet Explorer, Firefox, Safari, Google Chrome und Opera) ein eigenes Script erstellt wird, welches spezifische Workarounds beinhaltet, welche ansonsten von Hand fr jeden Browser gepflegt werden mssten. Durch die Verwendung eines speziellen Browser Plug-Ins kann der Java Code im Browser angezeigt werden, ohne die Applikation zuvor in Java Script zu bersetzen. Damit kann der Entwickler nderungen an der Applikation, direkt nach dem Aktualisieren der Seite im Browser betrachten. Da die bersetzung von Java Quelltext in Java Script derzeit, auch noch auf moderner Hardware, zeitaufwndig ist, stellt diese Komponente ein Kernstck des Toolkits dar, da ansonsten die Zeitspanne, bis eine nderung am Quelltext in der Applikation sichtbar wird, fr eine performante Entwicklung zu lange ist. Das Toolkit wird in der Form eines Self-Development-Kits vertrieben. Dieser umfasst den Java-in-Java Script Compiler, eine API Bibliothek und einen, speziell auf die Bedrfnisse des GWT zugeschnittenen, Entwicklungsserver. Weiters wird eine Erweiterung der Java IDE Eclipse angeboten, welche die Funktionen des SDK in die Entwicklungsumgebung einbindet. Derzeit liegt GWT in Version 2.0.3 vor, wobei im Mai 2010 der erste Meilenstein der Version 2.1 verffentlicht wurde. Mit dieser macht der Toolkit einen weiteren Schritt in Richtung der Entwicklung von Enterprise Web Applikationen indem Benutzerinterfacekomponenten integriert wurden welche speziell auf die Anzeige von umfangreichen und komplexen Datenmengen ausgelegt sind. Weiters enthlt die neue Version ein Model-View-Presenter Framework, um die neuen Komponenten mit Daten aus dem Backend zu verbinden. Da die Version 2.1 M1 erst kurz vor der Fertigstellung der in dieser Arbeit implementierten Anwendung verffentlich wurde, beschftigt sich diese nur mit den neuen Data Presentation Widgets, geht aber nicht auf das enthaltene MVP Framework ein. [GWB10] Bei dem Google Web Toolkit handelt es sich um freie Open Source Software, welche unter der Apache 2.0 Lizenz verffentlicht wird. Diese Lizenz besagt, dass die darunter verffentliche Software Open Source als auch in kommerziellen Closed Source Projekten verwendet werden darf ohne Gebhren an den Hersteller entrichten zu mssen. [APA10]

2.1. Funktionsweise
Das Herzstck des Google Web Toolkit stellt der GWT Compiler dar, welcher Java in Java Script bersetzt. Da sich Java Script, trotz des hnlichen Namens, grundlegend von
4

2.1. Funktionsweise

Java unterscheidet, ist der untersttzte Sprachumfang limitiert. Eine Liste an derzeit nativ untersttzten Java Klassen ist in Tabelle 1 angegeben.
Tabelle 1 - bersicht der in GWT untersttzten Java Klassen [GWT10]

Paket

Klasse Appendable, ArithmeticException, ArrayIndexOutOfBoundsException, ArrayStoreException, AssertionError, Boolean, Byte, CharSequence, Character, Class, ClassCastException, Cloneable, Comparable, Deprecated, Double, Enum, Error, Exception, Float, IllegalArgumentException, IllegalStateException, IndexOutOfBoundsException, Integer, Iterable, Long, Math, NegativeArraySizeException, NullPointerException, Number, NumberFormatException, Object, Override, Runnable, RuntimeException, Short, StackTraceElement, String, StringBuffer, StringBuilder, StringIndexOutOfBoundsException, SuppressWarnings, System, Throwable, UnsupportedOperationException, Void Annotation, AnnotationFormatError, AnnotationTypeMismatchException, Documented, ElementType, IncompleteAnnotationException, Inherited, Retention, RetentionPolicy, Target AbstractCollection, AbstractList, AbstractMap, AbstractQueue, AbstractSequentialList, AbstractSet, ArrayList, Arrays, Collection, Collections, Comparator, ConcurrentModificationException, Date, EmptyStackException, EnumMap, EnumSet, Enumeration, EventListener, EventObject, HashMap, HashSet, IdentityHashMap, Iterator, LinkedHashMap, LinkedHashSet, LinkedList, List, ListIterator, Map, Map.Entry, MissingResourceException, NoSuchElementException, PriorityQueue, Queue, RandomAccess, Set, SortedMap, SortedSet, Stack, TooManyListenersException, TreeMap, TreeSet, Vector FilterOutputStream, IOException, OutputStream, PrintStream, Serializable Date, Time, Timestamp

java.lang

java.lang.annotation

java.util

java.io java.sql

Obwohl diese Liste recht umfangreich ist, fehlen doch essenzielle Klassen, wie zum Beispiel die Calendar Klasse, welche Datums- und Zeitoperationen ermglicht. Fr manche, nicht direkt untersttzte Klassen, enthlt das Toolkit eigene Implementierungen, wobei deren Funktionalitt aufgrund der Limitierungen von JavaScript nicht vollstndig portiert wurde. Eine bersicht ber diese Klassen ist in Tabelle 2 aufgefhrt.

2.1. Funktionsweise

Tabelle 2 - GWT Implementierung von JRE Klassen [GWT10]

JRE Klasse java.util.DateTimeFormat java.util.NumberFormat java.io.Serializable java.util.Timer

GWT quivalent com.google.gwt.i18n.client.DateTimeFormat com.google.gwt.i18n.client.NumberFormat com.google.gwt.user.client.rpc.IsSerializeable com.google.gwt.user.client.Timer

Aufgrund dieser Einschrnkungen, kann auch nicht die gesamte Applikation vom GWT Compiler in Java Script bersetzt werden, sondern nur der Teilbereich, welcher fr die Benutzeroberflche zustndig ist. Um dies in einem Projekt umzusetzen, wird es in zwei Teile gegliedert. Der clientseitige Teil des Projektes ist jener Teil, welcher vom GWT Compiler in Java Script bersetzt und im Browser des Anwenders angezeigt wird. Der serverseitige Teil ist derjenige, welcher am Web Server ausgefhrt wird und auf die volle Funktionalitt der JRE zurckgreifen kann. Die Festlegung, welche Klassen zu welchem Teil der Applikation gehren, wird in der Projektkonfiguration definiert.

2.1.1. Aufbau eines GWT Projektes


Ein GWT Projekt besteht in seiner einfachsten Form aus 3 Paketen. Das client Paket enthlt jenen Code, der vom GWT Compiler in Java Script bersetzt werden soll. Das server Paket enthlt den Code, der am Web Server ausgefhrt wird. Mit der Version 2.0 des Toolkits hat Google ein weiteres Paket, namens shared, standardmig eingefhrt, welches Klassen enthlt, die sowohl in clientseitigen als auch serverseitigen Code verwendet werden. Im Stammordner des Projektes befindet sich eine GWT spezifische Projektkonfigurationsdatei im XML Format. Da GWT Projekte als Java Script Dateien auf einem Web Server gespeichert werden wird die Applikation ber einen SCRIPT Tag in einer HTML Seite geladen. Diese Datei befindet sich standardmig im war Ordner des Projektes und ist nach dem Projektnamen benannt. Die Projektstruktur ist in Abbildung 1 verdeutlicht.

Abbildung 1 - Struktur eines GWT Projektes

2.1. Funktionsweise

In diesem Demonstrationsprojekt werden bei der Kompilierung die Klassen Demo.java sowie FieldVerifier.java und die Interfaces GreetingService.java und GreetingServiceAsync.java in Java Script bersetzt. Die Klasse GreetingSericeImpl.java wird ausschlielich am Server ausgefhrt und nicht in Java Script kompiliert. In der Projektkonfigurationsdatei Demo.gwt.xml wird das Setup des Projektes vorgenommen. Deren Inhalt ist in Listing 1 aufgefhrt.
<?xml version="1.0" encoding="UTF-8"?> <module rename-to='demo'> <inherits name='com.google.gwt.user.User'/> <inherits name='com.google.gwt.user.theme.standard.Standard'/> <entry-point class='at.fh.campus.ittk.ba2.client.Demo'/> <source path='client'/> <source path='shared'/> </module>
Listing 1 - Inhalt der Demo.gwt.xml

Mittels des inherits Elementes werden bestimmte Funktionen des Toolkits ins Projekt eingebunden. In diesem Fall ist dies die Kernfunktionalitt des Toolkits, welche den Namen com.google.gwt.user.User trgt, sowie das Standarddesign. Das entry-point Element definiert die Startklasse der Applikation. Diese Klasse muss das Interface EntryPoint und damit die Methode onModuleLoad() implementieren, welche beim Start der Applikation automatisch aufgerufen wird. Diese Methode ist vergleichbar mit der in traditionellen Java Programmen verwendeten Startmethode public static void main(). Das source Element legt fest, welche Ordner und damit die darin enthaltenen Klassen des Projektes in Java Script bersetzt werden sollen. Dabei werden alle Unterordner automatisch mit einbezogen. Weiters knnen in der Konfigurationsdatei bei Bedarf externe GWT Bibliotheken eingebunden und der GWT Compiler parametrisiert werden.

2.1.2. Debuggen eines GWT Projektes


Um eine GWT Applikation zu debuggen wird diese in einem speziellen Modus namens Development Mode ausgefhrt. Dieser erlaubt es, mit Hilfe einer Browsererweiterung direkt mit der Applikation zu interagieren, ohne sie zuvor in Java Script zu bersetzten. Da der bersetzungsvorgang zeitaufwndig ist, beschleunigt dieses Verfahren den Entwicklungszyklus. Ein weiterer Vorteil des Development Modes ist, dass mit dem, von der IDE zur Verfgung gestellten Debugging Mechanismen, browser- sowie serverseitiger Code berprft werden knnen. Hierbei ist jedoch anzumerken, dass eine Applikation im Development Mode ungefhr um den Faktor 100 langsamer luft, als wenn sie in Java Script bersetzt wurde. [CAB10] Wenn nderungen am browserseitigen Code vorgenommen wurden muss der Development Mode nicht neu gestartet, sondern lediglich die Website im Browser aktualisiert werden. Nach nderungen am serverseitigen Code muss jedoch der im
7

2.2. Client Server Kommunikation

Toolkit integrierte Webserver neu geladen, und ebenfalls die Seite im Browser aktualisiert werden.

2.2. Client Server Kommunikation


Da browserseitiger Code in Java Script vorliegt kann dieser nicht direkt auf die Java Klassen am Webserver zugreifen. Um jedoch Daten, zum Beispiel aus einer Datenbank, zu laden und dem Benutzer anzeigen zu knnen, mssen diese vom Server an den Client bertragen werden. Dies erfolgt bei traditionellen AJAX Anwendungen direkt ber den XMLHttpRequest, womit Daten vom Browser an den Server gesendet und ebenfalls Daten vom Server an den Browser bermittelt werden knnen. Die standardmige Client-zu-Server Kommunikation bei GWT baut auf dieser Technologie auf, erweitert sie jedoch soweit, dass direkt Java Objekte bertragen werden knnen, ohne dass sich der Entwickler um deren Serialisierung vor der bertragung und Deserialisierung nach dem Empfang kmmern muss. Dieser Mechanismus, wird Remote Procedure Call genannt und basiert auf einer Kombination von dynamischer Code Generierung durch den GWT Compiler und Java Servlets. Um einen serverseitigen Service mittels RPC aufrufen zu knnen, werden 2 Interfaces und eine Klasse bentigt. Die Interfaces werden im clientseitigen Teil der Applikation definiert und legen die Methoden fest, welche der Service zu Verfgung stellt. Pro Service wird ein synchrones Interface definiert, welches die Servicemethoden definiert und von RemoteService abgeleitet werden muss und weiters ein asynchrones Interface, dessen Name dem des Synchronen entsprechen muss, plus dem Suffix Async. In diesem werden dieselben Methoden wie im synchronen Interface definiert, jedoch haben sie den Rckgabetyp Void und einen zustzlichen, generischen, Parameter vom Typ AsyncCallback. Der Unterschied zwischen dem synchronen und dem asynchronen Interface eines Services ist in Listing 2 und Listing 3 aufgezeigt.
@RemoteServiceRelativePath("greet") public interface GreetingService extends RemoteService { String greetServer(String name); }
Listing 2 - Synchrones Serviceinterface

public interface GreetingServiceAsync { void greetServer(String input, AsyncCallback<String> callback); }


Listing 3 - Asynchrones Serviceinterface

Die serverseitige Klasse des Services wird von der Klasse RemoteServiceServlet abgeleitet und implementiert nur das zugehrige, synchrone Interface und setzt damit die Funktionalitt des Services um. Im Hintergrund generiert GWT, transparent fr den Entwickler, automatisch einen Proxy welcher den eigentlichen Remote Procedure Call

2.2. Client Server Kommunikation

ausfhrt. Die Zusammenhnge der einzelnen, in diesen Prozess mit einbezogenen Klassen, sind in Abbildung 2 aufgezeigt

Abbildung 2 - RPC Klassendiagram[GWT10]

Die Annotation @RemoteServiceRelativePath aus Listing 2 gibt an, unter welchem Pfad das Servlet, welches den RPC Aufruf entgegennimmt, zu finden ist. Dafr muss zuerst in der web.xml Datei im Projektordner war/WEB-INF das Servlet definiert werden. Die dazu bentigten Eintrge sind in Listing 4 aufgefhrt.
<servlet> <servlet-name>greetServlet</servlet-name> <servlet-class> at.fh.campus.ittk.ba2.server.GreetingServiceImpl </servlet-class> </servlet> <servlet-mapping> <servlet-name>greetServlet</servlet-name> <url-pattern>/demo/greet</url-pattern> </servlet-mapping>
Listing 4 - Definition eines Servlets in der web.xml

Dabei legt der servlet-name Tag fest, unter welchem Namen das Servlet erstellt wird. Dies wird bentigt um im servlet-mapping Block darauf zu referenzieren. servlet-class legt die Klasse fest, in welcher das Servlet umgesetzt wurde. Diese muss das synchrone Interface des Services implementieren. url-pattern definiert, unter welcher URL das Servlet angesprochen werden kann. Dieser Wert enthlt den absoluten Pfad des Servlets und zustzlich muss der relative Teil dem Wert in der @RemoteServiceRelativePath Annotation entsprechen. Da eine Java Script Applikation im Browser nur in einem einzelnen Thread ausgefhrt wird, mssen die Serveraufrufe asynchron erfolgen, um nicht fr die Dauer des Aufrufes
9

2.2. Client Server Kommunikation

die Anwendung zu blockieren. Daher erfolgt die gesamte Kommunikation ber RPC mittels des asynchronen Serviceinterface. Wie in Listing 3 zu sehen ist, wird der Rckgabetyp der synchronen Funktion als generischer Parameter des Callback Parameters der asynchronen Version verwendet. Um den eigentlichen Aufruf ttigen zu knnen, muss zuerst das asynchrone Interface mittels der Funktion GWT.create() instanziiert werden. Die GWT.create() Funktion lst whrend der Kompilierung der Applikation die Codegenerierungsfunktion des GWT Compilers aus, und erzeugt damit den, fr den RPC Aufruf bentigten, Proxy. Anschlieend knnen die Funktionen des Interfaces aufgerufen werden. Diesen muss, neben den Parametern des Aufrufes, ein Objekt bergeben werden, welches das AsyncCallback Interface implementiert. Dieses Interface definiert zwei Methoden. onSuccess wird mit dem Rckgabewert der Serverfunktion aufgerufen, wenn der Aufruf erfolgreich durchgefhrt wurde. Im Gegensatz dazu wird onFailure aufgerufen, falls whrend der Verarbeitung am Server eine Ausnahme auftritt, oder der Server aus einem anderen Grund nicht erreichbar ist. Als Parameter wird onFailure die geworfene Ausnahme vom Typ Throwable bergeben. Listing 5 zeigt das Erzeugen eines asynchronen Serviceinterface sowie den eigentlichen RPC Aufruf.
final GreetingServiceAsync greetingService = GWT.create(GreetingService.class); greetingService.greetServer("A String", new AsyncCallback<String>() { @Override public void onFailure(Throwable caught) { } @Override public void onSuccess(String result) { } });
Listing 5 - Erzeugen und durchfhren eines RPC Aufrufes

Aufgrund der Natur von Java Script und RPC sind die Typen, welche durch dieses Verfahren bertragen werden knnen, limitiert. Alle Objekte die ber RPC bertragen werden sollen mssen serialisierbar sein, das bedeutet, dass es mglich ist das Objekt in eine Form umzuwandeln, welche ber das Netzwerk transportiert werden kann [MSN10]. Obwohl sowohl Java als auch GWT fr die Markierung eines Typs als serialisierbar das Interface java.io.Serializable verwenden, unterscheiden sich die beiden Mechanismen in der Art, dass das GWT Serialisierungssystem wesentlich simpler aufgebaut und auf die in Java Script umsetzbare Funktionalitt beschrnkt ist. Die aufgrund dieser Limitierung zu Verfgung stehenden Typen sind in Tabelle 3 aufgefhrt.
Tabelle 3 - Von RPC serialisierbare Typen

Typ

Anmerkung
10

2.3. Steuerelemente

Alle primitiven Typen Instanzen von String und Date Wrapper von primitiven Typen Enumerationen Arrays von serialisierbaren Typen Collections von serialisierbaren Typen Benutzerdefinierte serialisierbare Klassen

z.B.: char, byte, short, int, long, float, boolean und double

z.B.: Character, Byte, Short, Integer, Long, Float, Boolean und Double Werden nur als Name serialisiert Dies umfasst auch Arrays von Arrays von serialisierbaren Typen Aus dem java.util Paket, der Typ der Collection muss mittels des generischen Parameters spezifiziert werden. Mssen das Markierungsinterface java.io.Serializable oder com.google.gwt.user.client.rpc.IsSerializeable implementieren sowie einen argumentlosen und ffentlichen Konstruktor besitzen

Falls Klassen serialisiert werden sollen, welche zum Beispiel mittels Hibernate in einer Datenbank persistiert werden, kommt es hier zu Problemen, auf welche im Kapitel 3.3.1 dieser Arbeit nher eingegangen wird.

2.3. Steuerelemente
GWTs Steuerelemente sind ihren Pendants aus Swing oder SWT sehr hnlich, auer, dass sie durch dynamisch generiertes HTML dargestellt werden. In traditionellen AJAX Anstzen wird ein dynamisches Benutzerinterface durch direkte Manipulation des DOM des Browsers realisiert. Obwohl dies mit GWT ebenfalls mglich ist, ist es fr den Entwickler einfacher, die bereits vorgefertigte Komponenten, namens Widgets, zu verwenden. Diese basieren zwar auf demselben Prinzip, jedoch werden die Manipulationen am DOM fr den Entwickler transparent durchgefhrt. Ein Widget stellt ein Steuerelement, wie zum Beispiel eine Text Box oder eine Schaltflche, dar. Um es in einer Applikation anzuzeigen muss es zu einem Panel hinzugefgt werden. Panels definieren das Layout einer Applikation und knnen ihrerseits wiederum Panels oder Widgets enthalten. Das oberste Panel in der Hierarchie einer Applikation ist immer das RootPanel welches alle weiteren Panels und Widgets enthlt. Mittels der statischen get() Methode der RootPanel Klasse kann eine Instanz des Panels erhalten und mit der add(Widget w) Methode ein Panel oder Widget zum RootPanel hinzugefgt werden. Hierbei ist anzumerken, dass sowohl alle Benutzerkomponenten sowie Panels von der Widget Basisklasse abgeleitet sind. Eine bersicht ber die wichtigsten, zu Verfgung stehenden, Panels ist in Tabelle 4 gegeben.

11

2.3. Steuerelemente

Tabelle 4 - GWT Panel bersicht

Name

Funktion Ordnet die darin enthaltenen Komponenten vertikal an, wobei immer nur eine Ebene zugleich sichtbar ist

Abbildung

Stack Panel

Abbildung 3 - Stack Panel

Horizontal Panel

Ordnet die darin enthaltenen Komponenten horizontal an

Abbildung 4 - Horizontal Panel

Vertical Panel

Ordnet die darin enthaltenen Komponenten vertikal an


Abbildung 5 - Vertical Panel

Flow Panel

Ordnet die darin enthaltenen Komponenten nach dem standardmigen HTML Layout Prinzip an

Abbildung 6 - Flow Panel

Dock Panel

Ordnet seine Komponenten anhand der Himmelsrichtungen an, wobei die zentrale Komponente den gesamten, zu Verfgung stehenden Platz einnimmt.

Abbildung 7 - Dock Panel [GWT10]

Tab Panel

Ordnet seine Komponenten mittels Karteireiter an


Abbildung 8 - Tab Panel

Disclosure Panel

Der Inhalt dieses Panels kann dynamisch ein und ausgeblendet werden

Abbildung 9 - Disclosure Panel

Jedoch haben die hier aufgefhrten Panels, insbesondere das DockPanel signifikante Nachteile. Zum einen ist deren Verhalten auf unterschiedlichen Browsern nicht immer gleich, was oftmals extra Code erfordert, um diese Mngel zu beseitigen. Weiters arbeiten
12

2.3. Steuerelemente

sie nur korrekt im so genannten Quirks Modus eines Browsers, welcher toleranter gegenber nicht standardkonformen Layout Mechanismen ist als der Standard Modus. Daher wurde mit Version 2.0 des Toolkits eine neue Generation an Panels in den GWT aufgenommen, die so genannten Layout Panels. Deren Ziel ist es, das Layout einer Applikation so genau und vorhersagbar als mglich auf verschiedenen Browsern darzustellen. Weiters arbeiten sie nun auch korrekt im Standard Modus und werden auch nicht mehr von CSS Dekorationen wie Rahmen und Abstnden in dem Ausma beeinflusst wie ihre traditionellen Counterparts. Um dies umzusetzen verwenden sie die CSS Eigenschaften left, top, bottom, right, with und height welche ein natrliches System an Limitierungen bilden. Werden die left, top, bottom und right Eigenschaften eines Elementes zum Beispiel auf einen Pixel gesetzt, nimmt dieses Element den gesamten zu Verfgung stehenden Platz minus einen Pixel an den Rndern ein. Solch ein Verhalten war mit den bisherigen Komponenten nur sehr schwierig zu erreichen. Die Verwendung der neuen Panels erfolgt im Prinzip analog zu den bisherigen Komponenten, nur dass bei der Erstellung die Einheit, in der die Positionierung der Elemente erfolgen soll, angegeben werden muss. In Listing 6 ist aufgezeigt, wie mit den neuen Komponenten ein Layout erstellt werden kann, bei welchem die Kopf- und Fusektion jeweils konstant 10 Pixel hoch und der Rest der Seite mit Inhalt gefllt wird. Sollte der Inhalt zu gro fr die Seite sein, wird eine Scrollbar angezeigt wobei Kopf und Fu noch immer sichtbar sind.
DockLayoutPanel dp = new DockLayoutPanel(Unit.PX); FlowPanel header = new FlowPanel(); header.add(new Label("Header")); dp.addNorth(header, 20); FlowPanel footer = new FlowPanel(); footer.add(new Label("Footer")); dp.addSouth(footer, 20); ScrollPanel mainContent = new ScrollPanel(); mainContent.add(new Label(lotsOfText)); dp.add(mainContent); RootLayoutPanel.get().add(dp);
Listing 6 - Erstellen eines Applikationslayouts

Das Ergebnis ist in Abbildung 10 dargestellt.

Abbildung 10 - Screenshot des Layouts

13

2.3. Steuerelemente

Widgets sind generell fr die Prsentation und Eingabe von Daten sowie fr die Interaktion des Benutzers mit der Applikation zustndig. Sie bilden die Basis einer Applikation und das Verstndnis ihrer Funktionsweise ist Voraussetzung um Anwendungen mittels des GWT entwickeln zu knnen. Standardmig bringt das Toolkit 18 Widgets mit sich, wovon die Wichtigsten in Tabelle 5 aufgezeigt sind.
Tabelle 5 - bersicht der wichtigsten Standardwidgets

Name Button

Funktion Eine Schaltflche mit welcher auf Klicks des Benutzers reagiert werden kann. Ein Kontrollkstchen welches einen boolschen Typ reprsentiert.

Abbildung

Abbildung 11 Button [GWT10]

CheckBox

Abbildung 12 - CheckBox [GWT10]

DatePicker

Ein popup Kalender mit welchem ein Datum ausgewhlt werden kann.
Abbildung 13 - DatePicker [GWT10]

TextBox

Ein Texteingabefeld.

Abbildung 14 - TextBox [GWT10]

ListBox

Zeigt eine Liste von Werten an und ermglich deren Auswahl.

Abbildung 15 - ListBox [GWT10]

Tree

Zeigt Daten in einer ein- und ausklappbaren Baumstruktur an.


Abbildung 16 - Tree [GWT10]

SuggestBox

Ein Texteingabefeld welches anhand der eingegeben Zeichen einen entsprechenden Eintrag aus einer Liste auswhlen kann. Eine Tabelle zur tabellarischen Darstellung von Daten zu welcher dynamisch Spalten und Zeilen hinzugefgt werden knnen

Abbildung 17 - SuggestBox

FlexTable

Abbildung 18 - Flex Table

14

2.3. Steuerelemente

DialogBox

Erweitertes PopupPanel welches dem Anwender erlaubt es auf der Oberflche mit der Maus zu bewegen.

Abbildung 19 - DialogBox

Um ein Widget auf der Benutzeroberflche anzuzeigen, muss es zu einem Panel mittels dessen add(Widget w) Methode hinzugefgt werden. Anschlieend kann seine Sichtbarkeit durch die setVisible(Boolean visible) Methode gesteuert werden. Alle Eingabekomponenten bieten Events an, mit denen auf bestimmte Benutzeraktionen reagiert werden kann. Ein Button implementiert etwa das HasClickHandlers Interface, ber welches man sich fr das Click Event durch bergabe eines Handlers, welcher Aufgerufen wird sobald der Event gefeuert wird, registrieren kann. Analog zum Button bietet die CheckBox einen ValueChange Event an, welcher Aufgerufen wird, sobald der Benutzer den Zustand des Kontrollkstchens ndert oder etwa der Tree, einen Open Event, welcher beim ffnen eines Knotens gefeuert wird,. Letzteres kann dazu verwendet werden, hierarchische Daten schrittweise aus einer Datenbank im Backend zu laden. Weiters bieten diverse Widgets Events an, mittels denen auf Maus- und Tastatureingaben reagiert werden kann. Eine detailliertere Auseinandersetzung mit der Verwendung von Widgets wird im letzteren Teil der Arbeit vorgenommen und direkt an der praktischen Implementierung von Anwendungsfllen aufgezeigt.

2.3.1. Anpassung von Widgets


Obwohl standardmig eine Vielzahl an Widgets im Google Web Toolkit enthalten ist, reicht deren Funktionalitt oftmals nicht aus um komplexere Benutzeroberflchen zu realisieren. Deshalb ist es mglich, Widgets speziell an die eigenen Bedrfnisse anzupassen. Dazu stehen dem Entwickler prinzipiell zwei Mglichkeiten zur Auswahl, auf die in weiterer Folge nher eingegangen wird. Die erste und auch einfachste Methode um benutzerdefinierte Widgets zu erstellen ist, die Funktionalitt mehrerer Komponenten in einem Composite Widget zu gruppieren. Ein Composite ist ein spezieller Widget Typ welcher es erlaubt, ein oder mehrere Steuerelemente zu umschlieen. Wird ein Composite zu einem Panel hinzugefgt, verhlt er sich genau so, als ob die darin enthaltenen Widgets direkt hinzugefgt wurden. [SVN10] Jedoch werden dabei die einzelnen Methoden der im Composite enthaltenen Steuerelemente und Panels nicht nach auen zugnglich gemacht. Dies hat den Vorteil, dass der Entwickler festlegen kann, welche Methoden das Steuerelement nach auen hin zu Verfgung stellen soll. Um ein Composite Widget zu definieren erstellt man eine Klasse, welche von der Klasse Composite ableitet. Im Konstruktor initialisiert man die einzelnen Komponenten des Widgets und fgt sie zu einem Panel hinzu. Um das neue Steuerelement zu initialisieren muss die Methode initWidget(Widget w) der Composite Klasse mit dem obersten Panel
15

2.4. Data Presentation Widgets

der neuen Komponente als Parameter aufgerufen werden. Um diesen Vorgang zu verdeutlichen ist in Listing 7 zu sehen, wie ein Composite Widget erstellt wird, welches neben einem Eingabefeld (TextBox) noch ein Beschriftungsfeld (Label) und ein Feld fr eine Fehlermeldung (Label) enthlt. Solch eine Komponente ist speziell zur Erstellung von Formularen zur Dateneingabe sinnvoll.
public class TextInputField extends Composite { final final final final private private private private Label fieldLabel = new Label(); TextBox inputBox = new TextBox(); Label errorLabel = new Label(); HorizontalPanel panel = new HorizontalPanel();

public TextInputField() { panel.setVerticalAlignment(HasVerticalAlignment.ALIGN_MIDDLE); panel.add(fieldLabel); panel.add(inputBox); panel.add(errorLabel); initWidget(panel); } }


Listing 7 - Erstellung eines Composite Widgets

Die weitere Verwendung der Composite Widgets erfolgt analog zu den standardmigen Komponenten. Wie weiters in dem Beispiel in Listing 7 zu sehen ist, sind alle Komponenten des Composite Widgets als privat definiert. Durch Anlegen spezifischer Getter und Setter kann der Entwickler somit festlegten, welche Funktionalitten welcher Komponenten des neuen Widgets nach auen hin sichtbar sind. Die zweite Methode benutzerdefinierte Komponenten zu erstellen besteht darin, das neue Element von einem bereits bestehenden abzuleiten. Hierfr bieten sich die Basisklassen Widget oder FocusWidget an. Die Widget Klasse implementiert bereits die Funktionalitt Browser Events zu empfangen und die FocusWidget Klasse erweitert diese um die Funktionalitt den Eingabefokus zu erhalten. Generell ist diese Methode jedoch nicht zu empfehlen, da sie tiefgehendes Verstndnis der internen Funktionsweise des Google Web Toolkits voraussetzt und, sobald auch natives Java Script zum Einsatz kommt, die Browserkompatibilitt bercksichtigt werden muss. Da bei der Implementierung des LIMS Systems die gesamte Funktionalitt des Benutzerinterfaces ausschlielich durch Verwendung von Composite Widgets umgesetzt werden konnte, wird hier auf diese Methode nicht mehr weiter eingegangen. Bis Version 2.1M1 des Toolkits fehlten jedoch Widgets, mit welchen groe Mengen an Daten effektiv und performant angezeigt und bearbeitet werden knnen. Mit der FlexTable sowie dem Tree war dies zwar prinzipiell zu realisieren, nur musste das Navigieren ber Datenstzen sowie das Filtern und Sortieren selbst implementiert werden. Mit der Version 2.1M1 des GWT wurde dieses Defizit durch die Integration der Data Presentation Widgets beseitigt, auf welche im folgenden Unterkapitel dieser Arbeit nher eingegangen wird.
16

2.4. Data Presentation Widgets

2.4. Data Presentation Widgets


Die mit Version 2.1 M1 neu eingefhrten Data Presentation Widgets haben das Ziel, die tabellarische und hierarchische Darstellung von Daten, unabhngig von deren Menge, performant sowie Benutzer- und Entwicklerfreundlich umzusetzen. Derzeit besteht das Set aus 3 Komponenten, einer CellList, mit welcher einspaltige Datenstze angezeigt werden knnen und, basierend darauf, eine CellTable welche mehrspaltige Datenstze darstellt. Die dritte Komponente, der CellTree, ist auf die Anzeige von hierarchischen Datenstrukturen ausgelegt. Der wesentliche Unterschied der neuen Widgets gegenber den bisher existierenden FlexTable und Tree ist, dass sie so leichtgewichtig als mglich aufgebaut sind. Sie basieren auf einfachem HTML und bieten auch die von ihnen angebotenen Events und sind auf das Notwendigste beschrnkt. Weiters integrieren sie die Funktionalitt zur Navigation ber Stze an Daten in einer definierten API. In weiterer Folge soll auf die Details des CellTable Widgets eingegangen werden, da dies in der implementierten Applikation eine zentrale Rolle spielt. Auf das CellList Widget wird nicht eingegangen, da dessen Verwendung weitestgehend analog zur CellTable erfolgt und auch das CellTree Widget wird nicht weiter behandelt, da dessen Verwendung von Google bis zu diesem Zeitpunkt nicht ausreichend dokumentiert wurde.

2.4.1. Das CellTable Widget


Das Prinzip des CellTable Widgets basiert im Grunde auf der Idee, dass eine Tabelle die Darstellung einer Klasse bernimmt, wobei fr jede Instanz der Klasse eine Zeile und fr jede Eigenschaft eine Spalte erstellt wird. Durch dieses Vorgehen wird die Tabelle mit Zellen gefllt, welche jeweils dem Wert einer Eigenschaft einer Instanz der Klasse entsprechen. Durch die Verwendung von Java Generics und abstrakten Methoden bei der Implementierung der CellTable und deren Komponenten, lsst sich diese Darstellung typsicher durchfhren. Das Basiselement der CellTable ist die Zelle. Als Zelle kann jede Klasse verwendet werden, welche das Cell<C> Interface implementiert. Der generische Parameter C gibt an, welchen Typ diese Zelle darstellen soll. Die Methoden des Cell<C>-Interfaces sind in Tabelle 6 dargestellt.
Tabelle 6 - Das Cell<C> Interface

Methode Boolean consumesEvent() Boolean dependsOnSelection() Object onBrowserEvent(...)

Funktion Gibt an, ob die Zelle Events des Browsers verarbeiten soll. Gibt an, ob die Zelle abhngig von der Auswahl eines bestimmten Elementes ist. Wird aufgerufen, sobald ein Browser Event innerhalb der Zelle auftritt. Erhlt als String den Typ des Events bergeben.

17

2.4. Data Presentation Widgets

Void render(...)

Definiert wie der Typ, den die Zelle darstellt, in HTML gerendert wird. Der Funktion wird dafr der Typ sowie ein StringBuilder bergeben dessen Inhalt anschlieend als HTML interpretiert wird. Diese Methode wird vom bergeordneten Container der Zelle aufgerufen wenn Sie einen Wert anzeigen soll.

Void setValue(...)

Eine Basisimplementierung dieses Interfaces bietet die Klasse AbstractCell<C> an, welche alle Methoden, bis auf render(), implementiert. Von dieser Klasse sind alle derzeit im Toolkit enthaltenen Zellen abgeleitet. Diese knnen grob in drei Klassen gegliedert werden. Zellen welche ausschlielich fr das Anzeigen von Daten zustndig sind, Zellen welche zustzlich noch die Eingabe von Daten erlauben und Zellen auf deren Events von auen reagiert werden kann. Zu ersterer Gruppe gehrt die TextCell, welche einen String ohne Formatierung als HTML rendert, die DateCell welche ein Datum mit einem, optional sprachabhngigen Format, als HTML rendert und die CurrencyCell, welche einen Wert vom Typ Integer als Whrung inklusive Whrungszeichen anzeigt. Zur zweiten Klasse kann die CheckboxCell gezhlt werden, welche einen boolschen Wert in Form eines Auswahlkstchens anzeigt. Weiters erlaubt die TextInputCell sowie die EditTextCell die Eingabe von Zeichenketten, wobei die TextInputCell eine Textbox rendert, im Gegensatz zur EditTextCell welche die Textbox nur anzeigt, wenn die Zelle den Fokus erhlt. Ein weiterer Spezialfall der TextInputCell ist die SelectionCell, welche es erlaubt Werte aus einer vorgegeben Liste auszuwhlen. Die DatePickerCell zeigt bei Aktivierung einen Kalender an, aus welchem ein Datum ausgewhlt werden kann. In die dritte Klasse knnen die ActionCell, die ClickableTextCell sowie die ButtonCell eingeordnet werden. Alle drei ermglichen es auf einen Mausklick in der Zelle zu reagieren. Die Vererbungshierarchie der Cell Klassen ist in Abbildung 20 aufgezeigt.
Cell<C>

AbstractCell<C>

ActionCell<C>

String ButtonCell

Boolean CheckboxCell

Date DateCell

String ClickableTextCell

CompositeCell<C>

Integer CurrencyCell

Date DatePickerCell

String EditTextCell

IconCellDecorator<C>

String SelectionCell

String TextCell

String TextInputCell

Abbildung 20 - Vererbungshierarchie der Cell Klassen

18

2.4. Data Presentation Widgets

Durch diese Strukturierung kann der Entwickler fr Standardflle eine der mitgelieferten Implementierungen des Cell-Interfaces verwenden und fr spezielle Anforderungen, ausgehend von der AbstractCell<C> Klasse, selbst eine Implementierung vornehmen. Zellen bilden die Vorlage, wie eine Spalte der CellTable gerendert werden soll. Die Spalte dient als Container einer Zelle und reicht Daten sowie spezifische Events an diese weiter. Hierbei ist anzumerken, dass jede Spalte, unabhngig wie viele Zeilen in der Tabelle angezeigt werden, nur eine Instanz der Zelle enthlt. Um in einer Spalte zu definieren, welche Eigenschaft der darzustellenden Klasse sie rendern soll, muss bei der Instanziierung die abstrakte Methode C getValue(T object) implementiert werden, welche ein Tabellenobjekt bergeben bekommt. Der Rckgabetyp dieser Methode muss dem Typen entsprechen, fr welchen die Zelle definiert ist. Mehrere Spalten, zusammen mit deren optionalen Header und Footer Widgets, bilden nun die eigentliche CellTable. Um die gesamte Tabelle als HTML zu rendern, wird zuerst, ausgehend von der CellTable Klasse, die Grundstruktur sowie die Header und Footer Elemente gerendert. Anschlieend wird ber alle derzeit anzuzeigenden Instanzen der Datenklasse iteriert. In jeder Iteration wird den definierten Spalten das derzeitige Objekt bergeben. Jede Spalte extrahiert nun, mithilfe der berschriebenen getValue Methode, die fr die Spalte definierte Eigenschaft und gibt dieses an die Zelle weiter, welche nun das eigentliche HTML ausgibt. Die Darstellung von groen Datenmengen wird mittels Paging durchgefhrt. Dabei wird die Gesamtmenge an Daten in kleine Blcke gruppiert und immer nur ein Block dem Benutzer angezeigt. Mittels eines Pagers kann dieser ber die einzelnen Blcke navigieren. Dabei hlt das Widget immer nur die Daten im Speicher, welche auch gerade angezeigt werden. Um zu definieren, wie die CellTable Daten laden soll, kann ihr ein Delegate bergeben werden. Dies ist eine Funktion, welche aufgerufen wird, sobald die Tabelle neue Daten bentigt. Als bergabeparameter erhlt die Funktion, welcher Block an Datenstzen bentigt wird. Um die Vorgehensweise zur Definition und Verwendung einer CellTable zu verdeutlichen ist, in weiterer folge ein Beispiel implementiert. Listing 8 zeigt, wie eine CellTable fr eine Klasse Person mit den Eigenschaften firstName, lastName, beide vom Typ String und birthday vom Typ Date erstellt wird.
CellTable<Person> table = new CellTable<Person>();
Listing 8 - Erzeugen einer CellTable

Nun kann fr jede Eigenschaft eine Spalte erstellt werden. Dabei wird, wie in Listing 9 zu sehen, fr die Eigenschaften firstName und lastName eine TextCell sowie fr birthday eine DateCell als Zellenvorlage verwendet.

19

2.4. Data Presentation Widgets

Column<Person, String> firstNameCol = new Column<Person, String>(new TextCell()) { @Override public String getValue(Person object) { return object.getFirstName(); } }; Column<Person, Date> birthdayCol = new Column<Person, Date>(new DateCell(DateTimeFormat.getShortDateTimeFormat())) { @Override public Date getValue(Person object) { return object.getBirthday(); } };
Listing 9 - Definition der Spalten einer CellTable

Die Erstellung der Spalte zur Anzeige der lastName Eigenschaft erfolgt analog zur firstName-Spalte. Nun knnen diese mittels der addColumn() Methode zur Tabelle hinzugefgt werden, wie in Listing 10 zu sehen ist.
table.addColumn(firstNameCol); table.addColumn(lastameCol); table.addColumn(birthdayCol);
Listing 10 - Spalten zu einer CellTable hinzufgen

Damit ist die Definition der Tabelle abgeschlossen und sie kann mittels der add() Methode eines Panels zu diesem hinzugefgt und damit angezeigt werden. Um nun Daten der Tabelle zuzuweisen, muss dieser zuerst mitgeteilt werten, wie viele sie in Summe anzeigen soll. Dies wird mit der setDataSize(int size) Methode durchgefhrt. Als nchsten Schritt ist der CellTable ein Delegate zu bergeben welcher definiert, wie diese mit Daten gefllt werden soll. Ein Delegate muss die Methode onRangeChanged() implementieren, welche als Parameter eine ListView Instanz bergeben bekommt, durch deren Range Eigenschaft sich ermitteln lsst, welcher neue Datensatz bentigt wird. Die neuen Daten knnen der Tabelle mittels der setData() Methode bergeben werden. Anschlieend muss die redraw() Methode der CellTable aufgerufen werden, um die Tabelle mit den neuen Daten neu zu zeichnen.
table.setDataSize(personList.size(), true); table.setDelegate(new Delegate<Person>() { @Override public void onRangeChanged(ListView<Person> listView) { Range range = listView.getRange(); listView.setData(range.getStart(), range.getLength(), newEntries); table.redraw(); }});
Listing 11 - Datenmanagement einer CellTable festlegen

20

2.5. Das Model-View-Presenter Entwurfsmuster

Listing 11 zeigt hier die parktische Umsetzung des Datenmanagements einer CellTable. Hierbei ist anzumerken, dass die Daten der Tabelle als Liste (aus dem Packet java.util) bergeben werden mssen. Der Delegate ist auch der Ansatzpunkt, um die Tabelle dynamisch mit Daten aus dem Backend zu fllen. Dazu fhrt man im Delegaten einen RPC Aufruf durch, welcher den gewnschten Datensatz zurckliefert. Dabei zeigt die Tabelle automatisch fr die Dauer des Aufrufes einen Ladeindikator an.

2.5. Das Model-View-Presenter Entwurfsmuster


Bei der Entwicklung von umfangreichen Applikationen stellt sich generell das Problem, wie mehrere Entwickler gleichzeitig an ein und demselben Programm arbeiten knnen, ohne sich dabei gegenseitig zu beeinflussen und unbersichtlichen, sowie schwer wartbaren Quellcode zu erzeugen. Um dies in den Griff zu bekommen, werden Entwurfsmuster verwendet, welche eine Applikation und deren Logik in klar voneinander getrennte Bereiche unterteilen. Diese Bereiche, auch Schichten genannt, haben jeweils klar definierte Zustndigkeiten bezglich der Funktionalitt, welche sie umsetzten. Dies hat den Vorteil, dass unabhngig davon wie gro und umfangreich eine Applikation wird, sie durch die Trennung in Schichten noch immer bersichtlich und wartbar bleibt. Von diesem Problem sind auch Programme betroffen, welche mithilfe des Google Web Toolkits entwickelt werden. Aus den vielen derzeit existierenden Entwurfsmustern hat Google das Model View Presenter Muster ausgewhlt, da es, verglichen mit anderen Mustern wie dem Presentation-abstraction-control oder dem, in der Webentwicklung weit verbreiteten, Model-View-Controler Muster, einige, GWT spezifische, Vorteile mit sich bringt. Der wohl entscheidendste Punkt ist, dass sich GWT Anwendungen welche nach dem MVP Muster entwickelt wurden, Groteils mit JUnit testen lassen und nicht auf die langsame GWT JUnit Emulation GWTTestCase zurckgegriffen werden muss. [MVP10]

2.5.1. Prinzip
Das Prinzip des Model-View-Presenter Musters besteht darin, die Funktionalitt der Benutzeroberflche einer Applikation in drei definierte Schichten zu teilen. Dem Model, sowie ein oder mehrere View - Presenter Paare. Der Begriff Model umfasst dabei alle Geschftsobjekte, welche eine Applikation beinhalten und deren Beziehungen zueinander. In einem LIMS System wren dies zum Beispiel Proben, Auftrge, Analysen und Messergebnisse. Die Views beinhalten die Steuerelemente einer Applikation und sind fr das Layout derer zustndig. Sie haben jedoch keinerlei Kenntnis von dem Model, welches sie darstellen. Das bedeutet, ein View wei nicht, dass es ein bestimmtes Geschftsobjekt anzeigt, es wei nur, welche Steuerelemente es besitzt und wie es diese an der Oberflche anordnen soll. Nach auen hin definiert ein View nur ein Interface, welches Zugriff auf definierte Methoden zum Setzten und Auslesen von Daten bereitstellt. Somit kann die gesamte UI Funktionalitt in Klassen gekapselt werden, wodurch es in der Testphase mglich ist, den View komplett, durch so genannte Mock Objekte, zu ersetzten, welche nach auen hin
21

2.5. Das Model-View-Presenter Entwurfsmuster

dasselbe Verhalten als der View Besitzen, jedoch nur die unbedingt notwendige Funktionalitt implementieren. Damit lsst sich die Applikation ohne eigentliches Benutzerinterface testen, was einen Geschwindigkeitsvorteil mit sich bringt. Die Presenter bilden die Brcke zwischen den Views und dem Model. Sie implementieren die eigentliche Funktionalitt der Applikation, indem sie Daten aus dem Model an die Views weiterreichen und wiederum Daten aus den Views in das Model bertragen. Dabei ist ein Presenter fr genau einen View zustndig, wobei er nicht die eigentliche Implementierung dessen kennt, sondern nur sein Interface. Weiters besitzt der Presenter die Mglichkeit, auf Events der Benutzerkomponenten seines Views zu reagieren. Presenter kommunizieren untereinander ber Events. Diese werden ber einen applikationsweiten Event Bus an die Presenter verteilt, wobei diese nur die Events empfangen, fr welche sie sich zuvor am Bus registriert haben. Weiters existiert zumeist ein, allen Presentern bergeordneter, Root-Presenter welcher applikationsweit bentigte Logik, wie zum Beispiel die nderung des derzeit sichtbaren Views oder die Fehlerbehandlung, implementiert. Das Zusammenspiel der drei Komponenten ist in Abbildung 21 verdeutlicht.

Abbildung 21 - Abhngigkeiten des MVP Models [MVP09]

Um eine GWT Anwendung nach dem MVP Muster zu entwickeln, kann man entweder das Muster von Hand, nach der von Google verffentlichten Best Practice[MVP10] umsetzten, oder man greift auf eine externe Bibliothek zurck, welche bestimmte Elemente des Musters und die dafr bentigte Funktionalitt schon vorimplementieren und so die Menge an manuell zu schreibenden Quellcode reduzieren. In weiterer Folge soll auf die mvp4g Bibliothek eingegangen werden welche die Umsetzung des MVP Patterns mit GWT untersttzt und auch zur Implementierung des LIMS Systems verwendet wurde.

2.5.2. Die mvp4g Bibliothek


Die Abkrzung mvp4g steht fr Model-View-Presenter for GWT was bedeutet, dass diese Bibliothek die Anwendungsentwicklung nach dem MVP Model mit dem Google Web
22

2.5. Das Model-View-Presenter Entwurfsmuster

Toolkit untersttzt. Sie ist frei und als Open Source unter der Apache Licence 2.0 verfgbar. Um die Bibliothek in einem GWT Projekt zu verwenden muss sie mittels des inherits Tag in der GWT XML Konfigurationsdatei eingebunden und die dazugehrige jar Datei dem Projekt hinzugefgt werden. mvp4g erlaubt es, einen EventBus samt zugehrigen Events nur durch Erstellen eines Interfaces zu definieren. Zur Kompilierzeit wird automatisch eine Implementierung des EventBus und der zugehrigen Event Klassen mittels der Codegenerierungsfunktion des GWT Compilers vorgenommen. mvp4g erzeugt automatisch beim Applikationsstart eine Instanz fr jeden Presenter sowie den dazugehrigen View und injiziert den Event Bus in die Presenter. Damit reduziert sich der vom Entwickler zu schreibende Quellcode erheblich, da ohne diesen Mechanismus fr jeden Event alleine zwei separate Klassen, eine fr das Event selbst und eine fr die Argumente, erstellt werden mssten. Views bestehen bei mvp4g grundstzlich aus Composite Widgets. Um einen View zu definieren legt man zuerst in einem Interface fest, welche Methoden dieser nach auen hin anbieten soll. Dabei ist es gnstig, wenn man eine getAsWidget() Methode definiert, welche das Composite des Views als solches zurckgibt und damit ein und ausgeblendet werden kann. Die Klasse, in welcher die Umsetzung des Views erfolgt, leitet man von Composite ab und implementiert das zugehrige Interface. Bevor Presenter erstellt werden knnen, muss zuerst ein Event Bus definiert werden, welcher das Handling von applikationsweiten Events bernimmt. Dazu wird ein Interface, welches das EventBus Interface erweitert, angelegt. Weiters wird im Event Bus der Applikation definiert, welcher View beim Start der Anwendung angezeigt werden soll. Hierfr wird das Interface mit der @Events(startView = StartViewImpl.class) Annotation versehen, wobei dem startView Parameter das Klassenliteral der Implementierung des Views welcher angezeigt werden soll, bergeben wird. Events werden im EventBus durch definierten einer Methode erstellt. Jedes Event muss mit der @Event(handlers = Presenter.class) Annotation versehen werden, wobei der handlers Parameter festlegt, welche Presenter dieses Event verarbeiten. Um einen Presenter zu erstellen leitet man eine Klasse von der, im mvp4g enthaltenen, Basisklasse BasePresenter<V, E extends EventBus> ab. Dabei mssen die beiden generischen Typen definiert werden. Der erste Typ, V, gibt an, fr welches ViewInterface dieser Presenter zustndig ist. Der zweite, E extends EventBus, definiert, welchen EventBus dieser Presenter verwendet. Weiters muss diese Klasse noch mit @Presenter(view = ViewImpl.class) annotiert werden, wobei der view Parameter die konkrete Implementierung, als Klassenliteral, des im generischen Typ definierten View Interfaces angibt. Um in einem Presenter auf einen Event zu reagieren, muss dieser eine Methode derselben Signatur, mit der das Event im Event Bus definiert ist, implementieren, auer dass dem Methodennamen ein on vorgestellt wird. Listing 12 verdeutlicht diesen Zusammenhang indem ein Event error definiert wird, welcher vom ErrorPresenter verarbeitet wird. Hierbei ist speziell auf die Groschreibung des ersten Zeichens nach dem on Prfix zu achten.
23

2.5. Das Model-View-Presenter Entwurfsmuster

@Events(startView = RootViewImpl.class) public interface MainEventBus extends EventBus { @Event(handlers = ErrorPresenter.class) public void error(String message); } @Presenter(view = ErrorViewImpl.class) public class ErrorPresenter extends BasePresenter<ErrorView, MainEventBus> { public void onError(String message) { view.showError(message); } }
Listing 12 - Erstellen und Verarbeiten eines Events

Um in einem Presenter ein Event auszulsen, muss mittels der eventBus Eigenschaft der Klasse die dem Event zugeordnete Methode ausgefhrt werden. mvp4g leitet anschlieend automatisch den Event an alle darauf registrierten Presenter weiter. Hier ist anzumerken, dass die Verarbeitung von Events synchron erfolgt. Falls mehrere Presenter fr einen Event registriert sind, werden diese in der Reihenfolge ihrer Registrierung abgearbeitet. Die Zusammenhnge von EventBus, View und Presentern sind des Weiteren in Abbildung 22 verdeutlicht.

Abbildung 22 - Klassendiagram "mvp4g" EventBus - View Presenter

Im nun folgenden Kapitel dieser Arbeit sollen die bisher erarbeiteten theoretischen Grundlagen in die Praxis bertragen und zur Umsetzung des Designs eines LIMS Systems herangezogen werden.

24

3.1. Drei Schichten Architektur

3. Design eines LIMS Systems


Whrend in der Bakkalaureatsarbeit I ein LIMS System theoretisch spezifiziert und entworfen wurde, soll hier speziell auf die praktische Umsetzung dieses eingegangen werden. Dabei werden speziell die Probleme behandelt, welche bei der Implementierung aufgetreten sind. Diese erfolgte unter Verwendung der Eclipse IDE in Version 3.5, dem Google Web Toolkit in Version 2.1 M1, inklusive der Eclipse Erweiterung Als Entwicklungsdatenbank kam MySQL zum Einsatz und als Entwicklungsserver der im GWT inkludierte Jetty.

3.1. Drei Schichten Architektur


Die zuvor spezifizierte Drei-Schichten-Architektur, welche eine Applikation in eine Datenzugriffs-, Service- und Prsentationsschicht unterteilt, konnte auch in der praktischen Implementierung beibehalten werden. Um dies umzusetzen wurde fr jede Schicht ein eigenes Paket erstellt, welches alle Interfaces und Klassen enthlt. Die einzelnen Schichten und die dazugehrigen Pakete sind in Tabelle 7 zusammengefasst. GWT bedingt musste die Serviceschicht in ein clientseitiges Paket, welches die Interfacedefinitionen und ein serverseitiges Paket, welches die konkreten Implementierungen enthlt, aufgeteilt werden. Um in der Prsentationsschicht das MVP Model umzusetzen, ist diese des Weiteren in Presenter und View spezifische Pakete gruppiert.
Tabelle 7 - Umsetzung der drei Schichten Architektur

Schicht Entitten

Pakete org.oslims.domain org.oslims.server.dao Datenzugriffsschicht org.oslims.server.dao.hbm org.oslims.client.service Serviceschicht org.oslims.server.service.impl org.oslims.client.presenter Prsentationsschicht org.oslims.client.view org.oslims.client.view.impl In weiterer Folge soll auf die Implementierung der einzelnen Schichten eingegangen werden.

3.2. Domnenmodel
Das Domnenmodell konnte Groteils eins zu eins aus den Spezifikationen bernommen werden. Bei der MixtureComponent Entitt, die fr gemischte Proben definiert, welche Probe zu welchem Anteil in einer Mischung enthalten sind, fehlte die Referenz, zu welcher Mischung die Komponentendefinition zugeordnet werden soll. Dies wurde umgesetzt,
25

3.3. Datenzugriffsschicht

indem zur MixtureComponent Klasse eine weitere Eigenschaft namens rootSample hinzugefgt wurde, welche die Referenz auf die Mischung enthlt. Weiters wurde eine neue abstrakte Klasse namens AbstractSample eingefhrt, welche alle Eigenschaften enthlt, die fr Proben und Mischungen gleich sind, um einfache Operationen ber die Menge beider Entitten durchfhren zu knnen. Weiters wurden bei einigen Entitten Attribute hinzugefgt, um die Bi-Direktionale Navigation ber Assoziationen zu ermglichen. Alle Geschftsobjekte wurden als simple Java Beans modelliert, dass heit sie besitzen einen parameterlosen Konstruktor, alle ihre Eigenschaften sind privat und besitzen jeweils einen zugehrigen ffentlichen Getter und Setter. Das berarbeitete Klassendiagram ist in Abbildung 23 dargestellt.

Abbildung 23 - Klassendiagram des Domnenmodels

Um die Klassen der Entitten auf der Browser- sowie auf der Serverseite der Applikation verwenden zu knnen, wurden sie in einem separaten Paket namens org.oslims.domain definiert, welches auch in der GWT Konfigurationsdatei als Klient-Paket markiert wurde. Damit bersetzt der GWT Compiler alle Klassen in diesem Paket bei der Kompilierung der Applikation in Java Script, wodurch sie im klientseitigen Teil der Applikation zu Verfgung stehen. Da die Klassen jedoch auch serverseitig Verwendung finden, werden sie auch als Java Klassen kompiliert. Hierbei ist aber zu beachten, dass die Klassen sowohl den klientseitigen als auch serverseitigen Codekriterien entsprechen mssen.

3.3. Datenzugriffsschicht
Alle Objekte sollen, zur persistenten Speicherung, in einer Datenbank abgelegt werden. Um dies umzusetzen, verwendet die Applikation Hibernate, als objektrelationalen Mapper. Dieser bernimmt, basierend auf dem Domnenmodel, die Erzeugung des Datenbankschemas sowie das Speichern in die, und das Lesen aus der Datenbank. Dazu muss jede Klasse im Domnenmodel mit speziellen Annotationen versehen werden,
26

3.3. Datenzugriffsschicht

welche zum einen festlegen, welche Klasse in die Datenbank persistiert werden soll und zum anderen wie die jeweiligen Eigenschaften in den Datenbanktabellen reprsentiert werden sollen. Wie Hibernate auf die Datenbank zugreifen soll, wird in einer XML Konfigurationsdatei festgelegt, welche im Stammordner des Projektes unter dem Namen hibernate.cfg.xml zu finden ist. Ihr Inhalt ist in Listing 13 aufgefhrt. Dabei wird zuerst, durch Setzen der connection Eigenschaften, der zu verwendete JDBC Treiber, die URL, unter der die Datenbank zu erreichen ist, sowie der, fr die Verbindung zu verwendende Benutzer, und sein Passwort. In der Entwicklungsumgebung luft der MySQL Server auf derselben Maschine wie die Anwendung selbst und ist unter dem Port 3306 zu erreichen. Anschlieend wird der in der Hibernate Distribution enthaltener Verbindungspool c3p0 konfiguriert, welcher das automatische ffnen und Schlieen der Datenbankverbindungen bernimmt. Dieser wird so eingestellt, dass er minimal null und maximal zehn Verbindungen zur Datenbank ffnet und jede Stunde mit dem definierten Test Query SELECT 1 berprft, ob die geffneten Verbindungen noch valide sind. Falls nicht, erstellt er automatisch eine neue Verbindung. Dies verhindert, dass Hibernate Verbindungen verwendet, welche aufgrund des Inaktivittstimeouts der Datenbank geschlossen wurden. Weiters wird der von Hibernate zu verwendende SQL Dialekt fr die MySQL Datenbank definiert, sowie die Ausgabe aller durchgefhrten SQL Statements aktiviert. Als letzten Punkt wird noch das Caching von Hibernate explizit deaktiviert und das automatische Generieren von Data Definition Language Queries aktiviert, um alle nderungen am Domainmodel auch ins Datenbankschema zu bernehmen.
<!-- Database connection settings --> <property name="connection.driver_class">com.mysql.jdbc.Driver</property> <property name="connection.url">jdbc:mysql://localhost:3306/oslims</property> <property name="connection.username">root</property> <property name="connection.password">rost17</property> <!-- Connection Pool via c3p0--> <property name="c3p0.acquire_increment">1</property> <property name="c3p0.idle_test_period">3600</property> <!-- seconds --> <property name="c3p0.max_size">10</property> <property name="c3p0.max_statements">0</property> <property name="c3p0.min_size">0</property> <property name="c3p0.timeout">3605</property> <!-- seconds --> <property name="c3p0.preferredTestQuery">select 1;</property> <!-- SQL dialect --> <property name="dialect">org.hibernate.dialect.MySQLDialect</property> <property name="show_sql">true</property> <!-- Update the database schema on startup --> <property name="hbm2ddl.auto">update</property> <!-- Disable the second-level cache --> <property name="cache.provider_class">org.hibernate.cache.NoCacheProvider</property> <property name="cache.use_query_cache">false</property> <!-- Drop and re-create the database schema on startup --> <property name="hbm2ddl.auto">update</property>
Listing 13 - Configuration von Hibernate

27

3.3. Datenzugriffsschicht

Die Initialisierung von Hibernate wird mittels einer statischen Klasse namens HibernateUtil im Paket org.oslims.server.dao.util durchgefhrt. Diese initialisiert beim Start der Applikation automatisch alle Hibernate Komponenten, in dem in einem statischen Feld, basierend auf den Werten in der hibernate.cfg.xml und den Annotationen der Dmnenklassen, eine Session Factory erstellt wird. Mittels der Session Factory knnen in weiterer Folge einzelnen Sessions erzeugt werden, mit welchen der eigentliche Zugriff auf die Datenbank erfolgt. Eine Session bietet die fr den Datenbankzugriff bentigten Methoden zum Schreiben, Lesen und Lschen von Objekten. Um berall in der Applikation Zugriff auf eine Session zu erhalten, definiert die Klasse eine statische getSession() Methode welche ber die openSession() Methode der Session Factory eine neue Session erzeugt und an den Aufrufer zurckgibt. Um die fr den Datenbankzugriff spezifische Funktionalitt vom Rest der Applikation zu trennen, wird sie in der Datenzugriffsschicht gekapselt. Darin wird fr jede Entitt eine Datenzugriffsklasse erstellt, welche die Methoden zum Schreiben, Lesen und Lschen der Entitt aus der Datenbank nach auen hin anbietet. Um in der Serviceschicht unabhngig von der konkreten Implementierung der Datenzugriffsklassen zu sein, wird fr jede Klasse, mittels eines Interfaces, definiert welche Funktionalitt sie anbieten soll. Die Klasse in der die Funktionalitt umgesetzt wird implementiert anschlieend dieses Interface. Bei den Funktionen der Datenzugriffsklassen ist zwischen Methoden zu unterscheiden, welche fr alle Entitten verwendet werden und jenen, welche nur fr eine bestimmte Operation ber speziellen Entitten bentigt werden. Erstere wurden mittels einer abstrakten generischen Basisklasse implementiert, von welcher alle konkreten Implementierungen ableiten. Da bei der Ableitung der generische Typparameter definiert wird kann so die gesamte Basisfunktionalitt zentral in einer Klasse implementiert werden. Spezielle Funktionalitt, welche nur in der Datenzugriffsklasse einer Entitt zu Verfgung stehen soll, wird im zugehrigen Interface definiert und nur in der konkreten Klasse implementiert. Dieses Vorgehen minimiert den zu schreibenden Quellcode und trennt spezifische Funktionalitt von generischer, wodurch die einzelnen Datenzugriffsklassen kompakt und bersichtlich bleiben. Das Zusammenspiel zwischen der generischen Basisklasse, den Interfaces und der konkreten Implementierung ist im Klassendiagram in Abbildung 24 am Beispiel der Datenzugriffsklasse fr die Customer Entitt dargestellt.

28

3.3. Datenzugriffsschicht

Abbildung 24 - Klassendiagram der "Customer" Datenzugriffsklasse

Das vollstndige Klassendiagram der Datenzugriffsschicht ist im Anhang dieser Arbeit enthalten.

3.3.1. Hibernate und GWT


Bei der gemeinsamen Verwendung von Hibernate und GWT sind einige Punkte zu beachten, um ein reibungsloses Zusammenspiel der beiden Komponenten zu gewhrleisten. Das Kernproblem ist, dass Hibernate, um die transparente Persistierung eines Objektes zu ermglichen, dieses automatisch, durch direkte Modifikation des Java Bytecodes, erweitert, umso zustzliche Informationen darin zu speichern. Dies bringt in Verbindung mit dem GWT RPC Mechanismus nun ein Problem mit sich. Wie in Kapitel 2.2 beschrieben, muss jedes Objekt, welches ber RPC bertragen wird, das Interface Serializable implementieren. Nun ersetzt aber Hibernate Listen aus dem java.util Paket automatisch durch Listen vom Typ PersistentList welche fr die Umsetzung von Lazy Loading1 bentigt werden. PersistentList jedoch implementiert nicht Serializable und kann somit auch nicht ber RPC bertragen werden. Dasselbe Problem tritt auch bei der Verwendung von Sets oder Maps zur Modellierung von Assoziationen auf. Die einfachste Lsung wre, die von Hibernate durchgefhrten nderungen am Objekt direkt nach dem Laden aus der Datenbank wieder rckgngig zu machen Dadurch verliert man aber die Lazy Loading Funktionalitt auf der Serverseite. Auf der Clientseite steht Lazy Loading

Beim Lazy Loading werden Inhalte von Assoziationen in einem Objekt erst beim ersten Zugriff darauf aus der Datenbank geladen und nicht bei der Objekterstellung

29

3.3. Datenzugriffsschicht

generell nicht transparent zu Verfgung, da dies nicht direkt in JavaScript umgesetzt werden kann. Um das Problem des Transfers von erweiterten Objekten ber RPC zu lsen, gibt es im Prinzip nur die Mglichkeit, diese vor der bertragung in so genannte Datentransferobjekte zu kopieren, und diese ber RPC zu bertragen. Datentransferobjekte sind Objekte, welche dieselben Eigenschaften und Methoden wie die ursprnglichen Objekte der Entitten besitzen, jedoch nicht von Hibernate verwaltet und damit erweitert werden knnen. Um diese Objekte zu erzeugen gibt es laut [GWH10] drei Mglichkeiten. Die Erste ist, diese von Hand in einem separaten Paket zu erstellen. Dies bedeutet aber, dass alle nderungen am Domnenmodel auch manuell auf die Datentransferobjekte bertragen werden mssen. Dies bringt einen doppelten Arbeitsaufwand mit sich und erhht auch die Fehlerwahrscheinlichkeit. Desweiteren kann die Erzeugung von Datentransferobjekten komplex werden, sobald auch die Inhalte von Assoziationen in das Objekt eingebunden werden sollen. Der Vorteil an dieser Methode ist, dass der Entwickler genau festlegen kann, welche Eigenschaften eines Objektes zu welchem Zeitpunkt an den Klienten bertragen werden, womit sich die Menge an bertragenen Daten auf ein Minimum reduzieren lsst. Die zweite Mglichkeit ist die Verwendung der Open Source Bibliothek Dozer. Diese ermglicht es, basierend auf einer XML Konfiguration, automatisch Datentransferobjekte zu erstellen. Dabei entfllt die separate Definition dieser da Dozer so konfiguriert werden kann, dass ein Objekt in ein neues Objekt desselben Typs kopiert wird, welches allerdings nicht von Hibernate verwaltet und damit auch nicht erweitert wird. Diese Methode hat, im Gegensatz zum ersten Ansatz den Vorteil, dass keine separaten Klassen fr die Datentransferobjekte erstellt und verwaltet werden mssen bringt jedoch den Nachteil mit sich, dass Dozer beim Kopieren eines Objektes auch alle darin enthaltenen Referenzen auf weitere Objekte mit bertrgt. Dies kann so weit gehen, dass beim Erstellen eines Datentransferobjektes dessen gesamter Objektgraph aus der Datenbank geladen wird. Dozer lsst sich zwar so konfigurieren, dass bestimmte Eigenschaften eines Objekts nicht ins Datentransferobjekt mit bernommen werden, was allerdings nur auf Klassenbasis definiert werden kann. Dies hat den Nachteil, dass, falls eine Eigenschaft in einem Anwendungsfall bentigt wird und in einem weiteren eine andere, immer beide aus der Datenbank geladen werden mssen. Die dritte Mglichkeit, welche auch bei der Implementierung des LIMS Systems verwendet wurde, ist die Gilead Bibliothek auf deren Verwendung in weiterer Folge nher eingegangen werden soll.

3.3.2. Die Gilead Bibliothek


Gilead [GIL10] steht fr Generic Light Entity Adapter und entstand aus dem hibernate4gwt Projekt. Die Bibliothek steht als kostenlose Open Source Version unter der Apache 2.0 Lizenz frei zu Verfgung.
30

3.3. Datenzugriffsschicht

Ihre Kernfunktionalitt besteht darin, die Erweiterungen, welche Hibernate in Objekten einbindet, fr den Entwickler transparent wieder rckgngig zu machen. Dabei werden Assoziationen in einem Objekt, welche noch nicht aus der Datenbank geladen wurden, mit null und geladene mit den entsprechenden Basiscollections aus dem java.util Paket ersetzt. Die in den Hibernate Erweiterungen gespeicherten Informationen bleiben jedoch direkt im Objekt gespeichert, allerdings so, dass diese ber RPC bertragen werden knnen. Fr die Integration in GWT bringt Gilead einen eigenen Adapter mit, welcher auf dem Google RPC Servlet basiert und transparent bei allen ausgehenden Objekten die Hibernate Erweiterungen entfernt (clone) und bei allen eingehenden Objekten diese wiederherstellt (merge). Damit kann der Entwickler den Servercode so entwickeln, als knnten die von Hibernate erweiterten Objekte direkt ber RPC bertragen werden. Gilead ist nicht auf GWT beschrnkt, sondern untersttzt auch andere Technologien, wie zum Beispiel Adobe Flex, welche ebenfalls von dieser Problematik betroffen sind. Die Funktionsweise von Gilead ist zur Veranschaulichung in Abbildung 25 aufgefhrt.

Abbildung 25 - Funktionsweise von Gilead [GWH10]

Um Gilead in einem GWT Projekt zu verwenden, muss zuerst die Bibliothek mitsamt ihren Abhngigkeiten eingebunden werden. Alle Objekte, welche mithilfe von Gilead an den Klienten bertragen werden sollen, mssen von der Klasse LightEntity abgeleitet werden. In dem implementierten LIMS System war dies einfach umzusetzen, da alle Entitten von einer abstrakten Basisklasse namens AbstractBaseEntity abgeleitet wurden. Um die Funktionalitt der LightEntity Klasse nun in alle Entitten einzubinden, wurde die AbstractBaseEntity Klasse von LightEntity Klasse abgeleitet. Weiters mssen alle RPC Services nicht wie standardmig von RemoteServiceServlet, sondern von PersistentRemoteService abgeleitet werden. Der PersistentRemoteService enthlt bereits den BeanManager, welcher das transparente Klonen und Zusammenfgen der Objekte bernimmt. Dieser muss bei der Instanziierung der Klasse konfiguriert werden. Dazu erstellt man eine neue Instanz der Gilead spezifischen HibernateUtil Klasse, deren
31

3.3. Datenzugriffsschicht

man eine zuvor schon initialisierte Hibernate Session Factory bergibt. Mittels der Klasse GwtConfigurationHelper und dessen statische Methode initGwtStatelessBeanManager(HibernateUtil hibernateUtil) wird ein konfigurierter Bean Manager erzeugt und dieser anschlieend mittels der setBeanManager() Methode dem PersistentRemoteService zugewiesen. Die praktische Umsetzung dieses Vorganges ist in Listing 14 aufgefhrt.
net.sf.gilead.core.hibernate.HibernateUtil hibernateUtil = new net.sf.gilead.core.hibernate.HibernateUtil(HibernateUtil.getSessionFactory()); setBeanManager(GwtConfigurationHelper.initGwtStatelessBeanManager( hibernateUtil ));
Listing 14 - Initialisierung des Gilead Bean Managers

Anschlieend werden alle, von Hibernate verwalteten, Entitten automatisch vor dem Transfer ber RPC in ein Datentransferobjekt umgewandelt, welches ber RPC bertragen werden kann. Wie zuvor erwhnt, ersetzt Gilead beim Klonen eines Objektes alle nicht initialisierten Assoziationen mit null und alle initialisierten durch standardmige Java Collections. Daher mssen schon vor dem Senden eines Objektes an den Klienten alle Assoziationen, welche in weiterer Folge bentigt werden, initialisiert sein. Dies kann entweder durch Aufrufen der size() Methode der jeweiligen Collection, welche die Assoziation reprsentiert, oder durch spezielle HQL2 Queries erfolgen. Durch die distinct und join fetch HQL Befehle lassen sich bestimmte Assoziationen direkt beim Lesen eines Objektes aus der Datenbank vor-initialisieren (Eager Loading). Als Beispiel ist in Listing 15 aufgefhrt, wie mittels HQL alle Analysen inklusive der Parameter, welche durch sie bestimmt werden, geladen werden knnen.
Query q = this.getSession().createQuery("select distinct a from Analysis a left join fetch a.determinedParameters"); return q.list();
Listing 15 - HQL Join Fetch Syntax

Mchte man jedoch zustzlich zu den Parametern auch noch die Probentypen laden, fr welche diese Analyse definiert ist, wrde das entsprechende HQL Query wie in Listing 16 lauten.
Query q = this.getSession().createQuery("select distinct a from Analysis a left join fetch a.determinedParameters left join fetch a.validSampleTypes "); return q.list();
Listing 16 - HQL simultanes Laden von zwei Assoziationen

HQL ist ein, Hibernate spezifisches, objektorientiertes Derivat der SQL Abfragesprache und wird zur Durchfhrung komplexer Datenbankabfragen mittels Hibernate verwendet.

32

3.3. Datenzugriffsschicht

Jedoch erzeugt das Ausfhren eines solchen Queries folgende Ausnahme: MultipleBagFetchException: Cannot simultaneously fetch multiple bags. Diese Fehlermeldung sagt aus, dass mittels HQL immer nur eine Assoziation in einem Query gleichzeitig geladen werden kann. Fr das Laden weiterer Assoziationen muss ber die Ergebnisliste iteriert und fr jedes Objekt die size() Methode der weiteren Assoziationen aufgerufen werden. Bei der praktischen Anwendung von Gilead traten jedoch zwei Probleme auf. Ersteres betraf die LabStaff Entitt, welche die Superklasse der Benutzerentitten Operator und LabResponsible bildet. Diese besitzt, um zu modellieren fr welche Abteilungen ein LabStaff zustndig ist, eine Eigenschaft namens departments vom Typ List<Department>, welcher automatisch eine ArrayList<Department> bei der Instanziierung des Objektes zugewiesen wird. Deren Getter und Setter waren dafr wie in Listing 17 gezeigt definiert.
@Entity public abstract class LabStaff extends BaseUser { ... @ManyToMany(targetEntity = Department.class, cascade = CascadeType.ALL) @OrderBy("name") private List<Department> departments = new ArrayList<Department>(); ... public void setDepartments(ArrayList<Department> departments) { this.departments = departments; } public ArrayList<Department> getDepartments() { return departments; } ... }
Listing 17 - Definition der Departments Eigenschaft

Hierbei ist zu sehen, dass departments vom Typ List ist, der zugehrige Setter jedoch eine ArrayList erwartet. Sobald nun ein Objekt vom Typ LabStaff mit einem Eintrag in der Abteilungsliste vom Klienten an den Server bertragen wurde, trat whrend des Merge Prozesses von Gilead eine Ausnahme vom Typ IllegealArgumentException: Argument Type Mismatch auf. Dies wurde dadurch verursacht, dass Gilead versuchte, die ArrayList durch eine Hibernate PersistentList zu ersetzten. Dafr verwendet Gilead den jeweiligen Setter der Eigenschaft. Da dieser aber ein Objekt vom Typ ArrayList erwartet und PersistentList nicht in ArrayList konvertiert werden kann, kommt es zu der erwhnten Ausnahme. Dieser Fehler konnte behoben werden, indem der bergabetyp des Setters von ArrayList auf List gendert wurde, da PersistentList das ListInterface implementiert und somit die Zuweisung durchgefhrt werden kann. Obwohl der Fehler trivial zu beheben war, gestaltete sich die Fehlersuche selbst als sehr zeitaufwndig und erfordert detailliertes Wissen ber die interne Funktionsweise von

33

3.4. Serviceschicht

Gilead. Eine aussagekrftigere beschleunigen.

Fehlermeldung

wrde

hier

die

Fehlersuche

Ein weiteres Problem, welches bei der Verwendung von Gilead entdeckt wurde ist, dass Lazy Loading bei gemergten Objekten nicht mehr funktioniert. Dies tritt dann auf, wenn ein Objekt am Server geladen und zum Klient transportiert wird. Wird anschlieend das Objekt zurck am Server bertragen und versucht man dort auf eine, zuvor noch nicht initialisierte Collection dieses Objektes, zuzugreifen wird nur eine leere Liste zurckgegeben. Dieses Problem lsst sich umgehen, indem man das Objekt Serverseitig nochmals anhand seines Primrschlssels, aus der Datenbank ldt. Daraufhin funktioniert Lazy Loading wieder wie gewohnt.

3.4. Serviceschicht
Die Serviceschicht des implementierten LIMS Systems bildet die Brcke zwischen der Datenzugriffs- und Prsentationsschicht. Sie gruppiert die Implementierung der Geschftslogik des Systems und ist weiters fr den Datenaustausch mit der durch GWT in Java Script bersetzten Prsentationssicht zustndig. Daher wurden alle Klassen der Serviceschicht als RPC Services implementiert um Daten, fr den Entwickler transparent, vom Server an den Klient und zurck zu bertragen. Fr den Datenbankzugriff verwendet die Serviceschicht nur die, in der Datenzugriffsschicht definierten, Datenzugriffsobjekte, wobei die einzelnen Zugriffe in Transaktionen gruppiert werden um sie im Fehlerfall wieder rckgngig machen zu knnen. Weiters integrieren alle Klassen der Serviceschicht Gilead, wobei die Einbindung nach der in Kapitel 3.3.2 aufgefhrten Methodik durch Erweitern der PersistentRemoteService Basisklasse durchgefhrt wird. Der Aufbau der Serviceklassen wurde nach folgender Vorgehensweise durchgefhrt. Fr jede Entitt wurde eine eigene Serviceklasse erstellt, wobei fr hnliche Geschftsobjekte wie Proben und Mischungen sowie die einzelnen Benutzerklassen die Funktionalitt in einer Klasse gruppiert wurde. Jede Serviceklasse besitzt als private Eigenschaften die von ihr bentigten Datenzugriffsobjekte, wobei hier nur das Interface der Objekte verwendet wird, nicht deren konkrete Implementierung. Im Konstruktor der Klasse werden Instanzen der konkreten Implementierungen der Datenzugriffsobjekte erstellt und diesen den Eigenschaften zugewiesen. Beispielhaft ist in Listing 18 der Kopf der Department Serviceklasse aufgefhrt welche nur ein Datenzugriffsobjekt vom Typ DepartmentDao enthlt.
public class DepartmentServiceImpl extends PersistentRemoteService implements DepartmentService { DepartmentDao departmentDao; public DepartmentServiceImpl() { departmentDao = new HbmDepartmentDao(); //Gilead Konfiguration } }
Listing 18 - Kopf der Department Serviceklasse

34

3.4. Serviceschicht

Um in den Servicemethoden mit den Datenzugriffsobjekten arbeiten zu knnen muss diesen zuerst eine geffnete Hibernate Session bergeben werden. Bei Operationen welche schreibend auf die Datenbank zugreifen muss weiters, mittels der beginTransaction() Methode des Session Objektes, eine Transaktion gestartet werden. Wichtig ist es, die Transaktion nur dann durchzufhren wenn whren der gesamten Verarbeitung kein Fehler auftritt. Ist dies der Fall, muss diese mittels der session.getTransaction().rollback() Methode rckgngig gemacht werden. Nach Abschluss aller Datenzugriffe muss die Hibernate Session mittels der close() Methode geschlossen werden. Die Methodik dem Datenzugriffsobjekt in jeder Servicemethode eine neue Hibernate Session zuzuweisen wurde deshalb gewhlt, da laut der Hibernate Dokumentation eine Session, sobald eine Ausnahme beim Datenbankzugriff Auftritt, nicht mehr verwendet und somit verworfen werden muss[HBN10]. Verwendet man in der gesamten Serviceklasse immer nur eine Session, kann dies nur schwer implementiert werden. Die beispielhafte Umsetzung eines nur lesenden Datenzugriffs ist in Listing 19 aufgefhrt, wobei in Listing 20 der schreibende Zugriff aufgezeigt wird.
public List<Department> getAllDepartments(int start, int length, String sortBy, boolean desc) { Session session = HibernateUtil.getSession(); departmentDao.setSession(session); List<Department> response = departmentDao.findAllWithLabResp(start, length, sortBy, desc); session.close(); return response; }
Listing 19 - Auslesen aller angelegten Abteilungen

public void editDepartment(Department department) { Session session = HibernateUtil.getSession(); session.beginTransaction(); try { departmentDao.setSession(session); departmentDao.makePersistent(department); session.getTransaction().commit(); } catch (RuntimeException e) { session.getTransaction().rollback(); throw e; } finally { session.close(); } }
Listing 20 - Speichern der nderungen an einer Abteilung in der Datenbank

Das vollstndige Klassendiagram der Serviceschicht ist im Anhang dieser Arbeit enthalten.

35

3.5. Prsentationsschicht

3.4.1. Datenvalidierung
Da die Serviceschicht Daten von der Prsentationsschicht der Applikation verarbeitet und diese, da sie lokal im Browser des Benutzers luft, potentiell manipuliert werden knnen, werden alle empfangenen Daten, bevor sie in die Datenbank gespeichert werden, validiert. Diese Funktionalitt wurde mittels der gwt-validation[GVL10] Bibliothek umgesetzt welche gleichermaen auf der Klient- sowie Serverseite einer GWT Applikation verwendet werden kann und den JSR-303 Standard[JSR10] implementiert. Um dies umzusetzen werden alle Eigenschaften der Entitten, welche berprft werden sollen, mit spezifischen JSR-303 Annotationen wie @NotNull oder @Email versehen. gwt-validation stellt fr die serverseitige Validierung einen ServerValidator zur Verfgung welcher es erlaubt, ein Objekt durch Aufruf der validate(Object o) Methode zu validieren. Die Verwendung des Servervalidators ist in Listing 21 aufgezeigt.
//Erstellen des Servervalidators IValidator<Parameter> parameterValidator = new ServerValidator<Parameter>(); //Validieren eines Objektes vom Typ Parameter parameterValidator.validate(parameter);
Listing 21 - Verwendung des ServerValidators

Dabei gibt die validate Methode ein Set an InvalidConstraint Objekten zurck aus welchem ersichtlich ist, welche Eigenschaften nicht korrekt validiert werden konnten. Mit der size() Methode des Sets kann berprft werden ob das gesamte Objekt valide ist.

3.5. Prsentationsschicht
Die Prsentationsschicht stellt das primre Benutzerinterface der LIMS Applikation dar. Sie ist fr die Datenprsentation sowie der Dateneingabe und deren Erstvalidierung zustndig. Im Zuge der Verwendung des Google Web Toolkits wurde sie als Browserseitiger Code implementiert, das heit, bei der Kompilierung der Applikation wird sie vom GWT Compiler in Java Script bersetzt. Zur Kommunikation mit dem serverseitigen Teil der Applikation verwendet sie ausschlielich die als RPC Services implementierten Klassen der Serviceschicht. Die Prsentationsschicht selbst wurde unter Anwendung des MVP Entwurfsmusters und der mvp4g Bibliothek umgesetzt. In den folgenden Kapiteln wird zuerst auf den optischen Aufbau der Benutzeroberflche und anschlieend auf die Integration des MVP Patterns eingegangen.

3.5.1. Design der Benutzeroberflche


Die Benutzeroberflche des implementierten LIMS Systems soll derer einer traditionellen Desktop Applikation so weit als mglich hneln. Hierfr wurde die Oberflche in drei Teile gegliedert. Im obersten, statischen Teil der Applikation soll das Logo sowie der derzeit eingeloggte Benutzer angezeigt werden. Im linken, ebenfalls statischen Teil, soll sich das Men befinden, mit dem der Benutzer zwischen den einzelnen Teilbereichen der
36

3.5. Prsentationsschicht

Applikation navigieren kann. Dieses soll hnlich der von Microsoft Outlook bekannten Outlook Bar umgesetzt werden. Im dritten und zentralen Teil der Oberflche sollen, abhngig vom gewhlten Menpunkt, die entsprechenden Eingabe- und Abfragemasken dargestellt werden. Dieser Bereich soll den gesamten zu Verfgung stehenden Platz am Bildschirm einnehmen. Falls der Platz nicht ausreicht um alle Informationen anzuzeigen, soll eine horizontale und/oder vertikale Scrollbar angezeigt werden. Ein Entwurf dieses Designs ist in Abbildung 26 dargestellt.

Abbildung 26 - Design der Benutzeroberflche

Um dieses Design nun mittels des GWT umzusetzen wurde als Basispanel der Applikation, das in Kapitel 2.3 vorgestellte DockLayoutPanel gewhlt, wobei das Logo und der Benutzername im nrdlichen, das Men im westlichen und der Inhalt im zentralen Teil des Panels positioniert wird. Als Einheit, welche dem DockLayoutPanel zu Grunde liegt, wurde EM gewhlt, damit sich die Applikation dynamisch an die, im Browser des Anwenders eingestellte, Schriftgre anpasst. Die Erstellung des DockLayoutPanel ist in Listing 22 aufgezeigt.
private DockLayoutPanel appPanel = new DockLayoutPanel(Unit.EM);
Listing 22 - Erstellen des DockLayoutPanels

Um das Logo in die Applikation einzubinden, wird zuerst die Bilddatei im Ordner, welche auch die Klasse enthlt in derer das Layout implementiert wird, gespeichert. Anschlieend wird innerhalb dieser Klasse ein statisches Interface, welches vom Interface ClientBundle ableitet und eine Methode der Signatur ImageResouce logo() enthlt, erstellt. Wobei logo der Name der Bilddatei ohne Dateierweiterung ist. Nun kann mittels der statischen GWT.create(Ressources.class) Methode eine Instanz dieser Ressource erstellt werden. Um nun das Bild einem Panel zuweisen zu knnen, muss ein Widget vom Typ Image erstellt werden, wobei dem Konstruktor die logo() Ressource bergeben wird. Dieser Vorgang ist in Listing 23 aufgezeigt.
37

3.5. Prsentationsschicht

public static interface Resources extends ClientBundle { ImageResource logo(); } private static final Resources RESOURCES = GWT.create(Resources.class); Image logo = new Image(RESOURCES.logo());
Listing 23 - Einbinden des Logos in das Applikationslayout

Das Logo kann nun mittels der addNorth(Widget w) Methode des Applikationspanels im Kopf der Applikation positioniert werden. Analog dazu wird ein Label zur Anzeige des derzeit angemeldet Benutzers ebenfalls mittels der addNorth(Widget w) zum Applikationspanel hinzugefgt. Das Men der Applikation wurde unter Verwendung eines StackLayoutPanels umgesetzt. Dieses hnelt in seiner Funktionalitt und Design der Outlook Bar. Da es zur Gruppe der Layout Panels gehrt nimmt es automatisch die gesamte zu Verfgung stehende Hhe ein. Die Breite des Panels ergibt sich aus der maximalen Breite der darin enthaltenen Elemente. Die Erstellung des Panels erfolgte analog zur Erstellung des DockLayoutPanel. Als Einheit wurde wiederum EM gewhlt. Das StackLayoutPanel gruppiert einzelne Eintrge in Gruppen. Die Namen dieser Gruppen wurden so gewhlt, dass sie dem Kontext der darin enthaltenen Elemente und deren Funktionalitt entsprechen. Da fr jede Gruppe alle Elemente nur als ein Widget hinzugefgt werden knnen, mssen diese zuerst in einem Panel gruppiert werden. Hierfr wurde ein VerticalPanel gewhlt. Die einzelnen Elemente wurden als Schaltflchen mit einer fixen Breite umgesetzt, welche einzeln dem VerticalPanel mittels dessen add(Widget w) Methode hinzugefgt werden. Mittels dieser Methode tritt jedoch das Problem auf, dass die einzelnen Elemente gleichmig ber die gesamte zu Verfgung stehende Hhe des Mens verteilt werden, wie in Abbildung 27 ersichtlich ist, was optisch nicht dem gewnschten Verhalten entspricht.

Abbildung 27 - Men mit gleichmig verteilten Eintrgen

Dieses kann auch nicht mit der Definition der vertikalen Ausrichtung der Elemente im VerticalPanel korrigiert werden, da die Hhe jedes Elements des Panels so angepasst wird, dass das gesamte Panel den kompletten zu Verfgung stehenden Bereich ausfllt. Um dies zu lsen wird das VerticalPanel nochmals in ein zweites VerticalPanel
38

3.5. Prsentationsschicht

eingefgt, welches als umschlieendes Panel dient. Da dieses zweite Panel nun nur ein Element enthlt, nmlich das zuvor verwendete VerticalPanel, kann durch Setzen der vertikalen Ausrichtung, wie in Abbildung 28 , dieses bndig am oberen Ende positioniert werden.

Abbildung 28 - Men mit bndig verteilten Eintrgen

Das Erstellen der Meneintrge sowie deren hinzufgen zum Men ist weiters, exemplarisch an der Gruppe Auftragsverwaltung, in Listing 24 aufgezeigt.
VerticalPanel requestWrapper = new VerticalPanel(); VerticalPanel requests = new VerticalPanel(); requests.setVerticalAlignment(HasVerticalAlignment.ALIGN_TOP); requests.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_CENTER); requestManagementLink.setWidth(MENU_BUTTON_WITH); requests.add(requestManagementLink); requestWrapper.add(requests); menuPanel.add(requestWrapper, "Requests", 3);
Listing 24 - Einfgen eines Meneintrages

Um das Men nun zum Applikationslayout hinzuzufgen wird es, mittels der addWest(Widget w) Methode, als westliche Komponente des Applikationspanels gesetzt. In spterer Folge kann der Hauptinhalt der Applikation mittels der add(Widget w) Methode eingeblendet werden. Das umgesetzte Applikationslayout ist in Abbildung 29 aufgezeigt.

Abbildung 29 - Umsetzung des Applikationslayouts

39

3.5. Prsentationsschicht

3.5.2. Umsetzung des MVP Patterns


Wie schon in Kapitel 2.5.2 erwhnt, wurde zur Untersttzung der Entwicklung nach dem MVP Entwurfsmuster die mvp4g Bibliothek verwendet. Hierfr wurde zu allererst ein zentraler Event Bus namens MainEventBus im Paket org.oslims.client erstellt. In diesem wurden alle Events definiert, welche fr die globale Applikationssteuerung bentigt werden. Dies sind in erster Linie Events, welche das Anzeigen von bestimmten Formularen auslsen sowie ein zentrales Error Event welches im Fehlerfall die globale Fehlerbehandlung der Applikation auslst. Basierend auf den zuvor definierten Anwendungsfllen werden die Presenter und die dazugehrigen Views so gewhlt, dass zum Kontext passende Use Cases in einer Presenter View Kombination zusammengefasst werden knnen. Alle Views werden als Composite Widgets umgesetzt und leiten von der Klasse BaseViewImpl ab, welche das BaseView Interface implementiert und selbst wiederum von der Composite Klasse abgeleitet ist. Mittels der Widget getViewWidget() Methode des BaseView Interfaces kann der Presenter seinen View ins Hauptpanel der Applikation einblenden. Der Aufbau der Views ist Weiters in Abbildung 30 aufgezeigt wobei bei den konkreten View Interfaces und Klassen wie RootView und AnalysisPlaningView die darin definierten Methoden bersichtshalber nicht angefhrt wurden.

Composite

BaseView +Widget getViewWidget()

BaseViewImpl +Widget getViewWidget()

RootView

RootViewImpl

AnalysisPlaningView

AnalysisPlaningViewImpl

Weitere Views wurden analog zu den hier aufgefhrten Views umgesetzt

Abbildung 30 - Umsetzung der View Implementierung

Weiters wird bei den View Klassen zwischen dem RootView unterschieden, welcher das generelle Applikationslayout, wie Men und Logo nach Kapitel 3.5.1, anzeigt und allen anderen Views welche fr das Darstellen der Umsetzung der Anwendungsflle zustndig sind.
40

3.5. Prsentationsschicht

Jedem View ist weiters ein Presenter zugeordnet welcher dessen Funktionalitt umsetzt. Der RootPresenter implementiert zentral die Funktionalitt um zwischen verschiedenen Views umzuschalten. In allen anderen Presentern befindet sich die Logik welche bentigt wird, um Daten in den Formularen anzeigen sowie auslesen zu knnen. Die Kommunikation zwischen den Presentern erfolgt ausschlielich ber den Event Bus.

3.5.3. Applikationsstart
Beim Startvorgang der Applikation werden zuerst in der onModuleLoad() Methode der OSLims Klasse die mvp4g Komponenten initialisiert und der, als Start-View definierte RootView, zum RootLayoutPanel der Seite hinzugefgt. Hierbei wird gleichzeitig das start Event ausgelst, welches vom RootPresenter verarbeitet wird. Bevor jedoch das Event an diesen weitergegeben wird, wird zuerst dessen bind() Methode aufgerufen, in welcher sich der Presenter an seinen View bindet. Hier werden die Klick Handler der einzelnen Menelemente registriert welche spter bentigt werden um auf Klicks im Men zu reagieren. Nachdem die bind() Methode abgearbeitet wurde wird die onStart() Methode des RootPresenter aufgerufen. In dieser wird die showWelcomeScreen() Methode des Events Bus aufgerufen welche sukzessive das Anzeigen des Willkommensbildschirms auslst. Dieser Ablauf ist Weiters als Sequenzdiagramm in Abbildung 31 aufgezeigt.

Abbildung 31 - Sequenzdiagram des Startvorganges der Applikation

3.5.4. Wechsel des angezeigten Views


Das Men bietet die Funktionalitt, bestimmte Bereiche der Applikation direkt zu erreichen. Um dies umzusetzen, muss der derzeit angezeigte View aus dem Applikationspanel entfernt und ein neuer ins Panel eingefgt werden. Um diesen Vorgang umzusetzen, wurde im Event Bus fr jeden View ein showxxxView(DockLayoutPanel
41

3.5. Prsentationsschicht

mainWidget) Event definiert, welcher als Parameter das Applikationspanel erwartet. Die fr den jeweiligen View zustndigen Presenter abonnieren diesen Event durch Definition der onShowxxxView(DockLayoutPanel) Methode. In dieser wird zuerst das derzeit angezeigte Panel vom Applikationspanel entfernt. Jedoch bietet das DockLayoutPanel keine direkte Methode ein Widget, welches in einem bestimmten Teil angezeigt wird, zu entfernen. Widgets knnen nur durch Angabe ihres Indexes aus dem Panel entfernt werden. Um den Index des zentralen Widgets zu erhalten, muss zuerst ber alle Widgets, welche das Panel enthlt, iteriert werden. Nun kann mittels der getWidgetDirection(Widget w) Methode des DockLayoutPanel die Position ermittelt werden. Sobald der Rckgabewert dieser Methode der Konstante Direction.CENTER entspricht, hat man das zentrale Widget gefunden und kann es mittels der remove(int index) Methode aus dem Panel entfernen. Dieser Vorgang ist in Listing 25 aufgezeigt.
for (int i = 0; i < appPanel.getWidgetCount(); i++) { if (appPanel.getWidgetDirection(appPanel.getWidget(i)) == Direction.CENTER) { appPanel.remove(i); } }
Listing 25 - Entfernen des zentralen Widgets des Applikationspanels

Da diese Funktionalitt in jedem Presenter der Applikation bentigt wird, wurde der Code in die statische Methode removeCenterWidget(DockLayoutPanel appPanel) der WidgetUtils Klasse ausgelagert. Nun kann in jedem Presenter der derzeit angezeigte View durch Aufruf von WidgetUtils.removeCenterWidget(mainWidget) ausgeblendet werden. Um nun den dem Presenter zugehrigen View anzuzeigen, ruft dieser die add(Widget w) Methode des bergeben Applikationspanels auf und bergibt dieser den Rckgabewert der view.getAsViewWidget() Methode, welche jeder View, da er das Interface BaseView implementiert, besitzt. Der gesamte Vorgang zum Anzeigen eines neuen Views ist am Beispiel des Views zur Analysenplanung, in Listing 26 aufgezeigt.
public void onShowAnalysisPlaning(DockLayoutPanel mainWidget) { WidgetUtils.removeCenterWidget(mainWidget); mainWidget.add(view.getViewWidget()); }
Listing 26 - Umschalten des derzeit sichtbaren Views

42

4.1. Anwendungsfall Analysen verwalten

4. Implementierung ausgewhlter Anwendungsflle


In dem nun folgenden Kapitel wird die Implementierung ausgewhlter Anwendungsflle aufgezeigt. Hierbei werden nur die komplexesten Flle betrachtet, da die Einbeziehung aller umgesetzten Use Cases den Umfang dieser Arbeit bersteigen wrde. Weiters konnten, aufgrund des zeitlichen Rahmens, nicht alle Anwendungsflle vollstndig, wie in der Bakkalaureatsarbeit I definiert, umgesetzt werden. Der Quelltext der gesamten implementierten Applikation ist dieser Arbeit in elektronischer Form beigelegt

4.1. Anwendungsfall Analysen verwalten


Die beiden Anwendungsflle Analysen anlegen und Analysen bearbeiten, wurden zu einem gemeinsamen Anwendungsfall namens Analysen verwalten zusammengefasst implementiert, da die hierfr bentigte Funktionalitt nahezu ident ist. Gleichzeitig dient diese Implementierung als generelles Beispiel dafr, wie in der Applikation das Erstellen, Verwalten und Editieren von Entitten umgesetzt wurde.

4.1.1. Kurzbeschreibung des Anwendungsfalles


Chemische, mechanische oder physische Eigenschaften von Proben werden als Parameter bezeichnet. Diese werden immer durch eine Analyse bestimmt. Eine Analyse selbst hat einen Namen, einen Preis, gehrt zu einer gewissen Abteilung und bestimmt einen oder mehrere Parameter. Essoll die durchschnittliche Zeit erfasst werden, die bentigt wird um diese durchzufhren. Eine Analyse kann nur an bestimmten Probentypen durchgefhrt werden. Daher sind bei der Erstellung der Analyse die Probentypen auszuwhlen, fr welche sie valide ist. Weiters sollen Analysen bei Bedarf deaktiviert werden knnen falls sie nicht mehr bentigt werden.

4.1.2. Umsetzung im Domnenmodell


Um die Anforderungen dieses Anwendungsfalles im Domnenmodel abzubilden, enthlt die Analysis Entitt die Eigenschaften name, esitmatedTime, estimatedCost und active. Weiters besitzt sie eine eins zu n Beziehung mit der Department Entitt, sowie eine n zu m Beziehung zu den SampleType und Parameter Entitten. Das zugehrige Klassendiagram ist in Abbildung 32 aufgezeigt.

43

4.1. Anwendungsfall Analysen verwalten

Abbildung 32 - Klassendiagram der "Analysis" Entitt

4.1.3. Erstellen des Views


Der fr die Umsetzung dieses Anwendungsfalles zustndige View, soll primr alle Analysen in einer tabellarischen Ansicht anzeigen, welche den Namen, die Dauer der Analyse, die Kosten, die Abteilung und die damit bestimmten Parameter enthlt. Jede Zeile soll weiters eine Schaltflche Edit enthalten, mit welcher die ausgewhlte Analyse editiert werden kann. Zum Anlegen einer neuen Analyse soll der View eine Add Analysis Schaltflche enthalten. Die Edit und Add Analysis Schaltflche sollen ein Formular anzeigen in welchem die Daten zur Analyse eingegeben oder gendert werden knnen. Wird in diesem Formular ein nicht korrekter Eintrag gettigt soll eine Fehlermeldung in der entsprechenden Zeile angezeigt werden. Um dieses Verhalten umzusetzen, werden zuerst die bentigten View Komponenten erstellt. Hierbei wird mit dem Formular begonnen, welches zur Dateneingabe herangezogen wird. Dieses soll fr die Eingabe des Namens, der Dauer und der Kosten der Analyse jeweils ein Texteingabefeld, fr die Auswahl der Abteilung eine Auswahlliste und fr die Selektion der Parameter und Probentypen eine Mehrfachauswahl in Form einer PickList3 enthalten. Da Texteingabefelder in der gesamten Applikation mehrfach bentigt werden, werden sie als Composite Steuerelement umgesetzt. Dieses Element enthlt ein Beschriftungsfeld, eine Texteingabebox sowie eine weitere Beschriftung welche zur Anzeige einer Fehlermeldung verwendet wird. Diese drei Elemente sind horizontal in einer Linie ausgerichtet. Nach auen hin stellt dieses Steuerelement nur die, im Klassendiagram in Abbildung 33, aufgefhrten Methoden zu Verfgung.

Eine PickList ist ein Steuerelement welches zwei Listen beinhaltet. Die linke Liste enthlt die nicht selektierten und die rechte die selektierten Elemente. Mit Schaltflchen knnen ein oder mehrere Elemente von eine Liste in die Andere verschoben werden.

44

4.1. Anwendungsfall Analysen verwalten

TextInputField +TextInputField(String fieldName, String fieldCaptation, String labelSize, String boxSize) +String getFieldName() +showError(String errorMessage) +clearError() +HasValue<String> getInputField()

Abbildung 33 Klassendiagram des TextInputField

Dieses Steuerelement erwarten im Konstruktor vier Parameter. Der erste fieldName gibt an, fr welche Eigenschaft der bearbeiteten Entitt dieses Feld zustndig ist. fieldCaptation legt die angezeigte Beschriftung fest. labelSize definiert die Breite dieser und boxSize die Breite des Texteingabefeldes. Mittels der Methode showError(String errorMessage) kann eine Fehlermeldung angezeigt und mittels der clearError() Methode wiederum ausgeblendet werden. Die Methode getInputField() ist fr das Setzen und Lesen des Inhaltes des Eingabefelders zustndig. Analog zum Texteingabefeld wird ein weiteres Feld fr die Eingabe boolescher Werte definiert, welches statt der TextBox ein Kontrollkstchen anzeigt. Die Auswahlliste, namens DropDownInputField wird ebenfalls nach dem oben aufgezeigten Prinzip implementiert. Sie enthlt nur zustzlich die Methode setCollectionItems(Collection<String> items) mit welcher die, zur Auswahl zu Verfgung stehenden Elemente, gesetzt werden knnen. Als Eingabeelement enthlt sie eine Liste vom Typ ListBox. Um von auen direkt auf die Liste zugreifen zu knnen, wird weiters die Methode getInputBox() definiert, welche die Liste als solche zurckgibt. Das Klassendiagram der DropDownInputField Klasse ist in Abbildung 34 aufgezeigt.

DropDownInputField +DropDownInputField(String fieldName, String fieldCaptation, String labelSize, String boxSize) +String getFieldName() +setSelectionItems(Collection<String> items) +showError(String errorMessage) +clearError() +setSelectionItems(Collection<String> items)

Abbildung 34 Klassendiagram des DropDownInputField

Wesentlich komplexer gestaltet sich die Implementierung der PickList. Diese wird wiederum als Composite Steuerelement implementiert, jedoch mit einem generischen Parameter um die Auswahl der Elemente typsicher durchfhren zu knnen. Dem Konstruktor ist nur die Beschriftung des Feldes zu bergeben. Die Klasse selbst enthlt als Eigenschaften zwei generische assoziative Arrays vom Typ Map wobei als Schlssel die Stringreprsentation der darin enthaltenen Objekte verwendet wird. Zur Anordnung
45

4.1. Anwendungsfall Analysen verwalten

der zwei Listen, welche wiederum mittels des ListBox Steuerelementes realisiert werden, sowie den Schaltflchen dient ein horizontales Panel. Um die vertikale Ausrichtung der Schaltflchen zu realisieren wird ein vertikales Panel verwendet. Die Listeneintrge knnen mit der Methode setItems(Collection<T> unselectedItems, Collection<T> selectedItems) gesetzt werden. In dieser werden die bergebenen Elemente sowohl in die assoziativen Arrays als auch in die entsprechenden Listen bertragen. Um die Funktionalitt der Schaltflchen umzusetzen, wird ein Handler auf deren Klickevent registriert, in welchem die Verschiebung der Elemente durchgefhrt wird. Dabei erfolgt diese sowohl in den Listen, als auch in den assoziativen Arrays. Mittels der Methode List<T> getSelectedItems() knnen die derzeit gewhlten Elemente abgefragt werden. Das Klassendiagram der SelectManyBox ist in Abbildung 35 aufgezeigt.

SelectManyBox +SelectManyBox(String captation) +List<T> getSelectedItems() +setItems(Collection<T> unselectedItems, Collection<T> selectedItems)

Abbildung 35 - Klassendiagram der SelectManyBox

Nachdem die Basiselemente des Formulars definiert wurden, kann nun das Formular selbst implementiert werden. Dessen Basis bildet ein Panel vom Typ DialogBox. Dieses wird so konfiguriert, dass es modal angezeigt und nicht automatisch ausgeblendet wird, sobald der Benutzer auerhalb des Panels klickt. Die einzelnen Eingabefelder des Formulars werden mit Hilfe eines vertikalen Panels untereinander angeordnet. Weiters enthlt das Formular zwei Schaltflchen zum Besttigen und Abbrechen des Vorganges. Diese werden am unteren Ende mittels eines horizontalen Panels nebeneinander ausgerichtet. Die Formularklasse enthlt als Eigenschaften die zuvor aufgefhrten Eingabefelder, die zwei Schaltflchen, eine Referenz auf die Entitt, in diesem Fall die Analyse welche gerade bearbeitet wird, sowie ein assoziatives Array. In diesem sind alle Eingabefelder enthalten, wobei der Name der Eigenschaft, welche durch sie bearbeitet wird, als Schlssel dient. Dies wird in spterer Folge fr das Anzeigen einer Fehlermeldung bentigt. Die Definition der Eigenschaften ist in Listing 27 aufgefhrt.
final DialogBox editAnalysisBox = new DialogBox(false, true); final VerticalPanel editAnalysisBoxPanel = new VerticalPanel(); protected Map<String, InputField> inputFields = new HashMap<String, InputField>(); final HorizontalPanel buttonLine = new HorizontalPanel(); final Button saveButton = new Button("Save"); final Button cancelButton = new Button("Cancel");

46

4.1. Anwendungsfall Analysen verwalten

final TextInputField nameField = new TextInputField("name", "Name: ", "80px", "200px"); final TextInputField estTimeField = new TextInputField("estimatedTime", "Estimated Time: ", "80px", "200px"); final TextInputField estCostField = new TextInputField("estimatedCost", "Estimated Cost", "80px", "200px"); final DropDownInputField doneInField = new DropDownInputField("doneIn", "Done In: ", "80px", "200px"); final SelectManyBox<Parameter> parameterSelectionField = new SelectManyBox<Parameter>("Parameters: "); final SelectManyBox<SampleType> sampleTypeSelectionField = new SelectManyBox<SampleType>("Valid sample types: "); final BooleanInputField activeField = new BooleanInputField("active", "Active:", "80px", "200px"); private Analysis analysis;
Listing 27 - Definition der Eigenschaften der EditAnalysisBox Klasse

Im Konstruktor der Klasse werden die einzelnen Eingabefelder zu den jeweiligen Panels sowie dem assoziativen Array hinzugefgt. Nach auen hin bietet das Formular nur die Methoden an, welche im Klassendiagram in Abbildung 36 aufgefhrt sind.

EditAnalysisBox +hide() -clear() +showNew() +showEdit(Analysis a) +showError(String fieldName, String message) +clearError(String fieldName) +clearAllErrors() +HasValue<String> getName() +HasValue<String> getEstimatedTime() +HasValue<String> getEstimatedCost() +ListBox getDepartment() +SelectManyBox<Parameter> getParameterSelection() +SelectManyBox<SampleType> getSampleTypeSelection() +HasValue<Boolean> getActive() +HasClickHandlers getSaveButton() +HasClickHandlers getCancelButton() +Analysis getAnalysis()

Abbildung 36 - Klassendiagram der EditAnalysisBox

Mittels der Methode showNew() kann das Formular fr das Erzeugen einer neuen Analyse angezeigt werden. Zum Editieren einer bereits bestehenden Analyse kann es mittels der Methode showEdit(Analysis a) angezeigt werden. Dabei bernimmt das Formular automatisch die in der bearbeiteten Analyse enthaltenen Werte. Beim Anzeigen des Formulars wird die private Methode clear() aufgerufen, welche alle zuvor eingegebenen Daten aus dem Formular lscht. Mittels der showError(String fieldName, String message) Methode kann eine Fehlermeldung fr ein bestimmtes Eingabefeld
47

4.1. Anwendungsfall Analysen verwalten

eingeblendet werden. Dabei dient der erste Parameter als Schlssel um aus dem assoziativen Array das korrekte Eingabefeld zu erhalten. Um eine Fehlermeldung wieder auszublenden, kann entweder die clearError(string fieldName) oder die clearAllErrors() Methode verwendet werden. Um die einzelnen Eingaben des Benutzers im Presenter zu verarbeiten, besitzen alle Eingabefelder einen Getter, mit welchem auf den derzeit darin enthaltenen Wert zugegriffen werden kann. Das fertige Formular ist in Abbildung 37 aufgezeigt.

Abbildung 37 - Formular zum Erstellen einer neuen Analyse

Neben dem Formular enthlt der View noch eine Tabelle vom Typ CellTable<Analysis>, einen zugehrigen Pager vom Typ SimplePager<Analysis>, eine Schaltflche fr das Erstellen einer neuen Analyse, sowie eine Methode zum Abfragen der Anzahl an Elementen, welche standardmig auf einer Seite der Tabelle angezeigt werden sollen. Das View Interface ist in Abbildung 38 aufgefhrt.

48

4.1. Anwendungsfall Analysen verwalten

AnalysisEditorView BaseView +Widget getViewWidget() +Boolean confirmEdit(String message) +HasClickHandlers getAddAnalysisButton() +SimplePager<Analysis> getPager() +CellTable<Analysis> getTable() +EditAnalysisBox getEditAnalysisBox() +Integer getDefaultPageSize()

Abbildung 38 - Klassendiagram des View Interface

Die Implementierung des Views wird vom Basisview BaseViewImpl abgeleitet womit der gesamte View als Composite erstellt wird. Die Definition der durch das Interface definierten Eigenschaften ist in Listing 28 aufgefhrt.
final Button addAnalysisButton = new Button("Add Analysis"); final CellTable<Analysis> analysisTable = new CellTable<Analysis>(); Integer defaultPageSize = 18; final SimplePager<Analysis> pager = new SimplePager<Analysis>(analysisTable); EditAnalysisBox editAnalysisBox = new EditAnalysisBox();
Listing 28 - Definition der Eigenschaften der AnalysisEditorView Klasse

Um die einzelnen Elemente auf der Benutzeroberflche auszurichten, wird ein DockLayoutPanel mit EM als Einheit verwendet. Dessen nrdlicher Teil, welcher den Kopf des Views darstellt, wird auf eine Hhe von zwei EM gesetzt und enthlt die berschrift. Der sdliche Teil, welcher den Fu des Views darstellt, enthlt den Pager, mit welchem ber die einzelnen Seiten der Tabelle navigiert werden kann, sowie die Schaltflche zum Hinzufgen einer neuen Analyse, und ist fnf EM hoch. Damit beide untereinander angeordnet werden, werden sie zu einem vertikalen Panel hinzugefgt. Der zentrale Teil des DockLayoutPanel enthlt die Tabelle, welche von einem ScrollPanel umschlossen wird. Damit ist sichergestellt, dass auch wenn der vorhandene Platz zu klein ist, um die gesamte Tabelle darstellen zu knnen, der Benutzer die Mglichkeit hat, mittels Balken den angezeigten Ausschnitt zu verndern. Abschlieend wird noch die initWidget(Widget w) Methode der Composite Klasse mit dem DockLayoutPanel als Parameter aufgerufen um das Composite zu initialisieren. In der Implementierung, der im Interface definierten Getter wird jeweils die entsprechende Eigenschaft zurckgegeben.

4.1.4. Erstellen des Presenters


Die Grundstruktur des Presenters wird, wie in den Kapiteln 2.5.2 und 3.5.2 beschrieben, umgesetzt. Als Eigenschaften enthlt dieser die fr die Entitten Analysis, SampleType, Parameter und Department definierten RPC Services. Diese werden von mvp4g durch Definieren eines zugehrigen Setters, welcher mit @InjectService notiert ist, automatisch initialisiert. Weiters besitzt der Presenter drei assoziative Arrays, in welchen die jeweiligen Auswahlmglichkeiten fr die Abteilungen, Parameter und Probentypen
49

4.1. Anwendungsfall Analysen verwalten

gespeichert werden. Als Schlssel dient dabei der in den Entitten definierte Primrschlssel vom Typ Long. Um die Eintrge in der angezeigten Tabelle sortieren zu knnen, sind weiters die Eigenschaften currentSortProperty vom Typ String und currentSortDesc vom Typ Boolean definiert, welche festlegen, nach welchem Kriterium in welcher Richtung sortiert werden soll. Zu klientseitigen Validierung der eingegeben Werte enthlt der Presenter eine Eigenschaft namens analysisValidator vom Typ IValidator<Analysis>. Um nach der Initialisierung des Presenters diesen an seinen View zu binden, wird die bind() Methode berschrieben. Darin werden zuerst die Klick Handler der Schaltflchen des Views und des darin enthaltenen Formulars durch Aufruf der privaten Methode bindEditBox() registriert, wobei bei einem Klick auf die Add Analysis Schaltflche ein leeres Formular mit der Methode view.getEditAnalysisBox().showNew() angezeigt wird. Bei einem Klick auf die Cancel Schaltflche des Formulars wird dieses durch Aufruf der Methode view.getEditAnalysisBox().hide() ausgeblendet. Beim Bettigen der Save Schaltflche wird die private Methode saveAnalysis() des Presenters aufgerufen, welche das Speichern der Analyse in der Datenbank durchfhrt. Weiters werden in der bind() Methode durch Aufruf der Methode addColumns() die Spalten der Tabelle erzeugt. Die fr die Anzeige der Eigenschaften name, estimatedTime, estimatedCost und determinedParameters zustndigen Spalten werden als einfache Textspalten definiert. Da die Tabelle, bei einem Klick auf den Kopf der Analysennamenspalte, nach den Namen der Analyse sortiert werden soll, besitzt diese einen speziellen Kopf vom Typ SortableHeader [SRC10]. Dieser zeigt automatisch einen Pfeil an, welcher angibt, in welche Richtung die Eigenschaft sortiert wird. Um auf den Klick auf diesen Kopf reagieren zu knnen, wird dem Header ein ValueUpdater bergeben. Dessen Methode update() wird bei jedem Klick automatisch aufgerufen. Darin wird mittels toogleReverseSort() die Sortierrichtung gendert und der Name der Eigenschaft sowie die neue Richtung in die Klasseneigenschaften currentSortProperty und currentSortDesc bertragen. Anschlieend wird die Tabelle sowie deren Header Zellen aktualisiert. Dieser Vorgang ist in Listing 29 aufgezeigt.
final SortableHeader nameHeader = new SortableHeader("Name", "name"); nameHeader.setSorted(true); nameHeader.setUpdater(new ValueUpdater<String>() { @Override public void update(String value) { nameHeader.toggleReverseSort(); currentSortProperty = nameHeader.getPropertyName(); currentSortDesc = nameHeader.getReverseSort(); view.getTable().refresh(); view.getTable().refreshHeaders(); } }); view.getTable().addColumn(new TextColumn<Analysis>() { @Override 50

4.1. Anwendungsfall Analysen verwalten

public String getValue(Analysis object) { return object.getName(); } }, nameHeader);


Listing 29 - Definition der Analysennamenspalte

Zur Anzeige, ob eine Analyse aktiv ist, wird eine Spalte vom Typ Column<Analysis, Boolean> verwendet, welcher als Zelle eine CheckBoxCell bergeben wird. Zum Anzeigen der Edit Schaltflche in jeder Zeile wird eine Spalte vom Typ Column<Analysis, String> mit einer Zelle vom Typ ButtonCell verwendet. Der Zellentext wird mittels der berschriebenen getValue() Methode definiert, in welcher Edit zurckgegeben wird. Dieser Wert wird von der ButtonCell verwendet, um die Beschriftung der Schaltflche zu zeichnen. Um auf das Bettigen der Edit Schaltflchen zu reagieren, wird der Spalte ein FieldUpdater bergeben. Bei jedem Klick auf eine der Schaltflchen wird nun automatisch von der Tabelle die berschriebene update Methode des FieldUpdater aufgerufen, welche als Parameter die dieser Zeile entsprechende Analyse bergeben bekommt. Darin wird das Formular im Editiermodus durch Aufruf der Methode view.getEditAnalysisBox().showEdit(Analysis a) angezeigt. Nach der Definition der Tabellenspalten wird nun der Delegate definiert, welchen die Tabelle benutzt, um die anzuzeigenden Daten vom Server zu laden. Dies erfolgt innerhalb der Methode setDelegate() des Presenters. Hierin wird der Tabelle mittels der setDelegate() Methode ein Objekt vom Typ Delegate<Analysis> bergeben, wobei dessen onRangeChanged() Methode berschrieben wird. Darin wird aus der bergebenen ListView<Analysis> mittels der Methode getRange() ein Range Objekt erhalten, welches definiert, welchen Satz an Daten die Tabelle bentigt. Dies ist durch dessen Eigenschaften start und length festgelegt, welche ber ihre jeweiligen Getter ausgelesen werden knnen. Um die Analysen nun vom Server abzurufen, wird die Methode getAllAnalysis() des AnalysisService aufgerufen. Dieser werden zum einen die beiden Eigenschaften des Range Objektes, sowie die Eigenschaft und Richtung der Sortierung, als auch ein Objekt vom Typ AsyncCallback<List<Analysis>> bergeben. Serverseitig wird die Methode findAllWithParametersAndDepartment() des fr die Analysen definierten Datenzugriffobjektes inklusive der Anzahl an bentigten Daten sowie der Sortierungsdefinition aufgerufen. Dieses ldt, durch Ausfhren eines HQL Queries die Daten aus der Datenbank und gibt sie als Liste an Analysen zurck. Dabei werden durch den join fetch Befehl automatisch die zu jeder Analyse zugehrigen Parameter initialisiert. Da, aufgrund der in Kapitel 3.3.1 aufgefhrten Problematik, die Probentypen der Analysenobjekte nicht direkt geladen werden knnen, wird anschlieend ber die gesamte Liste iteriert und fr jedes Objekt die size() Methode der Liste, welche die Probentypen enthlt, aufgerufen. Die gesamte Implementierung des serverseitigen Aufrufs ist in Listing 30 aufgefhrt.
@Override public List<Analysis> getAllAnalysis(int start, int length, String sortBy, boolean desc) { 51

4.1. Anwendungsfall Analysen verwalten

Session session = HibernateUtil.getSession(); analysisDao.setSession(session); List<Analysis> result = analysisDao.findAllWithParametersAndDepartment(start, length, sortBy, desc); for (Analysis a : result) { a.getValidSampleTypes().size(); } session.close(); return result; }
Listing 30 - Serveraufruf zum Laden von Analysen aus der Datenbank

Die Liste wird nun dem klientseitigen Teil der Applikation als Parameter der onSuccess() Methode, des dem Aufruf bergebenen AsyncCallback Objekts bergeben. Um diese in die Tabelle zu laden, wird die Liste zusammen mit den Werten aus dem Range Objekt an die setData() Methode der Tabelle bergeben. Anschlieend wird die Tabelle durch einen Aufruf der Methode redraw() neu gezeichnet. Der klientseitige Teil zur Definition des Delegaten ist in Listing 31 aufgefhrt.
view.getTable().setDelegate(new Delegate<Analysis>() { @Override public void onRangeChanged(ListView<Analysis> listView) { final Range r = listView.getRange(); analysisService.getAllAnalysis(r.getStart(), r.getLength(), currentSortProperty, currentSortDesc, new AsyncCall<List<Analysis>>() { @Override protected void onSuccessE(List<Analysis> result) { view.getTable().setData(r.getStart(), r.getLength(), result); view.getTable().redraw(); } }); } });
Listing 31 - Definition des Delegaten der Analysentabelle

Der Presenter abonniert das Event ShowAnalysisManagement, welches bei einem Klick auf den Analysis Management Eintrag im Hauptmen der Applikation vom RootPresenter ausgelst wird. Darin wird zuerst der derzeit angezeigte View ausgeblendet und der neue View angezeigt. Anschlieend werden die, fr die Definition der Parameter, Abteilung und Probentypen einer Analyse, bentigten Auswahlmglichkeiten aus der Datenbank geladen. Dies erfolgt durch drei separate RPC Aufrufe in der Methode refreshChoices(). Hierbei werden alle bisher definierten Parameter, Abteilungen und Probentypen geladen und zu spterer Verwendung in den entsprechenden assoziativen Listen abgespeichert. Anschlieend werden die in der Tabelle anzuzeigenden Daten aus der Datenbank geladen. Hierfr wird zuerst mittels der
52

4.1. Anwendungsfall Analysen verwalten

getAnalysisCount() Methode des Analysenservices abgefragt, wie viele Analysen derzeit definiert sind. Dieser Wert wird verwendet, um die Gesamtseitenzahl der Tabelle festzulegen und, falls weniger Analysen definiert sind als auf einer Seite der Tabelle angezeigt werden knnen, den Pager auszublenden. Anschlieend wird die Tabelle mittels der refresh() Methode mit Daten gefllt. Die refresh() Methode verwendet den zuvor definierten Delegaten um die Daten zu laden. Der Ablauf, von der Anzeige des Views bis zum aktualisieren der Tabelle ist in Form eines Squenzdiagrames in Abbildung 39 aufgezeigt.

Abbildung 39 - Sequenzdiagram zum Anzeigen der Analysendefinition

4.1.5. Validieren und Speichern der Eingaben


Sobald der Benutzer ein Formular zum Erstellen oder ndern einer Analyse mittels der Save Schaltflche schliet, lst dies die Methode saveAnalysis() des Presenters aus. In dieser wird, abhngig davon, ob eine neue Analyse angelegt oder eine bereits bestehende bearbeitet wurde, entweder ein neues Analysenobjekt erstellt oder die bearbeitete mittels der getAnalysis() Methode des Formulars geladen. Anschlieend werden alle im Formular eingegebene Werte in die jeweilige Eigenschaft des Analysenobjektes bertragen. Um zu berprfen, ob die Daten valide sind, wird das Objekt der validate() Methode des als Klasseneigenschaft definierten Validator analysisValidator bergeben. Dieser gibt, analog zur serverseitigen Validierung, eine Liste an Validierungsfehlern zurck. Ist die Validierung einer oder mehrerer Eigenschaften fehlgeschlagen, wird ber die gesamte Liste iteriert. Mittels der getItemName() Methode des Validierungsfehlerobjektes erhlt man den Namen der Eigenschaft und mit der getMessage() Methode den Validierungsfehler. Diese beiden Werte werden, zur
53

4.1. Anwendungsfall Analysen verwalten

Anzeige, der showError() Methode des Formulars bergeben und damit dem Anwender angezeigt. Anschlieend wird das Speichern abgebrochen. Verluft die Validierung erfolgreich, wird die saveOrUpdateAnalysis Methode des Analysenservices aufgerufen, welche abhngig davon, ob die Analyse schon existiert, sie in der Datenbank aktualisiert oder einen neuen Eintrag anlegt. Verluft das Speichern der Analyse erfolgreich, wird das Formular ausgeblendet und die Tabelle neu geladen. Der Validierungsvorgang sowie das Speichern der Analyse ist in Listing 32 aufgezeigt.

54

4.2. Anwendungsfall Analysen Planen

Set<InvalidConstraint<Analysis>> analysisErrors = analysisValidator.validate(tempAnalysis); if (analysisErrors.size() > 0) { for (InvalidConstraint<Analysis> ic : analysisErrors) { editBox.showError(ic.getItemName(), ic.getMessage()); } return; } analysisService.saveOrUpdateAnalysis(tempAnalysis, new AsyncCall<Void>() { @Override public void onSuccessE(Void result) { view.getEditAnalysisBox().hide(); refreshData(); } });
Listing 32 - Validieren und Speichern einer Analyse

Die Umsetzung, des implementierten Anwendungsfalles ist in Abbildung 40 aufgezeigt.

Abbildung 40 - Umsetzung des Anwendungsfalls Analysen verwalten

4.2. Anwendungsfall Analysen Planen


Bei der Umsetzung dieses Anwendungsfalles soll aufgezeigt werden, wie Daten dynamisch beim Ausklappen eines Baumknoten aus der Datenbank im Backend geladen werden knnen. Weiters wird gezeigt, wie mit dem Auswahlmodell der CellTable Klasse gearbeitet wird.

55

4.2. Anwendungsfall Analysen Planen

4.2.1. Kurzbeschreibung des Anwendungsfalles


Vor der realen Analyse von Proben sollen Analysen im LIMS System geplant werden. Durch diese Planung wird festgelegt, welche Analysen an welchen Proben eines Auftrages durchzufhren sind. Jedoch kann nicht jede Analyse an jeder Probe durchgefhrt werden, sondern nur die fr diesen Typ im Anwendungsfall Analysen Verwalten definierten. Beim durchlaufen des Anwendungsfalles soll der Benutzer die Mglichkeit erhalten, aus einer Liste an Proben, welche nach dem Auftrag, welchem sie zugeordnet sind, gruppiert werden, jene auszuwhlen, zu welchen Analysen geplant werden sollen. In einer zweiten Liste sollen die fr die gewhlten Proben mglichen Analysen aufgelistet werden, aus denen der Benutzer die zu planenden auswhlen kann. Durch einen Klick auf eine Schaltflche Add Analysis sollen die gewhlten Analysen zu den gewhlten Proben hinzugefgt werden. Optional soll noch die Mglichkeit bestehen, eine Deadline anzugeben, welche aussagt, bis wann die Analysen fertiggestellt werden sollen.

4.2.2. Umsetzung im Domnenmodell


Um diesen Anwendungsfall im Domnenmodell umsetzen zu knnen, wird die Entitten AnalysisResult und ParameterResult definiert. Jedes Analysenergebnis besitzt eine Referenz auf die zugehrige Analyse und Probe und enthlt eine Liste an Parameterergebnissen welche durch Instanzen der Klasse ParameterResult reprsentiert werden. Die Klasse ParameterResult dient zur Speicherung der Ergebnisse der bestimmten Parameter und besitzt eine Referenz auf den zugehrigen Parameter, sowie dem Analysenergebnis. Das zugehrige Klassendiagram ist in Abbildung 41 aufgefhrt.

Analysis -id -name -doneIn: Department 1..* -estimatedTime: Double -estimatedCost -sops: List<SOP> -validSampleTypes: List<SampleType> -determinedParameters: List<Parameter> -active: Boolean 1 Parameter -id: Integer 1..* -name: String -unit: String -analysis: List<Analysis> -type: String -parameterResults: List<ParameterResult> 1

AbstractSample -id: Integer -code: String 1 -sampleType: SampleType -description: String -origin: String -samplingDateTime: Date -analysisResults: List<AnalysisResults> -storagePlace: String

AnalysisResult 0..* -id: Integer -sample: AbstractSample -analysis: Analysis 0..* 1 -assignedBy: LabStaff -assignedAt: Date -deadline: Date -startAt: Date -state: String -parameterResults: List<ParameterResult> -completedAt: Date

ParameterResult 0..*
-id: Integer -parameter: Parameter -measuredAt: Date 1..* -measuredBy: Operator -labValBy: Operator -labValAt: Date -scientValBy: LabStaff -scientValAt: Date -state: String -analysisResult: AnalysisResult

Abbildung 41 - Klassendiagram der Enitten

56

4.2. Anwendungsfall Analysen Planen

4.2.3. Erstellen des Views


Um den Anwendungsfall umzusetzen, enthlt der View einen Baum, in welchem die Proben nach Auftrgen gruppiert werden, wobei jeder Knoten einen Auftrag darstellt und jeder Ast eine Probe. Zum Anzeigen der Analysen wird eine Tabelle vom Typ CellTable<Analysis> verwendet. Um die Auswahl der Deadline einer Analyse zu ermglichen, wird eine eigene Eingabebox erstellt, welche einen DatePicker verwendet um die Eingabe des Datums zu ermglichen. Weiters enthlt der View noch ein Beschriftungsfeld, welches angezeigt wird, falls keine Analysen fr alle ausgewhlten Probentypen definiert sind. Zustzlich eine Schaltflche namens Add Analysis welche das Planen der Analysen auslst und eine weitere benutzerdefinierte Komponente, welche, basierend auf einer CellTable die derzeit fr eine Probe geplanten Analysen anzeigt. Das Klassendiagram des Views ist in Abbildung 38 aufgezeigt.

AnalysisPlaningView BaseView +Widget getViewWidget() +Boolean confirmEdit(String message) +Tree getSamplesTree() +CellTable<Analysis> getAnalysisList() +Label getNoAnalysisAvailableLabel() +HasClickHandlers getPlanAnalysisButton() +SelectDeadlineBox getSelectDeadlineBox() +ShowPlaningBox getPlaningBox()

Abbildung 42 - Klassendiagram des View Interfaces fr den Anwendungsfall Analysen Planen

Die Anordnung der Elemente am Bildschirm soll so erfolgen, dass der Baum sich im linken und die Analysenliste im rechten Teil der Seite befindet. Die Add Analysis Schaltflche soll im unteren Teil angezeigt werden. Im oberen Teil der Seite soll die Seitenbeschriftung platziert werden Um dies umzusetzen,wird wiederum ein Panel vom Typ DockLayoutPanel basierend auf der Einheit EM verwendet. Die Beschriftung und die Schaltflche werden jeweils zum nrdlichen und sdlichen Teil des Panels mit einer definierten Hhe von drei EM eingefgt. Die Analysenliste wird mit einem ScrollPanel umschlossen und dieses zum stlichen Teil des Panels mit einer definierten Breite von 25EM hinzugefgt. Der sich ebenfalls in einem ScrollPanel befindliche Baum bildet die zentrale Komponente der Ansicht und nimmt den gesamten noch zur Verfgung stehenden Platz ein. Die Implementierung des Views ist in Listing 33 aufgefhrt.
private final Tree samplesTree = new Tree(); private final CellTable<Analysis> analysisTable = new CellTable<Analysis>(); private final Label noAnalysisDefined = new Label("No Analysis found for the selection"); private final SelectDeadlineBox deadlineBox = new SelectDeadlineBox(); private final ShowPlaningBox planingBox = new ShowPlaningBox(); private Button addAnalysis = new Button("Add Analysis"); public AnalysisPlaningViewImpl() { DockLayoutPanel content = new DockLayoutPanel(Unit.EM); 57

4.2. Anwendungsfall Analysen Planen

content.setStyleName("mainContent"); Label header = new Label("Analysis Planing"); header.setStyleName("viewHeader"); content.addNorth(header, 3); VerticalPanel vpAnalysisPanel = new VerticalPanel(); vpAnalysisPanel.add(noAnalysisDefined); ScrollPanel spAnalysisTable = new ScrollPanel(); spAnalysisTable.add(analysisTable); vpAnalysisPanel.add(spAnalysisTable); content.addEast(vpAnalysisPanel, 25); content.addSouth(addAnalysis, 3); ScrollPanel spSamplesTree = new ScrollPanel(); spSamplesTree.add(samplesTree); content.add(spSamplesTree); initWidget(content); }
Listing 33 - Implementierung des Views des Anwendungsfalles Analysen planen

4.2.4. Erstellen des Presenters


Um im Presenter zu erfassen, welche Proben und Analysen ausgewhlt werden enthlt er als Eigenschaft zwei Objekte vom Typ MultiSelectionModel. Diese knnen zu einer CellTable hinzugefgt werden und ermglichen anschlieend automatisch die Auswahl eines oder mehrerer Elemente der Tabelle. Die Definition und Initialisierung der beiden Auswahlmodelle ist in Listing 34 aufgefhrt.
private MultiSelectionModel<AbstractSample> sampleSelection = new MultiSelectionModel<AbstractSample>(); private MultiSelectionModel<Analysis> analysisSelection = new MultiSelectionModel<Analysis>();
Listing 34 - Definition der Auswahlmodelle

Um den Presenter an den zuvor erstellten View zu binden, wird wiederum die bind() Methode berschrieben. Hierin wird zuerst die Tabelle, welche die Analysen enthlt, mit Spalten versehen. Die erste Spalte ist vom Typ SelectionColumn[SRC10] ,mit welcher ein Auswahlfeld in jeder Zeile angezeigt wird, womit spter die Selektion bestimmter Analysen erfolgt. In zwei weiteren Spalten vom Type TextColumn werden der Name sowie die zugehrige Abteilung der Analyse angezeigt. Um die Tabelle mit Daten zu fllen, kommt wiederum ein Delegate zum Einsatz. Da die angezeigten Analysen abhngig von den Probentypen der ausgewhlten Proben sind, werden hierin zuerst die Probentypen aller gewhlten Proben in einer Liste gespeichert und diese anschlieend der Methode getAnalysisForSampleTypes des Analysen RPC Services bergeben. Diese verwendet wiederum die findAllForSampleTypes Methode des Analysen
58

4.2. Anwendungsfall Analysen Planen

Datenzugriffsobjektes. In diesem werden die, fr jeden Probentyp definierten, Analysen ausgelesen und mit ihnen ein dynamisches HQL Query erstellt. Um nur die Analysen zu finden, welche an allen gewhlten Probentypen mglich sind, wird ber alle, fr jeden bergebenen Probentyp definierten, Analysen iteriert. Jeder Satz an Analysen bildet einen eigenen in Teil des HQL Queries. Die einzelnen Teile werden mit einer Und Verknpfung zusammengesetzt. Damit ist sichergestellt, dass nur die Analysen abgefragt werden, welche an allen gewhlten Probentypen durchgefhrt werden knnen. Sollte fr einen Probentyp noch keine Analysen definiert worden sein, gibt die Abfrage automatisch eine leere Liste an Analysen zurck. Die Implementierung dieses Verfahrens ist in Listing 35 aufgezeigt.
public List<Analysis> findAllForSampleTypes(List<SampleType> sampleTypes) { String whereClause = ""; for (SampleType st : sampleTypes) { whereClause += " a.id in ("; if (st.getPossibleAnalysis().size() == 0) { whereClause = ""; break; } for (Analysis a : st.getPossibleAnalysis()) { whereClause += a.getId() + ", "; } whereClause = whereClause.substring(0, whereClause.length() - 2); whereClause += ") and"; } if (!whereClause.isEmpty()) whereClause = whereClause.substring(0, whereClause.length() - 4); else return new ArrayList<Analysis>(); Query q = this.getSession().createQuery("select distinct a from Analysis a where " + whereClause + " order by a.doneIn.abbreviation, a.name"); return q.list(); }
Listing 35 - Abfrage der Analysen nach Probentypen

Da die Liste an mglichen Analysen nicht in Seiten unterteilt wird, werden die Daten so in die Tabelle geschrieben, dass immer alle Eintrge angezeigt werden. Dazu wird zuerst die Seitengre auf die Anzahl der zurckgegebenen Analysen gesetzt und anschlieend die gesamte Liste der setData() Methode bergeben. Mittels der redraw() Methode wird die Tabelle schlielich neu gezeichnet. Dieser Vorgang ist in Listing 36 aufgefhrt.
view.getAnalysisList().setPageSize(result.size()); view.getAnalysisList().setData(0, result.size(), result); view.getAnalysisList().redraw();
Listing 36 - Fllen einer Tabelle ohne Paging

59

4.2. Anwendungsfall Analysen Planen

Im nchsten Schritt wird ein Handler auf das ffnen eines Baumknotens des Auftragsbaumes registriert. Hierin werden die zu einem Auftrag zugeordneten Proben beim ffnen des Knotens aus der Datenbank geladen und in einer Tabelle angezeigt. Hierbei wird zuerst aus dem bergebenen Event der Knoten ausgelesen welcher geffnet wurde, und alle darin enthaltenen Unterelemente entfernt. Anschlieend wird zur Anzeige und Auswahl der Proben eine Tabelle vom Typ CellTable<AbstractSample> erstellt. Diese enthlt wiederum als erste Spalte eine SelectionColumn mit welcher die Auswahl der Elemente durchgefhrt werden kann. In den weiteren Spalten, welche als Textspalten umgesetzt werden, sollen Details wie Nummer und Beschreibung, der Proben angezeigt werden. Um die Tabelle mit Daten zu fllen wird wiederum ein Delegate verwendet. Dieser greift auf die Methode getAllSamplesReadyForAnalysisByRequest des Proben RPC Services zurck, um nur die Proben zu laden, welche den Status Erhalten oder Gemischt (fr Mischungen) haben und damit bereit fr die Analyse sind. Zum Setzen der Daten in der Tabelle wird wiederum die in Listing 36 aufgezeigte Methode ohne Paging verwendet. Um die Liste an Analysen automatisch bei Auswahl einer oder mehrerer Proben zu aktualisieren, wird ein Handler auf das SelectionChange Event des Proben Auswahlmodels registriert. In diesem wird lediglich die refresh() Methode der Analysenliste aufgerufen, welche automatisch eine Aktualisierung der fr die derzeitige Auswahl gltigen Analysen auslst. Um die eigentliche Planung der Analysen durchfhren zu knnen, wird ein Handler auf das Klick Event der Add Analysis Schaltflche registriert,in welchem, sofern eine Analyse oder Probe ausgewhlt ist, die Box zu Eingabe der Deadline eingeblendet wird. Auf deren OK Schaltflche ist wiederum ein Klick Handler registriert, welcher das eigentliche Planen der Analysen auslst. Dieses wird im Presenter mittels der createPlaningForSelection() Methode durchgefhrt. Darin wird fr jede gewhlte Analyse und Probe ein neues Objekt vom Typ AnalysisResult erstellt und in einer Liste gespeichert. ber dessen Eigenschaften sample und analysis wird das Objekt mit der jeweiligen Analyse und Probe verknpft. Anschlieend wird die gesamte Liste der saveNewAnalysisResults Methode des Analysenergebnis RPC Services bergeben. Am Server werden die einzelnen Analysenergebnisse in der Datenbank gespeichert. Weiters werden fr alle der Analyse zugeordneten Parameter neue Objekte vom Typ ParameterResult erstellt, mit der Analyse verknpft, und wiederum in der Datenbank gespeichert. Um die betroffenen Proben als zur Analyse bereit zu markieren, wird deren Status in In Analyzing gendert. Nachdem die neuen Analysen in der Datenbank gespeichert wurden, werden noch clientseitig die einzelnen Listen zur Anzeige der Probendetails aktualisiert, sowie die zuvor gettigte Auswahl an Proben und Analysen gelscht. Um die Ansicht beim Neuanzeigen des Views in den Ursprungszustand zu versetzten, werden im entsprechenden Event zuerst alle Knoten des Baumes entfernt und die Auswahlmodelle der Analysen und Proben gelehrt. Anschlieend werden die Auftrge mittels der getAllRequests Methode des Auftrags RPC Services aus der Datenbank geladen und fr jeden Auftrag ein eigener Baumknoten erstellt. Um in spterer Folge auf das Auftragobjekt, welches durch den Knoten reprsentiert wird, zugreifen zu knnen, wird dieses in der userObjekt Eigenschaft des Knotens gespeichert. Um anzuzeigen, dass der Knoten Unterelemente enthlt ohne jedoch diese zuvor laden zu mssen, wird

60

4.3. Anwendungsfall Ergebnisse eingeben

dem Knoten ein Unterknoten mit dem Text hinzugefgt. Beim Ausklappen des Auftragsknotens wird dieser automatisch in dem zuvor beschriebenen Vorgang entfernt. In Abbildung 43 ist der umgesetzte Anwendungsfall aufgezeigt.

Abbildung 43 - Umsetzung des Anwendungsfalles Analysen Planen

4.3. Anwendungsfall Ergebnisse eingeben


An der Umsetzung dieses Anwendungsfalles wird aufgezeigt, wie fr das CellTable Widget eine benutzerdefinierte Spalte erstellt wird, welche abhngig von einer Eigenschaft des dargestellten Objekts ein Texteingabefeld oder eine Auswahlliste anzeigt.

4.3.1. Kurzbeschreibung des Anwendungsfalles


Sobald eine Analyse beendet ist, sollen die Ergebnisse manuell ins LIMS System eingetragen werden knnen. Dazu soll fr jeden Parameter der Analyse ein Eingabefeld zu Verfgung stehen. Da im System vier verschiedene Arten an Parameter definiert sind, sollen die Eingabefelder typspezifisch aufgebaut sein. Fr einen Textparameter soll ein Texteingabefeld angezeigt werden, welches die Eingabe aller Zeichen zulsst. Fr einen Zahlenparameter soll ein Eingabefeld, welches nur die Eingabe von Zahlen zulsst, angezeigt werden. Gleichfalls soll fr einen Datumsparameter nur ein Datumswert im Feld akzeptiert werden. Fr einen booleschen Parameter soll eine Auswahlliste mit den Eintrgen Yes und No dargestellt werden. Um es den Benutzer einfach zu gestalten, die analysierte Probe im System zu finden, sollen die Proben wiederum nach Auftrgen gruppiert in einer Baumstruktur angezeigt werden.

4.3.2. Umsetzung im Domnenmodell


Zur Umsetzung der verschiedenen Typen an Parametern wurde im Domnenmodell fr jeden Typ eine eigene Klasse erstellt, welche die Eigenschaft result enthlt. Jeder dieser Klassen ist von der abstrakten Basisklasse ParameterResult abgeleitet, welche alle,
61

4.3. Anwendungsfall Ergebnisse eingeben

nicht typspezifischen Eigenschaften enthlt. Das Klassendiagram dieser Klassen ist in Abbildung 44 aufgezeigt.

ParameterResult
-id: Integer -parameter: Parameter -measuredAt: Date -measuredBy: Operator -labValBy: Operator -labValAt: Date -scientValBy: LabStaff -scientValAt: Date -state: String -analysisResult: AnalysisResult

TextParameterResult -result: String

BooleanParameterResult -result: Boolean

NumberParameterResult -result: Double

DateParameterResult -result: Date

Abbildung 44 - Domnenklassen des Ergebnisse eingeben Anwendungsfalles

4.3.3. Erstellen des Views


Bei der Umsetzung dieses Anwendungsfalles enthlt der View nur einen Baum, zu welchem im Presenter dynamisch einzelnen Knoten fr Auftrge, Proben und Analysen hinzugefgt werden. Der Baum wird wiederum mittels eines DockLayoutPanel auf der Benutzeroberflche angeordnet. Um in der CellTable, welche zur Eingabe der Parameterergebnisse dient, in einer Spalte Felder, abhngig von einer Eigenschaft der dargestellten Entitt zu erzeugen, muss eine spezieller Zelltyp erstellt werden. Auf diesen Vorgang wird in weiterer Folge nher eingegangen. Es wird zuerst eine neue Klasse namens ParameterResultCell erstellt, welche von der abstrakten Basisklasse AbstractCell<ParameterResult> ableitet. Diese enthlt eine Eigenschaft namens editPossible vom Typ Boolean mit welcher definiert werden kann, ob die Zelle das Editieren ihres Inhaltes zulsst. In der berschriebenen render Methode wird nun abhngig vom Typ des anzuzeigenden Parameterergebnisses ein Textfeld oder eine Auswahlliste als HTML mittels des bergeben StringBuilder gerendert. Falls das Editieren nicht erlaubt ist, wird das bergebene Objekt als simple Zeichenkette gerendert. Der in Listing 37 angefhrte Ausschnitt der Methode zeigt das Rendern einer einfachen Zeichenkette sowie eine Eingabebox jeweils abhngig vom Typ und Status des bergebenen Ergebnisses. Dieser Vorgang wird analog fr die weiteren mglichen Typen durchgefhrt.

62

4.3. Anwendungsfall Ergebnisse eingeben

public void render(ParameterResult value, Object viewData, StringBuilder sb) { if (!value.getState().equals("In Analyzing") || !editPossible) { sb.append(value.toString()); return; } if (value instanceof TextParameterResult) { TextParameterResult result = (TextParameterResult) value; sb.append("<input type='text'"); if (result.getResult() != null) { sb.append(" value='" + result.getResult() + "'"); } sb.append("></input>"); } else if (value instanceof NumberParameterResult) { NumberParameterResult result = (NumberParameterResult) value; sb.append("<input type='text'"); if (result.getResult() != null) { sb.append(" value='" + result.getResult() + "'"); } sb.append("></input>"); } }
Listing 37 - Typabhngiges Rendern des Inhaltes einer Zelle

Nun zeigt die Zelle zwar abhngig vom Typ das korrekte Eingabefeld an, jedoch kann ein neu eingegebener oder genderter Wert noch nicht in das angezeigte Objekt bernommen werden. Um dies zu erreichen, muss die Zelle auf den change Event reagieren, welcher geworfen wird, sobald das Eingabefeld den Eingabefokus verliert und sich dessen Inhalt gendert hat. Hierfr wird zum einen die Methode consumesEvents() so berschrieben, dass sie immer true zurckgibt. Damit wird der Spalte, welche die Zelle enthlt, signalisiert, dass sie Browser Events an die Zelle weitergeben soll. Weiters wird die onBrowserEvent Methode berschrieben welche automatisch das dazugehrige Ergebnisobjekt, den Typ des aufgetretenen Events, das Element welches das Event ausgelst und einen ValueUpdater bergeben bekommt. In dieser Methode kann nun, abhngig vom bergeben Typ des Parameterergebnisses der Wert des Eingabefeldes ausgelesen und validiert werden. Um dies durchzufhren wird zuerst berprft, ob der bergebene ValueUpdater nicht null ist und ob der aufgetretene Event vom Typ change ist. Ist beides der Fall, kann mittels der getFirstChild().cast() Methode des bergebenen Elementes auf das Eingabefeld zugegriffen werden. Deren Inhalt wird mittels der Methode getValue() abgefragt und in das Ergebnisfeld des Parameterergebnisses gespeichert. Anschlieend muss die update Funktion des bergebenen ValueUpdater mit dem genderten Objekt als Parameter aufgerufen werden um die nderungen zu bernehmen. Dieser Vorgang ist in Listing 38 am Beispiel eines Parameterergebnisses vom Typ Text aufgezeigt.
public Object onBrowserEvent(Element parent, ParameterResult value, Object viewData, NativeEvent event, ValueUpdater<ParameterResult> valueUpdater) { if (value instanceof TextParameterResult) { TextParameterResult result = (TextParameterResult) value; if (valueUpdater != null && "change".equals(event.getType())) { InputElement input = parent.getFirstChild().cast(); 63

4.3. Anwendungsfall Ergebnisse eingeben

result.setResult(input.getValue()); valueUpdater.update(result); } }

Listing 38 - Speichern eines Parameterergebnisses

Fr alle weiteren Typen an Ergebnissen wird dieser Vorgang analog ausgefhrt. Dabei wird der in der Zelle enthaltene Text mittels spezifischer Umwandlungsmethoden in den korrekten Datentyp konvertiert. Schlgt diese Umwandlung fehl, wird mittels der statischen Window.alert() Methode eine Fehlermeldung ausgegeben. Die eigentliche Verwendung dieser neuen Zelle wird im nchsten Abschnitt aufgezeigt.

4.3.4. Erstellen des Presenters


Der Aufbau des Presenters erfolgt im Prinzip analog zum Anwendungsfall Analysen Planen, jedoch entfllt die Liste der Analysen, und Proben werden nicht als Tabelle sondern als eigene Baumknoten angezeigt. Beim Aufklappen einer Probe werden die geplanten Analysen sowie deren Parametereingabefelder in einer Tabelle angezeigt. Diese Tabelle enthlt vier Spalten. In der ersten wird der Name des Parameters als Text angezeigt. Die zweite Spalte dient als Eingabefeld fr das Messdatum des Parameters. Diese basiert auf einer benutzerdefinierten Zelle namens MeasurementTimeCell. In dieser wird analog zur ParameterResultCell die Eingabe und Validierung des Messdatums durchgefhrt. Die dritte Spalte dient zur Eingabe der Analysenergebnisse und verwendet die zuvor beschriebene ParameterResultCell. In der letzten Spalte wird in jeder Zeile eine Schaltflche angezeigt, mit welcher die eingegebenen Daten gespeichert werden knnen. Um die beiden benutzerdefinierten Zellen zu verwenden, mssen sie in einer Spalte vom Typ Column<ParameterResult, ParameterResult> zum Einsatz kommen. Damit wird die Spalte so konfiguriert, dass sie das gesamte bergebene Objekt an die Zelle zur Anzeige weiterreicht. Hierfr muss weiters in der berschriebenen getValue Methode das gesamte bergebene Objekt zurckgegeben werden. Um neu eingegebene Werte im jeweiligen Zeilenobjekt speichern zu knnen, muss zu der Spalte ein Aktualisierter, vom Typ FieldUpdater<ParameterResult, ParameterResult> ,hinzugefgt werden. In dessen berschriebener update Methode wird das Zeilenobjekt gleich dem genderten Objekt gesetzt. Der Quellcode zu diesem Vorgang ist in Listing 39 aufgefhrt.
Column<ParameterResult, ParameterResult> resultCol = new Column<ParameterResult, ParameterResult>(new ParameterResultCell(true)) { @Override public ParameterResult getValue(ParameterResult object) { if (object.getMeasuredAt() == null) object.setMeasuredAt(new Date()); return object; } }; table.addColumn(resultCol, "Result"); 64

4.3. Anwendungsfall Ergebnisse eingeben

resultCol.setFieldUpdater(new FieldUpdater<ParameterResult, ParameterResult>() { @Override public void update(int index, ParameterResult object, ParameterResult value) { object = value; } );
Listing 39 - Anwendung der ParameterResultCell

Die weitere Realisierung des Presenters folgt im Prinzip der in den beiden vorherigen Kapiteln besprochenen Vorgehensweise und wird daher hier nicht aufgezeigt. Der umgesetzte Anwendungsfall ist in Abbildung 45 abgebildet.

Abbildung 45 - Umsetzung des Anwendungsfalles Ergebnisse eingeben

5. Zusammenfassung
Zusammenfassend lsst sich sagen, dass ungefhr 90% der zuvor spezifizierten Anwendungsflle in einem Zeitraum von drei Wochen implementiert werden knnen. Damit kann generell die Aussage getroffen werden, dass sich der Google Web Toolkit sehr gut fr die schnelle Entwicklung skalierender Webanwendungen eignet. Hierbei muss jedoch strikt darauf geachtet werden, dass das Model-View-Presenter Muster sowie die Trennung der Applikation in drei Schichten eingehalten wird, da es ansonsten sehr schnell zu unbersichtlichen Quellcode kommt. Teilweise musste, vor allem bei der Entwicklung der Presenter zum simplen Erstellen, Speichern und Editieren von Entitten viel hnlicher Code erstellt werden, welcher sich jedoch nicht in einem Basis Presenter generisch implementieren lie. Hier sollte jedoch die, mit der Version 2.1 des Toolkit
65

4.3. Anwendungsfall Ergebnisse eingeben

kommende Integration in Spring Roo, eine Verbesserung mit sich bringen, da damit eine solche Grundstruktur fr jede Entitt der Applikation automatisch generiert werden kann. Schlussendlich ist anzumerken, dass die hier aufgezeigten Vor- und Nachteile des Google Web Toolkits nicht nur auf LIMS Systeme beschrnkt, sondern auch auf hnliche Informations -Managementsysteme angewandt werden knnen.

6. Ausblick
In weiterer Folge soll, basierend auf der im Zuge dieser Arbeit erstellten Applikation, ein Open Source Projekt gestartet werden dessen Ziel es ist, eine offene und freie LIMS Lsung fr kleine und mittelstndische Auftragslabors anzubieten. Bevor dies jedoch durchgefhrt werden kann, muss die Implementierung der verbleibenden Anwendungsflle durchgefhrt, als auch eine Website zur Vermarktung erstellt werden.

66

Anhang

Anhang
Anhang 1 Klassendiagram der Datenzugriffsschicht

67

Anhang

Anhang 2 Klassendiagram der Serviceschicht

68

Anhang

Abbildungsverzeichnis
Abbildung 1 - Struktur eines GWT Projektes .......................................................... 6 Abbildung 2 - RPC Klassendiagram[GWT10] ............................................................. 9 Abbildung 3 - Stack Panel .................................................................................... 12 Abbildung 4 - Horizontal Panel ............................................................................. 12 Abbildung 5 - Vertical Panel ................................................................................. 12 Abbildung 6 - Flow Panel...................................................................................... 12 Abbildung 7 - Dock Panel [GWT10] .......................................................................... 12 Abbildung 8 - Tab Panel ....................................................................................... 12 Abbildung 9 - Disclosure Panel ............................................................................ 12 Abbildung 10 - Screenshot des Layouts ............................................................... 13 Abbildung 11 Button [GWT10]................................................................................ 14 Abbildung 12 - CheckBox [GWT10] .......................................................................... 14 Abbildung 13 - DatePicker [GWT10] ......................................................................... 14 Abbildung 14 - TextBox [GWT10].............................................................................. 14 Abbildung 15 - ListBox [GWT10] ............................................................................... 14 Abbildung 16 - Tree [GWT10] ................................................................................... 14 Abbildung 17 - SuggestBox .................................................................................. 14 Abbildung 18 - Flex Table..................................................................................... 14 Abbildung 19 - DialogBox ..................................................................................... 15 Abbildung 20 - Vererbungshierarchie der Cell Klassen ........................................ 18 Abbildung 21 - Abhngigkeiten des MVP Models [MVP09] ...................................... 22 Abbildung 22 - Klassendiagram "mvp4g" EventBus - View Presenter ............... 24 Abbildung 23 - Klassendiagram des Domnenmodels ......................................... 26 Abbildung 24 - Klassendiagram der "Customer" Datenzugriffsklasse .................. 29 Abbildung 25 - Funktionsweise von Gilead [GWH10] ................................................ 31 Abbildung 26 - Design der Benutzeroberflche .................................................... 37 Abbildung 27 - Men mit gleichmig verteilten Eintrgen .................................. 38 Abbildung 28 - Men mit bndig verteilten Eintrgen ........................................... 39 Abbildung 29 - Umsetzung des Applikationslayouts ............................................. 39 Abbildung 30 - Umsetzung der View Implementierung ......................................... 40 Abbildung 31 - Sequenzdiagram des Startvorganges der Applikation .................. 41 Abbildung 32 - Klassendiagram der "Analysis" Entitt ......................................... 44 Abbildung 33 Klassendiagram des TextInputField ............................................ 45 Abbildung 34 Klassendiagram des DropDownInputField .................................. 45 Abbildung 35 - Klassendiagram der SelectManyBox ............................................ 46
69

Anhang

Abbildung 36 - Klassendiagram der EditAnalysisBox ........................................... 47 Abbildung 37 - Formular zum Erstellen einer neuen Analyse ............................... 48 Abbildung 38 - Klassendiagram des View Interface ............................................. 49 Abbildung 39 - Sequenzdiagram zum Anzeigen der Analysendefinition .............. 53 Abbildung 40 - Umsetzung des Anwendungsfalls Analysen verwalten ................ 55 Abbildung 41 - Klassendiagram der Enitten ....................................................... 56 Abbildung 42 - Klassendiagram des View Interfaces fr den Anwendungsfall Analysen Planen ........................................................................................... 57 Abbildung 43 - Umsetzung des Anwendungsfalles Analysen Planen................... 61 Abbildung 44 - Domnenklassen des Ergebnisse eingeben Anwendungsfalles .. 62 Abbildung 45 - Umsetzung des Anwendungsfalles Ergebnisse eingeben ............ 65

70

Anhang

Tabellenverzeichnis
Tabelle 1 - bersicht der in GWT untersttzten Java Klassen [GWT10]..................... 5 Tabelle 2 - GWT Implementierung von JRE Klassen [GWT10] ................................... 6 Tabelle 3 - Von RPC serialisierbare Typen .......................................................... 10 Tabelle 4 - GWT Panel bersicht ......................................................................... 12 Tabelle 5 - bersicht der wichtigsten Standardwidgets ........................................ 14 Tabelle 6 - Das Cell<C> Interface ........................................................................ 17 Tabelle 7 - Umsetzung der drei Schichten Architektur ......................................... 25

71

Anhang

Quelltextverzeichnis
Listing 1 - Inhalt der Demo.gwt.xml ........................................................................ 7 Listing 2 - Synchrones Serviceinterface ................................................................. 8 Listing 3 - Asynchrones Serviceinterface ............................................................... 8 Listing 4 - Definition eines Servlets in der web.xml ................................................ 9 Listing 5 - Erzeugen und durchfhren eines RPC Aufrufes .................................. 10 Listing 6 - Erstellen eines Applikationslayouts ...................................................... 13 Listing 7 - Erstellung eines Composite Widgets ................................................... 16 Listing 8 - Erzeugen einer CellTable .................................................................. 19 Listing 9 - Definition der Spalten einer CellTable ............................................... 20 Listing 10 - Spalten zu einer CellTable hinzufgen ............................................ 20 Listing 11 - Datenmanagement einer CellTable festlegen.................................. 20 Listing 12 - Erstellen und Verarbeiten eines Events ............................................. 24 Listing 13 - Configuration von Hibernate .............................................................. 27 Listing 14 - Initialisierung des Gilead Bean Managers .......................................... 32 Listing 15 - HQL Join Fetch Syntax ...................................................................... 32 Listing 16 - HQL simultanes Laden von zwei Assoziationen ................................ 32 Listing 17 - Definition der Departments Eigenschaft ............................................. 33 Listing 18 - Kopf der Department Serviceklasse ................................................... 34 Listing 19 - Auslesen aller angelegten Abteilungen .............................................. 35 Listing 20 - Speichern der nderungen an einer Abteilung in der Datenbank ...... 35 Listing 21 - Verwendung des ServerValidators..................................................... 36 Listing 22 - Erstellen des DockLayoutPanels ....................................................... 37 Listing 23 - Einbinden des Logos in das Applikationslayout ................................. 38 Listing 24 - Einfgen eines Meneintrages .......................................................... 39 Listing 25 - Entfernen des zentralen Widgets des Applikationspanels ................. 42 Listing 26 - Umschalten des derzeit sichtbaren Views ......................................... 42 Listing 27 - Definition der Eigenschaften der EditAnalysisBox Klasse .................. 47 Listing 28 - Definition der Eigenschaften der AnalysisEditorView Klasse ............. 49 Listing 29 - Definition der Analysennamenspalte.................................................. 51 Listing 30 - Serveraufruf zum Laden von Analysen aus der Datenbank ............... 52 Listing 31 - Definition des Delegaten der Analysentabelle ................................... 52 Listing 32 - Validieren und Speichern einer Analyse ............................................ 55 Listing 33 - Implementierung des Views des Anwendungsfalles Analysen planen 58 Listing 34 - Definition der Auswahlmodelle ........................................................... 58 Listing 35 - Abfrage der Analysen nach Probentypen .......................................... 59
72

Anhang

Listing 36 - Fllen einer Tabelle ohne Paging ...................................................... 59 Listing 37 - Typabhngiges Rendern des Inhaltes einer Zelle .............................. 63 Listing 38 - Speichern eines Parameterergebnisses ............................................ 64 Listing 39 - Anwendung der ParameterResultCell ................................................ 65

73

Anhang

Literaturverzeichnis
Bcher
[GWT08] Sowa, H., Marinschek, M., Radinger, W. Google Web Toolkit Ajax-Anwendungen einfach und schnell entwickeln, 1. Auflage, Heidelberg: dpunkt.verlag

Internet
[GWT10] Getting Started - Google Web Toolkit - Google Code. Online im Internet: http://code.google.com/intl/de/webtoolkit/doc/latest/tutorial/gettingstarted.html (Stand 25.06.2010) GWT for Business - Google Web Toolkit - Google Code. Online im Internet: http://code.google.com/webtoolkit/business.html (Stand 25.06.2010) Using GWT with Hibernate - Google Web Toolkit - Google Code. Online im Internet: http://code.google.com/intl/de/webtoolkit/articles/using_gwt_with_hibernate.html (Stand 25.06.2010) Home Gilead. Online im Internet: http://noon.gilead.free.fr/gilead/ (Stand 25.06.2010) Apache License, Version 2.0 - The Apache Software Foundation. Online im Internet: http://www.apache.org/licenses/LICENSE-2.0.html (Stand 25.06.2010) Code and Be >> Blog Archive >> Optimizing startup time for GWT hosted mode. Online im Internet: http://robvanmaris.jteam.nl/2007/11/30/optimizing-startup-timefor-gwt-hosted-mode/ (Stand 25.06.2010) Serialisierung. Online im Internet: http://msdn.microsoft.com/dede/library/7ay27kt9%28VS.80%29.aspx (Stand 25.06.2010) google-web-toolkit - Revision 8320: /javadoc/2.0. Online im Internet: http://googleweb-toolkit.googlecode.com/svn/javadoc/2.0/ (Stand 25.06.2010) Google Web Toolkit Architecture: Best Practices For Architecting Your GWT App. Online im Internet: http://code.google.com/events/io/2009/sessions/GoogleWebToolkitBestPractices.ht ml (Stand 25.06.2010) Large scale application development and MVP - Google Web Toolkit - Google Code. Online im Internet: http://code.google.com/webtoolkit/articles/mvparchitecture.html (Stand 25.06.2010) Session Hibernate3.2.5 API Documentation and Javadoc. Online im Internet: http://www.jdocs.com/hibernate/3.2.5/org/hibernate/Session.html (Stand 25.06.2010) The Java Community Process(SM) Program - JSRs: Java Specification Requests detail JSR# 303. Online im Internet: http://jcp.org/en/jsr/detail?id=303 (Stand 26.06.2010)

[GWB10] [GWH10]

[GIL10] [APA10] [CAM10]

[MSN10] [SVN10] [MVP09]

[MVP10]

[HBN10]

[JSR10]

74

Anhang

[GVL10] [SRC10]

gwt-validation - Project Hosting on Google Code. Online http://code.google.com/p/gwt-validation/ (Stand 26.06.2010)

im

Internet:

google-web-toolkit - Project Hosting on Google Code - SVN Online im Internet: http://code.google.com/p/google-web-toolkit/source/browse/?r=8320 (Stand 26.06.2010, Revision 8320)

75

You might also like