Sauber getrennt ist halb gewonnen

Java Server Faces bieten dank Komponentenbaum und Action-/Eventhandling ein Programmiermodell, das stark an jenes klassischer Desktop-Anwendungen angelehnt ist. Tauscht man für das Rendering zusätzlich die im Standard enthaltene HTML-Bibliothek und JSP gegen alternative Techniken aus, gelingt eine klare Trennung von Seitenbeschreibung und Design sowie ein weiterer Schritt in Richtung Desktop-Look&Feel.

In Pocket speichern vorlesen Druckansicht 2 Kommentare lesen
Lesezeit: 5 Min.
Von
  • Detlef Bartetzko
  • Arvid Hülsebus
  • Lars Röwekamp
  • Udo Schnurpfeil

In den ersten beiden Teilen des Tutorials dienten Java Server Pages (JSP) als Grundlage für das Erstellen und die Darstellung der JSF-Views. Dieses initiale Vorgehen ergibt vor allem für Entwickler Sinn, die sich bereits mit dieser Programmierschnittstelle beschäftigt haben - also nahezu jeden, der schon einmal eine Java-basierte Webanwendung gebaut hat. Diesem Vorteil steht gegenüber, dass es bei der vermischten Verwendung von JSP und JSF nicht selten zu „unangenehmen“ Nebeneffekten kommt, die sich vornehmlich durch den voneinander abweichenden Life Cycle der beiden Techniken ergeben (siehe auch Kasten „Java Server Faces 1.2“ in der Print-Version).

Der vorliegende dritte Teil des Tutorials nimmt sich daher möglicher View-Alternativen im Umfeld der Java Server Faces an und stellt neben einer Open-Source-Lösung namens Facelets von Jacob Hookum das aus dem Apache-MyFaces-Umfeld stammende Framework Tobago vor. Beide Lösungen zusammen bringen einen erheblichen Mehrwert gegenüber der Standardkombination JSF/JSP mit sich. Das Adressbuch aus den vorherigen Tutorials wurde erweitert und angepasst und dient als durchgängiges Beispiel. Erhältlich sind die Quellen wie üblich über den iX-Listingsserver.

Darüber hinaus zeigt ein Ausblick auf die nächste Generation der Java Server Faces (JSF 1.2), dass die Expert Group das Problem der voneinander abweichenden Life Cycles ebenfalls erkannt hat.

Obwohl JSP oft als Standardtechnik für das Rendering von JSF-Seiten gilt und die meisten veröffentlichen Beispiele darauf zurückgreifen, weist diese Vorgehensweise einige Nachteile auf. Rendert eine JSP eine JSF-Seite, müssen während deren Verarbeitung zwei Dinge passieren: Zum einen muss das Framework den JSF-Komponentenbaum erzeugen und zum anderen die einzelnen Komponenten darstellen. Diese beiden Vorgänge laufen verwoben ab. Das bedeutet, eine Komponente wird in der Regel erzeugt und im Anschluss gerendert. Abhängigkeiten zwischen den Komponenten können hier leicht zu Problemen führen, da mitunter eine benötigte Komponente beim Rendering noch nicht erzeugt wurde.

JSF bietet zwar die Möglichkeit, das Rendering von Kindkomponenten der umgebenden Vaterkomponente zu überlassen, dies reicht aber nicht immer aus und bereitet weitere Schwierigkeiten: Verwendet der Programmierer auf der Java Server Page zusätzlich zu den Tags normalen HTML-Code, ist die Ausgabereihenfolge beim Rendering von Kindern durch den Vater nicht immer einfach nachzuvollziehen. Während die JSP den HTML-Code im Allgemeinen sofort zum Client schickt, kann sie das Rendering eines vorgelagerten oder eines umgebenden Tags durchaus herauszögern. Damit entspricht die deklarierte Reihenfolge auf der JSP-Seite nicht mehr der Ausgabereihenfolge auf dem Client.

Seit der Version 2.0 enthält die JSP-Spezifikation Tag Files, mit denen sich in der Anwendung häufig verwendeter JSP-Code kapseln lässt. Über an ein Tag File gebundene Attribute und Variablen ist der Inhalt parametrisierbar. Dieser Template-Mechanismus arbeitet ebenfalls nicht ausreichend mit JSF zusammen. Die meisten JSF-Tag-Libraries unterbinden wie die HTML-Standard-Bibliothek aus Sicherheitsgründen die Laufzeitevaluierung von Attributen. Aus diesem Grund können die übergebenen Attribute und Variablen des Template nicht in JSF-Method- oder Value Bindings verwendet werden. Dies schränkt die Parametrisierbarkeit von JSF-Fragmenten in Tag Files in der Regel zu stark ein.

Eine Lösung für die genannten Hürden bietet Facelets von Jacob Hookum. Dieses JSF-Framework für View-Definitionen ist Open Source und beinhaltet bereits einige Neuerungen der kommenden JSF-1.2-Spezifikation. Das Tutorial verwendet die Version 1.0.14.

Der vom Framework verfolgte Ansatz unterscheidet sich stark von der Realisierung mit JSP. Während JSP mit Hilfe von Tag-Klassen dynamischen Output und als Nebeneffekt die Komponenten erzeugt, trennt Facelets den Prozess in zwei Schritte: Zunächst erzeugt das Framework den kompletten Komponentenbaum auf der Basis einer XML-Seitenbeschreibung. An diesen Baum delegiert es dann das Rendering. Der Programmierer muss dafür keine eigenen Tag-Klassen schreiben, da das Framework die JSF-Komponenten direkt nutzt.

Das wesentliche Ergebnis eines Facelet-Aufrufs ist immer ein vollständiger Komponentenbaum. JSF-Output-Komponenten kapseln automatisch alle Elemente, für die nicht explizit eine Komponente angegeben ist - etwa HTML-Quellcode.

Für den Anwender bieten sich mit Facelets unter anderem die folgenden Vorteile:

  • Facelets verfügen über einen flexiblen, konfigurationsarmen Template-Mechanismus.
  • Häufig verwendete Teile des View lassen sich für die Wiederverwendung auf einfache Weise zu eigenen Tags zusammenfassen.
  • Das Framework unterstützt die komplette Expression Language (EL) inklusive der Funktionsaufrufe. Zudem vereinheitlicht es die EL von JSP und JSF und erlaubt das Inlining von EL-Ausdrücken.
  • Präzise Fehlermeldungen auf der Ebene von Zeilen, Tags und Attributen erleichtern das Debugging.
  • Übersetzungsanweisungen (jsfc) unterstützen Webeditoren analog zum Apache Tapestry-Framework (jakar ta.apache.org/tapestry/).

Die folgenden Ausführungen gehen auf die ersten drei Punkte näher ein.

Der Artikel geht auf die ersten drei Punkte näher ein. Außerdem beschreibt er, wie das Apache-Framework Tobago die Eigenschaften von JSF dahin gehend erweitert, dass Entwickler professionelle Webanwendungen mit wenig Aufwand schreiben können.

Mehr Infos

iX-TRACT

  • Nutzt man in JSF-Anwendungen für die Darstellung der Desktop-Komponenten Alternativen zu den im Framework enthaltenen Renderkits von HTML und JSP, kann man das Design klar von der Seitenbeschreibung trennen.
  • Sowohl Jacob Hookums Open Source Framework Facelets als auch das Apache-Projekt Tobago erlauben Entwicklern von Webanwendungen, ohne Aufwand ausgabeunabhängige Applikationen zu schreiben.
  • In Kombination mit ergänzenden Bibliotheken und der Vereinheitlichung der Expression Languages von JSP und JSF in der Version 1.2 der Java Server Faces hat das Web-Framework gute Aussichten, sich als Standard zu etablieren.

Teil 1: Grundlagen und generelle Funktionsweise der Java Server Faces

Teil 2: Fortgeschrittene JSF-Techniken und die Integration mit Spring und Struts

Mehr Infos

Listing 1

Ausschnitt des Seiten-Template der Beispielanwendung

<ui:composition>
<f:view locale="#{controller.language}">
<tc:page label="#{title}" ...>
...
<f:facet name="menuBar">
<ui:insert name="menuBar">
<ui:include src="/composition/menu.xml"/>
</ui:insert>
</f:facet>
<ui:insert name="toolbar">
<ui:include src="/composition/toolbar.xml"/>
</ui:insert>
<ui:insert name="content"/>
...
<ui:insert name="footer">
<ui:include src="/composition/footer.xml"/>
</ui:insert>
</tc:page>
</f:view>
</ui:composition>
Mehr Infos

Listing 2

Vereinfachter Ausschnitt der Editor-Seite

<ui:composition template="/composition/page.xml">
<ui:param name="title" value="Adressbucheditor"/>
<ui:define name="content">
...

<tc:box ...>
...

<tc:tabGroup>
<tc:tab label="Persönlich">
<ui:include src="/composition/tab/personal.xml"/>
</tc:tab>
<tc:tab label="Geschäftlich" ...>
<ui:include src="/composition/tab/business.xml"/>
</tc:tab>
</tc:tabGroup>
...

</tc:box>
</ui:define>
</ui:composition>
Mehr Infos

Listing 3

Definition des Tags buttonPanel in der Datei buttonPanel.xml

<ui:composition>
<tc:panel>
...
<tc:button action="#{bean[actionOk]}" label="#{labelOk}"
defaultCommand="true"/>
<tc:button action="#{bean[actionCancel]}"
label="#{labelCancel}" immediate="true"/>
</tc:panel>
</ui:composition>
Mehr Infos

Listing 4

Ausschnitt aus list.xml

<tc:sheet value="#{controller.addressRows}" var="row" 
showRowRange="left" showPageRange="right"
showDirectLinks="center">
<tc:column label="#{bundle.list_first_name}" sortable="true">
<tc:out value="#{row.address.firstName}" />
</tc:column>
<tc:column label="#{bundle.list_last_name}" sortable="true">
<tc:out value="#{row.address.lastName}" />
</tc:column>
</tc:sheet>
Mehr Infos

Listing 5

Ausschnitt aus editor.xml

<tc:tabGroup switchType="client">
<tc:tab label="#{bundle.editor_tab_personal}">
<ui:include src="/composition/tab/personal.xml"/>
</tc:tab>
<tc:tab label="#{bundle.editor_tab_business}" rendered="#{!controller.simple}">
<ui:include src="/composition/tab/business.xml"/>
</tc:tab>
</tc:tabGroup>
Mehr Infos

Listing 6

Ausschnitt aus composition/menu.xml

  <tc:menu label="#{bundle.menu_file}">
<tc:menuItem action="#{controller.createAddress}"
image="icon/contact-new.png"
label="#{bundle.menu_file_new}"
disabled="#{facesContext.viewRoot.viewId
!= '/list.xml'}"/>
</tc:menu>
<tc:menu label="#{bundle.menu_settings}">
<tc:menu label="#{bundle.menu_settings_language}" >
<tc:menuRadio value="#{controller.language}"
action="#{controller.languageChanged}">
<f:selectItems value="#{controller.languages}" />
</tc:menuRadio>
</tc:menu>
...
</tc:menu>
...
</tc:menuBar>
Mehr Infos

Listing 7

Ausschnitt aus composition/toolbar.xml

<tc:toolBar iconSize="big">
<tc:toolBarCommand action="#{controller.search}"
image="icon/address-book-32.png"
label="#{bundle.toolbar_address_list}"
immediate="true"
disabled="#{facesContext.viewRoot.viewId =='/list.xml'}"/>
...
</tc:toolBar>
Mehr Infos

Listing 8

Vereinfachter Ausschnitt aus composition/tab/personal.xml

<tc:panel>
<f:facet name="layout">
<tc:gridLayout columns="*" rows="fixed;fixed;fixed;*"/>
</f:facet>
<tf:in ... />
<tf:in ... />
<tf:in rendered="#{! controller.simple}" ... />
<tf:textarea ... />
</tc:panel>

(ka)