Loading...
 
  Überprüfen der Project-Stage(Variante 2)
 
  Überprüfen der Project-Stage (Variante 1)
 
  Zugriff auf eine Managed-Bean im Java-Code
 
  View-Parameter im Einsatz
 
  Templating-Hierarchie von MyGourmet
 
  Template-Client mit View-Parametern
 
  Template-Client mit mehreren Templates
 
  Template sideBox.xhtml
 
  Template mit View-Parametern
 
  Tag-Bibliothek mit einer EL-Funktion
 
  Tag-Bibliothek in der web.xml einbinden
 
  Project-Stage in web.xml setzen
 
  MyGourmet 12: Listenkonverter
 
  MyGourmet 12: Listener-Methode für ein System-Event
 
  MyGourmet 12: Einsatz des Listenkonverters
 
  MyGourmet 11: Template für Kundenseiten
 
  MyGourmet 11: Linke Seitenleiste
 
  MyGourmet 11: Kundenseite im Browser
 
  Java-Code der EL-Funktion
 
  h:link mit View-Parametern
 
  h:link im Einsatz
 
  Gerenderte Ausgabe von h:link
 
  Fragment für einen Seitenkopf
 
  faces-config.xml mit Spring-EL-Resolver
 
  Ersetzbare Bereiche des Templating-Beispiels
 
  EL-Funktion im Einsatz
 
  Einsatz mehrerer Konfigurationsdateien
 
  Einsatz des benutzerdefinierten Validator-Tags
 
  Einsatz des benutzerdefinierten Konverter-Tags
 
  Einfügen des Seitenkopfs mit ui:include
 
  Einbinden mehrerer Tag-Bibliotheken
 
  Deployment-Deskriptor von MyGourmet 1
 
  Definition eines Validator-Tags
 
  Definition eines Konverter-Tags
 
  Beispiele von Ressourcen
 
  Beispiel eines Templates in Facelets
 
  Beispiel eines Template-Clients in Facelets
 
  Applikationsobjekte anlegen

4 Advanced JSF

Nachdem in den vorangegangenen Kapiteln die Grundlagen von JSF im Mittelpunkt standen, wollen wir uns in diesem Kapitel den etwas weiterführenden Themen zuwenden.
Nach einer kurzen Vorstellung der in JSF 2.0 neu hinzugekommenen Project-Stage in Abschnitt [Sektion:  Project-Stage] zeigen wir Ihnen in Abschnitt [Sektion:  Advanced Facelets] erweiterte Aspekte von Facelets, die hauptsächlich die Wiederverwendung von Inhalten betreffen. Ein zentrales Thema für beinahe jedes Webprojekt ist Templating, das mit der Integration von Facelets nun endlich auch in den JSF-Standard Einzug gehalten hat. Abschnitt [Sektion:  Templating] zeigt, wie Templating mit Facelets funktioniert. Abschnitt [Sektion:  Bookmarks und GET-Anfragen in JSF] präsentiert ein weiteres, lang ersehntes Feature von JSF 2.0: die Unterstützung von GET-Anfragen und View-Parametern. Anschließend folgt in Abschnitt [Sektion:  Verwaltung von Ressourcen] eine kurze Einführung in die ebenfalls mit JSF 2.0 eingeführten Ressourcen. Abschließend werfen wir in Abschnitt [Sektion:  Die JSF-Umgebung: Faces-Context und External-Context] noch einen etwas ausführlicheren Blick auf den Faces-Context und den External-Context, bevor wir das Kapitel mit einigen Details der Konfiguration von JSF in Abschnitt [Sektion:  Konfiguration von JavaServer Faces] abschließen.
Damit die Praxis nicht zu kurz kommt, werden die vorgestellten Konzepte in den Beispielen MyGourmet 10 , MyGourmet 11 und MyGourmet 12 umgesetzt.

4.1 Project-Stage

Die in JSF 2.0 eingeführte Project-Stage ist an RAILS_ENV von Ruby on Rails angelehnt und bietet eine Möglichkeit, die aktuelle Phase des Projekts für die Entwicklung bereitzustellen. Die möglichen Werte sind in der Enum javax.faces.application.ProjectStage festgelegt und lauten folgendermaßen:
Die Projektphase kann auf folgende Arten auf einen der oben angeführten Werte gesetzt werden:
Mit dem Ausschnitt aus der web.xml in Listing Project-Stage in web.xml setzen wird die Project-Stage zum Beispiel auf den Wert Development gesetzt.
<context-param>
  <param-name>javax.faces.PROJECT_STAGE</param-name>
  <param-value>Development</param-value>
</context-param>
Zur Laufzeit wird die aktuelle Project-Stage im Application-Objekt abgelegt und kann mit der Methode getProjectStage() von dort ausgelesen werden. Listing Überprüfen der Project-Stage (Variante 1) zeigt ein kleines Codebeispiel.
FacesContext fc = FacesContext.getCurrentInstance();
Application a = fc.getApplication();
if (a.getProjectStage() == ProjectStage.Development) {
  // Beliebiger Code
}
Mit der Hilfsmethode isProjectStage(ProjectStage) im FacesContext lässt sich das vorherige Codefragment noch weiter vereinfachen. In Listing Überprüfen der Project-Stage(Variante 2) finden Sie ein Beispiel.
FacesContext fc = FacesContext.getCurrentInstance();
if (fc.isProjectStage(ProjectStage.Development)) {
  // Beliebiger Code
}
Wo benötigen Sie die neue Project-Stage-Eigenschaft? Überall dort, wo Sie Code abhängig von der aktuellen Projektphase ausführen wollen. In JSF 2.0 wird das bereits in der Spezifikation an einigen Stellen berücksichtigt.
Wenn die Project-Stage auf Development gesetzt ist, wird in jede Seite eine h:messages -Komponente eingefügt, falls diese nicht vorhanden ist. Damit wird verhindert, dass Validierungsfehler in Formularen unbemerkt bleiben.
Ein weiteres Beispiel findet sich beim Ressourcenmanagement. JSF cacht Ressourcen nur dann, wenn die Project-Stage auf Production gesetzt ist. Andernfalls werden sie bei jedem Zugriff neu geladen.
In MyFaces steuert die Project-Stage zusätzlich das Überprüfen von Seitendeklarationen auf Änderungen. Ist die Project-Stage auf Production gesetzt, aktualisiert Facelets Seitendeklarationen nach dem ersten Aufruf der Seite nicht mehr. Bei allen anderen Project-Stages werden Änderungen nach zwei Sekunden wieder berücksichtigt, was die Entwicklung erheblich vereinfacht. Mehr zu diesem Thema erfahren Sie in Abschnitt [Sektion:  Die Webkonfigurationsdatei web.xml] bei der Beschreibung des Kontextparameters javax.faces.FACELETS_REFRESH_PERIOD .
Die Project-Stage ist eine der kleineren neuen Features in JSF 2.0, wird aber bereits an einigen Stellen verwendet und bietet viel Potenzial für weitere Einsatzgebiete.

4.2 Advanced Facelets

In allen bisherigen Beispielen haben wir Facelets nur als Seitendeklarationssprache und bessere Alternative zu JSP eingesetzt. Facelets kann aber viel mehr und bietet eine breite Palette an Features, die das Leben eines JSF-Entwicklers einfacher machen. Im Laufe dieses Abschnitts werden wir einige davon vorstellen.
Facelets stellt dazu eine eigene Tag-Bibliothek mit dem Namensraum http://java.sun.com/jsf/facelets bereit. Üblicherweise wird diese Bibliothek mit dem Präfix ui in Seitendeklarationen eingebunden. Die wichtigsten Tags daraus werden wir im Rest dieses Abschnitts präsentieren.

4.2.1 Wiederverwendung von Inhalten mit Facelets

Facelets bietet Entwicklern die Möglichkeit, Ansichten modular aufzubauen und wiederkehrende Inhalte an zentraler Stelle zu definieren. Das dafür grundlegende Konzept sind die sogenannten Kompositionen, die einen Teil eines Komponentenbaums gruppieren.
Facelets kann eine Ansicht aus einer beliebigen Anzahl von Kompositionen aufbauen, die jeweils in einem eigenen XHTML-Dokument deklariert sind. Trifft Facelets beim Aufbau des Komponentenbaums auf ein ui:include -Tag, wird das Dokument mit dem im Attribut src angegebenen Dateinamen in die Ansicht mit aufgenommen. Der Pfad des Dokuments kann absolut oder relativ zur aktuellen Ansicht angegeben sein.
Sehen wir uns das im Kontext von MyGourmet an. Listing Fragment für einen Seitenkopf definiert eine Komposition für einen Seitenkopf, der unter /WEB-INF/includes/header.xhtml abgelegt ist.
In Listing Einfügen des Seitenkopfs mit ui:include sehen Sie den Ausschnitt der Seitendeklaration showCustomer.xhtml mit dem über ui:include eingefügten Seitenkopf. Das Tag ui:param übergibt den Text für die Überschrift zweiter Ordnung als Parameter an das eingefügte Seitenfragment - doch dazu später mehr.
Wie funktioniert in Facelets die Zusammensetzung der Deklaration showCustomer.xhtml mit dem eingefügten Fragment header.xhtml ? Wie Sie vielleicht bemerkt haben, handelt es sich bei beiden Dateien um komplette XHTML-Dokumente. Es soll allerdings nur ein einziges Dokument an den Browser geschickt werden. Des Rätsels Lösung liegt darin, wie Facelets das Tag ui:composition behandelt - es ignoriert beim Einfügen des Seitenfragments sämtliche Inhalte außerhalb des Tags ui:composition .
Der Parameter pageTitle ermöglicht eine individuelle Definition der Überschrift bei jedem Einfügen des Fragments. Werfen Sie nochmals einen Blick auf Listing Fragment für einen Seitenkopf , dann sehen Sie die Verwendung dieses Parameters. Mit dem EL-Ausdruck #{pageTitle} wird der Wert direkt im h2 -Element ausgewertet.
<html xmlns="http://www.w3.org/1999/xhtml"
    xmlns:h="http://java.sun.com/jsf/html"
    xmlns:ui="http://java.sun.com/jsf/facelets">
<head><title>MyGourmet header</title></head>
<body>
  <ui:composition>
    <h:panelGroup style="width: 100; height: 40px;"
        layout="block">
      <h:graphicImage value="/images/logo.png"
          style="float: left;"/>
      <h1 style="display: inline; margin-left: 5px;">
        #{msgs.title_main}
      </h1>
    </h:panelGroup>
    <h2>#{pageTitle}</h2>
  </ui:composition>
</body>
</html>
<html xmlns="http://www.w3.org/1999/xhtml"
    xmlns:f="http://java.sun.com/jsf/core"
    xmlns:h="http://java.sun.com/jsf/html"
    xmlns:ui="http://java.sun.com/jsf/facelets">
  <head>
    <title>#{msgs.title_main}</title>
  </head>
  <body>
    <ui:include src="/WEB-INF/includes/header.xhtml">
      <ui:param name="pageTitle"
          value="#{msgs.title_show_customer}"/>
    </ui:include>
    ...
  </body>
</html>
Das ui:component -Tag bietet die gleiche Funktionalität wie das Tag ui:composition - im Komponentenbaum wird aber zusätzlich eine Wurzelkomponente für die Komponentengruppe eingefügt.
Die hier gezeigte Vorgangsweise ist die einfachste Form, Komponentenbäume in Facelets aus mehreren Kompositionen aufzubauen. Wir werden Ihnen im Laufe der nächsten Abschnitte noch weitere Möglichkeiten zeigen, Seitendeklarationen modular aufzubauen.

4.2.2 Tag-Bibliotheken mit Facelets erstellen

Wir haben mittlerweile mit der Core-, der HTML- und der Facelets-Tag-Library drei verschiedene Tag-Bibliotheken kennengelernt. Jede von ihnen bietet unter einem im System eindeutigen Namensraum verschiedenste Tags zum einfachen Aufbau von Seitendeklarationen an. Wie wäre es, wenn Sie für Ihre eigenen Komponenten, Konverter und Validatoren auch eigene Tags definieren könnten? Das würde die tägliche Arbeit mit JSF doch erheblich vereinfachen. Facelets bietet auch dafür eine einfache Lösung an.
Eine benutzerdefinierte Tag-Bibliothek erlaubt die Definition von Tags für eigene Komponenten, Konverter und Validatoren. Wie die Tag-Bibliotheken der Standardkomponenten hat auch jede benutzerdefinierte Tag-Bibliothek einen im System eindeutigen Namensraum, mit dem sie in jede Seitendeklaration eingebunden werden kann. Neben Tag-Definitionen kann eine Tag-Bibliothek auch sogenannte EL-Funktionen enthalten, mit denen statische Funktionen in EL-Ausdrücken verfügbar gemacht werden.
Nachdem wir bis jetzt noch keine eigenen Java-basierten Komponenten erstellt haben, werden wir mit der Definition eines entsprechenden Tags noch bis Kapitel Kapitel:  Die eigene JSF-Komponente warten. Wir wollen den folgenden Abschnitt mit der Definition einer EL-Funktion beginnen, wobei wir Ihnen auch gleich zeigen, wie Sie eine Tag-Bibliothek erstellen und im System registrieren können. Was wir Ihnen überdies nicht vorenthalten wollen, ist das Erstellen eines Tags für einen Konverter und einen Validator.

4.2.2.1 Definition einer EL-Funktion

JavaServer Pages ab Version 2.1 und Facelets bieten die Möglichkeit, statische Funktionen in EL-Ausdrücken verfügbar zu machen - und das mit einer beliebigen Anzahl von Parametern. Nachdem die Beispiele im Buch Facelets als Seitendeklarationssprache einsetzen, werden wir uns an dieser Stelle auf die Definition einer EL-Funktion mit Facelets beschränken. In JSP funktioniert die Definition allerdings sehr ähnlich.
Als Beispiel implementieren wir eine Funktion, die für ein Geburtsdatum das Alter berechnet und als Zahl zurückliefert. Der dazu notwendige Java-Code beschränkt sich auf wenige Zeilen in der statischen Methode getAge der Klasse MyGourmetUtil . Diese Klasse ist in Listing Java-Code der EL-Funktion zu sehen.
public class MyGourmetUtil {
  public static int getAge(Date birthday) {
    Calendar birthCal = Calendar.getInstance();
    birthCal.setTime(birthday);
    Calendar today = Calendar.getInstance();
    int age = today.get(Calendar.YEAR)
        - birthCal.get(Calendar.YEAR);
    if (today.get(Calendar.DAY_OF_YEAR) 
        < birthCal.get(Calendar.DAY_OF_YEAR))
      age--;
    return age;
  }
}
Die hinter der EL-Funktion liegende Methode ist damit vorhanden, jetzt muss sie noch in einer Tag-Bibliothek verfügbar gemacht werden. Listing Tag-Bibliothek mit einer EL-Funktion zeigt die Tag-Bibliothek mygourmet.taglib.xml mit der Definition der EL-Funktion in einem function -Element.
<facelet-taglib version="2.0"
    xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
        http://java.sun.com/xml/ns/javaee/
        web-facelettaglibrary_2_0.xsd">
  <namespace>http://at.irian/mygourmet</namespace>
  <function>
    <function-name>getAge</function-name>
    <function-class>
      at.irian.jsfatwork.gui.util.MyGourmetUtil
    </function-class>
    <function-signature>
      int getAge(java.util.Date)
    </function-signature>
  </function>
</facelet-taglib>
Der Name, unter dem die Funktion später in EL-Ausdrücken einsetzbar ist, wird im Kindelement function-name angegeben. Die Klasse und die aufzurufende Methode werden in den Elementen function-class und function-signature definiert. Sie müssen in beiden Werten qualifizierte Namen verwenden, damit die jeweiligen Klassen gefunden werden.
Das Einbinden der Tag-Bibliothek in die Anwendung erfolgt mit dem Kontextparameter javax.faces.FACELETS_LIBRARIES in der web.xml . Facelets interpretiert den Wert dieses Parameters als eine über Semikolons separierte Liste von Tag-Bibliotheken. Nach der Registrierung ist die Tag-Bibliothek über die im Element namespace definierte URI http://at.irian/mygourmet im System verfügbar. Listing Tag-Bibliothek in der web.xml einbinden zeigt den Ausschnitt der web.xml -Datei.
<context-param>
  <param-name>
    javax.faces.FACELETS_LIBRARIES
  </param-name>
  <param-value>
    /WEB-INF/mygourmet.taglib.xml
  </param-value>
</context-param>
Facelets bindet Tag-Bibliotheken aus Jar-Dateien im Classpath automatisch ein, wenn sie im META-INF -Verzeichnis liegen und ihr Dateiname mit .taglib.xml endet.
Dem Einsatz der EL-Funktion steht jetzt nichts mehr im Weg. Die benutzerdefinierte Tag-Bibliothek mygourmet.taglib.xml wird ähnlich den bestehenden Tag-Bibliotheken eingebunden. In Listing EL-Funktion im Einsatz sehen wir die Ausgabe des Alters unter Zuhilfenahme unserer Funktion. Bitte beachten Sie, dass beim Aufruf der Funktion das Präfix mg: mit angegeben werden muss.
<html xmlns="http://www.w3.org/1999/xhtml"
    xmlns:h="http://java.sun.com/jsf/html"
    xmlns:mg="http://at.irian/mygourmet">
  ...
  <h:outputText value=
      "#{mg:getAge(customerBean.customer.birthday)}"/>
  ...
</html>

4.2.2.2 Definition eines Konverter-Tags

In Abschnitt Sektion:  Benutzerdefinierte Konverter haben wir bereits einen Konverter für die Postleitzahl definiert und unter dem Bezeichner at.irian.ZipCode registriert. Eingebunden wurde dieser Konverter mit f:converter unter Angabe dieses Bezeichners. Schön wäre es, wenn ein eigenes Tag mit einem sprechenden Namen und der Möglichkeit, Attribute an diesen Konverter zu übergeben, existieren würde - nichts einfacher als das.
Das Hinzufügen der Zeilen in Listing Definition eines Konverter-Tags zu unserer Bibliothek reicht aus, um den Konverter unter dem Tag convertZipCode zur Verfügung zu stellen. Beim Aufbau des Komponentenbaums fügt Facelets dann für jedes Tag mit dem Namen convertZipCode aus unserer Bibliothek den Konverter mit dem Bezeichner at.irian.ZipCode ein.
<tag>
  <tag-name>convertZipCode</tag-name>
  <converter>
    <converter-id>at.irian.ZipCode</converter-id>
  </converter>
</tag>
Listing Einsatz des benutzerdefinierten Konverter-Tags zeigt das neue Tag in einer Seitendeklaration. Als Voraussetzung gilt auch hier, dass die Tag-Bibliothek in der Deklaration unter dem Präfix mg bekannt gemacht wurde.
<h:inputText id="zipCode" size="30"
    value="#{addressBean.address.zipCode}">
  <mg:convertZipCode/>
</h:inputText>
In MyGourmet 12 (Abschnitt [Sektion:  MyGourmet 12: View-Parameter und GET] ) erstellen wir einen weiteren benutzerdefinierten Konverter mit eigenem Tag zum Umwandeln von Collections in Zeichenketten. Im nächsten Abschnitt über Validatoren zeigen wir Ihnen, wie auch Attribute übergeben werden können.

4.2.2.3 Definition eines Validator-Tags

Der Vorgang der Definition eines Tags für einen Konverter funktioniert in exakt der gleichen Weise auch für Validatoren. Obwohl in MyGourmet die Validierung über Bean-Validation abgewickelt wird, werden wir hier einen Validator für das Alter einer Person registrieren. Der Validator soll über die beiden optionalen Eigenschaften minAge und maxAge steuerbar sein.
Listing Definition eines Validator-Tags zeigt die Zeilen für die Definition des Validator-Tags. Der interessante Aspekt an diesem Validator sind die beiden Eigenschaften minAge und maxAge .
<tag>
  <tag-name>validateAge</tag-name>
  <validator>
    <validator-id>at.irian.Age</validator-id>
  </validator>
</tag>
Die Werte der beiden Eigenschaften können direkt über Attribute des Tags an den Validator übergeben werden. Facelets verknüpft diese dann automatisch mit gleichnamigen Eigenschaften der dahinterliegenden Validator-Objekte. In Listing Einsatz des benutzerdefinierten Validator-Tags sehen Sie das Tag mg:validateAge mit gesetztem Attribut minAge im Einsatz.
<h:inputText id="birthday" size="30"
    value="#{customerBean.customer.birthday}">
  <f:convertDateTime pattern="dd.MM.yyyy"/>
  <mg:validateAge minAge="18"/>
</h:inputText>

4.2.3 MyGourmet 10: Advanced Facelets

Das Beispiel MyGourmet 10 fasst alle Änderungen aus Abschnitt [Sektion:  Advanced Facelets] zusammen. Ein Großteil der Neuerungen hat direkt oder indirekt mit der neuen Tag-Bibliothek /WEB-INF/mygourmet.taglib.xml zu tun, die unter dem Namensraum http://at.irian/mygourmet in der Anwendung verfügbar ist.
Alle Ansichten haben jetzt einen einheitlichen Seitenkopf, der über mg:pageHeader eingebunden ist. Genauso gut wäre es möglich, direkt das dahinterliegende Seitenfragment header.xhtml aus dem Verzeichnis /WEB-INF/includes über ui:include zu verwenden.
Der Konverter für die Postleitzahl in editAddress.xhtml und der Validator für das Alter des Kunden in editCustomer.xhtml sind jetzt direkt über Tags aus der neuen Bibliothek eingebunden. In der Ansicht showCustomer.xhtml wird zusätzlich das Alter der Person über die EL-Funktion mg:getAge ausgegeben.

4.3 Templating

Layout und Design spielen bei der Entwicklung vieler Webanwendungen eine wichtige Rolle. Neben einem ausgefeilten grafischen Design ist eine konsistente und durchgängige Seitenstruktur oft die Grundvoraussetzung für den Erfolg einer Applikation. Ein einheitliches Seitenlayout vereinfacht nicht nur die Bedienbarkeit für den Benutzer, sondern ermöglicht auch die konsequente Umsetzung eines Unternehmensdesigns (Corporate Identity) auf allen Seiten. Diese Anforderungen lassen sich in der Entwicklung mithilfe von Templates umsetzen.
Der Einsatz von Templates verringert nicht nur die Redundanz der erstellten Anwendung, sondern bietet auch entscheidende Vorteile während der Entwicklung. Templates fördern durch den modularen Aufbau der Seiten die Wiederverwendung von Code und erleichtern die Trennung von Design und Inhalt. Diese Entkopplung unterstützt eine konsequente Durchsetzung des Designs im gesamten Projekt und schwächt die Auswirkung von nachträglichen Änderungen ab. Im Idealfall muss dann nur das Template oder ein zentral definiertes Seitenfragment angepasst werden, was Entwicklungs- und Wartungskosten spart.
Facelets bietet eine sehr elegante Templating-Lösung, die perfekt in den JSF-Lebenszyklus integriert ist. Ein Template ist in Facelets in erster Linie eine XHTML-Datei - wie jede andere Seitendeklaration. Den Unterschied macht das Tag ui:insert aus der Facelets-Tag-Library , mit dem ersetzbare Bereiche im Template definiert werden können. Eine Seitendeklaration, die auf diesem Template aufbaut (der sogenannte Template-Client), kann diese Bereiche mit dem eigentlichen Content ersetzen. Die komplette Ansicht besteht dann aus dem im Template definierten Inhalt und den ersetzten Bereichen aus dem Template-Client.
Sehen wir uns nun anhand eines kleinen Beispiels an, wie das Templating mit Facelets in der Praxis aussieht. Die Seiten dieses Beispiels sollen über eine Kopfzeile, einen Content-Bereich und eine Fußzeile verfügen. Diese Anforderung setzen wir in Form eines Templates mit der entsprechenden Struktur und drei ersetzbaren Bereichen um. Dadurch ist das Layout zentral definiert und einfach auf alle Seiten anwendbar. Das entsprechende Template mit dem Namen template.xhtml ist in Listing Beispiel eines Templates in Facelets zu finden.
<html xmlns="http://www.w3.org/1999/xhtml"
    xmlns:h="http://java.sun.com/jsf/html"
    xmlns:ui="http://java.sun.com/jsf/facelets">
<head>
  <title>MyGourmet</title>
  <link rel="stylesheet" type="text/css" href="style.css"/>
</head>
<body>
  <div id="header">
    <ui:insert name="header">
      <h1>MyGourmet</h1>
    </ui:insert>
  </div>
  <div id="content">
    <ui:insert name="content"/>
  </div>
  <div id="footer">
    <ui:insert name="footer">
      <h:outputText value="Copyright (c) 2009"/>
    </ui:insert>
  </div>
</body>
</html>
Das Template ist ein einfaches XHTML-Dokument, in dem die grundlegende Seitenstruktur mit div -Elementen abgebildet ist. Die drei ui:insert -Tags mit den Namen header , content und footer definieren die ersetzbaren Bereiche. Bei den ui:insert -Bereichen für die Kopf- und die Fußzeile nutzen wir die Möglichkeit, Default-Content zu definieren. Falls ein Template-Client den entsprechenden Bereich nicht überschreibt, fügt Facelets den Inhalt innerhalb des ui:insert -Tags in die Ausgabe ein. Diese Vorgehensweise ist besonders dann praktikabel, wenn der Inhalt in weiten Teilen der Applikation gleich bleibt.
Im nächsten Schritt werden wir die Seite showCustomer.xhtml erstellen. Sie basiert auf unserem Template und definiert einen eigenen Content-Bereich. Facelets bietet dafür die Tags ui:composition und ui:define an. ui:composition stellt eine Verbindung zum Template mit dem im Attribut template angegebenen Namen her - in unserem Fall template.xhtml . Innerhalb von ui:composition können die Zielbereiche des Templates mit ui:define -Blöcken überschrieben werden. Welcher mit ui:insert definierte Bereich des Templates durch den ui:define -Block ersetzt wird, bestimmt das Attribut name .
Bevor wir etwas genauer analysieren, wie Facelets eine Ansicht mit einem Template rendert, werfen wir in Listing Beispiel eines Template-Clients in Facelets noch einen Blick auf den kompletten Template-Client showCustomer.xhtml .
<html xmlns="http://www.w3.org/1999/xhtml"
    xmlns:h="http://java.sun.com/jsf/html"
    xmlns:ui="http://java.sun.com/jsf/facelets">
<head>
  <title>Show Customer</title>
</head>
<body>
  <ui:composition template="template.xhtml">
    <ui:define name="content">
      <h2>Kundendaten</h2>
      <h:panelGrid id="grid" columns="2">
        <h:outputText value="Vorname:"/>
        <h:outputText value="#{customer.firstName}"/>
        <h:outputText value="Nachname:" />
        <h:outputText value="#{customer.lastName}"/>
      </h:panelGrid>
    </ui:define>
  </ui:composition>
</body>
</html>
Wie baut Facelets die Ansicht aus showCustomer.xhtml mit dem Template auf? Wie schon beim Einsatz von ui:include ignoriert Facelets auch hier sämtliche Inhalte außerhalb ui:composition und der Aufbau des Komponentenbaums beginnt mit dem referenzierten Template. Während des Seitenerstellungsvorgangs werden die mit ui:insert definierten Bereiche im Template ersetzt. In unserem Beispiel kommt der Inhalt der Kopf- und Fußzeile aus dem Template und der Inhalt des Content-Bereichs stammt aus dem ui:define -Block in showCustomer.xhtml .
Abbildung Ersetzbare Bereiche des Templating-Beispiels zeigt die ersetzbaren ui:insert -Bereiche des Templates anhand der gerenderten Ausgabe unseres Beispiels. Die Umrahmungen mit den Namen der einzelnen Teile in der linken oberen Ecke dienen nur der besseren Visualisierung und wurden nicht von JSF gerendert.
Abbildung:Ersetzbare Bereiche des Templating-Beispiels
Facelets bietet für das Templating noch einiges mehr als die im letzten Abschnitt beschriebene Basisfunktionalität. Nach der Vorstellung von mehrstufigem Templating in Abschnitt [Sektion:  Mehrstufiges Templating] werden wir in Abschnitt [Sektion:  Mehrere Templates pro Seite] einen Blick auf den Einsatz von mehreren Templates in einem Template-Client werfen.

4.3.1 Mehrstufiges Templating

Mehrstufiges Templating ermöglicht den Aufbau einer Hierarchie von Templates. Das ist besonders dann praktisch, wenn eine Anwendung in mehrere Bereiche gegliedert ist, die ein gemeinsames Layout, aber unterschiedliche Inhalte haben. Im Fall von MyGourmet wäre das zum Beispiel ein Kundenbereich zum Bestellen von Gerichten, ein Bereich für Restaurants und Anbieter und ein allgemeiner Administrationsbereich. Das grundlegende Layout der Seiten mit Kopfzeile, linker Seitenleiste, Content-Bereich und Fußzeile bleibt gleich und wird daher im Haupttemplate aufgebaut. Dort landet auch ein Standardwert für den Inhalt der Kopf- und Fußzeile. In den abgeleiteten Templates wird die linke Seitenleiste überschrieben und mit bereichsspezifischem Inhalt gefüllt. Der Content-Bereich bleibt weiterhin leer und wird erst in den konkreten Seiten überschrieben. Abbildung Templating-Hierarchie von MyGourmet zeigt die mehrstufige Templating-Hierarchie in MyGourmet inklusive der bereits bekannten Seite showCustomer.xhtml aus dem Kundenbereich.
Abbildung:Templating-Hierarchie von MyGourmet
Der Aufbau einer mehrstufigen Templating-Hierarchie gestaltet sich einfach, da jeder Template-Client wiederum die Rolle eines Templates einnehmen kann - in Facelets gibt es keine strikte Trennung zwischen diesen beiden Rollen. Die oben erwähnten und in Abbildung Templating-Hierarchie von MyGourmet ersichtlichen Templates für die Anwendungsbereiche nehmen beide Rollen ein. Einerseits sind sie Template-Clients, da sie mit folgendem Code das Haupttemplate referenzieren:
<ui:composition template="template.xhtml">
Für die konkreten Seiten im Anwendungsbereich sind sie allerdings Templates, die neben den geerbten Inhalten aus dem Haupttemplate den Inhalt der linken Seitenleiste deklarieren. In der Seite customerPage.xhtml wird das Template dann beispielsweise mit folgendem Code referenziert:
<ui:composition template="customerTemplate.xhtml">
Eine genauere Betrachtung des mehrstufigen Templatings in der Praxis folgt mit Beispiel MyGourmet 11 in Abschnitt [Sektion:  MyGourmet 11: Templating mit Facelets] .

4.3.2 Mehrere Templates pro Seite

In manchen Fällen macht es Sinn, neben einem Template für die Ansicht selbst zusätzliche Templates für wiederkehrende Bereiche der Seite zu verwenden. Denken Sie zum Beispiel an speziell gestaltete Bereiche in einer Seitenleiste oder an Vorlagen für unterschiedliche Typen von Seiteninhalten. Die bereits bekannte Methode mit ui:composition führt in diesem Fall nicht zum Erfolg, da der Content außerhalb des Tags abgeschnitten wird. Bei zwei geschachtelten ui:composition -Tags mit gesetztem template -Attribut gewinnt immer das innere - dieser Ansatz ist also für unsere Zwecke nicht brauchbar.
Facelets bietet aber auch dafür eine Lösung an. Mit ui:decorate existiert eine Variante von ui:composition , bei deren Verwendung der außerhalb des Tags liegende Code nicht abgeschnitten wird. Wie der Name bereits sagt, wird der Content innerhalb von ui:decorate mit dem Inhalt des referenzierten Templates dekoriert.
Sehen wir uns das anhand eines kleinen Beispiels an. Listing Template-Client mit mehreren Templates zeigt einen Ausschnitt aus dem Quelltext eines Template-Clients, der ein Template für die Seite und eines für eine Box in der Seitenleiste beinhaltet.
<ui:composition template="template.xhtml">
  ...
  <ui:define name="left_sidebar">
    <ui:decorate template="sideBox.xhtml">
    	<ui:param name="title" value="Meldungen"/>
      <h:outputText value="#{bean.msg}"/>
    </ui:decorate>
  </ui:define>
  ...
</ui:composition>
Innerhalb von ui:decorate wird dem referenzierten Template sideBox.xhtml mit dem Tag ui:param der Parameter mit dem Namen title übergeben. Der restliche Inhalt von ui:decorate bildet den Inhalt der Box.
Das Template für die Box ist ein XHTML-Dokument mit einer kleinen Besonderheit. Da es sich um ein Template für einen Teil der kompletten Seite handelt, darf das HTML-Grundgerüst nicht gerendert werden. Dazu dient das Tag ui:composition - diesmal allerdings ohne das Attribut template . Auf diese Weise eingesetzt definiert es einen Teilkomponentenbaum bestehend aus seinem Inhalt. Alle Elemente außerhalb werden abgeschnitten.
Der im Template-Client gesetzte Parameter title ist im Template als Variable verfügbar und wird über einen EL-Ausdruck referenziert. Der Inhalt der Box steht direkt im ui:decorate -Tag. Durch den Einsatz von ui:insert ohne das Attribut name fügt Facelets beim Rendern den kompletten Inhalt von ui:decorate ein. Das komplette Template sideBox.xhtml für die Box finden Sie in Listing Template sideBox.xhtml .
<html xmlns="http://www.w3.org/1999/xhtml"
    xmlns:f="http://java.sun.com/jsf/core"
    xmlns:h="http://java.sun.com/jsf/html"
    xmlns:ui="http://java.sun.com/jsf/facelets">
<head>
  <title>Template for a box in a side bar</title>
</head>
<body>
  <ui:composition>
    <div class="side_box">
    <p class="header">#{title}</p>
    <ui:insert>Default body</ui:insert>
    </div>
  </ui:composition>
</body>
</html>
Das Beispiel MyGourmet 11 in Abschnitt [Sektion:  MyGourmet 11: Templating mit Facelets] benutzt ebenfalls mehrere Templates pro Seite, um Boxen in der Seitenleiste zu formatieren.

4.3.3 MyGourmet 11: Templating mit Facelets

Nach der Vorstellung der Templating-Fähigkeiten von Facelets wird es Zeit, diese in unserem Beispiel anzuwenden. MyGourmet 11 erweitert das Vorgängerbeispiel MyGourmet 10 um ein einfaches, mithilfe von Templates umgesetztes Layout. Bevor wir allerdings auf die Details der Implementierung eingehen, wollen wir kurz präsentieren, wie die Anwendung im Browser aussieht. Abbildung MyGourmet 11: Kundenseite im Browser zeigt die gerenderte Ausgabe der Seite showCustomer.xhtml .
Abbildung:MyGourmet 11: Kundenseite im Browser
In diesem Beispiel kommt die bereits kurz vorgestellte mehrstufige Template-Hierarchie aus Abbildung Templating-Hierarchie von MyGourmet zum Einsatz. Das Haupttemplate mit dem Namen template.xhtml bietet nicht viel Neues. Es definiert das grundlegende Layout der Anwendung mit je einem div -Container für die Kopfzeile, die linke Seitenleiste, den Content-Bereich und die Fußzeile. Innerhalb dieser Container befindet sich je ein ui:insert -Tag mit einem eindeutigen Namen. Das in Abbildung MyGourmet 11: Kundenseite im Browser ersichtliche Design ist in einem verlinkten CSS-Dokument definiert.
Wenden wir uns nun dem Template für die Seiten im Kundenbereich ( customerTemplate.xhtml ) zu. Es leitet sich vom Haupttemplate ab und definiert die Standardinhalte der Kopf- und Fußzeile und der Seitenleiste für den Kundenbereich von MyGourmet . Einen Ausschnitt zeigt Listing MyGourmet 11: Template für Kundenseiten .
<ui:composition template="template.xhtml">
  <ui:define name="header">
    <h:graphicImage value="/images/logo.png"/>
    <h1>#{msgs.title_main}</h1>
  </ui:define>
  <ui:define name="left_sidebar">
    <ui:include src="leftSideBar.xhtml"/>
  </ui:define>
  <ui:define name="footer">
    <h:outputText value="#{msgs.footer_left_text}"
        style="float: left;"/>
    <h:outputText value="#{msgs.footer_right_text}"
        style="float: right"/>
  </ui:define>
</ui:composition>
Die Definition der Kopf- und Fußzeile erfolgt direkt im Template - die Inhalte sind relativ überschaubar. Für die Seitenleiste kommt jedoch eine andere Vorgehensweise zum Einsatz: Ihr Inhalt wird im separaten XHTML-Dokument leftSideBar.xhtml definiert und mit dem Tag ui:include in das Template eingebunden.
Die Seitenleiste besteht aus einer Box mit einem kleinen Menü und einer Box mit aktuellen Meldungen. Die Umsetzung entspricht dem in Abschnitt [Sektion:  Mehrere Templates pro Seite] vorgestellten Beispiel für den Einsatz von mehreren Templates mit ui:decorate . Listing MyGourmet 11: Linke Seitenleiste zeigt einen Ausschnitt der leftSideBar.xhtml -Datei.
<ui:composition>
  <ui:decorate template="/META-INF/templates/sideBox.xhtml">
    <ui:param name="title" value="#{msgs.menu_title}"/>
    <h:form id="menu">
      <h:panelGrid columns="1">
        <h:commandLink action="showCustomer">
            #{msgs.menu_show_customer}
        </h:commandLink>
      </h:panelGrid>
    </h:form>
  </ui:decorate>
  <ui:decorate template="/META-INF/templates/sideBox.xhtml">
    <ui:param name="title" value="#{msgs.news_title}"/>
    <p>MyGourmet - jetzt mit Facelets und Templating</p>
  </ui:decorate>
</ui:composition>

4.4 Bookmarks und GET-Anfragen in JSF

JSF bis Version 1.2 ist nur eingeschränkt in der Lage, Bookmarks zu setzen und mit GET-Anfragen umzugehen. Das liegt vor allem an der Tatsache, dass jeder Klick auf eine h:commandLink - oder h:commandButton -Komponente eine POST-Anfrage auslöst. Diesem Umstand wird in Version 2.0 der Spezifikation mit einer erweiterten Unterstützung von GET-Anfragen Rechnung getragen.

4.4.1 Navigation mit h:link und h:button

Die Basis der GET-Unterstützung in JSF 2.0 bilden mit h:link und h:button zwei neue Komponenten, die als Link beziehungsweise Schaltfläche gerendert werden und eine GET-Anfrage absetzen. Der Clou ist, dass dabei trotzdem der Navigationsmechanismus von JSF zum Einsatz kommt. Zu diesem Zweck haben beide Komponenten das Attribut outcome , dessen Wert zum Auflösen der URL an den Navigation-Handler übergeben wird. Dieser versucht zuerst einen Navigationsfall zu finden, für den from-outcome mit dem Wert von outcome übereinstimmt. Bleibt die Suche erfolglos, wird der Wert von outcome direkt als View-ID interpretiert. Im Unterschied zur klassischen Navigation wird die View-ID bereits beim Rendern der Ansicht aufgelöst und nicht dynamisch in der Invoke-Application-Phase beim Postback. Dieses Konzept wird daher auch als präemptive Navigation bezeichnet.
Zur Demonstration der neuen GET-Fähigkeiten von JSF 2.0 erhält MyGourmet zwei neue Ansichten. Die erste neue Seite mit der View-ID providerList.xhtml zeigt eine Liste von Anbietern, die Essen ausliefern. Jeder Eintrag dieser Liste verweist mit einem h:link -Tag auf die Detailseite showProvider.xhtml . Listing h:link im Einsatz zeigt einen Ausschnitt der Seitendeklaration providerList.xhtml mit dem Link zur Detailseite.
<h:dataTable var="provider"
    value="#{providerBean.providerList}">
  <h:column>
    <f:facet name="header">
      <h:outputText value="#{msgs.provider_name}"/>
    </f:facet>
    <h:link outcome="showProvider"
        value="#{provider.name}">
      <f:param name="id" value="#{provider.id}"/>
    </h:link>
  </h:column>
</h:dataTable>
Der Wert des Attributs value wird dabei als Linktext gerendert. Wir nutzen an dieser Stelle die implizite Navigation und geben im Attribut outcome direkt die View-ID der Detailseite an. Der eindeutige Bezeichner des entsprechenden Anbieters wird mit dem Tag f:param als Kind der Linkkomponente bereitgestellt.
Listing Gerenderte Ausgabe von h:link zeigt, wie JSF 2.0 die Links rendert. Hier sehen Sie auch, was der Begriff präemptive Navigation in der Praxis bedeutet. Bereits beim Rendern der Ansicht wird für jede h:link - oder h:button -Komponente die resultierende URL abhängig vom Attribut outcome bestimmt. Aktiviert der Benutzer einen der Links beziehungsweise eine der Schaltflächen, schickt der Browser eine simple GET-Anfrage an den Server und es gibt in diesem Fall keinen Postback. Deswegen ist es auch nicht notwendig, h:link und h:button in ein h:form -Tag einzubetten.
<a href="/showProvider.jsf?id=1">Pizzeria Venezia</a>
<a href="/showProvider.jsf?id=2">Rhodos</a>
<a href="/showProvider.jsf?id=3">Frying Dutchman</a>
Nachdem der Browser eine GET-Anfrage schickt, stimmt auch die URL in der Adressleiste mit der tatsächlich gerenderten Seite überein. Der Anwender kann daher auch ein Lesezeichen auf diese Ansicht setzen. Das hört sich trivial an, trifft aber bei der klassischen Navigation nicht immer zu, da die Steuerkomponenten h:commandLink und h:commandButton erst einen Postback auf die aktuelle Seite machen, bevor JSF die Navigation ausführt und eine neue Ansicht rendert. Daher hinkt die Adressleiste um eine Ansicht hinterher.

4.4.2 View-Parameter

Wenn der Benutzer den von h:link gerenderten Link aktiviert, muss JSF den übergebenen Parameter id verarbeiten und den richtigen Anbieter anzeigen. Dabei kommen die sogenannten View-Parameter ins Spiel, die Request-Parameter direkt ans Modell binden. Diese Parameter sind im Grunde nichts anderes als Eingabekomponenten, die über Request-Parameter befüllt werden. Wie bei herkömmlichen Eingabekomponenten werden auch hier die Werte zuerst konvertiert und anschließend validiert.
View-Parameter werden in einer Seitendeklaration innerhalb des Tags f:metadata in Form von f:viewParam -Komponenten angegeben. Listing View-Parameter im Einsatz zeigt den f:metadata -Bereich der Ansicht showProvider.xhtml . Der darin eingebettete View-Parameter verbindet den Request-Parameter mit dem Namen id direkt mit der Eigenschaft providerBean.id in der Backing-Bean.
<f:metadata>
  <f:viewParam name="id" value="#{providerBean.id}"/>
</f:metadata>
Sie können überprüfen, ob sich der View-Parameter wie eine Eingabekomponente verhält (oder treffender gesagt eine ist): Rufen Sie die Seite im Browser mit einem nichtnumerischen Wert für den Parameter id auf. Das Ergebnis ist eine Fehlermeldung des JSF-Number-Konverters, da die Eigenschaft providerBean.id den Typ long aufweist. Es ist auch ohne Weiteres möglich, einen Validator einzusetzen oder die Eigenschaft mit Bean-Validation-Metadaten zu versehen.
Nachdem der Bezeichner erfolgreich in die Bean übertragen wurde, müssen vor dem Rendern der Ansicht noch die Daten des Anbieters geladen werden. JSF 2.0 gibt uns mit System-Events das richtige Werkzeug dafür in die Hand. Wir verschieben die Erläuterung der Details in den Abschnitt [Sektion:  MyGourmet 12: View-Parameter und GET] über MyGourmet 12 .
Wenn die Zielseite eines h:link - oder h:button -Elements View-Parameter enthält, können diese automatisch übernommen werden. Dazu muss lediglich das Attribut includeViewParams der Tags h:link und h:button auf den Wert true gesetzt werden. Als Beispiel fügen wir auf showProvider.xhtml den in Listing h:link mit View-Parametern gezeigten Link auf die Seite editProvider.xhtml zum Bearbeiten des Anbieters hinzu. Beim Rendern der HTML-Ausgabe dieses Links werden die View-Parameter der Zielseite als Parameter hinzugefügt. Vorausgesetzt, editProvider.xhtml definiert den selben View-Parameter wie showProvider.xhtml , ergibt sich folgende URL: /editProvider.xhtml?id=1 .
<h:link outcome="editProvider"
    includeViewParams="true"
    value="#{msgs.edit_provider}"/>

4.4.2.1 Positionierung von f:metadata

Das Tag f:metadata muss immer ein direktes Kind von f:view sein und darf nicht in ein Template oder ein mit ui:include eingefügtes Seitenfragment ausgelagert werden. Die Verbindung von Templating und View-Parametern lässt sich dennoch sehr einfach bewerkstelligen. Dazu muss das Template einen ersetzbaren Bereich für die View-Parameter definieren, der dann im Template-Client ersetzt wird. Listing Template mit View-Parametern zeigt ein Beispiel für ein Template mit dem ersetzbaren Bereich metadata .
<html xmlns="http://www.w3.org/1999/xhtml"
    xmlns:ui="http://java.sun.com/jsf/facelets"
    xmlns:f="http://java.sun.com/jsf/core">
<body>
  <f:view>
    <ui:insert name="metadata"/>
    <div id="content">
      <ui:insert name="content"/>
    </div>
  </f:view>
</body>
</html>
Listing Template-Client mit View-Parametern zeigt einen Template-Client, der auf dem zuvor definierten Template aufbaut und den View-Parameter-Bereich überschreibt. Wie Sie sehen, muss das komplette f:metadata -Tag im Template-Client deklariert werden.
<html xmlns="http://www.w3.org/1999/xhtml"
    xmlns:ui="http://java.sun.com/jsf/facelets"
    xmlns:f="http://java.sun.com/jsf/core">
<body>
  <ui:composition template="template.xhtml">
    <ui:define name="metadata">
      <f:metadata>
        <f:viewParam name="id" value="bean.id"/>
      </f:metadata>
    </ui:define>
    <ui:define name="metadata">
      Page content
    </ui:define>
  </ui:composition>
</body>
</html>

4.4.2.2 Lebenszyklus mit View-Parametern

Wir klären jetzt noch die Frage, wie sich die Ausführung des Lebens-zyklus ändert, wenn View-Parameter ins Spiel kommen. Bei einer initialen Anfrage auf eine Ansicht handelt es sich ja immer um eine GET-Anfrage. Vor JSF 2.0 sprang bei einer solchen Anfrage die Ausführung des Lebenszyklus nach Phase 1 sofort zu Phase 6 und die Ansicht wurde gerendert.
Dieses Verhalten hat sich verändert: In Phase 1 wird zunächst geprüft, ob es einen Metadatenbereich und View-Parameter gibt. Wenn ja, wird eine neue Ansicht erzeugt, die nur die View-Parameter enthält. Damit wird dann der komplette Lebenszyklus durchlaufen. Gibt es in der Anfrage Parameter, werden die Daten in den folgenden Phasen wie bei einem Postback behandelt: Zuerst werden Sie den einzelnen View-Parametern zugeordnet, dann konvertiert und validiert und ins Modell zurückgeschrieben, falls keine Fehler aufgetreten sind. Abschließend wird die Ansicht wie bisher gerendert.

4.4.3 MyGourmet 12: View-Parameter und GET

Das Beispiel MyGourmet 12 fasst alle Änderungen rund um das Thema View-Parameter zusammen. Die augenscheinlichste Neuerung ist der neue Anbieterbereich in der Anwendung. Als Einstiegspunkt dient die Seite providerList.xhtml mit einer Übersicht der Anbieter. Diese Liste wird beim Erzeugen der Backing-Bean ProviderBean mit einigen Werten initialisiert. Von dieser Seite führt pro Anbieter eine h:link -Komponente zu showProvider.xhtml . Die Daten eines Anbieters werden in Instanzen der Klasse Provider abgelegt.
Wir wollen nun unser weiter oben gegebenes Versprechen einlösen und auf das Laden der Anbieterdaten mithilfe von System-Events eingehen. System-Events werden zu bestimmten Zeitpunkten im Lebenszyklus ausgelöst. JSF 2.0 definiert eine ganze Reihe dieser Ereignisse, für die Listener registriert werden können. Uns interessiert hier das PreRenderViewEvent . Dieses Ereignis wird kurz vor dem Rendern der Ansicht ausgelöst und erfüllt somit genau unsere Anforderungen.
Über das Tag f:event registrieren wir direkt in der Seitendeklaration die Methode preRenderView() der Backing-Bean als Listener für dieses Ereignis. Hier die Registrierung in showProvider.xhtml :
<f:event type="javax.faces.event.PreRenderViewEvent"
    listener="#{providerBean.preRenderView}"/>
Listing MyGourmet 12: Listener-Methode für ein System-Event zeigt die zuvor registrierte Listener-Methode in der Klasse ProviderBean . Hier erfolgt das Laden der Anbieterdaten, falls beim Konvertieren und Validieren des View-Parameters kein Fehler aufgetreten ist. Seit JSF 2.0 lässt sich diese Abfrage einfach über die Methode isValidationFailed am Faces-Context bewerkstelligen. Sollte kein Anbieter mit dem angegebenen Bezeichner existieren, erzeugen wir eine entsprechende Nachricht. Damit endet der kurze Ausflug zum Thema System-Events.
public void preRenderView(ComponentSystemEvent ev) {
  FacesContext ctx = FacesContext.getCurrentInstance();
  if (!ctx.isValidationFailed()) {
    this.provider = findProvider(id);
    if (provider == null) {
      ctx.addMessage(null, GuiUtil.getFacesMessage(ctx,
          FacesMessage.SEVERITY_ERROR,
          "error_non_existing_provider", id));
    }
  }
}
Da wir seit MyGourmet 11 Templating benutzen, mussten wir das Template (wie in Abschnitt [Sektion:  Positionierung von f:metadata] beschrieben) für den Einsatz von View-Parametern anpassen.
Eine weitere kleine Änderung betrifft die linke Seitenleiste. Damit der Anbieterbereich erreichbar ist, haben wir das Menü um einen Link erweitert. Zur besseren Unterstützung von Bookmarking haben wir das Menü auf h:link -Komponenten umgestellt. Als angenehmer Nebeneffekt kann dadurch die Form eingespart werden.
Listing MyGourmet 12: Einsatz des Listenkonverters zeigt den Einsatz eines neuen Konverters, der Collections in Zeichenketten umwandelt. Mit dem Attribut bundleName kann ihm der Name eines Resource-Bundles übergeben werden, aus dem die Einträge der Liste aufgelöst werden. Nachdem mittlerweile der Anbieter und der Kunde eine Liste von Kategorien aufweisen, die aber nur symbolische Konstanten enthalten, spart dieser Konverter einiges an Quelltext.
<h:outputText value="#{providerBean.provider.categories}">
  <mg:convertList separator=", " bundleName="msgs"/>
</h:outputText>
Listing MyGourmet 12: Listenkonverter zeigt die getAsString -Methode und die Eigenschaften der Konverterklasse ListConverter , die über die Attribute des Custom-Tags mg:convertList gesetzt werden. Dieses Tag wurde, wie schon im letzten Beispiel gezeigt, in der Tag-Bibliothek mygourmet.taglib.xml definiert.
private String separator;
private String bundleName;

public String getAsString(FacesContext ctx,
    UIComponent comp, Object value) {
  StringBuilder builder = new StringBuilder();
  if (value instanceof Collection) {
    for (Object obj : (Collection)value) {
      String item = obj.toString();
      if (builder.length() > 0 && separator != null) {
        builder.append(separator);
      }
      if (bundleName != null && bundleName.length() > 0) {
        builder.append(GuiUtil.getResourceText(
            ctx, bundleName, item));
      } else {
        builder.append(item);
      }
    }
  }
  return builder.toString();
}

4.5 Verwaltung von Ressourcen

In JSF handelt es sich bei Ressourcen um Artefakte wie Bilder, Skripte oder Stylesheets , die eine Komponente benötigt, um vollständig am Client angezeigt zu werden.
Die Verwaltung von Ressourcen ist eine Anforderung, die in der einen oder anderen Form für jede Anwendung relevant ist. Besonders für Komponentenbibliotheken ist es wichtig, die Abhängigkeiten zwischen Komponenten und Ressourcen wie Skripten oder Stylesheets zu definieren. Außerdem müssen diese Ressourcen für den Anwendungsentwickler transparent zur Verfügung gestellt werden. Vor JSF 2.0 hat es dafür keinen standardisierten Weg gegeben. Viele Anbieter haben daher eigenständige Lösungen entwickelt, die allerdings in den wenigsten Fällen miteinander kompatibel sind.
Mit JSF 2.0 gibt es jetzt einen standardisierten Weg, Ressourcen zu verwalten und flexibel in der Ansicht zu positionieren. Davon profitieren nicht nur Komponentenbibliotheken, sondern alle Anwendungen mit eigenen Bildern, Stylesheets oder Skripten.

4.5.1 Identifikation von Ressourcen -- Teil 1

Ressourcen werden in JSF 2.0 im einfachsten Fall durch ihren Namen identifiziert. Sehen wir uns das am besten anhand eines Beispiels an. Folgender Code fügt das Bild image.png in eine Ansicht ein:
<h:graphicImage name="image.png"/>
Erfahrene JSF-Entwickler werden sofort bemerkt haben, dass in JSF~1.2 noch kein Attribut name für das h:graphicImage -Tag definiert ist. Der Wert dieses Attributs ist der Name der Ressource, die als Bild ausgegeben werden soll. Es handelt sich dabei nicht um eine Pfadangabe im klassischen Sinn, sondern um einen Bezeichner, der intern in den tatsächlichen Pfad der Ressource aufgelöst wird.
JSF sucht Ressourcen an den folgenden Stellen einer Anwendung (in der angegebenen Reihenfolge):
  1. Im Wurzelverzeichnis der Webapplikation unter /resources
  2. In /META-INF/resources und somit auch in allen Jar-Dateien im Classpath
In unserem Fall versucht JSF die Bezeichnung image.png an einem der oben genannten Orte aufzulösen. Daher legen wir folgende Datei an:
/resources/image.png
Das oben angeführte Beispiel zeigt den einfachen Fall einer Ressource, die über ihren Namen referenziert wird. JSF 2.0 bietet aber darüber hinaus eine Einteilung in Bibliotheken, eine Versionierung und die Lokalisierung von Ressourcen.
Bibliotheken sind eine Möglichkeit, Ressourcen unter einem gemeinsamen Namen zu gruppieren. Der Bibliotheksname wird dann gemeinsam mit dem Ressourcennamen zur Identifikation der Ressource verwendet. Wir erweitern unser Beispiel um eine Bibliothek images , in der alle Bilder abgelegt sind. Die Codezeile von oben ändert sich wie folgt ab:
<h:graphicImage library="images" name="image.png"/>
JSF interpretiert die Bibliothek beim Auflösen der Ressource als zusätzliches Verzeichnis. Der Pfad der Bilddatei sieht folgendermaßen aus:
/resources/images/image.png
Doch damit noch nicht genug - Ressourcen und Bibliotheken können in mehreren Versionen existieren und lokalisiert werden. Die Funktionsweise zeigt Abschnitt [Sektion:  Identifikation von Ressourcen -- Teil 2] .
Das Auflösen der Ressourcen und das Ausliefern der Daten an den Client übernimmt intern die Klasse ResourceHandler . Wie viele andere Teile von JSF kann auch der ResourceHandler über die faces-config.xml mit einer eigenen Implementierung dekoriert werden. Denkbar wären Implementierungen, die Ressourcen aus einer Datenbank holen oder dynamisch erzeugen - der Fantasie sind keine Grenzen gesetzt.

4.5.2 Ressourcen im Einsatz

Es gibt mehrere Wege, in JSF 2.0 Ressourcen in die Seite einzubinden. Folgende Standardkomponenten verfügen über die Attribute name und library , um direkt die auszugebende Ressource zu referenzieren:
Ressourcen können auch direkt über einen EL-Ausdruck im Attribut value der entsprechenden Komponente referenziert werden - das implizite Objekt resource dient diesem Zweck. Eigenschaften dieses Objekts werden beim Auswerten des Ausdrucks als Ressourcenbezeichner interpretiert. Dieser Bezeichner kann der Name der Ressource oder der Name der Bibliothek gefolgt vom Namen der Ressource mit einem Doppelpunkt als Trennzeichen sein.
Hier nochmals das Beispiel aus dem letzten Abschnitt, diesmal allerdings über einen EL-Ausdruck realisiert:
<h:graphicImage value="#{resource['images:image.png']}"/>
Kommt als VDL Facelets zum Einsatz, kann dieser EL-Ausdruck sogar direkt im HTML-Code verwendet werden:
<img src="#{resource['images:image.png']}"/>
Die dritte Methode zum Einbinden von Ressourcen erfolgt im Java-Code und ist vor allem für Entwickler von Komponenten interessant. Mit den beiden Annotationen @ResourceDependency und @ResourceDependencies können Abhängigkeiten zu Ressourcen bereits in der Komponenten- beziehungsweise Rendererklasse definiert werden. Folgender Code verknüpft zum Beispiel eine Komponente mit der Ressource script.js aus der Bibliothek scripts :
@ResourceDependency(name="script.js", library="scripts")
public class MyComponent extends UIComponentBase {
...
}
Diese Methode wird hier nur der Vollständigkeit halber erwähnt. Weiterführende Informationen zum Thema Komponentenentwicklung und Ressourcen finden Sie in Abschnitt Sektion:  Schreiben der Rendererklasse .

4.5.3 Positionierung von Ressourcen

Einen wichtigen Aspekt des Ressourcenmanagements von JSF haben wir bis jetzt noch nicht erwähnt. Stellen Sie sich vor, Sie benutzen eine Komponente aus einer Komponentenbibliothek, die ein spezielles Skript oder Stylesheet verwendet. Wie kommt diese Ressource dann in die Ansicht? Als Anwender der Bibliothek wollen wir uns nicht darum kümmern. Bei einigen Ressourcen wie Stylesheets und manchen Skripten kommt noch hinzu, dass sie an speziellen Stellen der Ansicht ausgegeben werden müssen, damit beim Benutzer die Seite richtig funktioniert. Wie die Verbindung zwischen Komponente und Ressource modelliert wird, haben wir bereits im letzten Abschnitt gezeigt. Das erklärt aber noch nicht, wie ein Link auf die Ressource in die Ansicht übernommen wird.
JSF erlaubt die Positionierung einzelner Ressourcen in definierten Bereichen der Ansicht wie dem Head oder dem Body. Damit JSF diese Bereiche richtig identifizieren kann, gibt es folgende neue Komponenten in der HTML-Tag-Library :
Beim Einbinden einer Ressource kann einer dieser Bereiche direkt adressiert werden. Dafür existiert in @ResourceDependency das Element target und in h:outputScript ein gleichnamiges Attribut. Die erlaubten Werte sind head , body und form , wobei Stylesheets allerdings unabhängig von der Angabe immer im Head ausgegeben werden (gemäß HTML-Standard müssen Stylesheets im Head-Bereich verlinkt werden, damit der Quelltext der Seite gültiges HTML bleibt).
Damit das Positionieren von Ressourcen funktioniert, ist es unbedingt nötig, h:head und h:body in allen Ansichten einzusetzen. Mit Facelets können Sie das in einem Template zentral für alle Seiten erledigen. Wie das funktioniert, erfahren Sie in Abschnitt [Sektion:  Templating] .
Sehen wir uns anhand eines Beispiels an, wie das Positionieren von Ressourcen in der Praxis aussieht. Das folgende Dokument enthält im Body-Bereich ein Stylesheet ohne Positionsangabe und ein Skript mit der Position head :
<html xmlns="http://www.w3.org/1999/xhtml"
    xmlns:h="http://java.sun.com/jsf/html">
<h:head>
  <title>Ressourcen-Test</title>
</h:head>
<h:body>
  <h:outputStylesheet name="style.css"/>
  <h:outputScript name="test.js" target="head"/>
  <h:outputText value="Test"/>
</h:body>
</html>
Hier der gerenderte HTML-Code:
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
  <title>Ressourcen-Test</title>
  <link type="text/css" rel="stylesheet"
      href="/app/javax.faces.resource/style.css.jsf"/>
  <script type="text/javascript"
      src="/app/javax.faces.resource/test.js.jsf">
  </script>
</head>
<body>
  Test
</body>
</html>
Der Code zeigt, dass beide Ressourcen, das Skript und das Stylesheet, im Head-Bereich der Seite gerendert wurden. Mit Komponenten aus einer Bibliothek funktioniert das genauso - vorausgesetzt wird, dass der Entwickler die Komponente mit @ResourceDependency annotiert und das target -Attribut auf den Wert head gesetzt hat. Wenn Sie dann h:head und h:body auf der Seite einsetzen, erledigt JSF den Rest.

4.5.4 Identifikation von Ressourcen -- Teil 2

In Abschnitt [Sektion:  Identifikation von Ressourcen -- Teil 1] haben wir zum Abschluss noch kurz darauf hingewiesen, dass JSF bei Ressourcen und Bibliotheken Versionierung und Lokalisierung unterstützt.
Versionsnummern sind bei Bibliotheken und Ressourcen mit durch Unterstrich ( _ ) getrennte Zahlen wie 1_0 oder 1_0_1 angegeben. Sie werden, getrennt durch einen Schrägstrich ( / ), an den Namen der Ressource oder der Bibliothek angehängt. Bei Ressourcennamen kann die Version zusätzlich eine Dateierweiterung wie .png oder .css aufweisen. Warum das so ist, sehen wir gleich. Hier unser Beispiel mit Versionsnummern für die Bibliothek und die Ressource:
<h:graphicImage library="images/1_0"
    name="image.png/1_1.png"/>
JSF interpretiert Bibliotheksversionen beim Auflösen als ein weiteres Verzeichnis im Pfad der Ressource. Ressourcenversionen werden dahingegen etwas anders behandelt. Existiert eine Ressource in mehreren Versionen, wird der Name der Ressource zu einem Verzeichnis, und die einzelnen Versionen sind die eigentlichen Ressourcendateien. Der neue Pfad der Bilddatei lautet dann folgendermaßen:
/resources/images/1_0/image.png/1_1.png
In den meisten Fällen ist es aber nicht nötig, die Versionsnummern beim Einsatz von Ressourcen zu definieren. Wenn keine expliziten Versionen angegeben sind, verwendet JSF automatisch die Ressource mit der höchsten Versionsnummer.
Um die verschiedenen Kombinationen von Ressourcennamen, Bibliotheksnamen und Versionsnummern zu veranschaulichen, wollen wir unser Beispiel erweitern. Abbildung Beispiele von Ressourcen zeigt das Ressourcenverzeichnis der Anwendung mit einer Bibliothek und den zwei Ressourcen image.png und new.png . Links neben dem Namen der Bilddatei ist jeweils das Bild selbst dargestellt.
Abbildung:Beispiele von Ressourcen
Basierend auf dem Verzeichnisbaum aus Abbildung Beispiele von Ressourcen wollen wir nun verschiedene Ressourcen auflösen und uns das Ergebnis ansehen. Tabelle tab:resource-resolution zeigt für eine Reihe von Kombinationen aus Bibliotheks- und Ressourcenname, welches Bild dadurch angezeigt wird. Beachten Sie bitte vor allem Namen ohne Versionsangaben und wie diese immer zur höchsten Version aufgelöst werden.
BibliothekRessource
images image.png
file=grafiken/resources-2_1.eps
images image.png/2 _ 1.png
file=grafiken/resources-2_1.eps
images/2 _ 0 image.png
file=grafiken/resources-2_1.eps
images/2 _ 0 image.png/2 _ 1.png
file=grafiken/resources-2_1.eps
images image.png/2 _ 0.png
file=grafiken/resources-2_0.eps
images/1 _ 0 image.png/1 _ 0.png
file=grafiken/resources-1_0.eps
images/1 _ 0 image.png
file=grafiken/resources-1_1.eps
images new.png
file=grafiken/resources-new.eps
Zum Schluss wollen wir noch die Lokalisierung von Ressourcen besprechen. JSF sucht beim Auflösen von Ressourcen nach folgendem Eintrag im Application-Message-Bundle :
javax.faces.resource.localePrefix=<Wert>
Falls dieser Eintrag für das aktuelle Locale gesetzt ist, wird dessen Wert als Teil des Pfads der Ressourcendatei interpretiert. Ist der Wert im deutschen Resource-Bundle beispielsweise auf de gesetzt, sieht der Pfad zu unserem Bild wie folgt aus:
/resources/de/images/image.png
Weiterführende Informationen zur Internationalisierung und zum Application-Message-Bundle finden sich in Abschnitt Sektion:  Internationalisierung .

4.5.5 Ressourcen in MyGourmet 12

Die Umstellung von MyGourmet auf Ressourcen ist im momentanen Stand der Entwicklung trivial - wir erstellen dafür kein neues Beispiel.
Die wichtigste Änderung ist die Umstellung des Haupttemplates template.xhtml auf die Elemente h:head und h:body . Dafür müssen aber nur die entsprechenden HTML-Elemente ersetzt werden. Sobald das geschehen ist, können auch das Stylesheet und das Logo ins Verzeichnis /resources verschoben und als Ressourcen verwendet werden.
Die Ressourcenverwaltung wird erst ab dem nächsten Beispiel MyGourmet 13 interessant, wenn sich alles um die neuen Kompositkomponenten von JSF 2.0 dreht. Mehr dazu erfahren Sie in Abschnitt Sektion:  Kompositkomponenten .

4.6 Die JSF-Umgebung: Faces-Context und External-Context

Immer wieder sind wir bisher an den unterschiedlichsten Stellen auf den Faces-Context gestoßen. Dieser Kontext wird in JSF durch die Klasse javax.faces.context.FacesContext repräsentiert. Der Faces-Context stellt die zentrale Schaltstelle einer JSF-Anwendung dar. Er wird ganz am Anfang jeder HTTP-Anfrage vom Faces-Servlet initialisiert und steht dem Entwickler ab dann als Parameter vieler Methoden, aber auch jederzeit über den Aufruf der Methode FacesContext.getCurrentInstance() zur Verfügung.
Die häufigste Anwendung des Faces-Contexts ist die Auflösung von Managed-Beans aus dem Quelltext einer Anwendung heraus. Listing Zugriff auf eine Managed-Bean im Java-Code zeigt, wie der Zugriff auf eine Managed-Bean namens personList in einer anderen Managed-Bean aussieht. Es bietet sich an, solch syntaktische Grausamkeiten in eine Utility- oder eine Basisklasse auszulagern.
FacesContext fc = FacesContext.getCurrentInstance();
fc.getApplication().getELResolver().getValue(
    fc.getELContext(), null, "personList");
Eine weitere wichtige Anwendung des Faces-Contexts ist das Hinzufügen von Nachrichten für die Darstellung auf der Webseite - und die Möglichkeit, auf die bisher hinzugefügten Nachrichten zuzugreifen. Zu diesem Zweck existieren folgende Methoden:
Weiterführende Details zum Hinzufügen und Verwalten von Nachrichten finden Sie in Abschnitt Sektion:  Nachrichten .
Applikationsobjekte anlegen: Über den Faces-Context gelangen Sie auch zur Application , und die hilft Ihnen sowohl beim Erzeugen von neuen Komponenten als auch von Method - und Value-Expressions (siehe Listing Applikationsobjekte anlegen ).
fc.getApplication().getExpressionFactory().
    createValueExpression(ELContext ctx,
        String expression, Class expectedType);

fc.getApplication().getExpressionFactory().
    createMethodExpression(ELContext ctx, String expression,
    Class expectedReturnType, Class[] params);

fc.getApplication().createComponent(String componentType);
Wobei der ELContext - wie in Listing Zugriff auf eine Managed-Bean im Java-Code bereits gezeigt - als Eigenschaft des Faces-Contexts verfügbar ist. Auch hier zahlt es sich aus, Utility-Methoden für das Erzeugen neuer Elemente vorzusehen.
Lebenslauf beeinflussen: Ein wichtiger Bereich im Faces-Context ist die Möglichkeit, den Lebenslauf einer HTTP-Anfrage zu beeinflussen. Dazu gibt es folgende Methoden, die bereits bei der Ereignisbehandlung in Abschnitt Sektion:  Ereignisse und Ereignisbehandlung zum Einsatz gekommen sind:
External-Context: Schließlich bietet der Faces-Context noch die Möglichkeit, auf den External-Context zuzugreifen. Der External-Context ist der Wrapper rund um die der Webanwendungs-Umgebung zugrundeliegende Funktionalität; also in den meisten Fällen um entweder den ServletContext oder PortletContext . Hier der für einen Zugriff notwendige Code:
FacesContext fc = FacesContext.getCurrentInstance();
ExternalContext ec = fc.getExternalContext();
Auch der External-Context bietet einige interessante Methoden, die sich aus der Funktionalität des Basis-Contexts ergeben. Hier eine selektive Auswahl:
Der External-Context bietet noch einige weitere Methoden, die Sie am besten der API-Dokumentation entnehmen.

4.7 Konfiguration von JavaServer Faces

In den bisherigen Kapiteln wurden die Konfigurationsmöglichkeiten von JSF bereits in Beispielen behandelt, im kommenden Abschnitt sehen wir uns die Konfiguration ein wenig detaillierter an.
JSF verwendet ein Minimum an zu editierenden XML-Dateien. Sieht man von einer eventuellen Verwendung von Tiles oder Portlets ab, existieren nur zwei Konfigurationsdateien für eine JSF-basierte Webanwendung:
Diese beiden müssen im Verzeichnis WEB-INF der Applikation vorhanden und fehlerfrei sein, sonst lässt sich die Webanwendung im Applikationsserver oder Servlet-Container nicht hochfahren.

4.7.1 Die Webkonfigurationsdatei web.xml

Sehen wir uns nun in weiterer Folge eine typische web.xml -Datei einer JSF-Applikation genauer an. Der wichtigste Teil des Deployment-Deskriptors ist die Spezifikation des Faces-Servlets , das die Anfragen an die JSF-Anwendung bearbeitet, und dessen Mapping . Ein weiterer wichtiger Aspekt der Webapplikation, der in diesem Abschnitt behandelt wird, sind Konfigurationsparameter.

4.7.1.1 Faces-Servlet und Mapping

Jede JSF-Applikation muss ein Faces-Servlet konfigurieren. Listing Deployment-Deskriptor von MyGourmet 1 zeigt nochmals die web.xml -Datei des Beispiels MyGourmet 1 , in der selbstverständlich auch ein Servlet und ein zugehöriges Servlet-Mapping definiert sind.
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/j2ee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
      http://java.sun.com/xml/ns/j2ee/web-app_2_5.xsd"
    version="2.5">
  <description>JSF 2.0 - MyGourmet 1</description>
  <servlet>
    <servlet-name>Faces Servlet</servlet-name>
    <servlet-class>
      javax.faces.webapp.FacesServlet
    </servlet-class>
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>Faces Servlet</servlet-name>
    <url-pattern>*.jsf</url-pattern>
  </servlet-mapping>
  <welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
    <welcome-file>index.html</welcome-file>
  </welcome-file-list>
</web-app>
Als Faces-Servlet können (in aufsteigender Schwierigkeitsstufe der Verwendung) folgende Klassen eingesetzt werden:
Implementieren Sie das Faces-Servlet frei, sollten Sie zumindest den Faces-Context initialisieren und den Lebenslauf starten. Befinden sich in der web.xml mehrere Servlets, gewinnt die Einstellung im Element load-on-startup an Bedeutung. Hier ist es möglich, die Reihenfolge der beim Start initialisierten Servlets zu bestimmen.
Welche Anfrage auf welches Servlet weitergeleitet wird, zeigt das servlet-mapping -Element an. Der Wert des url-pattern -Elements definiert ein Präfix oder Postfix der Anfrageadresse, das dem Faces-Servlet zugewiesen wird. Im Beispiel MyGourmet 1 wurde die Postfix-Zuordnung (auch Extension-Mapping genannt) *.jsf gewählt, wobei sämtliche Anfragen mit der Endung .jsf durch das Faces-Servlet gehandhabt werden. Intern wird diese Adresse dann auf die View-ID der Seitendefinition umgelegt.
Die zweite Möglichkeit, ein Servlet-Mapping zu definieren, ist eine Präfix-Zuordnung <url-pattern>/faces/*</url-pattern> . Die View-ID der Seitendefinition ergibt sich in diesem Fall direkt aus der URL, nachdem das Präfix entfernt wurde.
Sehen wir uns kurz den entscheidenden Unterschied zwischen Präfix- und Postfix-Mapping anhand eines Beispiels an. Wir wollen dazu die Seite mit der Seitendefinition /helloWorld.jsp der fiktiven Webanwendung http://www.mustermann.org im Browser laden. Mit einem Postfix-Mapping müssen wir dazu die URL
http://www.mustermann.org/helloWorld.jsf
in die Adressleiste eingeben. Mit einem Präfix-Mapping sieht die URL folgendermaßen aus:
http://www.mustermann.org/faces/helloWorld.jsp
In der Regel sind beide Methoden für eine JSF-Anwendung einsetzbar. In manchen Fällen, wie beim Einsatz von Tomahawk oder Trinidad, kann es allerdings von Vorteil sein, ein Präfix-Mapping zu verwenden.

4.7.1.2 Kontextparameter

An erster Stelle in der Konfiguration stehen üblicherweise die Kontextparameter. Die optionale Angabe von context-param -Elementen dient der Definition von Parametern zur Initialisierung des Servlet-Contexts . Hier können Basiseinstellungen vorgenommen werden. Die folgende Liste zeigt eine Übersicht der wichtigsten Einstellungen für JSF:

4.7.2 Die JSF-Konfigurationsdatei -- faces-config.xml

In diesem Abschnitt geht es darum, zentrale Einstellungen für JavaServer Faces zu treffen. Einerseits bietet die faces-config.xml die Möglichkeit, alltägliche Konfigurationseinstellungen in der Entwicklung einer JSF-Applikation zu setzen. Dazu gehört die Konfiguration von Managed-Beans , Navigationsregeln sowie Einstellungen zur Applikation selbst. Der zweite Aufgabenbereich, die Registrierung von Komponenten, Renderern, Validatoren und Konvertern, ist für den Entwickler von Komponenten (und Komponentenbibliotheken) interessant. Zuletzt gibt es noch erweiterte Möglichkeiten, wie das Einbinden von Phase-Listenern und die Konfiguration von Factories für die Erzeugung von JSF-Kernklassen.
JSF 2.0 bietet für die meisten Einstellungen in der Konfigurationsdatei faces-config.xml alternativ die Möglichkeit, Annotationen einzusetzen.
Die Konfiguration von Managed-Beans erfolgt in jeweils einem managed-bean -Element pro Bean oder ab JSF 2.0 mit der Annotation @ManagedBean . Eine genauere Beschreibung der umfassenden Einstellmöglichkeiten findet sich in Abschnitt subsec Konfiguration von Managed-Beans .
Die Regeln für die Navigation in einer JSF-Anwendung werden mithilfe von navigation-rule -Elementen definiert. Wie das genau funktioniert, zeigt Abschnitt Sektion:  Navigation . Im Laufe der Entwicklung einer JSF-Webapplikation können sehr viele Navigationsregeln anfallen. Um die Übersicht zu behalten, empfiehlt sich die Auslagerung einzelner Teile der Konfiguration in separate Dateien, wie es im Abschnitt der JSF-Konfigurationsdatei faces-config.xml beschrieben wurde.

4.7.2.1 Anwendungseinstellungen -- application

Ein zentrales Element in der faces-config.xml ist das Tag application . Darin werden wichtige Einstellungen für Kernbereiche von JSF getroffen. Das Element application kann als die zentrale Schaltstelle einer JSF-Anwendung betrachtet werden. Hier ist es möglich, neben Einstellungen zur Lokalisierung und der Definition von Message- und Resource-Bundles, essenzielle Teile wie den View-Handler oder den EL-Resolver von JSF mit eigenen Implementierungen zu dekorieren. Damit wird dem Benutzer ein mächtiges Werkzeug in die Hand gegeben, um die Applikation an eigene Bedürfnisse anzupassen.
Listing faces-config.xml mit Spring-EL-Resolver zeigt ein Beispiel für eine faces-config.xml , auf deren Elemente wir weiter unten eingehen werden.
<faces-config>
<application>
  <navigation-handler>
    at.irian.jsfatwork.MyNavigationHandler
  </navigation-handler>
  <el-resolver>
    org.springframework.web.jsf.el.SpringBeanFacesELResolver
  </el-resolver>
  <message-bundle>
    at.irian.jsfatwork.messages
  </message-bundle>
  <locale-config>
    <default-locale>de</default-locale>
    <supported-locale>en</supported-locale>
  </locale-config>
  <resource-bundle>
    <base-name>at.irian.jsfatwork.text</base-name>
    <var>text</var>
  </resource-bundle>
</application>
</faces-config>
In der folgenden Auflistung finden Sie eine Übersicht der wichtigsten Einstellungen. Bei den einzelnen Punkten handelt es sich jeweils um Kindelemente des Tags application :
Die weiteren möglichen Elemente der faces-config.xml , wie die Registrierung der Renderer, Konverter oder Validatoren, werden in den Abschnitten Sektion:  Konvertierung und Sektion:  Validierung beziehungsweise im Kapitel Kapitel:  Die eigene JSF-Komponente (für die Konfiguration von Komponenten) noch genauer behandelt.