JavaServer Faces technology is a server-side user interface component framework for Java technology-based web applications.
The main components of JavaServer Faces technology are as follows:
An API for representing UI components and managing their state; handling events, server-side validation, and data conversion; defining page navigation; supporting internationalization and accessibility; and providing extensibility for all these features
Two JavaServer Pages (JSP) custom tag libraries for expressing UI components within a JSP page and for wiring components to server-side objects
The well-defined programming model and tag libraries significantly ease the burden of building and maintaining web applications with server-side UIs. With minimal effort, you can
Drop components onto a page by adding component tags
Wire component-generated events to server-side application code
Bind UI components on a page to server-side data
Construct a UI with reusable and extensible components
Save and restore UI state beyond the life of server requests
As shown in Figure 10–1, the user interface you create with JavaServer Faces technology (represented by myUI in the graphic) runs on the server and renders back to the client.
The JSP page, myform.jsp, is a JavaServer Faces page, which is a JSP page that includes JavaServer Faces tags. It expresses the user interface components by using custom tags defined by JavaServer Faces technology. The UI for the web application (represented by myUI in the figure) manages the objects referenced by the JSP page. These objects include
The UI component objects that map to the tags on the JSP page
Any event listeners, validators, and converters that are registered on the components
The JavaBeans components that encapsulate the data and application-specific functionality of the components
This chapter gives an overview of JavaServer Faces technology. After going over some of the primary benefits of using JavaServer Faces technology and explaining what a JavaServer Faces application is, it describes a simple application and specifies which part of the application the developers of each role work on. It then describes the UI component model, the navigation model, and the backing bean features supported by JavaServer Faces technology. Finally, this chapter uses a page from a simple application to summarize the life cycle of a JavaServer Faces page.
One of the greatest advantages of JavaServer Faces technology is that it offers a clean separation between behavior and presentation. Web applications built using JSP technology achieve this separation in part. However, a JSP application cannot map HTTP requests to component-specific event handling nor manage UI elements as stateful objects on the server, as a JavaServer Faces application can. JavaServer Faces technology allows you to build web applications that implement the finer-grained separation of behavior and presentation that is traditionally offered by client-side UI architectures.
The separation of logic from presentation also allows each member of a web application development team to focus on his or her piece of the development process, and it provides a simple programming model to link the pieces. For example, page authors with no programming expertise can use JavaServer Faces technology UI component tags to link to server-side objects from within a web page without writing any scripts.
Another important goal of JavaServer Faces technology is to leverage familiar UI-component and web-tier concepts without limiting you to a particular scripting technology or markup language. Although JavaServer Faces technology includes a JSP custom tag library for representing components on a JSP page, the JavaServer Faces technology APIs are layered directly on top of the Servlet API, as shown in Figure 3–2. This layering of APIs enables several important application use cases, such as using another presentation technology instead of JSP pages, creating your own custom components directly from the component classes, and generating output for various client devices.
Most importantly, JavaServer Faces technology provides a rich architecture for managing component state, processing component data, validating user input, and handling events.
For the most part, a JavaServer Faces application is like any other Java web application. A typical JavaServer Faces application includes the following pieces:
A set of JSP pages (although you are not limited to using JSP pages as your presentation technology)
A set of backing beans, which are JavaBeans components that define properties and functions for UI components on a page
An application configuration resource file, which defines page navigation rules and configures beans and other custom objects, such as custom components
A deployment descriptor (a web.xml file)
Possibly a set of custom objects created by the application developer. These objects might include custom components, validators, converters, or listeners.
A set of custom tags for representing custom objects on the page
A JavaServer Faces application that includes JSP pages also uses the standard tag libraries defined by JavaServer Faces technology for representing UI components and other objects on the page.
This section describes the general steps involved in developing a simple JavaServer Faces application from the perspective of different development roles. These roles are:
Page author, who creates pages by using the JavaServer Faces tag libraries.
Application developer, who programs custom converters, validators, listeners, and backing beans.
Component author, who creates custom UI components and renderers.
Application architect, who configures the application, including defining the navigation rules, configuring custom objects, and creating deployment descriptors.
This application is quite simple, and so it does not include any custom components. See chapter Writing a Method to Handle a Value-Change Event to learn about the responsibilities of a component writer.
Developing a simple JavaServer Faces application usually requires these tasks:
Mapping the FacesServlet instance.
Creating the pages using the UI component and core tags.
Defining page navigation in the application configuration resource file.
Developing the backing beans.
Adding managed bean declarations to the application configuration resource file.
The example used in this section is the guessNumber application, located in the tut-install/javaeetutorial5/examples/web/ directory. It asks you to guess a number between 0 and 10, inclusive. The second page tells you whether you guessed correctly. The example also checks the validity of your input. The system log prints Duke’s number. Figure 10–2 shows what the first page looks like.
The source for the guessNumber application is located in the tut-install/javaeetutorial5/examples/web/guessNumber/ directory created when you unzip the tutorial bundle (see Chapter 2, Using the Tutorial Examples).
To build, package, deploy, and run this example using NetBeans IDE, follow these steps:
In NetBeans IDE, select File->Open Project.
In the Open Project dialog, navigate to:
tut-install/javaeetutorial5/examples/web/ |
Select the guessNumber folder.
Select the Open as Main Project check box.
Click Open Project.
In the Projects tab, right-click the guessNumber project, and select Undeploy and Deploy.
To run the application, open the URL http://localhost:8080/guessNumber in a browser.
To build, package, and deploy this example using Ant, follow these steps:
Go to tut-install/javaeetutorial5/examples/web/guessNumber/.
Type ant.
Start the Application Server.
Type ant deploy.
To run the application, open the URL http://localhost:8080/guessNumber in a browser.
To learn how to configure the example, refer to the deployment descriptor (the web.xml file), which includes the following configurations:
A display-name element that specifies the name that tools use to identify the application.
A servlet element that identifies the FacesServlet instance.
A servlet-mapping element that maps FacesServlet to a URL pattern.
All JavaServer Faces applications must include a mapping to the FacesServlet instance in their deployment descriptors. The FacesServlet instance accepts incoming requests, passes them to the life cycle for processing, and initializes resources. The following piece of the guessNumber example’s deployment descriptor performs the mapping to the FacesServlet instance:
<servlet> <display-name>FacesServlet</display-name> <servlet-name>FacesServlet</servlet-name> <servlet-class>javax.faces.webapp.FacesServlet </servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>FacesServlet</servlet-name> <url-pattern>/guess/*</url-pattern> </servlet-mapping>
The mapping to FacesServlet shown above uses a prefix mapping to identify a JSP page as having JavaServer Faces components. Because of this, the URL to the first JSP page of the application must include the mapping. To accomplish this, the guessNumber example includes an HTML page that has the URL to the first JSP page:
<a href="guess/greeting.jsp">
See Identifying the Servlet for Life Cycle Processing for more information on how to map the FacesServlet instance.
Creating the pages is the page author’s responsibility. This task involves laying out UI components on the pages, mapping the components to beans, and adding tags that register converters, validators, or listeners onto the components.
In this section you will build the tut-install/javaeetutorial5/examples/examples/web/guessNumber/web/greeting.jsp page, the first page of the guessNumber application. As with any JSP page, you’ll need to add the usual HTML and HEAD tags to the page:
<HTML xmlns="http://www.w3.org/1999/xhtml"xml:lang="en"> <HEAD> <title>Hello</title> </HEAD> ... </HTML>
You’ll also need a page directive that specifies the content type:
<%@ page contentType="application/xhtml+xml" %>
In order to use JavaServer Faces components in JSP pages, you need to give your pages access to the two standard tag libraries, the HTML component tag library and the core tag library using taglib declarations:
<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %> <%@ taglib uri="http:.//java.sun.com/jsf/core" prefix="f" %>
The first taglib declaration declares the HTML component tag library with a prefix, h. All component tags in the page have this prefix. The core tag library is declared with the prefix f. All core tags in the page have this prefix.
User Interface Component Model includes a table that lists all the component tags included with JavaServer Faces technology. Adding UI Components to a Page Using the HTML Component Tags discusses the tags in more detail.
All JavaServer Faces pages are represented by a tree of components, called a view. The view tag represents the root of the view. All JavaServer Faces component tags must be inside of a view tag, which is defined in the core tag library.
The form tag represents an input form component, which allows the user to input some data and submit it to the server, usually by clicking a button. All UI component tags that represent editable components (such as text fields and menus) must be nested inside the form tag. In the case of the greeting.jsp page, some of the tags contained in the form are outputText, inputText, commandButton, and message. You can specify an ID for the form tag. This ID maps to the associated form UI component on the server.
With the view and form tags added, our page looks like this (minus the HTML and HEAD tags):
<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %> <%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %> <f:view> <h:form id="helloForm1"> </h:form> </f:view>
The outputText tag represents a label. The greeting.jsp page has two outputText tags. One of the tags displays the number 0. The other tag displays the number 10:
<h:outputText lang="en_US" value="#{UserNumberBean.minimum}"/> <h:outputText value="#{UserNumberBean.maximum}"/>
The value attributes of the tags get the values from the minimum and maximum properties of UserNumberBean using value expressions, which are used to reference data stored in other objects, such as beans. See Backing Beans for more information on value expressions.
With the addition of the outputText tags (along with some static text), the greeting page looks like the following:
<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %> <%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %> <f:view> <h:form id="helloForm1"> <h2>Hi. My name is Duke. I’m thinking of a number from <h:outputText lang="en_US" value="#{UserNumberBean.minimum}"/> to <h:outputText value="#{UserNumberBean.maximum}"/>. Can you guess it?</h2> </h:form> </f:view>
To display images on a page, you use the graphicImage tag. The url attribute of the tag specifies the path to the image file. Let’s add Duke to the page using a graphicImage tag:
<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %> <%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %> <f:view> <h:form id="helloForm1"> <h2>Hi. My name is Duke. I’m thinking of a number from <h:outputText lang="en_US" value="#{UserNumberBean.minimum}"/> to <h:outputText value="#{UserNumberBean.maximum}"/>. Can you guess it?</h2> <h:graphicImage id="waveImg" url="/wave.med.gif" /> </h:form> </f:view>
The inputText tag represents a text field component. In the guessNumber example, this text field takes an integer input value. The instance of this tag included in greeting.jsp has three attributes: id, label, and value.
<h:inputText id="userNo" label="User Number" value="#{UserNumberBean.userNumber}"> ... </h:inputText>
The id attribute corresponds to the ID of the component object represented by this tag. In this case, an id attribute is required because the message tag (which is used to display validation error messages) needs it to refer to the userNo component.
The label attribute specifies the name to be used by error messages to refer to the component. In this example, label is set to User Number. As an example, if a user were to enter 23, the error message that would be displayed is:
User Number: Validation Error: Value is greater than allowable maximum of 10. |
The value attribute binds the userNo component value to the bean property UserNumberBean.userNumber, which holds the data entered into the text field.
After adding the inputText tag, the greeting page looks like the following:
<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %> <%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %> <f:view> <h:form id="helloForm1"> <h2>Hi. My name is Duke. I’m thinking of a number from <h:outputText lang="en_US" value="#{UserNumberBean.minimum}"/> to <h:outputText value="#{UserNumberBean.maximum}"/>. Can you guess it?</h2> <h:graphicImage id="waveImg" url="/wave.med.gif" /> <h:inputText id="userNo" label="User Number" value="#{UserNumberBean.userNumber}"> ... </h:inputText> </h:form> </f:view>
See Backing Beans for more information on creating beans, binding to bean properties, referencing bean methods, and configuring beans.
See Using Text Components for more information on the inputText tag.
By nesting the validateLongRange tag within a text field’s component’s tag, the page author registers a LongRangeValidator onto the text field. This validator checks whether the component’s local data is within a certain range, defined by the validateLongRange tag’s minimum and maximum attributes.
In the case of the greeting page, you need to validate the number the user enters into the text field. So, you add a validateLongRange tag inside the inputText tag. The maximum and minimum attributes of the validateLongRange tag get their values from the minimum and maximum properties of UserNumberBean using the value expressions #{UserNumberBean.minimum} and #{UserNumberBean.maximum}. See Backing Beans for details on value expressions.
After adding the validateLongRange tag, the page looks like this:
<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %> <%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %> <f:view> <h:form id="helloForm1"> <h2>Hi. My name is Duke. I’m thinking of a number from <h:outputText lang="en_US" value="#{UserNumberBean.minimum}"/> to <h:outputText value="#{UserNumberBean.maximum}"/>. Can you guess it?</h2> <h:graphicImage id="waveImg" url="/wave.med.gif" /> <h:inputText id="userNo" label="User Number" value="#{UserNumberBean.userNumber}"> <f:validateLongRange minimum="#{UserNumberBean.minimum}" maximum="#{UserNumberBean.maximum}" /> </h:inputText> </h:form> </f:view>
For more information on the standard validators included with JavaServer Faces technology, see Using the Standard Validators.
JavaServer Faces technology provides standard error messages that display on the page when conversion or validation fails. In some cases, you might need to override the standard message. For example, if a user were to enter a letter into the text field on greeting.jsp, he or she would see the following error message:
User Number: ’m’ must be a number between -2147483648 and 2147483647 Example: 9346 |
This is wrong because the field really only accepts values from 0 through 10.
To override this message, you add a converterMessage attribute on the inputText tag. This attribute references the custom error message:
<h:inputText id="userNo" label="User Number" value="#{UserNumberBean.userNumber}" converterMessage="#{ErrMsg.userNoConvert}"> ... </h:inputText>
The expression that converterMessage uses references the userNoConvert key of the ErrMsg resource bundle. The application architect needs to define the message in the resource bundle and configure the resource bundle. See Configuring Error Messages for more information on this.
See Referencing Error Messages for more information on referencing error messages.
The commandButton tag represents the button used to submit the data entered in the text field. The action attribute specifies an outcome that helps the navigation mechanism decide which page to open next. Defining Page Navigation discusses this further.
With the addition of the commandButton tag, the greeting page looks like the following:
<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %> <%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %> <f:view> <h:form id="helloForm1"> <h2>Hi. My name is Duke. I’m thinking of a number from <h:outputText lang="en_US" value="#{UserNumberBean.minimum}"/> to <h:outputText value="#{UserNumberBean.maximum}"/>. Can you guess it?</h2> <h:graphicImage id="waveImg" url="/wave.med.gif" /> <h:inputText id="userNo" label="User Number" value="#{UserNumberBean.userNumber}"> <f:validateLongRange minimum="#{UserNumberBean.minimum}" maximum="#{UserNumberBean.maximum}" /> </h:inputText> <h:commandButton id="submit" action="success" value="Submit" /> </h:form> </f:view>
See Using Command Components for Performing Actions and Navigation for more information on the commandButton tag.
A message tag is used to display error messages on a page when data conversion or validation fails after the user submits the form. The message tag in greeting.jsp displays an error message if the data entered in the field does not comply with the rules specified by the LongRangeValidator implementation, whose tag is registered on the text field component.
The error message displays wherever you place the message tag on the page. The message tag’s style attribute allows you to specify the formatting style for the message text. Its for attribute refers to the component whose value failed validation, in this case the userNo component represented by the inputText tag in the greeting.jsp page.
Put the message tag near the end of the page:
<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %> <%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %> <f:view> <h:form id="helloForm1"> <h2>Hi. My name is Duke. I’m thinking of a number from <h:outputText lang="en_US" value="#{UserNumberBean.minimum}"/> to <h:outputText value="#{UserNumberBean.maximum}"/>. Can you guess it?</h2> <h:graphicImage id="waveImg" url="/wave.med.gif" /> <h:inputText id="userNo" label="User Number" value="#{UserNumberBean.userNumber}" converterMessage="#{ErrMsg.userNoConvert}"> <f:validateLongRange minimum="#{UserNumberBean.minimum}" maximum="#{UserNumberBean.maximum}" /> </h:inputText> <h:commandButton id="submit" action="success" value="Submit" /> <h:message showSummary="true" showDetail="false" style="color: red; font-family: ’New Century Schoolbook’, serif; font-style: oblique; text-decoration: overline" id="errors1" for="userNo"/> </h:form> </f:view>
Now you have completed the greeting page. Assuming you have also done the response.jsp page, you can move on to defining the page navigation rules.
Defining page navigation involves determining which page to go to after the user clicks a button or a hyperlink. Navigation for the application is defined in the application configuration resource file using a powerful rule-based system. Here is one of the navigation rules defined for the guessNumber example:
<navigation-rule> <from-view-id>/greeting.jsp</from-view-id> <navigation-case> <from-outcome>success</from-outcome> <to-view-id>/response.jsp</to-view-id> </navigation-case> </navigation-rule> <navigation-rule> <from-view-id>/response.jsp</from-view-id> <navigation-case> <from-outcome>success</from-outcome> <to-view-id>/greeting.jsp</to-view-id> </navigation-case> </navigation-rule>
This navigation rule states that when the button on the greeting page is clicked the application will navigate to response.jsp if the navigation system is given a logical outcome of success.
In the case of the Guess Number example, the logical outcome is defined by the action attribute of the UICommand component that submits the form:
<h:commandButton id="submit" action="success" value="Submit" />
To learn more about how navigation works, see Navigation Model.
In case the standard error messages don’t meet your needs, you can create new ones in resource bundles and configure the resource bundles in your application configuration resource file. The guessNumber example has one custom converter message, as described in Adding a Custom Message.
This message is stored in the resource bundle, ApplicationMessages.properties:
userNoConvert=The value you entered is not a number.
The resource bundle is configured in the application configuration file:
<application> <resource-bundle> <base-name>guessNumber.ApplicationMessages</base-name> <var>ErrMsg</var> </resource-bundle> </application>
The base-name element indicates the fully-qualified name of the resource bundle. The var element indicates the name by which page authors refer to the resource bundle with the expression language. Here is the inputText tag again:
<h:inputText id="userNo" label="User Number" value="#{UserNumberBean.userNumber}" converterMessage="#{ErrMsg.userNoConvert}"> ... </h:inputText>
The expression on the converterMessage attribute references the userNoConvert key of the ErrMsg resource bundle.
See Registering Custom Error Messages for more information on configuring custom error messages.
Developing beans is one responsibility of the application developer. A typical JavaServer Faces application couples a backing bean with each page in the application. The backing bean defines properties and methods that are associated with the UI components used on the page.
The page author binds a component’s value to a bean property using the component tag’s value attribute to refer to the property. Recall that the userNo component on the greeting.jsp page references the userNumber property of UserNumberBean:
<h:inputText id="userNo" label="User Number" value="#{UserNumberBean.userNumber}"> ... </h:inputText>
Here is the userNumber backing bean property that maps to the data for the userNo component:
Integer userNumber = null; ... public void setUserNumber(Integer user_number) { userNumber = user_number; } public Integer getUserNumber() { return userNumber; } public String getResponse() { if(userNumber != null && userNumber.compareTo(randomInt) == 0) { return "Yay! You got it!"; } else { return "Sorry, "+userNumber+" is incorrect."; } }
See Backing Beans for more information on creating backing beans.
After developing the backing beans to be used in the application, you need to configure them in the application configuration resource file so that the JavaServer Faces implementation can automatically create new instances of the beans whenever they are needed.
The task of adding managed bean declarations to the application configuration resource file is the application architect’s responsibility. Here is a managed bean declaration for UserNumberBean:
<managed-bean> <managed-bean-name>UserNumberBean</managed-bean-name> <managed-bean-class> guessNumber.UserNumberBean </managed-bean-class> <managed-bean-scope>session</managed-bean-scope> <managed-property> <property-name>minimum</property-name> <property-class>long</property-class> <value>0</value> </managed-property> <managed-property> <property-name>maximum</property-name> <property-class>long</property-class> <value>10</value> </managed-property> </managed-bean>
This declaration configures UserNumberBean so that its minimum property is initialized to 0, its maximum property is initialized to 10, and it is added to session scope when it is created.
A page author can use the unified EL to access one of the bean’s properties, like this:
<h:outputText value="#{UserNumberBean.minimum}"/>
For more information on configuring beans, see Configuring a Bean.
JavaServer Faces UI components are configurable, reusable elements that compose the user interfaces of JavaServer Faces applications. A component can be simple, such as a button, or compound, such as a table, which can be composed of multiple components.
JavaServer Faces technology provides a rich, flexible component architecture that includes the following:
A set of UIComponent classes for specifying the state and behavior of UI components
A rendering model that defines how to render the components in various ways
An event and listener model that defines how to handle component events
A conversion model that defines how to register data converters onto a component
A validation model that defines how to register validators onto a component
This section briefly describes each of these pieces of the component architecture.
JavaServer Faces technology provides a set of UI component classes and associated behavioral interfaces that specify all the UI component functionality, such as holding component state, maintaining a reference to objects, and driving event handling and rendering for a set of standard components.
The component classes are completely extensible, allowing component writers to create their own custom components. See Chapter 13, Creating Custom UI Components for an example of a custom image map component.
All JavaServer Faces UI component classes extend UIComponentBase, which defines the default state and behavior of a UI component. The following set of UI component classes is included with JavaServer Faces technology:
UIColumn: Represents a single column of data in a UIData component.
UICommand: Represents a control that fires actions when activated.
UIData: Represents a data binding to a collection of data represented by a DataModel instance.
UIForm: Encapsulates a group of controls that submit data to the application. This component is analogous to the form tag in HTML.
UIInput: Takes data input from a user. This class is a subclass of UIOutput.
UISelectBoolean: Allows a user to set a boolean value on a control by selecting or deselecting it. This class is a subclass of UIInput.
UISelectMany: Allows a user to select multiple items from a group of items. This class is a subclass of UIInput.
UISelectOne: Allows a user to select one item from a group of items. This class is a subclass of UIInput.
In addition to extending UIComponentBase, the component classes also implement one or more behavioral interfaces, each of which defines certain behavior for a set of components whose classes implement the interface.
These behavioral interfaces are as follows:
ActionSource: Indicates that the component can fire an action event. This interface is intended for use with components based on JavaServer Faces technology 1.1_01 and earlier versions.
ActionSource2: Extends ActionSource, and therefore provides the same functionality. However, it allows components to use the unified EL when referencing methods that handle action events.
EditableValueHolder: Extends ValueHolder and specifies additional features for editable components, such as validation and emitting value-change events.
NamingContainer: Mandates that each component rooted at this component have a unique ID.
StateHolder: Denotes that a component has state that must be saved between requests.
ValueHolder: Indicates that the component maintains a local value as well as the option of accessing data in the model tier.
UICommand implements ActionSource2 and StateHolder. UIOutput and component classes that extend UIOutput implement StateHolder and ValueHolder. UIInput and component classes that extend UIInput implement EditableValueHolder, StateHolder, and ValueHolder. UIComponentBase implements StateHolder. See the JavaServer Faces Technology 1.2 API Specification for more information on these interfaces.
Only component writers will need to use the component classes and behavioral interfaces directly. Page authors and application developers will use a standard UI component by including a tag that represents it on a JSP page. Most of the components can be rendered in different ways on a page. For example, a UICommand component can be rendered as a button or a hyperlink.
The next section explains how the rendering model works and how page authors choose how to render the components by selecting the appropriate tags.
The JavaServer Faces component architecture is designed such that the functionality of the components is defined by the component classes, whereas the component rendering can be defined by a separate renderer. This design has several benefits, including:
Component writers can define the behavior of a component once but create multiple renderers, each of which defines a different way to render the component to the same client or to different clients.
Page authors and application developers can change the appearance of a component on the page by selecting the tag that represents the appropriate combination of component and renderer.
A render kit defines how component classes map to component tags that are appropriate for a particular client. The JavaServer Faces implementation includes a standard HTML render kit for rendering to an HTML client.
The render kit defines a set of Renderer classes for each component that it supports. Each Renderer class defines a different way to render the particular component to the output defined by the render kit. For example, a UISelectOne component has three different renderers. One of them renders the component as a set of radio buttons. Another renders the component as a combo box. The third one renders the component as a list box.
Each JSP custom tag defined in the standard HTML render kit is composed of the component functionality (defined in the UIComponent class) and the rendering attributes (defined by the Renderer class). For example, the two tags in Table 10–1 represent a UICommand component rendered in two different ways.
Table 10–1 UICommand Tags
Tag |
Rendered As |
---|---|
commandButton |
|
commandLink |
|
The command part of the tags shown in Table 10–1 corresponds to the UICommand class, specifying the functionality, which is to fire an action. The button and hyperlink parts of the tags each correspond to a separate Renderer class, which defines how the component appears on the page.
The JavaServer Faces implementation provides a custom tag library for rendering components in HTML. It supports all the component tags listed in Table 10–2. To learn how to use the tags in an example, see Adding UI Components to a Page Using the HTML Component Tags.
Table 10–2 The UI Component Tags
A JavaServer Faces application can optionally associate a component with server-side object data. This object is a JavaBeans component, such as a backing bean. An application gets and sets the object data for a component by calling the appropriate object properties for that component.
When a component is bound to an object, the application has two views of the component’s data:
The model view, in which data is represented as data types, such as int or long.
The presentation view, in which data is represented in a manner that can be read or modified by the user. For example, a java.util.Date might be represented as a text string in the format mm/dd/yy or as a set of three text strings.
The JavaServer Faces implementation automatically converts component data between these two views when the bean property associated with the component is of one of the types supported by the component’s data. For example, if a UISelectBoolean component is associated with a bean property of type java.lang.Boolean, the JavaServer Faces implementation will automatically convert the component’s data from String to Boolean. In addition, some component data must be bound to properties of a particular type. For example, a UISelectBoolean component must be bound to a property of type boolean or java.lang.Boolean.
Sometimes you might want to convert a component’s data to a type other than a standard type, or you might want to convert the format of the data. To facilitate this, JavaServer Faces technology allows you to register a Converter implementation on UIOutput components and components whose classes subclass UIOutput. If you register the Converter implementation on a component, the Converter implementation converts the component’s data between the two views.
You can either use the standard converters supplied with the JavaServer Faces implementation or create your own custom converter.
To create and use a custom converter in your application, three things must happen:
The application developer must implement the Converter class. See Creating a Custom Converter.
The application architect must register the Converter with the application. See Registering a Custom Converter.
The page author must refer to the Converter object from the tag of the component whose data must be converted. See Using a Custom Converter.
The JavaServer Faces event and listener model is similar to the JavaBeans event model in that it has strongly typed event classes and listener interfaces that an application can use to handle events generated by UI components.
An Event object identifies the component that generated the event and stores information about the event. To be notified of an event, an application must provide an implementation of the Listener class and must register it on the component that generates the event. When the user activates a component, such as by clicking a button, an event is fired. This causes the JavaServer Faces implementation to invoke the listener method that processes the event.
JavaServer Faces technology supports three kinds of events: value-change events, action events, and data-model events.
An action event occurs when the user activates a component that implements ActionSource. These components include buttons and hyperlinks.
A value-change event occurs when the user changes the value of a component represented by UIInput or one of its subclasses. An example is selecting a check box, an action that results in the component’s value changing to true. The component types that can generate these types of events are the UIInput, UISelectOne, UISelectMany, and UISelectBoolean components. Value-change events are fired only if no validation errors were detected.
Depending on the value of the immediate property (see The immediate Attribute) of the component emitting the event, action events can be processed during the invoke application phase or the apply request values phase, and value-change events can be processed during the process validations phase or the apply request values phase.
A data-model event occurs when a new row of a UIData component is selected. The discussion of data-model events is an advanced topic. It is not covered in this tutorial but may be discussed in future versions of this tutorial.
There are two ways to cause your application to react to action events or value-change events emitted by a standard component:
Implement an event listener class to handle the event and register the listener on the component by nesting either a valueChangeListener tag or an actionListener tag inside the component tag.
Implement a method of a backing bean to handle the event and refer to the method with a method expression from the appropriate attribute of the component’s tag.
See Implementing an Event Listener for information on how to implement an event listener. See Registering Listeners on Components for information on how to register the listener on a component.
See Writing a Method to Handle an Action Event and Writing a Method to Handle a Value-Change Event for information on how to implement backing bean methods that handle these events.
See Referencing a Backing Bean Method for information on how to refer to the backing bean method from the component tag.
When emitting events from custom components, you must implement the appropriate Event class and manually queue the event on the component in addition to implementing an event listener class or a backing bean method that handles the event. Handling Events for Custom Components explains how to do this.
JavaServer Faces technology supports a mechanism for validating the local data of editable components (such as text fields). This validation occurs before the corresponding model data is updated to match the local value.
Like the conversion model, the validation model defines a set of standard classes for performing common data validation checks. The JavaServer Faces core tag library also defines a set of tags that correspond to the standard Validator implementations. See Table 11–7 for a list of all the standard validation classes and corresponding tags.
Most of the tags have a set of attributes for configuring the validator’s properties, such as the minimum and maximum allowable values for the component’s data. The page author registers the validator on a component by nesting the validator’s tag within the component’s tag.
The validation model also allows you to create your own custom validator and corresponding tag to perform custom validation. The validation model provides two ways to implement custom validation:
Implement a Validator interface that performs the validation. See Implementing the Validator Interface for more information.
Implement a backing bean method that performs the validation. See Writing a Method to Perform Validation for more information.
If you are implementing a Validator interface, you must also:
Register the Validator implementation with the application. See Registering a Custom Validator for more information.
Create a custom tag or use a validator tag to register the validator on the component. See Creating a Custom Tag for more information.
If you are implementing a backing bean method to perform validation, you also must reference the validator from the component tag’s validator attribute. See Referencing a Method That Performs Validation for more information.
The JavaServer Faces navigation model makes it easy to define page navigation and to handle any additional processing needed to choose the sequence in which pages are loaded.
As defined by JavaServer Faces technology, navigation is a set of rules for choosing the next page to be displayed after a button or hyperlink is clicked. These rules are defined by the application architect in the application configuration resource file (see Application Configuration Resource File) using a small set of XML elements.
To handle navigation in the simplest application, you simply
Define the rules in the application configuration resource file.
Refer to an outcome String from the button or hyperlink component’s action attribute. This outcome String is used by the JavaServer Faces implementation to select the navigation rule.
The Guess Number example uses this kind of simple navigation. Here is an example navigation rule from the guessNumber application described in Defining Page Navigation:
<navigation-rule> <from-view-id>/greeting.jsp</from-view-id> <navigation-case> <from-outcome>success</from-outcome> <to-view-id>/response.jsp</to-view-id> </navigation-case> </navigation-rule>
This rule states that when the button component on greeting.jsp is activated, the application will navigate from the greeting.jsp page to the tut-install/javaeetutorial5/examples/web/guessNumber/web/response.jsp page if the outcome referenced by the button component’s tag is success. Here is the commandButton tag from greeting.jsp that specifies a logical outcome of success:
<h:commandButton id="submit" action="success" value="Submit" />
As the example demonstrates, each navigation-rule element defines how to get from one page (specified in the from-view-id element) to the other pages of the application. The navigation-rule elements can contain any number of navigation-case elements, each of which defines the page to open next (defined by to-view-id) based on a logical outcome (defined by from-outcome).
In more complicated applications, the logical outcome can also come from the return value of an action method in a backing bean. This method performs some processing to determine the outcome. For example, the method can check whether the password the user entered on the page matches the one on file. If it does, the method might return success; otherwise, it might return failure. An outcome of failure might result in the logon page being reloaded. An outcome of success might cause the page displaying the user’s credit card activity to open. If you want the outcome to be returned by a method on a bean, you must refer to the method using a method expression, using the action attribute, as shown by this example:
<h:commandButton id="submit" action="#{userNumberBean.getOrderStatus}" value="Submit" />
When the user clicks the button represented by this tag, the corresponding component generates an action event. This event is handled by the default ActionListener instance, which calls the action method referenced by the component that triggered the event. The action method returns a logical outcome to the action listener.
The listener passes the logical outcome and a reference to the action method that produced the outcome to the default NavigationHandler. The NavigationHandler selects the page to display next by matching the outcome or the action method reference against the navigation rules in the application configuration resource file by the following process:
The NavigationHandler selects the navigation rule that matches the page currently displayed.
It matches the outcome or the action method reference it received from the default ActionListener with those defined by the navigation cases.
It tries to match both the method reference and the outcome against the same navigation case.
If the previous step fails, the navigation handler attempts to match the outcome.
Finally, the navigation handler attempts to match the action method reference if the previous two attempts failed.
When the NavigationHandler achieves a match, the render response phase begins. During this phase, the page selected by the NavigationHandler will be rendered.
For more information on how to define navigation rules, see Configuring Navigation Rules.
For more information on how to implement action methods to handle navigation, see Writing a Method to Handle an Action Event.
For more information on how to reference outcomes or action methods from component tags, see Referencing a Method That Performs Navigation.
A typical JavaServer Faces application includes one or more backing beans, each of which is a JavaServer Faces managed bean that is associated with the UI components used in a particular page. Managed beans are JavaBeans components (see JavaBeans Components) that you can configure using the managed bean facility, which is described in Configuring Beans. This section introduces the basic concepts on creating, configuring, and using backing beans in an application.
In addition to defining a no-arg constructor, as all JavaBeans components must do, a backing bean class also defines a set of UI component properties and possibly a set of methods that perform functions for a component.
Each of the component properties can be bound to one of the following:
A component’s value
A component instance
A converter instance
A listener instance
A validator instance
The most common functions that backing bean methods perform include the following:
Validating a component’s data
Handling an event fired by a component
Performing processing to determine the next page to which the application must navigate
As with all JavaBeans components, a property consists of a private data field and a set of accessor methods, as shown by this code from the Guess Number example:
Integer userNumber = null; ... public void setUserNumber(Integer user_number) { userNumber = user_number; } public Integer getUserNumber() { return userNumber; } public String getResponse() { ... }
Because backing beans follow JavaBeans component conventions, you can reference beans you’ve already written from your JavaServer Faces pages.
When a bean property is bound to a component’s value, it can be any of the basic primitive and numeric types or any Java object type for which the application has access to an appropriate converter. For example, a property can be of type Date if the application has access to a converter that can convert the Date type to a String and back again. See Writing Bean Properties for information on which types are accepted by which component tags.
When a bean property is bound to a component instance, the property’s type must be the same as the component object. For example, if a UISelectBoolean is bound to the property, the property must accept and return a UISelectBoolean object.
Likewise, if the property is bound to a converter, validator, or listener instance then the property must be of the appropriate converter, validator, or listener type.
For more information on writing beans and their properties, see Writing Bean Properties.
JavaServer Faces technology supports a sophisticated managed bean creation facility, which allows application architects to do the following:
Configure simple beans and more complex trees of beans
Initialize bean properties with values
Place beans in a particular scope
Expose the beans to the unified EL so that page authors can access them
An application architect configures the beans in the application configuration resource file. To learn how to configure a managed bean, see Configuring Beans. The managed bean configuration used by the Guess Number example is the following:
<managed-bean> <managed-bean-name>UserNumberBean</managed-bean-name> <managed-bean-class> guessNumber.UserNumberBean </managed-bean-class> <managed-bean-scope>session</managed-bean-scope> <managed-property> <property-name>minimum</property-name> <property-class>long</property-class> <value>0</value> </managed-property> <managed-property> <property-name>maximum</property-name> <property-class>long</property-class> <value>10</value> </managed-property> </managed-bean>
The JavaServer Faces implementation processes this element on application startup time. When UserNumberBean is first referenced from the page, the JavaServer Faces implementation initializes it and sets the values of the properties, maximum and minimum. The bean is then stored in session scope if no instance exists. As such, the bean is available for all pages in the application.
A page author can then access the bean properties from the component tags on the page using the unified EL, as shown here:
<h:outputText value="#{UserNumberBean.minimum}"/>
The part of the expression before the . matches the name defined by the managed-bean-name element. The part of the expression after the . matches the name defined by the property-name element corresponding to the same managed-bean declaration.
Notice that the application configuration resource file does not configure the userNumber property. Any property that does not have a corresponding managed-property element will be initialized to whatever the constructor of the bean class has the instance variable set to. The next section explains more about using the unified EL to reference backing beans.
For more information on configuring beans using the managed bean creation Facility, see Configuring Beans.
To bind UI component values and objects to backing bean properties or to reference backing bean methods from UI component tags, page authors use the unified expression language (EL) syntax defined by JSP 2.1. As explained in Unified Expression Language, some of the features this language offers are:
Deferred evaluation of expressions
The ability to use a value expression to both read and write data
Method expressions
These features are all especially important for supporting the sophisticated UI component model offered by JavaServer Faces technology.
Deferred evaluation of expressions is important because the JavaServer Faces life cycle is split into separate phases so that component event handling, data conversion and validation, and data propagation to external objects are all performed in an orderly fashion. The implementation must be able to delay the evaluation of expressions until the proper phase of the life cycle has been reached. Therefore, its tag attributes always use deferred evaluation syntax, which is distinguished by the #{} delimiters. The Life Cycle of a JavaServer Faces Page describes the life cycle in detail.
In order to store data in external objects, almost all JavaServer Faces tag attributes use lvalue value expressions, which are expressions that allow both getting and setting data on external objects.
Finally, some component tag attributes accept method expressions that reference methods that handle component events, or validate or convert component data.
To illustrate a JavaServer Faces tag using the unified EL, let’s suppose that the userNo tag of the guessNumber application referenced a method rather than using LongRangeValidator to perform the validation of user input :
<h:inputText id="userNo" value="#{UserNumberBean.userNumber}" validator="#{UserNumberBean.validate}" />
This tag binds the userNo component’s value to the UserNumberBean.userNumber backing bean property using an lvalue expression. It uses a method expression to refer to the UserNumberBean.validate method, which performs validation of the component’s local value. The local value is whatever the user enters into the field corresponding to this tag. This method is invoked when the expression is evaluated, which is during the process validation phase of the life cycle.
Nearly all JavaServer Faces tag attributes accept value expressions. In addition to referencing bean properties, value expressions can also reference lists, maps, arrays, implicit objects, and resource bundles.
Another use of value expressions is binding a component instance to a backing bean property. A page author does this by referencing the property from the binding attribute:
<inputText binding="#{UserNumberBean.userNoComponent}" />
Those component tags that use method expressions are UIInput component tags and UICommand component tags. See sections Using Text Components and Using Command Components for Performing Actions and Navigation for more information on how these component tags use method expressions.
In addition to using expressions with the standard component tags, you can also configure your custom component properties to accept expressions by creating ValueExpression or MethodExpression instances for them. See Creating Custom Component Classes and Enabling Component Properties to Accept Expressions for more information on enabling your component’s attributes to support expressions.
To learn more about using expressions to bind to backing bean properties, see Binding Component Values and Instances to External Data Sources.
For information on referencing backing bean methods from component tags, see Referencing a Backing Bean Method.
The life cycle of a JavaServer Faces page is somewhat similar to that of a JSP page: The client makes an HTTP request for the page, and the server responds with the page translated to HTML. However, the JavaServer Faces life cycle differs from the JSP life cycle in that it is split up into multiple phases in order to support the sophisticated UI component model. This model requires that component data be converted and validated, component events be handled, and component data be propagated to beans in an orderly fashion.
A JavaServer Faces page is also different from a JSP page in that it is represented by a tree of UI components, called a view. During the life cycle, the JavaServer Faces implementation must build the view while considering state saved from a previous submission of the page. When the client submits a page, the JavaServer Faces implementation performs several tasks, such as validating the data input of components in the view and converting input data to types specified on the server side.
The JavaServer Faces implementation performs all these tasks as a series of steps in the JavaServer Faces request-response life cycle. Figure 10–3 illustrates these steps.
The life cycle handles both kinds of requests: initial requests and postbacks. When a user makes an initial request for a page, he or she is requesting the page for the first time. When a user executes a postback, he or she submits the form contained on a page that was previously loaded into the browser as a result of executing an initial request. When the life cycle handles an initial request, it only executes the restore view and render response phases because there is no user input or actions to process. Conversely, when the life cycle handles a postback, it executes all of the phases.
Usually, the first request for a JavaServer Faces pages comes in as a result of clicking a hyperlink on an HTML page that links to the JavaServer Faces page. To render a response that is another JavaServer Faces page, the application creates a new view and stores it in the FacesContext instance, which represents all of the contextual information associated with processing an incoming request and creating a response. The application then acquires object references needed by the view and calls FacesContext.renderResponse, which forces immediate rendering of the view by skipping to the Render Response Phase of the life cycle, as is shown by the arrows labelled Render Response in the diagram.
Sometimes, an application might need to redirect to a different web application resource, such as a web service, or generate a response that does not contain JavaServer Faces components. In these situations, the developer must skip the rendering phase (Render Response Phase) by calling FacesContext.responseComplete. This situation is also shown in the diagram, this time with the arrows labelled Response Complete.
The most common situation is that a JavaServer Faces component submits a request for another JavaServer Faces page. In this case, the JavaServer Faces implementation handles the request and automatically goes through the phases in the life cycle to perform any necessary conversions, validations, and model updates, and to generate the response.
This rest of this section explains each of the life cycle phases using the guessNumber example.
The details of the life cycle explained in this section are primarily intended for developers who need to know information such as when validations, conversions, and events are usually handled and what they can do to change how and when they are handled. Page authors don’t necessarily need to know the details of the life cycle.
When a request for a JavaServer Faces page is made, such as when a link or a button is clicked, the JavaServer Faces implementation begins the restore view phase.
During this phase, the JavaServer Faces implementation builds the view of the page, wires event handlers and validators to components in the view, and saves the view in the FacesContext instance, which contains all the information needed to process a single request. All the application’s component tags, event handlers, converters, and validators have access to the FacesContext instance.
If the request for the page is an initial request, the JavaServer Faces implementation creates an empty view during this phase and the life cycle advances to the render response phase, during which the empty view is populated with the components referenced by the tags in the page.
If the request for the page is a postback, a view corresponding to this page already exists. During this phase, the JavaServer Faces implementation restores the view by using the state information saved on the client or the server.
The view for the greeting.jsp page of the guessNumber example would have the UIView component at the root of the tree, with helloForm as its child and the rest of the JavaServer Faces UI components as children of helloForm.
After the component tree is restored, each component in the tree extracts its new value from the request parameters by using its decode method. The value is then stored locally on the component. If the conversion of the value fails, an error message associated with the component is generated and queued on FacesContext. This message will be displayed during the render response phase, along with any validation errors resulting from the process validations phase.
In the case of the userNo component on the greeting.jsp page, the value is whatever the user entered in the field. Because the object property bound to the component has an Integer type, the JavaServer Faces implementation converts the value from a String to an Integer.
If any decode methods or event listeners called renderResponse on the current FacesContext instance, the JavaServer Faces implementation skips to the render response phase.
If events have been queued during this phase, the JavaServer Faces implementation broadcasts the events to interested listeners.
If some components on the page have their immediate attributes (see The immediate Attribute) set to true, then the validation, conversion, and events associated with these components will be processed during this phase.
At this point, if the application needs to redirect to a different web application resource or generate a response that does not contain any JavaServer Faces components, it can call FacesContext.responseComplete.
At the end of this phase, the components are set to their new values, and messages and events have been queued.
During this phase, the JavaServer Faces implementation processes all validators registered on the components in the tree. It examines the component attributes that specify the rules for the validation and compares these rules to the local value stored for the component.
If the local value is invalid, the JavaServer Faces implementation adds an error message to the FacesContext instance, and the life cycle advances directly to the render response phase so that the page is rendered again with the error messages displayed. If there were conversion errors from the apply request values phase, the messages for these errors are also displayed.
If any validate methods or event listeners called renderResponse on the current FacesContext, the JavaServer Faces implementation skips to the render response phase.
At this point, if the application needs to redirect to a different web application resource or generate a response that does not contain any JavaServer Faces components, it can call FacesContext.responseComplete.
If events have been queued during this phase, the JavaServer Faces implementation broadcasts them to interested listeners.
In the case of the greeting.jsp page, the JavaServer Faces implementation processes the standard validator registered on the userNo inputText tag. It verifies that the data the user entered in the text field is an integer in the range 0 to 10. If the data is invalid or if conversion errors occurred during the apply request values phase, processing jumps to the render response phase, during which the greeting.jsp page is rendered again, with the validation and conversion error messages displayed in the component associated with the message tag.
After the JavaServer Faces implementation determines that the data is valid, it can walk the component tree and set the corresponding server-side object properties to the components’ local values. The JavaServer Faces implementation will update only the bean properties pointed at by an input component’s value attribute. If the local data cannot be converted to the types specified by the bean properties, the life cycle advances directly to the render response phase so that the page is re-rendered with errors displayed. This is similar to what happens with validation errors.
If any updateModels methods or any listeners called renderResponse on the current FacesContext instance, the JavaServer Faces implementation skips to the render response phase.
At this point, if the application needs to redirect to a different web application resource or generate a response that does not contain any JavaServer Faces components, it can call FacesContext.responseComplete.
If events have been queued during this phase, the JavaServer Faces implementation broadcasts them to interested listeners.
At this stage, the userNo property of the UserNumberBean is set to the local value of the userNumber component.
During this phase, the JavaServer Faces implementation handles any application-level events, such as submitting a form or linking to another page.
At this point, if the application needs to redirect to a different web application resource or generate a response that does not contain any JavaServer Faces components, it can call FacesContext.responseComplete.
If the view being processed was reconstructed from state information from a previous request and if a component has fired an event, these events are broadcast to interested listeners.
The greeting.jsp page from the guessNumber example has one application-level event associated with the UICommand component. When processing this event, a default ActionListener implementation retrieves the outcome, success, from the component’s action attribute. The listener passes the outcome to the default NavigationHandler. The NavigationHandler matches the outcome to the proper navigation rule defined in the application’s application configuration resource file to determine which page needs to be displayed next. See Configuring Navigation Rules for more information on managing page navigation. The JavaServer Faces implementation then sets the response view to that of the new page. Finally, the JavaServer Faces implementation transfers control to the render response phase.
During this phase, the JavaServer Faces implementation delegates authority for rendering the page to the JSP container if the application is using JSP pages. If this is an initial request, the components represented on the page will be added to the component tree as the JSP container executes the page. If this is not an initial request, the components are already added to the tree so they needn’t be added again. In either case, the components will render themselves as the JSP container traverses the tags in the page.
If the request is a postback and errors were encountered during the apply request values phase, process validations phase, or update model values phase, the original page is rendered during this phase. If the pages contain message or messages tags, any queued error messages are displayed on the page.
After the content of the view is rendered, the state of the response is saved so that subsequent requests can access it and it is available to the restore view phase.
In the case of the guessNumber example, if a request for the greeting.jsp page is an initial request, an empty view representing this page is built and saved in FacesContext during the restore view phase. During this phase, the empty view is populated with the components referenced in the page and then rendered during this phase. If a request for the page is a postback (such as when the user enters some invalid data and clicks Submit), the tree is rebuilt during the restore view phase and continues through the request processing life cycle phases.
For more information on JavaServer Faces technology, see:
The JavaServer Faces 1.2 TLD documentation:
http://java.sun.com/javaee/javaserverfaces/1.2/docs/tlddocs/index.html
The JavaServer Faces 1.2 standard Render Kit documentation:
http://java.sun.com/javaee/javaserverfaces/1.2/docs/renderkitdocs/index.html
The JavaServer Faces 1.1 API Specification:
http://java.sun.com/javaee/javaserverfaces/1.2/docs/api/index.html
The JavaServer Faces 1.1 Specification:
The JavaServer Faces web site: