Vous êtes sur la page 1sur 68

Berner Fachhochschule

Software Schule Schweiz

JavaServer Faces
java.sun.com/javaee/javaserverfaces

Dr. Beatrice Amrhein

May 08
2
Table of Contents
1 Introduction ...............................................................................................................................5
1.1 JSF in Comparison to other Web Frameworks....................................................................................................5
1.1 The JSF Application Structure..............................................................................................................................8
1.2 The JSF Concepts................................................................................................................................................9
1.3 UIComponents.....................................................................................................................................................9
1.4 Renderers...........................................................................................................................................................10
1.5 Validators...........................................................................................................................................................10
1.6 Backing Beans...................................................................................................................................................10
1.7 Converters..........................................................................................................................................................10
1.8 Events and Event Listeners................................................................................................................................10
1.9 Navigation..........................................................................................................................................................10
1.10 The JSF expression language............................................................................................................................11

2 Easy Example: Hello World! ..................................................................................................13


2.1 Hello.jsp..............................................................................................................................................................13
2.2 HelloBean.java...................................................................................................................................................15
2.3 faces-config.xml.................................................................................................................................................16
2.4 web.xml..............................................................................................................................................................16

3 JSF Application Configuration .............................................................................................17


3.1 The Directory Structure......................................................................................................................................17
3.2 The Deployment Descriptor................................................................................................................................17
3.3 The JSF Configuration File.................................................................................................................................18
3.4 Configuration and Navigation Example..............................................................................................................21
3.5 Hello.jsp..............................................................................................................................................................21
3.6 PersonDetails.jsp...............................................................................................................................................22
3.7 Goodbye.jsp.......................................................................................................................................................23
3.8 faces-config.xml.................................................................................................................................................23
3.9 Navigation..........................................................................................................................................................25
3.10 HelloBean.java...................................................................................................................................................26

4 The Standard JSF Components ............................................................................................27


4.1 The Layout of the Components..........................................................................................................................27
4.2 The Output Components....................................................................................................................................28
4.3 The Basic Input Components.............................................................................................................................28
4.4 Choice Input Components..................................................................................................................................29
4.5 Data Tables........................................................................................................................................................31
4.6 Processing Row-Specific Events........................................................................................................................32
4.7 The Command Components..............................................................................................................................34

5 Messaging ...............................................................................................................................35
5.1 Messages...........................................................................................................................................................35
5.2 Overriding standard Messages..........................................................................................................................36
5.3 Constructing Application Messages...................................................................................................................37

6 Request Processing ...............................................................................................................41


6.1 Restore View .....................................................................................................................................................41
6.2 Apply Request Values .......................................................................................................................................42
6.3 Process Validation..............................................................................................................................................42
6.4 Update Model Values ........................................................................................................................................42
6.5 Invoke Application .............................................................................................................................................42
6.6 Render Response..............................................................................................................................................42

7 Validators and Converters .....................................................................................................43


7.1 Standard Validators............................................................................................................................................43
7.2 Validator Methods..............................................................................................................................................44
7.3 Validator Classes...............................................................................................................................................44
7.4 Automatic Conversion........................................................................................................................................45
7.5 Standard Converters..........................................................................................................................................45
7.6 Using Custom Converters..................................................................................................................................46

3
8 Internationalization .................................................................................................................47
8.1 Load the Resource Bundle.................................................................................................................................47
8.2 Configuring Locales............................................................................................................................................48
8.3 Creating Resource Bundles...............................................................................................................................48
8.4 Using Resource Bundles....................................................................................................................................49
8.5 Constructing Localized Messages .....................................................................................................................49
8.6 Using Localized Message Bundles for Application Messages ..........................................................................51

9 Custom Tags ...........................................................................................................................53


9.1 The different parts of a Custom Tag...................................................................................................................53
9.2 The Greater-Than Validator ..............................................................................................................................57

10 JSF Custom Components ......................................................................................................61


10.1 The Component Hierarchy.................................................................................................................................61
10.2 Component Data Collections..............................................................................................................................61
10.3 Value Holder.......................................................................................................................................................62
10.4 Example of a Custom Component ....................................................................................................................63

4
1 Introduction
Web Frameworks
1.1 JSF in Comparison to other Web Frameworks

Automatic markup generation


Declarative integration of backing beans
UI component model
JSF
Server side handling of UI events
Type conversion
Navigation
Struts
Form handling and validation
Extensible templating mechanism JSP
Integration with Java
(session management, error handling, ...) Servlets
HTTP request / response Web server

3
Like the Struts framework, JSF defines a set of JSP tags that generate HTML form elements that
can be bound to JavaBean properties. The greatest advantage that JSF technology has over
Struts is its flexible, extensible UI component model, which includes:
• A standard component API for a wide range of components, including simple ones, such as
input fields, or more complex ones, such as scrollable data tables. Developers can also
create their own components based on the JSF APIs, and many third parties have already
done so and have made their component libraries publicly available (e.g. MyFaces,
http://www.myfaces.org/).
• A separate rendering model that defines how to render the components in various ways.
For example, a component used for selecting an item from a list can be rendered as a
menu or a set of radio buttons.
• An event model that defines how to handle events generated by activating a component,
such as what to do when a user clicks a button or a hyper link.
• Conversion and validation.
Because the JavaServer Faces technology architecture separates the definition of a component
from its rendering, you can render your components in different ways or even for different clients,
such as a WML client. Moreover, the extensible component APIs of JavaServer Faces technology
allow you to extend the standard set of components and create entirely new components. None of
this is possible with Struts. In fact, Struts has no notion of server-side components, which also
means that it has no event model for responding to component events and no facility for saving
and restoring component state. While Struts does have a useful tag library for rendering
components on the page, these components have no object representation on the server and they
can only be rendered to an HTML client.

Another distinct advantage of JavaServer Faces technology is that it has been designed to allow
easy integration into tools. As a result, JavaServer Faces technology already has wide industry
support and is build in several web application development IDEs (Sun Java Studio Creator, IBM
WebSphere Application Developer, Oracle JDeveloper).

5
Web browsers don't know anything about JSF components or events. When a user clicks a button
in a JSF application, it causes a request to be sent from your web browser to the server, or more
precisely to the FacesServlet. JSF is responsible for translating that request into an event that can
be processed by your application logic on the server (usually by the backing bean). JSF is also
responsible for making sure that every UIComponent you have used on your pages is properly
displayed on your browser.
JSF applications run on the server and can integrate with other subsystems like EJBs, web
services or databases.
faces-config.xml is the central configuration file for JSF applications. Here, we define the
navigation rules, the used backing beans and so on.

6
A simple JSF Page
Here is an example of a simple page with a label („Your Name“) with an input text field and a
submit button („Say Hello“).

<jsp:root xmlns:jsp="http://java.sun.com/JSP/Page"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html" version="2.1">
<jsp:directive.page contentType="text/html"/>

<html xmlns="http://www.w3.org/1999/xhtml">
<head> <title>Hello, world!</title> </head>
<body>
<f:view>
<h:form>
<h:outputText value="Your Name: "/>
<h:inputText value="#{helloBean.name}"/>
<h:outputText value="Your Age: "/>
<h:commandButton value="Say Hello"
action="#{helloBean.sayHello}"/>
</h:form>
</f:view>
</body>
</html>
</jsp:root>

For the web page designer, a JSF page looks similar to a normal HTML or JSP page. As soon as
we define the JavaServer tag namespaces (core and html), all JSF tags can be used. These pages
can also be designed by an IDE like Sun Java Studio Creator, IBM WebSphere or Oracle
JDeveloper.
At runtime, the FacesServlet automatically translates these tags to a HTML form. After translation,
the generated HTML page looks as follows:

<?xml version="1.0" encoding="UTF-8"?>

<html><head><title>Hello, world!</title></head>
<body>
<form id="main" name="main" method="post"
action="/helloWorld1/faces/hello.jsp"
enctype="application/x-www-form-urlencoded">
<input type="hidden" name="main" value="main" />
<input type="hidden"
id="javax.faces.ViewState" value="j_id1:j_id2" />
<span id="main:o1">Your Name: </span>
<input id="main:i1" type="text" />
<input id="main:submit" type="submit" value="Say Hello"/>
</form></body>
</html>

The outputText is converted to normal text, the inputText to a input tag and the submit button to a
submit input tag.
Hidden input fields are used to transmit state information about the client or server.

7
1.1 The JSF Application Structure

Developing a simple JavaServer Faces application usually requires the following tasks:
• Create the JSP Pages: The JSP Pages using html and core tags.
• Develop the Model Object (business logic)
• Develop the backing beans with the properties as well as the used action methods.
• Add managed bean declarations to the application configuration file (Faces Config). The
configuration file contains the name of the corresponding backing bean.
• Define page navigation in the application configuration resource file
In the JSP Page we use the the unified expression language (EL, cf. Section 1.10) to bind UI
component values and objects to backing bean properties or to reference backing bean methods
from UI component tags.
The HTML Page (with HTML Elements) as well as all the JSF Views (with the necessary UI
Components) are automatically generated form the JSP Page. The Faces Servlet is provided by
the JSF Application and is responsible for the communication between the server and the clients
(Front Controller pattern).

Client Server

HTML HTTP Faces


JSF View
Page Servlet

HTML UI EL Backing Model


Elements Components Bean Object

Faces
JSP Page
Config

8
1.2 The JSF Concepts
The following is a UML class diagram showing the different concepts of JSF.
The view object contains a tree of UIComponents (output labels, command buttons, text fields, ...),
which are displayed by the dedicated renderer. On user input, the backing beans are automatically
updated. Converters translate and format the components value and generate an error message (if
necessary). Validators verify the value of a component and generate an error message (if
necessary).
In general, JSF applications communicate by events. Backing beans contain event listeners and
action methods. The outcome of an action method can be used to specify the next page to be
shown (navigation). Event listeners consume events and can execute model objects, which
perform the core application logic.
In JSF applications, model objects don't know anything about the user interface. This enforces a
MVC-style architecture.

1.3 UIComponents
Like Swing components, UIComponents are built as JavaBeans. This means, they have properties,
methods, and support event handling. Unlike Swing, JSF UIComponents live on the server side,
not on the client.
Providing these UI elements as components makes development much easier, because the core
functions are encapsulated within a reusable package. In order to use a UIComponent, you just
have to configure some properties, such as the color or the default value, and you don't have to
develop any complicated combinations of HTML, CSS and JavaScript. JSF provides all the
standard components like labels, buttons, hyper links, text fields, list boxes, panels or data tables.

9
1.4 Renderers
Not all JSF components are responsible for their own rendering. JSF allows separate classes to
handle the rendering process. Those classes are called renderers. JSF provides a standard render
kit for its UIComponents. However, JSF supports the development of custom renderers as well.
Renderers create a visual representation for the client (encoding) and, when JSF receives a
response form the user, the renderer extracts the request parameters (decoding).

1.5 Validators
Validators are used to examine the correctness of the given input values. JSF handles validation in
three ways:
• at the UIComponent level
• via validator methods in backing beans
• in validator classes
UIComponents usually handle simple validation, such as whether a value is required or not.
Validator methods are useful when you need to validate one or more fields on a form (and you
don't need this validator for other components). External validators are useful for generic cases.
You can attach one or more validators to any input component.

1.6 Backing Beans


In JSF applications the interaction between the model and the user interface is performed by
backing beans. They contain properties you want to retrieve from the user and provide event
listener methods which can act on these properties and perform some application processing.
JSF allows you to declaratively associate backing beans with UIComponents. You can use a JSF
EL expression to bind the value of a UIComponent with a specific backing bean property.
Whenever the value of the UIComponent changes, the associated backing bean property is
automatically updated.

1.7 Converters
Converters translate an object to a string for display and from an input string to a Java object.
Furthermore, they handle formatting and localization. JSF ships with converters for common types
like dates, boolean or numbers, but anybody can develop additional converters which are applied
internally during encoding and decoding.

1.8 Events and Event Listeners


In JSF applications there is no need of thinking in terms of HTTP requests and responses. Events
capture the way the user interacts with UI components.
Like Swing, JSF uses JavaBeans to handle events with event listeners and handlers. Any
component may fire one or more events, which means you register one or more event listeners
with it. There are four standard events: value-change events (value change of a component),
action events (clicking on a button or link), data model events (select a row for processing) and
phase events (at the beginning and at the end of each phase in the processing life cycle, see
chapter 6).

1.9 Navigation
JSF provides an elegant navigation system. The navigation handler is responsible for deciding
which page to load depending on the outcome of an action method. Navigation rules define what
outcomes are understood and which page to load on what outcome. These rules are defined in the
JSF configuration file (faces-config.xml).

10
1.10 The JSF expression language
The main point of JSF expressions is to allow you to reference JavaBean methods, to read or
update bean properties, or to evaluate simple statements, without writing any Java code.
JSF expressions are used to associate UIComponent properties with backing beans, but you can
use them for logical and mathematical statements as well. They are evaluated at runtime.

JSF 1.2 uses the Unified Expression Language (EL), i.e. it uses the same expression language
as JSP 2.1. JSF 1.2 depends on the unified EL API (javax.el).

• The EL uses the number sign (#) to mark the beginning of an expression.
• EL expressions can be two way: they can retrieve a properties value or update it.
• EL expressions can also reference object methods.

Value Expressions:
• #{myBean.myProperty} returns the value of myProperty of the object myBean.
• #{myBean.myList[2]} returns the second element of (the list or array) myList of
myBean.
• #{myBean.myMap['key']} returns the object stored under the key 'key' of the map
myMap.

Method Expressions:
• #{myBean.myMethod} assigns the method myMethod of the bean myBean.

Expressions with operators


• #{myBean.myProperty > 10} returns true, if the (actual) value of myProperty in
myBean is greater than 10.
• #{myBean.myProperty != 20 && myBean.myProperty > 10} returns true, if the
(actual) value of myProperty is not equal to 20 and greater than 10.
• #{not empty myBean.myProperty}
returns true, if myProperty is not null, the empty string or an empty collection.

Usage of EL expressions in tags:

• <h:outputText value="#{helloBean.helloText}"/> associates the helloText property of the


helloBean backing bean with the output text component.

• <h:commandButton value="Say Hello" action="#{helloBean.sayHello}"/> assigns the action


method „sayHello“ of the helloBean backing bean to the command button.

• <h:inputText value="#{helloBean.name}" rendered="#{not empty helloBean.name}" />


renders this input text component only if helloBean.name is not null.

11
12
2 Easy Example: Hello World!
We start with an easy but complete example, where we learn to know all the key pieces which
belong to a JSF application.

We start with the JSP page:

2.1 Hello.jsp
1. <?xml version="1.0" encoding="UTF-8"?>
2. <jsp:root xmlns:jsp="http://java.sun.com/JSP/Page"
3. xmlns:f="http://java.sun.com/jsf/core"
4. xmlns:h="http://java.sun.com/jsf/html" version="2.1">
5. <jsp:directive.page contentType="text/html"/>
6.
7. <html xmlns="http://www.w3.org/1999/xhtml">
8. <head>
9. <link href="styles.css" rel="stylesheet" type="text/css"/>
10. <title>Hello, world!</title>
11. </head>
12. <body>
13. <f:view>
14. <h:form id="main">
15. <h:outputText value="#{helloBean.helloText}"
16. styleClass="header"/>
17. <p>
18. <h:outputText value="Your Name: "/>
19. <h:inputText id="helloInput"
20. value="#{helloBean.name}"/>
21. </p>
22. <p>
23. <h:outputText value="Your Age: "/>
24. <h:inputText id="helloAge"
25. value="#{helloBean.age}"/>
26. </p>
27. <h:commandButton id="sayHello" value="Say Hello"
28. action="#{helloBean.sayHello}"/>
29. </h:form>
30. </f:view>
31. </body>
32. </html>
33.</jsp:root>

13
Lines 1 to 5: First, we declare the namespaces for the core JSF tag libraries. These provide
custom tags like text boxes, output labels and forms. Usually the prefixes „f“ and „h“ are used for
these namespaces.
The „h“ tag library elements usually render HTML elements, whereas the core tags are
independent of a particular render kit (like <f:view>, <f:validator>, <f:converter> and so on).
The jsp:directive is used to define the content type of the target HTML page.

Lines 8-11: The header of the HTML page.

Line 13: The <f:view> tag must enclose all other JSF related tags.
Line 14: The <h:form> tag represents an HtmlForm component, which is a container for other
components and is used for posting information back to the server. We can have more than one
HtmlForm on the same page, but all input controls must be nested within a <h:form> tag.

Line 15: The <h:outputText> tag creates an HtmlOutputText component, which displays read-only
text on the screen. The value attribute #{helloBean.helloText} specifies an JSF Expression
Language reference to the property helloText of the backing bean. JSF automatically
synchronizes the value of the outputText with the helloText property. JSF tags can use the
usual CSS-styles of HTML.

Lines 19: <h:inputText> creates a new HtmlInputText component that accepts text input. The
value attribute #{helloBean.name} references the property name of the backing bean.

Line 27: The <h:commandButton> specifies an HtmlCommandButton component. The value


attribute defines the button label, here "Say Hello". HtmlCommandButtons send action
events to the application when they are clicked by a user. The action attribute references the
action method that computes the new helloText. The outcome of the action method can be
used to handle navigation.

14
2.2 HelloBean.java

package helloWorld;

public class HelloBean {

/** The name of the person. */


private String name;
/** The age of the person. */
private int age;
/** The hello text. */
private String helloText = "Hello World!";
/** Get the age. */ // property methods for age
public int getAge() {
return age;
}
/** Set the age. */
public void setAge(int age) {
this.age = age;
}
/** Get the person name. */ // property methods for name
public String getName() {
return name;
}
/** Set the person name. */
public void setName(String name) {
this.name = name;
}
/** Get the hello text. */ // property method for hello text
public String getHelloText() {
return helloText;
}
/** Define the text to say hello. */ // action method for „Say Hello“
public String sayHello() { // button
if(age < 11)
helloText="Hello " + name + "!";
else
helloText="Good Morning " + name + "!";
return "hello";
}
}

The sayHello() method is called, whenever the „Say Hello“ button is pressed. It computes the new
helloText. Its return value can be used to define the next page (navigation).

15
2.3 faces-config.xml
<?xml version='1.0' encoding='UTF-8'?>
<faces-config 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-facesconfig_1_2.xsd"
version="1.2">
<managed-bean>
<description>The HelloBean.</description>
<managed-bean-name>helloBean</managed-bean-name>
<managed-bean-class>helloWorld.HelloBean </managed-bean-class>
<managed-bean-scope>session</managed-bean-scope>
</managed-bean>
</faces-config>

In the faces-config.xml file we declare all of the managed beans. Those are automatically
instantiated. Here the only managed bean is helloWorld.HelloBean. The name of the bean object is
helloBean. This name is also used in the EL expressions in hello.jsp (e.g. #{helloBean.name}).
It is good practice to choose similar names for the bean class and its object.
2.4 web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" 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-app_2_5.xsd">
<display-name>Hello, World!</display-name>
<description>Welcome to JavaServer Faces</description>
<!-- Faces Servlet : Front Controller -->
<servlet>
<servlet-name>FacesServlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
</servlet>
<!-- Faces Servlet Mapping -->
<servlet-mapping>
<servlet-name>FacesServlet</servlet-name>
<url-pattern>/faces/*</url-pattern>
</servlet-mapping>
<!-- Welcome File -->
<welcome-file-list>
<welcome-file>faces/hello.jsp</welcome-file>
</welcome-file-list>
<!-- jsp pages are xml documents -->
<jsp-config>
<jsp-property-group>
<url-pattern>*.jsp</url-pattern>
<is-xml>true</is-xml>
</jsp-property-group>
</jsp-config>
</web-app>

All J2EE web applications are configured by a deployment descriptor file (web.xml). Furthermore,
JSF applications require that you specify the FacesServlet, which is the main servlet (front
controller) of the application. All JSF requests are mapped to the FacesServlet.

16
3 JSF Application Configuration
3.1 The Directory Structure

Because JSF applications are standard Java web


applications, all of the necessary files must be
packed in a directory structure that can be deployed
to the web container.
For JSF applications, there are two additions: the
faces-config.xml file (where all the JSF configuration
is placed) and (if your web container doesn't already
support JSF) the jar files of your JSF library.
For the reference implementation (we use for this
course), the required jar files for all JSF applications
are jsf-api.jar, jsf-impl.jar, jstl.jar and standard.jar.

3.2 The Deployment Descriptor


JSF applications require a servlet, which acts as a front controller for the entire application
(FacesServlet). This servlet is configured in the web.xml deployment descriptor file.

<?xml version="1.0"?>
<web-app version="2.5" 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-app_2_5.xsd">
<display-name>Display Name used by GUI Tools</display-name>
<description>Description of the Web application </description>
<!-- Configuration of faces-config file(s) (comma separated) -->
<context-param>
<param-name>javax.faces.CONFIG_FILES</param-name>
<param-value>/WEB-INF/faces-config.xml</param-value>
</context-param>
<!-- FacesServlet configuration and mapping -->
<servlet>
<servlet-name>Name of the Front Controller for your JSF Application,
usually FacesServlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Name of the Front Controller (the same as
above!)</servlet-name>
<url-pattern>path/*</url-pattern>
</servlet-mapping>
<!-- Welcome File -->
<welcome-file-list>
<welcome-file>path/firstPage.jsp</welcome-file>
</welcome-file-list>

17
<!-- all pages ending with .jsp are xml docs -->
<jsp-config>
<jsp-property-group>
<url-pattern>*.jsp</url-pattern>
<is-xml>true</is-xml>
</jsp-property-group>
</jsp-config>
</web-app>

The value of servlet-name is arbitrary, but the servlet-class must be javax.faces.webapp.Faces-


Servlet. The servlet-mapping makes sure, that every request to a resource of the form
http://myURL/pattern is handled by the JSF servlet. The faces servlet will then handle the request
with the corresponding JSP page.

3.3 The JSF Configuration File


The main configuration file for a JSF application is the faces-config.xml file. All elements of the
configuration file must be enclosed within a <faces-config> element. All top level elements
(application, managed-bean, ..., factory) are optional and can be included once or more than once.
The first group of elements are used for general application configuration, to declare the backing
beans and for the navigation configuration. The second group of elements are used to define
custom behaviour (e.g. custom validators or converters). The third group of elements is used to
define advanced features like the registration of phase listeners.
Usually, you only need the first three configuration elements. The other elements are used for
advanced programming.

The faces-config elements


The application element contains basic configuration information, such as the supported locales
and message resource bundle. Strings defined in this bundle can replace standard validation and
conversion error messages (cf. Chapter 8).

18
The component, render-kit, validator and converter elements are used to declare custom
components, custom renderers, custom validators and custom converters (cf. Chapter 7).
The life cycle element allows you to register one or more phase listeners, which are executed before
or after each phase of the Request Processing Life cycle (cf. Chapter 6).
The factory element provides a mechanism to define custom Factories like a custom Application- or
FacesContextFactory.
The managed-bean element is used to configure a managed bean, which will be created and
initialized by the Managed Bean Creation Facility the first time it is requested by a JSF EL
expression. Every managed bean must be declared in a separate entry.
The managed-bean element has a subelement named managed-property which can be used to
initialize any read/write properties (Setter Injection pattern).
The following figure shows the full hierarchy of the managed bean element. <description>,
<display-name>, <icon>, ... are optional elements, generally used for tools.

19
The managed property element can even be used to assign a reference to a previously defined
managed bean. You must be careful about the scope of these objects, because a managed bean
can’t reference an object with a shorter life span than the managed bean itself. For an example of
a bean reference confer to the faces-config.xml of the next chapter.

Web applications usually have multiple pages, and we must have some way to move between
them. For any given page, a navigation-rule defines what outcomes are understood, and what
pages to load based on those outcomes. Each specific mapping between an outcome and a page
is a navigation-case.

<navigation-rule>
<description>description of navigation cases</description>
<from-view-id>fromPage</from-view-id>
<navigation-case>
<from-action>action</from-action>
<from-outcome>a return value of the action</from-outcome>
<to-view-id>toPage</to-view-id>
</navigation-case>
<navigation-case>
<from-action>action</from-action>
<from-outcome>other return value of the action</from-outcome>
<to-view-id>toPage</to-view-id>
</navigation-case>
. . . (other navigation cases for this page)

</navigation-rule>

The from-action element can be left out, which means that the outcome may be produced by an
arbitrary action method or even be a constant value.

The fromPage value can also be an asterisk ( * ), which means that this rule applies to all pages.
The same result is achieved by omitting the <from-view-id> element.

<description>, <display-name> and <icon> elements are optional and are generally used for tools.

The next chapter shows a full example of a managed bean with initial values for (some of) its
properties and different navigation rules.

20
3.4 Configuration and Navigation Example
We extend our first easy example by introducing two new features: navigation rules and managed
properties. The hello.jsp page obtains two more buttons (Details / Goodbye). By pressing the
Details button, the user loads the persons detail page, the Goodbye button leads to the goodbye
page.

3.5 Hello.jsp
<jsp:root xmlns:jsp="http://java.sun.com/JSP/Page"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html" version="2.1">
<jsp:directive.page contentType="text/html"/>

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<link href="styles.css" rel="stylesheet" type="text/css"/>
<title>Hello, world!</title>
</head>
<body>
<f:view>
<h:form>
<h:outputText value="#{helloBean.helloText}"
styleClass="header"/>
<p>
<h:panelGrid columns="2" cellpadding="3">
<h:outputText value="Your Name:"/>
<h:outputText value="#{personDetails.name}"/>
<h:outputText value="Your Age:"/>
<h:outputText id="helloAge" value="#{personDetails.age}"/>
</h:panelGrid>
</p>
<h:commandButton value="Say Hello"
action="#{helloBean.sayHello}"/>
<h:commandButton value="Details" action="details"/>
<h:commandButton value="Goodbye"
action="#{helloBean.sayGoodbye}"/>
</h:form>
</f:view>
</body>
</html>
</jsp:root>

When we load the hello.jsp page for the first time, the outputText fields for name and age get their
values from the personDetails backing bean. The default values for name and age in the backing
bean are set by the Managed Bean Creation facility (managed-property in the faces
configuration file) at creation time (cf. faces-config.xml below).

21
3.6 PersonDetails.jsp
The PersonDetails page can be used to change the properties for
name, age and the favorite numbers of the given person.
The favorite numbers are saved in an array or vector of integers in
the person details backing bean.
All of these properties read their initial value at creation time from
the faces-config.xml file.

<?xml version="1.0" encoding="UTF-8"?>


<jsp:root xmlns:jsp="http://java.sun.com/JSP/Page"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html" version="2.1">
<jsp:directive.page contentType="text/html"/>

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<link href="styles.css" rel="stylesheet"
type="text/css"/>
<title>Person Details</title>
</head>

<body>
<f:view>
<h:form>
<h:outputText value="Person Details" styleClass="header"/>
<p>
<h:panelGrid columns="2" cellpadding="3">
<h:outputText value="Your Name:"/>
<h:inputText value="#{personDetails.name}"/>
<h:outputText value="Your Age:"/>
<h:inputText id="helloAge" value="#{personDetails.age}" size="4"/>
</h:panelGrid>
</p>
<p>
<h:outputText value="Enter your favorite Numbers:"/>
<h:panelGrid columns="3" cellpadding="3">
<h:inputText
value="#{personDetails.favoriteNumbers[0]}" size="4"/>
<h:inputText
value="#{personDetails.favoriteNumbers[1]}" size="4"/>
<h:inputText
value="#{personDetails.favoriteNumbers[2]}" size="4"/>
</h:panelGrid>
</p>

<h:commandButton value="Back" action="back"/>


</h:form>
</f:view>
</body>
</html>
</jsp:root>

The panelGrid components above is used to align the two input text fields for name and age. The
back button leads back to the hello page.

22
3.7 Goodbye.jsp
The goodbye.jsp page doesn't need a backing bean for its own, as it only prints out the goodbye
helloText.

<?xml version="1.0" encoding="UTF-8"?>


<jsp:root xmlns:jsp="http://java.sun.com/JSP/Page"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html" version="2.1">
<jsp:directive.page contentType="text/html"/>

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<link href="styles.css" rel="stylesheet"
type="text/css"/>
<title>Hello, world! </title>
</head>
<body>
<f:view>
<h:form>
<h:outputText value="#{helloBean.helloText}"
styleClass="header"/>
</h:form>
</f:view>
</body>
</html>
</jsp:root>

3.8 faces-config.xml
The Managed Bean Creation Facility uses the <managed-bean> element to create an instance
of helloWorld.PersonDetails and and store it in the session under the name personDetails
the first time the bean is accessed. As long as the same session is in use, the same instance of
personDetails will be used. This instance can be referenced with the expression #{personDetails}
(or #{sessionScope.personDetails }).
The same holds for the helloWorld.helloBean backing bean.

The properties are initialized with <managed-property> elements. The <value> element contains
the default value of the property specified in the <property-name> element. The Bean Creation
facility uses the associated setter method to assign the initial values to the right properties
(Property Injection: cf. Setter Injection pattern).

favoriteNumbers is a vector of (three) numbers. The vector is initialized by the <list-entries>


element and its three <values> children. The corresponding setFavoriteNumbers method takes a
Vector or a List of values as input argument.

<?xml version='1.0' encoding='UTF-8'?>

<faces-config 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-facesconfig_1_2.xsd"
version="1.2">

23
<managed-bean>
<description>Detail Information of a person</description>
<managed-bean-name>personDetails</managed-bean-name>
<managed-bean-class>helloWorld.PersonDetails</managed-bean-class>
<managed-bean-scope>session</managed-bean-scope>
<managed-property>
<property-name>name</property-name>
<value>John</value>
</managed-property>
<managed-property>
<property-name>age</property-name>
<value>17</value>
</managed-property>
<managed-property>
<property-name>favoriteNumbers</property-name>
<property-class>java.util.Vector</property-class>
<list-entries>
<value-class>java.lang.Integer</value-class>
<value>3</value>
<value>17</value>
<value>347</value>
</list-entries>
</managed-property>
</managed-bean>

<managed-bean>
<managed-bean-name>helloBean</managed-bean-name>
<managed-bean-class>helloWorld.HelloBean </managed-bean-class>
<managed-bean-scope>session</managed-bean-scope>
<managed-property>
<property-name>personDetails</property-name>
<value>#{personDetails}</value>
</managed-property>
<managed-property>
<property-name>helloText</property-name>
<value>Hello World!</value>
</managed-property>
</managed-bean>

To print out the name and the age of the given person, the helloBean backing bean needs a
reference to the personDetails backing bean. The reference to the previously defined managed
bean (PersonDatails) can be assigned to the helloBean via a normal JSF EL expression
(Dependency Injection).

24
3.9 Navigation

In the faces configuration file, we find three navigation cases for hello.jsp and one for the
personDetails.jsp page:
• By pressing the „Say Hello“ button, the sayHello action is processed which produces the
outcome „hello“. Therefore the hello.jsp page will be reloaded (with the new values entered
by the user).
• Pressing the „Details“ button leads us to the personDetails.jsp page.
• Pressing the „Goodbye“ button executes the sayGoodbye action method which produces
the outcome „goodbye“, which leads us to the goodbye.jsp page.
• From the personDetails page we can go back to the hello.jsp page by pressing the „Back“
button.

<!-- navigation rules -->


<navigation-rule>
<description>Navigation from the hello page.</description>
<from-view-id>/hello.jsp</from-view-id>
<navigation-case>
<from-action>#{helloBean.sayHello}</from-action>
<from-outcome>hello</from-outcome>
<to-view-id>/hello.jsp</to-view-id>
</navigation-case>
<navigation-case>
<from-outcome>details</from-outcome>
<to-view-id>/details.jsp</to-view-id>
</navigation-case>
<navigation-case>
<from-action>#{helloBean.sayGoodbye}</from-action>
<from-outcome>goodbye</from-outcome>
<to-view-id>/goodbye.jsp</to-view-id>
</navigation-case>
</navigation-rule>

<navigation-rule>
<description>Navigation from the Person Details page.</description>
<from-view-id>/details.jsp</from-view-id>
<navigation-case>
<from-outcome>back</from-outcome>
<to-view-id>/hello.jsp</to-view-id>
</navigation-case>
</navigation-rule>

</faces-config>

25
3.10 HelloBean.java
The helloBean.java file has a new action method for the Goodbye button: sayGoodbye():

package helloWorld;

public class HelloBean {

/** The reference to the person deatils backing bean */


private PersonDetails personDetails;

/** The hello text. */


private String helloText;

/** Set the person details reference. */


public void setPersonDetails(PersonDetails personDetails) {
this.personDetails = personDetails;
}

/** Get the hello text. */


public String getHelloText() {
return helloText;
}

/** Set the hello text. */


public void setHelloText(String text) {
helloText = text;
}

/** Define the text to say hello. */


public String sayHello() {
if (personDetails.getAge() < 11)
helloText = "Hello " + personDetails.getName() + "!";
else
helloText = "Good Morning " + personDetails.getName() + "!";
return "hello";
}

/** Define the text to say goodbye. */


public String sayGoodbye() {
if (personDetails.getAge() < 11)
helloText = "See you, " + personDetails.getName() + "!";
else
helloText = "Goodbye " + personDetails.getName() + "!";
return "goodbye";
}
}

26
4 The Standard JSF Components
In this chapter, we cover the standard components that all JSF implementations must support.
They provide the basic set of functionality necessary for building HTML-based web applications.
You can expect third-party developers to provide additional components as well. Here we will focus
on the most important components only.
We start with the basic attributes, which are applicable to most of the components.
• id: An identifier for a component
• rendered: A boolean value, if set to false suppresses rendering of this component
• value: The components value, typically a value binding
• required: A boolean value, if true a value is required for this input field
• styleClass The CSS class name which should be used for this component

4.1 The Layout of the Components


HtmlPanelGrid is useful for creating arbitrary, static component layouts (it maps to the <table>
element). You can also configure header and footer with facets that map to the <thead> and
<tfoot> table subelements, respectively.
Child components are organized according to the specified number of columns. When we specify
two columns, the first two components form the first row (one per column), the next two form the
second row, and so on. The width, border, and cellpadding properties are passed through to the
HTML table. Unlike the HTML table, you don’t have to explicitly denote columns and rows.

<h:panelGrid columns="2" headerClass="page-header"


cellpadding="1" border="1" width="40%">
<f:facet name="header">
<h:outputText value="This is the table header"/>
</f:facet>
<h:outputText value="(1,1)"/>
<h:outputText value="(1,2)"/>
<h:outputText value="(2,1)"/>
<h:outputText value="(2,2)"/>
</h:panelGrid>

The HtmlPanelGroup component groups a set of components together, so that they can be
treated as a single entity.

<h:panelGrid columns="2" headerClass="page-header"


cellpadding="1" border="1" width="40%">
<h:outputText value="(1,1)"/>
<h:panelGroup>
<h:outputText value="(1,2.1)"/>
<h:outputText value="(1,2.2)"/>
</h:panelGroup>
<h:panelGroup>
<h:outputText value="(2.1,1)"/>
<h:outputText value="(2.2,1)"/>
</h:panelGroup>
<h:outputText value="(2,2)"/>
</h:panelGrid>

27
4.2 The Output Components

The purpose of the output components is to display data. You can specify literally the data that
they display or have them display properties from backing beans.
The most basic output component is HtmlOutputText (<h:outputText>). HtmlOutputText converts
the given value to a string and displays it with optional CSS style support.
Example:
<h:outputText value="#{helloBean.helloText}" styleClass="header"/>
<h:outputText value="#{helloBean.goodbyeText}" styleClass="header"/>

The HtmlOutputLabel component is used for associating labels with form elements (InputText,
ChoiceButton, ...). HtmlOutputLabel is translated to the HTML <label> element. This allows target
devices to define shortcuts for input elements.

Example
<h:panelGroup>
<h:outputLabel for="helloInput" accesskey="N">
<h:outputText value="Your Name:"/>
</h:outputLabel>
<h:inputText id="helloInput" value="#{helloBean.name}"
required="true" accesskey="N"/>
</h:panelGroup>

4.3 The Basic Input Components

The HtmlInputText component is used for basic user input. It maps to a simple text field—the
<input> element with type “text”.

<h:inputText id="helloInput" value="#{helloBean.name}" size="30" required="true"/>


<h:inputText id="helloAge" value="#{helloBean.age}" size="4" disabled="true"/>

The size and disabled properties are passed through to the HTML input tag. In this example, the
component is associated via a value-binding expression with the name property of helloBean.
HtmlInputText is the most common input control, but it is
restricted to a single line.

If you need a multi line input field, you can use the
HtmlInputTextarea component.
<h:inputTextarea value="#{helloBean.helloText}" rows="5" />

28
The HtmlInputSecret component is used to display a password input field. Any text the user types
is displayed using the asterisk or some other character (depending on the browser).

<h:inputSecret value="#{user.password}" size="10" maxlength="10"/>

For the input of boolean values, we can use a HtmlSelectBooleanCheckbox component.

<h:outputLabel for="accepted" accesskey="A">


<h:outputText value="Accepted"/>
</h:outputLabel>
<h:selectBooleanCheckbox value="#{helloBean.accepted}" id="accepted"/>

The selectBooleanCheckbox component works fine for a single check box on a form. If you want to
associate multiple check boxes with a single property, you preferably use a HtmlSelectMany-
Checkbox (see next chapter).

4.4 Choice Input Components


User interfaces often allow a user to select one or more items from a set of possible choices. In
JSF, a selection item represents a single choice, and has a value, a description, and a label.
Components in the SelectMany and SelectOne families, like HtmlSelectManyCheckbox and
HtmlSelectOneListbox, display lists of items.

A UISelectItem component are used to display items in a list and to select one or more items from
this list. You can either use the value itemDescription, itemLabel, and itemValue properties or a
value-binding expression.

<f:selectItem itemValue="0" itemLabel="cats"/>


<f:selectItem value="#{myBean.animal[3]}"/>

Alternatively, you can use a selectItems tag with a value binding to a list or array of elements.
<f:selectItems value="#{myBean.animalList}"/>

These selectItem(s) tag can be used to configure another component’s selection list (e.g. for
components like HtmlSelectManyCheckbox, HtmlSelectOneRadio, HtmlSelectOneListbox or
HtmlSelectOneMenu).

All of these choice components work in a similar way. Therefore, only one of these components is
described here: HtmlSelectOneMenu.

HtmlSelectOneMenu displays its child items in a list box using the HTML <select> element. The
number of items displayed is always one, so the result is a combo box (also called a drop-down list
box).

29
<h:outputText value="Your Favorite Animal "/>
<h:selectOneMenu id="animal" value="#{helloBean.animal}" accesskey="A">
<f:selectItems value="#{helloBean.animals}"/>

</h:selectOneMenu>

In the corresponding JavaBean, you have to provide an array or a


list property named animals, which can either be initialized in the
backing bean (e.g. as list of strings) or in the faces configuration
file.
Initialization in the faces configuration file (faces-config.xml):

<managed-bean>
<description>The one and only HelloBean.</description>
<managed-bean-name>helloBean</managed-bean-name>
<managed-bean-class>helloWorld.HelloBean </managed-bean-class>
<managed-bean-scope>session</managed-bean-scope>
<managed-property>
<property-name>animals</property-name>
<list-entries>
<value>Cat</value>
<value>Dog</value>
<value>Bird</value>
</list-entries>
</managed-property>
</managed-bean>

In the backing bean, you have to provide the corresponding get and set methods for the favorite
animal and the selection list of animals:

private String animal;


private List<SelectItem> animals;

public String getAnimal() {


return animal;
}
public void setAnimal(String a) {
this.animal = a;
}
public List<SelectItem> getAnimals() {
return animals;
}
public void setAnimals(List<String> items) {
animals = new ArrayList<SelectItem>();
for (String item : items)
animals.add(new SelectItem(item));
}

30
4.5 Data Tables
The HtmlDataTable component displays an HTML <table>. The columns are specified with
column components. For each row, HtmlDataTable uses the column components as a
template for each column. If the facet tag has a name=“header“ attribute, it is translated to a
<thead> (table header) HTML tag. The var property defines the name of the iterator
variable (here person). If the row property
is specified, it displays that many rows
(starting with the first).

<h:dataTable value="#{helloBean.friends}" var="person" first="0" rows="2">


<h:column>
<f:facet name="header">
<h:outputText value="Last Name"/>
</f:facet>
<h:inputText value="#{person.lastName}"/>
</h:column>
<h:column>
<f:facet name="header">
<h:outputText value="First Name"/>
</f:facet>
<h:inputText value="#{person.firstName}"/>
</h:column>
<h:column>
<f:facet name="header">
<h:outputText value="Age"/>
</f:facet>
<h:inputText value="#{person.age}"/>
</h:column>
</h:dataTable>

In the backing bean, you have to provide a corresponding list of friends (here Person) with a
firstName, a lastName and an age attribute.

private Person[] friends = {


new Person("Hans", "Muster", 33),
new Person("Peter", "Meier", 44),
new Person("Heidi", "Schmid", 22)};

public Person[] getFriends(){


return friends;
}

The Person class provides the corresponding entries:


public class Person {
String firstName;
String lastName;
int age;
Person(String firstName, String lastName, int age){
this.firstName = firstName;
this.lastName = lastName;
this.age = age;
}

31
public String getFirstName(){
return firstName;
}
public void setFirstName(String firstName){
this.firstName = firstName;
}

public String getLastName(){


return lastName;
}
. . .
}

4.6 Processing Row-Specific Events


A very common application feature is to have a table with
summery information where each row is linked to the details
about the item in that row. To implement this feature, we
must figure out which table row the user selected to make
the corresponding details available for display.

In the JSF table we have to change the following entries:

<h:dataTable value="#{personHandler.personModel}" var="person"


border="1" cellspacing="0" rows="2">
<h:column>
<f:facet name="header">
<h:outputText value="Last Name"/>
</f:facet>
<h:commandLink action="#{personHandler.select}" immediate="true">
<h:outputText value="#{person.lastName}"/>
</h:commandLink>
</h:column>
<h:column>
<f:facet name="header">
<h:outputText value="First Name"/>
</f:facet>
. . .
</h:column>
</h:dataTable>

The table looks similar to the previous one, but there are some important differences. The Last-
Name column uses an <h:commandLink> component instead of an outputText and the value of the
<h:dataTable> is now an instance of javax.faces.model.DataModel instead of the previous array of
Person.

How can we determine which row of the table has been selected when handling the action event?
You could find it out by using a query string parameter or a hidden field.
However, JSF offers a much easier way to represent tabular data through the abstract DataModel
class. DataModel has two subclasses: ListDataModel and ArrayDataModel. These are
convenience implementations of the abstract DataModel class with the following properties:

32
• boolean: rowAvailable is true, when the rowIndex property holds the index of an
existing row, false otherwise.
• int: rowCount is the number of rows (or -1 if unknown)
• Object: rowData the object at rowIndex (or null if rowIndex = -1)
• int: rowIndex gives the currently selected row (or -1, if no row is selected)
• Object: wrappedData is the object representing the table.

The <h:dataTable> uses the personModel DataModel to read the table entries from. There are
no changes necessary in the HelloBean or Person class. All we need is a new PersonHandler
class as a wrapper for the array of Person objects.

package helloWorld;
import javax.faces.model.*;

public class PersonHandler {


private DataModel personModel = new ArrayDataModel();
private HelloBean helloBean;
private Person selectedPerson;

public DataModel getPersonModel() {


personModel.setWrappedData(getPersons());
return personModel;
}

public Person[] getPersons() {


return helloBean.getFriends();
}

public String select() {


selectedPerson = (Person) personModel.getRowData();
return "success";
}

public Person getSelectedPerson() {


return selectedPerson;
}

public void setHelloBean(HelloBean helloBean) {


this.helloBean = helloBean;
}
}

The getPersonModel() method creates an instance of the javax.faces.model.ArrayDataModel


class which is a subclass of DataModel. Then, it populates the ArrayDataModel with the Person
array returned by getPersons().
Other sublasses of DataModel are ListDataModel (for Lists) or ResultSetDataModel (for a JDBC
ResultSet).

The <h:commandLink> in each table row is bound to the PersonHandlers select() method. The
renderer together with the UIData component ensure that the DataModels rowIndex is
positioned to the selected row when the action method is invoked. Therefore, we can use
getRowData() in the select() method to read the data of the selected person.

33
4.7 The Command Components
The command components represent an action initiated by the user. The two standard command
components are HtmlCommandButton (for displaying a button) and HtmlCommandLink (for
displaying a hyper link). Because they perform the same operation, their usage is quite similar.

<h:commandButton value="Say Hello"


action="#{helloBean.sayHello}"/>
<h:commandButton value="Goodbye"
action="#{helloBean.sayGoodbye}"/>

The corresponding action Methods are defined in the backing


bean:

public String sayHello() {


if (age < 11)
helloText = "Hello " + name + "!";
else
helloText = "Good Morning " + name + "!";
return "hello";
}

34
5 Messaging
5.1 Messages
Multiple parts of a JSF application (validators, converters, application exceptions ... ) can generate
messages. Usually, these messages have to be displayed to the user.

HtmlMessage is designed to display a message for a specific UI component, and is useful


whenever you need to inform the user of any errors. It is typically used with input controls, but
that’s not a requirement.
Messages contain a summary and a detail text.

Example: Message for input control helloInput.

<h:message for="helloInput" showDetail="true" showSummary="true"


errorStyle="color: red"/>

The attributes showDetail and showSummary are optional. The default value for showDetail is true,
that for showSummary is false.

Every message has a severity level which is equal to one of the following values.
• Info - Represents an informational text to be send back to the user. You can insert an
infoClass or an infoStyle attribute to define a CSS class / CSS style for messages
with Info severity.
• Warn - Indicates that an error may have occurred.You can insert a warnClass or a
warnStyle attribute to define a CSS class / CSS style for messages with Warn severity.
• Error - Indicates an error like validation or conversion error. You can insert an
errorClass or an errorStyle attribute to define a CSS class / CSS style for messages
with error severity.
• Fatal - Indicates a serious (application) error. You can insert an fatalClass or a
fatalStyle attribute to define a CSS class / CSS style for messages with fatal severity.
Whenever possible, the error is placed next to the component (so the user knows where the
problem arises). If more than one message is registered for a component (which can happen if
more than one validator is registered, or if a validator has problems with conversion), HtmlMessage
displays only the first one.

If you need to display multiple messages for a page, you should use HtmlMessages instead.

Example: all messages for this page:


<h:messages showDetail="true" showSummary="true" layout="table"
errorStyle="color: red"/>

35
5.2 Overriding standard Messages
All of the standard validators and converters have default messages. These are configured using a
normal Java message bundle. In the reference implementation, for example, we would find the
following key/value pair, creating a message for an empty input field with a required=“true“
attribute:

javax.faces.component.UIInput.REQUIRED={0}: Validation Error: Value is required.


javax.faces.component.UIInput.CONVERSION={0}: Conversion error occurred.

The used parameters are defined in the JSF documentation for the corresponding messages.

In general, these default messages are not very user friendly. Therefore we often would like to
override these texts with custom messages. One possibility is to define an error message in the
tag of the corresponding input component. Possible values are
– requiredMessage for required input,
– converterMessage for conversion errors and
– validatorMessage for validation errors.

<h:inputText id="helloInput" value="#{helloBean.name}" required="true"


requiredMessage="Please enter your name into this input field">

Furthermore, the details message texts are often missing. We can override the default messages
by a custom message bundle. Each JSF application can be associated with a single message
bundle (e.g. messages.properties), which is configured in the faces-config.xml file:

<faces-config>
<application> <!-- messages.properties file at /WEB-INF/classes -->
<message-bundle>messages</message-bundle>
</application>
. . .
</faces-config>
Once, you have defined a message bundle, you can selectively override the standard messages,
as long as you use the correct keys (see java.sun.com/javaee/javaserverfaces/
1.2_MR1/docs/api/index.html for the list of message keys).

The messages.properties file then might look as follows:

javax.faces.converter.IntegerConverter.INTEGER=The given input value '{0}' is


not an integer.
javax.faces.converter.IntegerConverter.INTEGER_detail=The input value should be
an integer like 17.
javax.faces.component.UIInput.REQUIRED=Input value for {0} is required.
javax.faces.component.UIInput.REQUIRED_detail=Input value for {0} must not be
void.

Whenever a JSF component, validator or converter looks for an error message, it will look for them
in the JSP page and in the custom messages bundle (messages.properties). Only if there is no
user defined message, it will take the predefined standard message.

36
5.3 Constructing Application Messages
Whenever one of your backing beans throws an exception or when an error occurs in your
application logic (e.g. system or connection errors), you want to inform the users about this.
For this, you can create a message in your backing bean (or validator or converter class or
method).

Creating a Faces Message in the Backing Bean


In the following action method we create a FacesMessage to inform the users about errors in the
name input field. The FacesMessage constructor takes the arguments severity, the summary string
and the detail string.
/** Define the text to say hello. */
public String sayHello() {

if (!isValidName(name)) {

// create faces message


FacesMessage message =
new FacesMessage(FacesMessage.SEVERITY_ERROR,
"Name is not valid!",
"Your name must not be empty and not start with letter 'A'");

// add message to faces context


FacesContext context = FacesContext.getCurrentInstance();
context.addMessage(null, message);
helloText = "Hello!";

} else { // name is valid


if (age < 10)
helloText = "Hello " + name + "!";
else
helloText = "Good Morning " + name + "!";
}
return "hello";
}

/** test whether given string is a valid name. */


private boolean isValidName(String s) {
return (name.length() > 0 && name.charAt(0) == 'A');
}

You have to add this messages to the FacesContext, from where the JSP page will read it
afterwards: context.addMessage(null,message));

The addMessage function takes two parameters: the message id (either the component id or null, if
the message does not belong to any component) and the FacesMessage.

Application messages do not belong to any component on the jsp page. If we want to retrieve the
application messages only (the messages, which belong to no component) we use the
globalOnly attribute:
<h:messages globalOnly=“true“>.

37
Retrieving Message Texts from the Message Bundle

In the previous example, we used hard coded message texts from our backing beans. Usually, you
want to read those messages from a message bundle, instead. Therefore, you preferably use the
custom message bundle to define your application messages and read these message texts from
there.
In the following example we take this improved approach. In your backing bean, you create a
message (of type FacesMessage) by first extracting the name of the message bundle and from this
the summary and detail string of the desired message.

The following MessageFactory provides us with the desired FacesMessage:

public class MessageFactory {


public static FacesMessage getMessage(FacesMessage.Severity severity,
String key, Object... params) {
String summary = "?? key " + key + " not found ??";
String detail = null;
FacesContext context = FacesContext.getCurrentInstance();
String name = context.getApplication().getMessageBundle(); // ( 1 )
if (name == null)
name = FacesMessage.FACES_MESSAGES;
ResourceBundle bundle = ResourceBundle.getBundle(name); // ( 2 )
try {
summary = bundle.getString(key); // ( 3 )
summary = MessageFormat.format(summary, params);
detail = bundle.getString(key + "_detail"); // ( 3 )
detail = MessageFormat.format(detail, params);
} catch (MissingResourceException e) {}
return new FacesMessage(severity, summary, detail); // ( 4 )
}
}

38
Example: Print out an information message for invalid name values (cf. HelloWorld4).

helloBean.java
/** Define the text to say hello. */
public String sayHello() {
FacesContext context = FacesContext.getCurrentInstance();
if (!isValidName(name)) {

// create hello message and add it to faces context


context.addMessage(null, MessageFactory.getMessage(
FacesMessage.SEVERITY_ERROR, "helloWorld.nameMessage", name));

helloText = "Hello!";
} else {
if (age < 10)
helloText = "Hello " + name + "!";
else
helloText = "Good Morning " + name + "!";
}
return "hello";
}

/** test whether given string is a valid name. */


private boolean isValidName(String s) {
return (name.length() > 0 && name.charAt(0) == 'A');
}

The messages.properties file for the application message contains messages of the form:
javax.faces.component.UIInput.REQUIRED= This value is required.
javax.faces.component.UIInput.REQUIRED_detail={0}: Input value must not be void.
javax.faces.converter.IntegerConverter.INTEGER=The given input value ''{0}'' is
not an integer.
javax.faces.converter.IntegerConverter.INTEGER_detail={2}: The input value
should be an integer like 17.

helloWorld.nameMessage= Name ''{0}'' is not valid!

hello.jsp
<h:form id="main">
<h:outputText value="#{helloBean.helloText}" styleClass="header"/>
<h:panelGrid columns="3">
<h:outputText value="Your Name"/>
<h:inputText id="name" label="Name" value="#{helloBean.name}"
required="true" requiredMessage="Please enter your name"/>
<h:message for="name" errorClass="errorStyle"
showDetail="false" showSummary="true"/>

39
<h:outputText value="Your Age"/>
<h:inputText id="age" label="Age" value="#{helloBean.age}"
required="true"/>
<h:message for="age" errorClass="errorStyle" showDetail="false"
showSummary="true"/>

<h:outputText value="Country"/>
<h:inputText id="country" label="Country"
value="#{helloBean.country}" required="true"/>
<h:message for="country" errorClass="errorStyle" showDetail="false"
showSummary="true"/>
</h:panelGrid>

<h:commandButton value="Hello" action="#{helloBean.sayHello}"/>


<h:commandButton value="Goodbye" action="#{helloBean.sayGoodbye}"/>
<p>
<h:messages layout="table" showDetail="true" showSummary="false"
infoClass="infoStyle" errorClass="errorStyle" globalOnly="false"/>
</p>
</h:form>

We then obtain either one or more error messages (in case of any input errors):

or the application message created by the MessageFactory:

40
6 Request Processing
When a JSF view is requested, the components in the view are asked to perform tasks in a certain
order, defined as phases of a request processing life cycle. The following graphic shows the main
tasks for each phase.

6.1 Restore View


• Extract the view ID and find current view
• Look up the components for the current view, create them if necessary
• Restore or create the component values, event listeners, validators and converters
• If there is no (new) user input, skip to render response phase (6)

41
6.2 Apply Request Values
• Decoding: extract all user input from the input fields (and save them in the submittedValue
attribute of the component).
• Create action events and add them to the faces context for later processing.
• If the immediate attribute of a component is set to true, validation takes place in this phase
instead of the process validation phase.
• If there is a command button or a hyper link with an immediate property set to true, the
corresponding actions will be fired in this phase instead of the invoke application phase. This
can be used for example for Cancel buttons, because it prevents the validation of any input
fields.
6.3 Process Validation
• Convert submitted values: Convert the value of the submittedValue attribute of the
component from string type to object.
• Validate submitted values: After conversion, the value is validated and set as the local value
of this component.
• If the conversion or the validation process throws an exception, the control will skip to the
render response phase (6).
• If the local value has changed, a valueChangeEvent is fired and consumed by the registered
listeners.

6.4 Update Model Values


• Evaluate the JSF EL expressions in the components' value attribute to find the associated
backing beans and properties (depending on the beans' scope: request, session, application).
• The set methods of these properties are called, which update the backing bean with the
(new) validated and converted local values of the components.

6.5 Invoke Application


• Handle all fired events.
• Execute default action listener method.
• Call the event handler methods of all registered event listeners.
• Choose the next page based on the action method's outcome.

6.6 Render Response


• Save the state of the new view for later use in the restore view phase (1).
• Invoke the converters (object to string).
• Display the next view with the new values from the backing beans.

42
7 Validators and Converters
JSF supports validation and conversion through validator or conversion methods of backing beans
and validator and converter objects.

Validation checks the value of a control to see if its current value is acceptable. The associated
object in the backing bean is updated only if the value is accepted. Otherwise, an error message is
generated for that specific component, and the associated object is not modified. These
error messages can then be displayed back to users with a <h:message> or <h:messages> tag.

When users see an object on the screen, they see it in terms of recognizable text, like May 23,
1980. A Java Date object, on the other hand, is much more than just a string. Two Date objects
can be compared and we can compute the elapsed time between the two dates.
This is the purpose of a converter - to create a string representation of an object, and to create an
object representation of a string.
JSF provides a set of standard converters to satisfy the basic type conversion needs. You can
also write your own converters, and third-party vendors will provide them as well.
As with validators, converters create converter exceptions and send them back to the user as
faces messages.

7.1 Standard Validators


JSF includes a few standard validators for the most common validation problems:

<f:validateLength> can be used to ensure that the number of letters given in the input field is
greater/smaller than or equal to the specified minimum/maximum value.

<h:outputText value="Your Name:"/>


<h:inputText id="helloInput" value="#{helloBean.name}">
<f:validateLength minimum="2" maximum="10"/>
</h:inputText>
<h:message for="helloInput" styleClass="errorMessage"/>

<f:validateLongRange> and <f:validateDoubleRange> can be used to ensure that the


(long/double) value inserted in the input field is greater than or equal to the specified maximum
(long/double) value (smaller than or equal to the minimum value).

<h:inputText id="helloAge" value="#{helloBean.dateOfBirth}">


<f:validateLongRange minimum="0" maximum="120"/>
</h:inputText>
<h:message for="helloAge" styleClass="errorMessage"/>

43
7.2 Validator Methods
An input field can also be associated with a validation method on a backing bean. Validation
methods are generally used for application specific validation and can not be reused for different
applications. For any input component you can register one or more validators.

<h:inputText id="helloInput" value="#{helloBean.name}"


validator="#{helloBean.nameCheck}">
<f:validateLength minimum="2" maximum="10"/>
</h:inputText>

The corresponding nameCheck method in the backing bean:

public void nameCheck( FacesContext context,


UIComponent component, Object value)
{
if (!value.toString().trim().matches("[A-Z][a-z]*"))
{
FacesMessage message = MessageFactory.getMessage(
FacesMessage.SEVERITY_ERROR, "NameValidator.INVALID_NAME");
throw new ValidatorException(message);
}
}

7.3 Validator Classes


Validator classes raise some additional work. On the other hand, validator classes are generic and
designed for use in different applications.
The validator interface demands for one method: validate().

public class NameValidator implements Validator {


/** The identifier of the validator. */
public static final String VALIDATOR_ID = "NameValidator";
/** The identifier of the error message. */
public static final String INVALID_NAME_MESSAGE_ID
= "NameValidator.INVALID_NAME";

public void validate(FacesContext context,


UIComponent component, Object value) {
if (!value.toString().trim().matches("[A-Z][a-z]*")) {
FacesMessage message = MessageFactory.getMessage(
FacesMessage.SEVERITY_ERROR, INVALID_NAME_MESSAGE_ID);
throw new ValidatorException(message);
}
}
}

To ensure that this validator class is instantiated, we have to declare it as validator in the faces-
config.xml file:

44
<faces-config>
<managed-bean>
. . .
</managed-bean>
<navigation-rule>
. . .
</navigation-rule>
<validator>
<validator-id>NameValidator</validator-id>
<validator-class>helloWorld.NameValidator</validator-class>
</validator>
</faces-config>

This class can then be used as validator in any JSP page:

<h:inputText id="helloInput" value="#{helloBean.name}">


<f:validator validatorId="NameValidator"/>
</h:inputText>

7.4 Automatic Conversion


If you don’t specify a converter, JSF will pick one for you. The JSF framework has standard
converters for all the basic Java types: BigDecimal, BigInteger, Boolean, Byte, Character, Integer,
Short, Double, Float, and Long. All primitive types are converted to their object counterparts. So for
all these types, conversion is performed automatically.

7.5 Standard Converters


There are two converter tags: <f:convertDateTime> and <f:convertNumber>

<h:inputText value="#{helloBean.dateOfBirth}">
<f:convertDateTime type="date"/>
</h:inputText>

f:convertDateTime can be used to convert a Date object to a string (and vice versa). The type
attribute is optional and can be either date or time or both, depending on what you want to print
out.

The number converter is useful for displaying numbers in basic formats like a currency or a
percentage.

<h:inputText value="#{helloBean.price}">
<f:convertNumber pattern="SFr. #,##0.00"/>
</h:inputText>

We would obtain a similar result by the code:

<h:inputText value ="#{helloBean.price}">


<f:convertNumber maxFractionDigits="2"/>
</h:inputText>

45
7.6 Using Custom Converters
In many cases, the standard converters will be sufficient; they handle all of the standard Java data
types, and also provide sophisticated formatting functionality for dates and numbers.
You have to develop custom converters any time you want to make it easy for a front-end
developer to display a special data type, or accept input for that special data type.

In our example, the user can insert a two letter country code, which is automatically converted into
the corresponding country name.

public class CountryConverter implements Converter {


/** The identifier of the converter. */
public static final String CONVERTER_ID = "CountryConverter";

/** The identifier of the error message. */


public static final String COUNTRY_CONVERTER_MESSAGE_ID =
"CountryConverter.INVALID_COUNTRY_KEY";

HashMap<String, String> countries;

public Object getAsObject(FacesContext context,


UIComponent component, String value)
throws ConverterException {
if(value.trim().length() < 2) {
FacesMessage message = MessageFactory.getMessage( ... );
throw new ConverterException(message);
}
if(countries.containsKey(value))
return countries.get(value);
return value;
}

public String getAsString(FacesContext context,


UIComponent component, Object value) throws ConverterException {
return value.toString();
}
}

You can use this converter in the JSP page:

<h:inputText id="country" value="#{helloBean.country}">


<f:converter converterId="CountryConverter"/>
</h:inputText>

The converter has to be configured in the faces-config.xml file:

<converter>
<converter-id>CountryConverter</converter-id>
<converter-class>helloWorld.CountryConverter
</converter-class>
</converter>

46
8 Internationalization
Enabling an application to support multiple locales is called internationalization. The process of
modifying an application to support a (new) locale is called localization. Some implementations,
like the reference implementation, provide localized messages for validator and converter errors for
certain languages (English, French and German).

8.1 Load the Resource Bundle


Using a resource bundle in a JSF application is as simple as using a value-binding expression. All
you have to do is to define the proper resource bundle in the faces-config file.

<faces-config . . . >
<application>
<locale-config>
<default-locale>en</default-locale>
<supported-locale>de</supported-locale>
</locale-config>
<message-bundle>messages</message-bundle>
<resource-bundle>
<base-name>texts</base-name>
<var>label</var>
</resource-bundle>
</application>

If the bundles are placed in WEB-INF/classes, no prefix is needed. However, if we had nested
them deeper, like in the WEB-INF/classes/org/jia directory, the basename would be “org.jia.texts”.

Once the bundle has been loaded, you can grab a particular string from that bundle with an
ordinary value-binding expression such as #{label.theKey}.
If the resource bundle can not find a key, it will return the string “??? key ???” instead.

With JSF 1.1 you had to define the texts with the <f:loadBundle> tag. The following tag loads the
bundle and stores it in the request scope.

<f:view ... >


<f:loadBundle basename="texts" var="label"/>
. . . .

<f:view>

The basename attribute specifies the name of the resource bundle, prefixed by its location in your
classpath. The var attribute specifies the name which is used in your JSF component tags. Both
attributes (basename and var) are required.

47
8.2 Configuring Locales
The first step towards supporting multiple languages is to tell your JSF application which locales it
should support and which of the supported locales should be used as the default locale. You
specify the supported locales with the <locale-config> element in the faces configuration file:

<faces-config>
<application>
<locale-config>
<default-locale>en</default-locale>
<supported-locale>de</supported-locale>
<supported-locale>fr</supported-locale>
<supported-locale>it</supported-locale>
</locale-config>
</application>
...

</faces-config>

8.3 Creating Resource Bundles

Resource bundles are not a JSF feature—they are a fundamental part of the way Java handles
internationalization and localization. Resource bundles are normal property files with key/value
pairs. Each string has a key, which is the same for all locales. So the key „helloWorld“ points to the
string that represents the welcome message, whether it is in English, French, or German.
texts_de.properties
helloWorld=Hallo, ihr alle!
yourName=Ihr Name
dateOfBirth=Geburtsdatum
country=Land
hello=Hallo
goodMorning=Guten Tag
goodbye=Auf Wiedersehen
seeYou=Tschüss
texts_en.properties
helloWorld=Hello, world!
yourName=Your Name
dateOfBirth=Date of Birth
country=Country
hello=Hello
goodMorning=Good Morning
goodbye=Goodbye
seeYou=See you

48
8.4 Using Resource Bundles
Once you have created one or more resource bundles, you will have to make sure that your JSF
components use the string in the bundle instead of a hard coded text value:

<h:outputText value="#{label.yourName}"/>
<h:outputText value="#{label.dateOfBirth}"/>
<h:commandButton value="#{label.goodbye}"
action="#{helloBean.sayHello}"/>

If you need localized texts in your backing beans, a getText method like the following can be
useful:
private String getText(String key) {
String text = "???" + key + "???";
try {
FacesContext context = FacesContext.getCurrentInstance();
Locale locale = context.getViewRoot().getLocale();
ResourceBundle bundle = ResourceBundle.getBundle("texts", locale);
text = bundle.getString(key);
}
catch (MissingResourceException e) {}
return text;
}

You can use this method to extract the correct string from the bundle:
helloText = getText("goodbye") + " " + name + "!";

8.5 Constructing Localized Messages


In order to localize your error or information messages, you can configure an application-wide
message bundle. The name of your message bundle (here messages) and the supported locales
have to be defined in the faces-config.xml file:

<faces-config>
<application>
<locale-config>
<default-locale>en</default-locale>
<supported-locale>en</supported-locale>
<supported-locale>de</supported-locale>
</locale-config>
<message-bundle>messages</message-bundle>
</application>
...
</faces-config>

49
For each of the supported locales, you have to provide a corresponding messages_xx.properties
file:
messages_de.properties (German message bundle)
javax.faces.validator.LengthValidator.MAXIMUM=Die Eingabe ist zu lang.
javax.faces.validator.LengthValidator.MAXIMUM_detail=Der Eingabewert darf
höchstens {0} Zeichen lang sein.
javax.faces.validator.LengthValidator.MINIMUM=Die Eingabe ist zu kurz.
javax.faces.validator.LengthValidator.MINIMUM_detail=Der Eingabewert muss
mindestens {0} Zeichen lang sein.
NameValidator.INVALID_NAME=Ungültiger Namenswert.
NameValidator.INVALID_NAME_detail=Namenswert entspricht nicht dem Pattern [A-Z]
[a-z]*
CountryConverter.INVALID_COUNTRY_KEY=Ungültiger Ländercode.
CountryConverter.INVALID_COUNTRY_KEY_detail=Land muss ein Ländercode aus 2
Buchstaben sein

messages_en.properties (English message bundle)


javax.faces.validator.LengthValidator.MAXIMUM=Input value too long.
javax.faces.validator.LengthValidator.MAXIMUM_detail=The input value can''t be
more than ''{0}'' characters long.
javax.faces.validator.LengthValidator.MINIMUM=Input value too short.
javax.faces.validator.LengthValidator.MINIMUM_detail=The input value must be at
least ''{0}'' characters long.
NameValidator.INVALID_NAME=Invalid value for name.
NameValidator.INVALID_NAME_detail=Name value does not match pattern [A-Z][a-z]*
CountryConverter.INVALID_COUNTRY_KEY=Invalid country key.
CountryConverter.INVALID_COUNTRY_KEY_detail=Country must be a 2 letter country
code

JSF will use your bundles to override default validation and conversion error messages.

The corresponding JSP page uses a normal message tag:


<h:message for="country" styleClass="errorMessage"/>
<h:messages showDetail="true" layout="table" styleClass="errorMessage"/>

50
8.6 Using Localized Message Bundles for Application Messages
You can also use the message bundle to create your own (error) messages.

In your backing bean, validator or converter, you can create a message (of type FacesMessage)
by first extracting the client's locale, the name of the message bundle and from this the summary
and detail string of the dedicated message. The FacesMessage constructor takes the arguments
severity (SEVERITY_INFO, SEVERITY_WARN, SEVERITY_ERROR, or SEVERITY_FATAL)
summary string and detail string.
The MessageFactory from chapter has to be changed somewhat to provide us with the desired
localized FacesMessage:

MessageFactory.java
public class MessageFactory {

public static FacesMessage getMessage(FacesMessage.Severity severity,


String key, Object... params) {
String summary = "?? key " + key + " not found ??";
String detail = null;
FacesContext context = FacesContext.getCurrentInstance();
String name = context.getApplication().getMessageBundle();
if (name == null)
name = FacesMessage.FACES_MESSAGES;
Locale locale = context.getViewRoot().getLocale();
ResourceBundle bundle = ResourceBundle.getBundle(name, locale);
try {
summary = bundle.getString(key);
summary = MessageFormat.format(summary, params);
detail = bundle.getString(key + "_detail");
detail = MessageFormat.format(detail, params);
} catch (MissingResourceException e) { }
return new FacesMessage(severity, summary, detail);
}
}

We can use this MessageFactory in any backing bean, custom converter or custom validator, to
create localized error messages:

public class NameValidator implements Validator {

/** The identifier of the validator. */


public static final String VALIDATOR_ID = "NameValidator";

/** The identifier of the error message. */


public static final String INVALID_NAME_MESSAGE_ID =
"NameValidator.INVALID_NAME";

public void validate( FacesContext context,


UIComponent component, Object value ) {
if (!value.toString().trim().matches("[A-Z][a-z]*")) {
FacesMessage message = MessageFactory.getMessage(
FacesMessage.SEVERITY_ERROR, INVALID_NAME_MESSAGE_ID);
throw new ValidatorException(message);
}
}
}

51
52
9 Custom Tags
As we’ve already seen, JavaServer Faces has several services that enable you to build web
applications quickly. Many standard components are available already, and different IDE vendors
provide many additional components.
However, the real power of JSF lies in its sophisticated component model and an extensible
architecture that allows you to create your own user interface (UI) extensions—components,
renderers, validators, and converters.
In this chapter we learn how to create our own custom tags.

Before you write a new custom tag or custom component, you should make sure that there is no
alternative way you can reach your goal: you can visit the JSF Central page (www.jsfcentral.com),
for example, to find out about different JSF products and libraries.

With custom tags for validators or converters we are able to provide custom tag attributes. These
attributes are used as custom properties (e.g. a regular expression used by a custom validator to
match certain input strings <g:validateRegex pattern="[a-z]{5}"/>).

Custom tags for validators and converters are implemented in the same way. The following
sections show all the details needed to implement a custom validator tag.

9.1 The different parts of a Custom Tag


To create a custom validator tag, we first have to write a CustomValidator class which implements
the Validator and the StateHolder interfaces. The validator Interface requires a public validate()
method. By implementing the StateHolder interface, we make sure that the state of the validator
(its properties) is saved between different requests.

53
The Validator Tag Class
The validator tag class has to extend the abstract ValidatorELTag class, which means it has to
implement a createValidator() method. Furthermore, the validator tag class needs setter methods
for all attributes of the tag. If the custom tag provides any attributes, the tag class should
implement a release() method.
public class MyValidatorTag extends ValidatorELTag {

public Validator createValidator() throws JspException {


. . . // create validator object
return validator;
}

public void release() { // release state


super.release();
// set validator properties to null
}

// setter methods for validator properties


}

The createValidator Method


To be able to share the same validator object between different pages, the validator class should
be created in the following way.

54
The Tag Library Description File
For the JSP integration we need a Tag-Library description of the new tag (customValidator.tld):
<taglib . . . >
<tlib-version>1.0</tlib-version>
<short-name> ns-Prefix </short-name>
<uri> tag_URI </uri>

<tag>
<name> tag_name </name>
<tag-class> tag_class_name </tag-class>
<body-content> normally empty</body-content>
<attribute>
<description> . . . </description>
<name>attribute name</name>
<required>true | false</required>
<deferred-value>
<type>type of attribute</type>
</deferred-value>
</attribute>
</tag>
. . .
<taglib>

The Validator Class


public class MyValidator implements Validator, StateHolder {
// Custom Validator ID as defined in faces-config.xml file
public static String VALIDATOR_ID = CustomValidatorId;

/** The identifier of the error message. */


public static final String MESSAGE_ID = "name of message";

private boolean transientValue = false; // parameters are not transient


// implement Validator interface
public void validate( FacesContext facesContext,
UIComponent uiComponent, Object value) {
if (value does not match requirements) {
// raise a validator exception
FacesMessage message = MessageFactory.getMessage(
FacesMessage.SEVERITY_ERROR, MESSAGE_ID, msg.params...);
throw new ValidatorException(message);
}
}
// implement StateHolder interface
public void restoreState(FacesContext fc, Object state) {
// read parameters from state
}
public Object saveState(FacesContext arg0) {
// return wrapped parameters in a serializable Object
}

// getter and setter methods for all properties and transient value
. . .
}

55
In the faces-config.xml file we have to register all custom validators by their id and fully qualified
class name:

<validator>
<validator-id>CustomValidatorId</validator-id>
<validator-class>package.CustomValidatorClass</validator-class>
</validator>

Configuration Summary

The Directory Structure


The Tag-Library Description files name is arbitrary, as long as it has a *.tld file extension.

56
9.2 The Greater-Than Validator

We implement an example validateGreaterThan tag which compares the values of two


components. Here, the value of the age component must be smaller than the value of the mother's
age. The validateGreaterThan tag demands a „comparedToId“ attribute to define the (id of the)
component, whose value is compared to this component's value:
<mytags:validateGreaterThan compareToId="main:age"/>

The GreaterThanValidator Class

public class GreaterThanValidator implements Validator, StateHolder {

/** The identifier of the validator. */


public static final String VALIDATOR_ID = "GreaterThanValidator";

/** The identifier of the error message. */


public static final String GREATER_THAN_MESSAGE_ID =
"GreaterThanValidator.GREATER_THAN_ERROR";

// id of component whose value is compared to this components value


private String compareToId;

// compareToId is not transient


private boolean transientValue = false;

// implement Validator interface


public void validate(FacesContext facesContext, UIComponent uiComponent,
Object value) {
if (value == null)
return;
UIComponent compareToComponent = uiComponent.findComponent(compareToId);
if (compareToComponent instanceof EditableValueHolder) {
Object greaterThanValue = ((EditableValueHolder) compareToComponent)
.getValue();
if (greaterThanValue == null)
return;

if (Integer.parseInt(value.toString()) <= Integer


.parseInt(greaterThanValue.toString())) {
// raise a validator exception
FacesMessage message = MessageFactory.getMessage(
FacesMessage.SEVERITY_ERROR, GREATER_THAN_MESSAGE_ID,
((HtmlInputText) compareToComponent).getLabel(), greaterThanValue);
throw new ValidatorException(message);
}
}
}

57
// value holder method
public void restoreState(FacesContext fc, Object state) {
compareToId = (String) state;
}

// value holder method


public Object saveState(FacesContext arg0) {
return compareToId;
}

// value holder method


public boolean isTransient() {
return transientValue;
}

// value holder method


public void setTransient(boolean value) {
transientValue = value;
}

// return the compareToId


public String getCompareToId() {
return compareToId;
}

// store the value of compareToId


public void setCompareToId(String compareToId) {
this.compareToId = compareToId;
}
}

58
The GreaterThanValidatorTag Class
The ValidatorTag class must implement the createValidator() method as well as a setter
method for its properties (compareToId) and a release method.

public class GreaterThanValidatorTag extends ValidatorELTag {

// attribute of the tag


private ValueExpression compareToId;

public void setCompareToId(ValueExpression compareToId) {


this.compareToId = compareToId;
}

public void release() {


super.release();
compareToId = null;
}

public Validator createValidator() throws JspException {


FacesContext context = FacesContext.getCurrentInstance();
GreaterThanValidator validator = (GreaterThanValidator) context
.getApplication().createValidator(GreaterThanValidator.VALIDATOR_ID);
String cId;
if (compareToId.isLiteralText())
cId = compareToId.getExpressionString();
else
cId = (String) compareToId.getValue(context.getELContext());
validator.setCompareToId(cId);
return validator;
}
}

The Tag Library Description: taglib.tld

<?xml version="1.0" encoding="UTF-8" ?>

59
<taglib version="2.1"
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-jsptaglibrary_2_1.xsd">

<tlib-version>1.0</tlib-version>
<short-name>myTags</short-name>
<uri>http://helloWorld/taglib</uri>

<tag>
<name>validateGreaterThan</name>
<tag-class>helloWorld.GreaterThanValidatorTag</tag-class>
<body-content>empty</body-content>
<attribute>
<description>Id of component this field is compared to</description>
<name>compareToId</name>
<required>true</required>
<deferred-value>
<type>java.lang.String</type>
</deferred-value>
</attribute>
</tag>
. . .

</taglib>

The custom tag can then be used in the JSP page like this:
<jsp:root version="2.1" xmlns:jsp="http://java.sun.com/JSP/Page"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:g="http://helloWorld/taglib">
....

<f:view>
<h:form id="main">
....
<h:outputText value="#{label.yourAge}" />
<h:inputText id="age" label="#{label.yourAge}"
value="#{helloBean.age}" required="true" />
<h:message for="age" styleClass="errorMessage" />

<h:outputText value="#{label.mothersAge}" />


<h:inputText id="mothersAge" label="#{label.mothersAge}"
value="#{helloBean.mage}">
<g:validateGreaterThan compareToId="main:age" />
</h:inputText>
<h:message for="mothersAge" styleClass="errorMessage" />
....
</jsp:root>

10 JSF Custom Components


The JSF framework offers a lot of standard components out of the box. The JSF component model

60
and the extensible architecture allow to create new components. But the development of custom
components requires special expertise.

Writing a custom component is necessary if you want


• to support special HTML features (e.g. file upload)
• provide additional functionality (e.g. sortable data table)
• create new types of components (e.g. tree view)
• support functionality for other markup languages (e.g. progress bar)

10.1 The Component Hierarchy

StateHolder ValueHolder Editable


ValueHolder

UIComponent UIOutput UIInput


Base
localValue submittedValue
id value validators
parent converter
children decode()
attributes updateModel()
valueExpressions

encodeBegin()
encodeChildren()
encodeEnd()
saveState()
restoreState()

10.2 Component Data Collections


Components have three types of data collections:
• attributes which are untyped key/value pairs
• value expressions which define bindings to backing bean properties
• individual properties with corresponding setter and getter methods

The put() and get() methods of the attributes indirectly access the properties and value
expressions if available. If a component defines properties, it must implement the StateHolder
interface to save and restore them.

61
10.3 Value Holder

The ValueHolder interfaces support a component's values which are used during request
processing:
• a submitted value which is the value entered by a user and decoded from the request
• a local value which is the value after successful processing by any registered converter and
validators
• a backing bean property to which the local value is transferred through a value expression

The getValue() method either returns the submitted value, the local value or the value of the
associated backing bean property

Values during Request Processing

PROCESS VALIDATIONS
APPLY REQUEST VALUES 2: validate()
1: decode() 2a: setValue()
1a: setSubmittedValue() 2b: clearSubmittedValue()

3b: setProperty()
Input Backing
Component Bean
5c: getProperty()

UPDATE MODEL VALUES RENDER RESPONSE INVOKE APPLICAION


3: updateModel() 5: encodeBegin() 4: action()
3a: getLocalValue() 5a: getSubmittedValue()
3c: clearValue() 5b: getValue()

62
10.4 Example of a Custom Component

In order to develop a custom UI component, the following steps are needed:


1. Implement the component class by subclassing an appropriate base class (e.g. UIInput)
2. Register the class in the JSF application configuration file (faces-config.xml)
3. Integrate the class with JSP, i.e. implement a custom tag (tag handler class, tag library
descriptor).

UIComponent UIComponent
Base ELTag

Custom uses Custom


Component ComponentTag

registers registers

JSF Tag
Configu- Library
ration Descriptor

In this example a custom input component is developed which allows a user to select a number
within a range of numbers. The custom component may be included in a JSP page using a custom
tag which specifies the range of numbers and a value binding for the selected number:

<h:form>
...
<h:outputText value="#{label.age}" />
<g:selectNumber id="helloAge" min="1" max="50" value="#{helloBean.age}" />
...
<h:commandButton value="#{label.hello}" action="#{helloBean.sayHello}" />
</h:from>

63
The Component Class: SelectNumber

The component class


• subclasses an appropriate base class (e.g. UIInput)
• defines its type as a constant (COMPONENT_TYPE)
• sets its renderer type (not necessary for simple components)
• defines its family which is used to find an appropriate renderer (usually inherited from the
base class)
• implements the methods encodeBegin(), encodeChildren() and encodeEnd(), which are
called in order to render a component
• implements the decode() method, which interprets browser input and sets the submitted
value of the component

public class SelectNumber extends UIInput {

/** The identifier of the component. */


public static final String COMPONENT_TYPE = "SelectNumber";

/** Sets the renderer type. */


public SelectNumber() {
setRendererType(null);
}

/** Renders the number selection to the response. */


public void encodeBegin(FacesContext context) throws IOException {
Integer min = (Integer)getAttributes().get("min");
Integer max = (Integer)getAttributes().get("max");
ResponseWriter writer = context.getResponseWriter();
writer.startElement("select", this);
writer.writeAttribute("name", "number", null);
for (int val = min; val <= max; val++) {
writer.startElement("option", this);
writer.writeAttribute("value", val, null);
if (getValue().equals(val))
writer.writeAttribute("selected", "true", null);
writer.writeText(val, null);
writer.endElement("option");
}
writer.endElement("select");
}

/** Decodes the selected number from the request. */


public void decode(FacesContext context) {
Map<String, String> params =
context.getExternalContext().getRequestParameterMap();
String value = params.get("number");
setSubmittedValue(value);
}
}

64
The Configuration File: faces-config.xml

In the application configuration file, the component has to be declared by specifying its type and its
implementation class

<?xml version='1.0' encoding='UTF-8'?>


<faces-config version="1.2"
xmlns="http://java.sun.com/xml/ns/javaee" .... >

<managed-bean>
<description>The one and only HelloBean.</description>
<managed-bean-name>helloBean</managed-bean-name>
<managed-bean-class>helloWorld.HelloBean</managed-bean-class>
<managed-bean-scope>session</managed-bean-scope>
</managed-bean>
. . .
<component>
<component-type>SelectNumber</component-type>
<component-class>helloWorld.SelectNumber</component-class>
</component>
. . .
</faces-config>

The Component Tag Handler Class: SelectNumberTag

The component tag handler class is derived from the UIComponentELTag class. The component
tag handler associates the tag with a component and with a renderer (if the component does not
render itself).

If the component has attributes or properties which should be exposed as tag attributes, the tag
handler class has to define corresponding properties (here min, max, and value). We need setter
methods as well as a release method for those properties.

The setProperties() method maps the properties of the tag class to attributes or value expressions
of the component

public class SelectNumberTag extends UIComponentELTag {

/** The minimum value. */


private String min;

/** The maximum value. */


private String max;

/** The value binding. */


private ValueExpression value;

/** Returns the component type. */


public String getComponentType() {
return SelectNumber.COMPONENT_TYPE;
}

65
/** Returns the renderer type. */
public String getRendererType() {
return null;
}

/** Sets the minimum value. */


public void setMin(String min) {
this.min = min;
}

/** Sets the maximum value. */


public void setMax(String max) {
this.max = max;
}

/** Sets the value binding. */


public void setValue(ValueExpression value) {
this.value = value;
}

/** Sets the properties of the component. */


public void setProperties(UIComponent component) {
super.setProperties(component);
component.getAttributes().put("min", new Integer(min));
component.getAttributes().put("max", new Integer(max));
if (value.isLiteralText())
component.getAttributes().put("value",
value.getExpressionString());
else
component.setValueExpression("value", value);
}

/** Releases the resources. */


public void release() {
super.release();
min = max = null;
value = null;
}
}

66
The Tag Library Descriptor: taglib.tld

The tag library descriptor (TLD) groups different JSP tags into a tag library which is identified by a
URI. A tag description maps a tag name (here selectNumber) to a tag handler class (here
helloWorld.SelectNumberTag) and defines the valid tag attributes (max, min, value and id).

<?xml version="1.0"?>
<taglib . . . >

<tlib-version>1.1</tlib-version>
<short-name>myTags</short-name>
<uri>http://helloWorld/taglib</uri>
<tag>
<name>selectNumber</name>
<tag-class>helloWorld.SelectNumberTag</tag-class>
<body-content>empty</body-content>
<attribute> <name>id</name>
</attribute>
<attribute> <name>min</name> <required>true</required>
</attribute>
<attribute> <name>max</name> <required>true</required>
</attribute>
<attribute>
<name>value</name>
<required>true</required>
<deferred-value>
<type>java.lang.Integer</type>
</deferred-value>
</attribute>
</tag>

</taglib>

The JSP page: index.jsp

In the JSP page, the URI of the tag library has to be defined as XML namespace of the tag
element.

<jsp:root xmlns:jsp="http://java.sun.com/JSP/Page" version="2.1"


xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:g="http://helloWorld/taglib">

<jsp:directive.page contentType="text/html"/>
<html xmlns="http://www.w3.org/1999/xhtml">

<f:view>
<h:form>
<g:selectNumber min="1" max="10" value="#{helloBean.number}"/>
<h:commandButton value="Submit"/>
</h:form>
</f:view>
</html>
</jsp:root>

67
Packaging the Component

A custom UI component can be packaged together with the application's web archive or in a
separate JAR file which can then be included in an application's web archive

jsf-application.war jsf-component.jar

index.jsp /META-INF
... faces-config.xml
/WEB-INF taglib.tld
web.xml /jsf/examples
faces-config.xml SelectNumber.class
/WEB-INF/classes SelectNumberTag.class
...
/WEB-INF/lib
jsf-component.jar

Summary of Select Number Example

68

Vous aimerez peut-être aussi