Details

Details und links zum Thema GWT / Requestfactory

Dieser Beitrag ist aus der Notwendigkeit heraus entstanden, dass ich den Kommunikationsteil meiner GWT / GAE Applikation mit GWT-RPC implementiert habe, dann aber relativ schnell an die Grenzen dieser Implementierung gestoßen bin.

Die GWT-RPC Implementation ist einfach zu implementieren und einfach zu verstehen - es ist bei weitem nicht so viel "Magic" dabei wie bei der RequestFactory. Nachdem ich die RPC Kommunikation eingebaut hatte war ich wirklich begeistert, wie schnell und einfach das Ganze über die Bühnen gegangen ist.

Da ich als nächsten Schritt die Server bzw. Client-Validation machen wollte, habe ich ein wenig recherchiert und habe mich für die aktuell JSR 303 bean validation entschieden. JSR 303 hat sicher Zukunft bei GWT und die Unterstützung für das GWT-Editor-Framework scheint ja auch ziemlich weit oben auf der GWT ToDo-Liste zu stehen.

Allerdings haben die Probleme genau hier angefangen. 

Annotations vs. TOs

Ohne Annotations klappt der Datentransfer problemlos, mit Annotation, und die sind nun mal für die Verification notwendig, wird jede Menge Zusatzcode per RPC übertragen und genau hier scheitert RPC.

Die Bedingungen, die notwendig sind um ein Objekt mit RPC zu serialisieren, kurz gesagt ein reines TO-Object, beschränken sich vorwiegend auf primitive Datentypen.

Wenn bei dem zu serialisierendem Objekt aber die ganzen Verification-Notationen dabei sind, kommt es zu dem Problem das auf Stackoverflow nachzulesen ist.

Implementation der RF

Prinzipiell gibt es bei der RequestFactory zwei Möglichkeiten die Basisfunktionalität (also was mit dem transferierten Objekt gemacht werden soll) zu implementieren.

Die erste Variante implementiert die Funktionalität als statische Funktion direkt im betreffenden Objekt selbst. Diese Variante wird auch im GWT Tutorial gezeigt.

Die zweite Variante läuft über einen sogenannten Entity- bzw. ServiceLocator. Aus meiner Sicht ist die zweite Variante zu bevorzugen, da damit eine bessere Kapselung möglich ist.

Projektstruktur + wer macht was

Projektstruktur

Die Person-Klasse ist im Prinzip das TO-Objekt. Im Prinzip - denn bei der RF wird ja nicht das TO-Objekt übertragen sondern die Kommunikation läuft über die entsprechende Proxy-Klasse. 

Hier fällt auch gleich eine Besonderheit auf - diese Person-Klasse befindet sich nur im Server-Bereich. Daran sieht man also auch, dass die Server-Seite und die Client-Seite unabhängig voneinander implementiert sind bzw. funktionieren können. 

In diesem Beispiel erbt Person von DatastorObject - der Grund ist, dass die Applikation für die ich die Tests gemacht habe, Ojectify verwendet. Ein interessantes Sample dazu ist hier zu finden.

PersonDAO implementiert die CRUD Funktionen für die Person-Klasse.

PersonRequestFactory definiert die  Verbindung zwischen PersonDAO und dem DAOServiceLocator.

Die PersonRequestFactory wird also beim Starten der Applikation angelegt und dient in weiterer Folge zum Erstellen des Request-Contexts. Wie man sieht ist sowohl die RequestFactory, als auch der RequestContext, jeweils ein Interface.

PersonProxy - da die Client- und die Serverseite durch die RF sauber getrennt sind, wird auf der Clientseite nicht das Person-Objekt direkt verwendet, sonder es wird über den RequestContext ein PersonProxy-Objekt erzeugt.  Über dieses Proxy-Objekt werden die Daten per Getter und Setter gesetzt bzw. gelesen. Genau aus diesem Grund muss das Person-Object nicht GWT kompatibel sein.

PersonProxy dient als Verbindung zwischen Person und UniversalEntityLocator.

Wichtig ist hier, dass jedes Proxy-Objekt dem Context zugewiesen ist von dem es erzeugt worden ist. 

Nur Proxy-Objekte die mit RequestContext.create() erstellt worden sind, sind editierbar (mutabel), kommt es vom Server retour ist es nicht veränderbar. Wenn das Proxy-Objekt nicht editierbar ist, kann es mit der edit() Funktion editierbar gemacht werden.

Ab dem Zeitpunkt, zu dem über die fire()-Funktion des RequestContexts die gewünschte Funktion aufgerufen wird (hier persistPerson), ist der RequestContext nicht mehr gültig.

Hier gilt die Grundregel: für jedes "fire" ein eigener RequestContext.

Ablaufdiagramm für "Save"

Sooo - und jetzt wünschen ich nur noch viel Spaß und Erfolg mit der RF.

Kommentare