Wie GWT mit seinen Spielkameraden redet

GWT meets Ajax und PHP

Frank Wisniewski

Das Google Web Toolkit bietet eine Entwicklungsumgebung zur Erzeugung von RIAs auf Basis von Ajax. Das Herzstück bildet ein Compiler, der in Java geschriebenen clientseitigen Code nach JavaScript übersetzt. Durch Verwendung dieser Standardtechnologien stellt sich die Frage, inwiefern GWT in bereits vorhandene Lösungen integriert werden kann. Dieser Artikel beschreibt die diesbezüglichen Interna des Toolkits und arbeitet die entsprechenden Schnittstellen anhand von Beispielen heraus.

Java Magazin

Der Artikel „GWT meets Ajax und PHP“ von Frank Wisniewski ist erstmalig erschienen im

Java Magazin 10.2012

GWT [1] erleichtert Programmierern aus dem Java-Umfeld den Einstieg in die Entwicklung von Webanwendungen, indem serverseitige Anwendungslogik in Servlet-Container verpackt und für die Clientseite das JRE emuliert wird. Der Compiler versucht dann die entsprechenden Methoden bzw. Klassen in die Welt aus JavaScript, HTML und CSS zu übersetzen. Zusätzlich befinden sich im API Pakete, die der Manipulation von DOM-Elementen und der Erstellung von UI-Elementen dienen, jedoch der Java-Syntax gehorchen. Die einzelnen Vor- und Nachteile dieses Konzepts sollen hier nicht näher diskutiert werden (siehe [2] für eine kritische Einführung), es sei aber erwähnt, dass sich der Entwicklungsprozess einer Webanwendung mit GWT bspw. dank Debug-Werkzeugen und automatischer Syntax-Vervollständigung als durchaus komfortabel erweist [3]. Durch die Verwendung von Java kann der Entwickler die „native Implementierung“ des Clients außer Acht lassen, da GWT diese generiert. Sobald man allerdings den gesteckten technologischen Rahmen verlassen möchte, muss diese Abstraktionsschicht durchbrochen werden. Denn der Istzustand der meisten Webprojekte gibt bereits eine bestimmte Infrastruktur vor. So soll GWT-Funktionalität in einem bestehenden Webauftritt eingebettet und nicht eigens ein neuer Webserver mit Servlet-Container aufgesetzt werden. Auch soll das vorhandene Design bzw. Erscheinungsbild unverändert bleiben. Wie dies mit GWT geleistet werden kann soll im Folgenden gezeigt werden. Um die einzelnen Schnittstellen zur Anbindung an alternative Webtechnologien zu erklären, wird der Artikel folgende drei Aspekte behandeln:

  • Anpassung an vorhandene clientseitige Infrastruktur in Bezug auf Design und Layout
  • Aufruf und Einbinden von externem JavaScript und Exportieren von GWT-Funktionalität
  • Kommunikation mit einem alternativen Webserver ohne Servlet-Container

Analog zur Intention hinter dem Toolkit soll auch bei den weiteren Betrachtungen die Clientseite im Mittelpunkt stehen. Dieser Artikel setzt grundlegende Kenntnisse im Umgang mit GWT voraus. Nichtsdestotrotz möchte ich die elementaren Bestandteile des Zusammenspiels zwischen GWT und dem DOM im folgenden Abschnitt kurz skizzieren. Sollten Sie mit der Materie vertraut sein, können Sie ihn getrost überlesen.

GWT und das DOM

Um den technischen Details von GWT auf den Grund zu gehen, reicht ein Blick in die offizielle Dokumentation oft nicht aus. In diesen Fällen kommt dem Anwender zu Gute, dass GWT Open Source ist. Mit einem grundlegenden Verständnis, in welcher Klasse Google ein analoges Problem löst, findet man im Quelltext auch das „wie“. Auch weiterführende Informationen bzgl. der Architektur lassen sich leichter erschließen. Dies wird z. B. nötig, sobald eine neue Komponente nicht aus den vorhandenen Widgets zusammengesetzt werden kann. Das nach Google empfohlene Vorgehen ist, sich am Quelltext für die Klassen Button und TextBox zu orientieren und Implementierungen über JSNI möglichst zu vermeiden [4]. Im Folgenden wollen wir die Umsetzung von Button untersuchen.

Tipp

Bei direkter Manipulation des DOM über das API sind die Entwicklerwerkzeuge der modernen Webbrowser zu empfehlen. Chrome bietet von Hause aus Funktionalität zur Visualisierung des DOM und Syntax-Vervollständigung in der JavaScript-Konsole auch im „Hosted Mode“. Für Firefox bietet sich das Firebug Plug-in an [5], [6]. Insgesamt lässt sich so analysieren, ob GWT die DOM-Elemente korrekt einfügt bzw. modifiziert und welche Style Sheets auf ihnen greifen.

Im Package com.google.gwt.dom.client liegen die JavaScript Wrapper für den nativen Zugriff über das JavaScript Native Interface (JSNI) auf das DOM. Aufbauend auf dem Node-Objekt wird hier die gesamte Hierarchie abgebildet, wobei die Klasse Document den Wurzelknoten repräsentiert. Sie bietet Methoden zur Erstellung der Element-Unterklassen wie DivElement oder ButtonElement, welche wiederum typisierte Knotenobjekte darstellen. Auch das Event-System besitzt hier einen Grundbaustein, auf den aber in diesen Artikel nicht näher eingegangen wird.

Typisiert bedeutet in diesem Zusammenhang, dass einem Element über die Annotation TagName dem Tag des korrespondierenden HTML-Elements eindeutig zugeordnet wird. Bei einem Blick auf die Sourcen fällt auf, dass das Mapping nicht vollständig ist; es fehlen bspw. <code>, <i> und <b>. Welches Tag auf ein Element gemappt worden ist, lässt sich zur Laufzeit über getTag() herausfinden. Die eigentliche Funktionalität hinter den Methoden der Document-Klasse wird in der abstrakten Klasse DOMImpl implementiert. Der Code für browserspezifische Eigenheiten wird für jeden unterstützten Browser über „Deferred-Binding“ vom GWT jeweils einzeln kompiliert (siehe dazu offizielle Dokumentation) und ist in den Klassen zu finden, welche mit „DOMImpl…“ beginnen. Hierfür ein Beispiel aus Document.java:

public final DivElement createDivElement() {
  return (DivElement) DOMImpl.impl.createElement(this, DivElement.TAG);
}

Machen wir nun den Schritt in die „GWT-Welt“ und schauen uns das Paket com.google.gwt.user.client an. Als Ausgangspunkt dient die Klasse DOM, welche als Brücke für das hierarchische System von oben dient. Hier werden die Methoden aus Document gewrappt und zusätzliche Methoden wieder über Deferred-Binding in „Impl“-Klassen umgesetzt:

public static Element createDiv() {
  return Document.get().createDivElement().cast();
}

Daher sind die Getter für Element-Objekte wie z. B. getElementByID() von DOM, Document und RootPanel auch äquivalent. Doch wie sattelt ein Widget auf diesem Konstrukt auf und wie wird es in das Dokument eingebunden? Abbildung 1 illustriert exemplarisch die Vererbungshierarchie des Button Widgets und veranschaulicht zeitgleich die einzelnen Abstraktionsschichten des GWT.

Abb. 1: Vererbungshierarchie für das Button Widget

Als Grundlage bzw. Oberklasse für alle UI-Objekte des GWT dient das UIObject, ein Wrapper für ein Element aus dem DOM-Paket. Unterklassen können einmalig die protected-Methode setElement(…) aufrufen, um ihr HTML-Pendant zu definieren. Auch der Zugriff auf die Attribute des Elements – bspw. für die Ausmaße oder die Style Sheets – werden hier umgesetzt. Die nächste Ebene bilden die Klassen Widget bzw. FocusWidget. Hier wird das Event Handling eingebunden, indem entsprechende Schnittstellen mit Leben gefüllt werden, wobei letzteres seinen Unterklassen noch einen Konstruktor spendiert:

protected FocusWidget(Element elem) {
  setElement(elem);
}

Button und ButtonBase geben einem Widget schlussendlich Gestalt, dadurch dass sie über das Document ein ButtonElement instanziieren und das class-Attribut setzen. Listing 1 zeigt beispielhaft die Realisierung einiger Methoden aus dem Quelltext der beiden Klassen. Zum Programmieren eigener Komponenten sind neben dem Konstruktor die Setter-Methoden interessant, in denen der Inhalt des HTML-Elements gesetzt wird. Nun aber genug der grauen Theorie, im nächsten Abschnitt wenden wir uns einem konkreten Anwendungsfall zu, um dem Ganzen ein wenig Kontur zu geben.

Listing 1

public Button() {
  super(Document.get().createPushButtonElement());
  setStyleName("gwt-Button");
}
...
public void click() {
  getButtonElement().click();
}
  
protected ButtonElement getButtonElement() {
  return getElement().cast();
}

public void setHTML(String html) {
  getElement().setInnerHTML(html);
}

public void setHTML(SafeHtml html) {
  setHTML(html.asString());
}

public void setText(String text) {
  getElement().setInnerText(text);
}
Geschrieben von
Frank Wisniewski
Kommentare

Schreibe einen Kommentar

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