Page Navigation in JavaServer Faces
by Budi Kurniawan10/29/2003
Page navigation is an important aspect of web programming. The more complex an application is, the harder it is to manage how users navigate from one page to another. JavaServer Faces (JSF) solves this problem by allowing page navigation to be configured in the Application Configuration file. This is one of the features that will make JSF the first choice of web application development in Java in the future. You can download the sample application here. The examples were tested using JSF Early Access 4. Refer to the article "Introducing JavaServer Faces" on ONJava.com on how to deploy your JSF application. The article can also be the first reference if you are not familiar with JSF.
All multi-page web applications need some mechanism to manage page navigation for their users. If you are familiar with Model 1 and Model 2 of the servlet and JSP design models, you know that page navigation can be complicated in Model 1 applications because the link to the user's next destination is hard-coded. The difficulty of page navigation management often makes Model 1 inappropriate for medium-sized-to-large applications. Model 2 alleviates the problem somewhat, because the next links are confined to the Controller servlet. However, changing a link requires the recompilation of the servlet. JSF, however, offers page navigation through page navigation rules in the Application Configuration file.
Page navigation is crucial to JSF application programming. All multi-page
JSF applications will require the user to navigate between pages. In JSF, the
user navigates to another page by clicking a UICommand component
on the page, represented by either the command_button tag or the
command_hyperlink tag. Clicking this component emits an
Event object of the type javax.faces.event.ActionEvent. Normally, to capture an
ActionEvent, you need to write an ActionListener.
However, JSF provides a default action listener for page navigation. As a
result, you don't have to write your own. But how does the default action
listener know which page to present next when the user clicks a
UICommand? Through the page navigation rules in the Application
Configuration file. Because the Application Configuration file is an XML
document, you can use any text editor to update it. This means page navigation
is easy to modify.
|
Related Reading
Java Servlet & JSP Cookbook |
This article explains what navigation rules are and how to use them. It
continues with an example of a simple navigation. Afterwards, it discusses the
Action class and its role in page navigation. The article
concludes with another more complex example that illustrates conditional page
navigation. Let's start with navigation rules.
Navigation Rules
Clicking the UICommand component will send an
ActionEvent to the default application handler. The default
application handler is registered automatically to every UICommand
component.
Each navigation rule in the Application Configuration file specifies a page of origin and one or more possible targets. A page is represented by its tree identifier, and each possible target is represented by a navigation case. You need to specify a navigation rule for each page from which the user can navigate to another page.
To understand this better, consider a page called login.jsp that contains a login form. When the user clicks the submit button to log in, the application can redirect control to either a welcome.jsp page (if the login was successful) or back to the login.jsp page (if the login failed). In this case, the login.jsp page will have two navigation cases, one for a successful login and one for a failed login.
A navigation rule is defined by the navigation-rule element in
the Application Configuration file. The element is described as follows.
<!ELEMENT navigation-rule
(description*, display-name*, icon*, from-tree-id?, navigation-case*)>
The asterisk denotes that the element preceding the asterisk appears zero
or many times. Therefore, description, display-name,
icon, and navigation-case are all optional or can
appear many times. The question mark (?) denotes that the
preceding element can appear zero or one time. The two most important
sub-elements of the navigation-rule element are
from-tree-id and navigation-case.
The value of a from-tree-id sub-element is the tree identifier
of the page of origin. To describe the navigation rule for a JSP page called
login.jsp, you would have the following as the value of the
from-tree-id sub-element:
<from-tree-id>login.jsp</from-tree-id>
The navigation-case sub-element represents a possible target. A
navigation-rule element can have zero or more
navigation-case sub-elements. Each of these elements specifies
the target page for a particular outcome of the from-tree-id
processing. An outcome can be obtained from the action or
actionRef attributes of the UICommand component in
the from-tree-id element.
The navigation-case element is described as follows:
<!ELEMENT navigation-case
(description*, display-name*, icon*, from-action-ref?, from-outcome?, to-tree-id)>
Use the description element to describe the navigation case. The
display-name and icon sub-elements are useful only
for an XML tool you use to edit the Application Configuration file. Both are
infrequently used. The from-action-ref, from-outcome,
and to-tree-id are explained below.
The to-tree-id element specifies the target page of this
navigation case. The from-outcome is the outcome of processing
the from-tree-id. It is obtained from the value of the
action property of the UICommand component that
triggered the ActionEvent in the from-tree-id.
The from-action-ref element also represents the outcome of
processing the from-tree-id. However, its value comes from the
actionRef property of the UICommand component that
raised the ActionEvent.
Simple Example
The following example illustrates the simplest navigation rule. This application consists of two pages: a.jsp and b.jsp. From a.jsp, the user can click the button to go to b.jsp, and vice versa. Listing 1 shows the navigation rules.
Listing 1. The navigation rules for a.jsp and b.jsp
<navigation-rule>
<from-tree-id>/a.jsp</from-tree-id>
<navigation-case>
<to-tree-id>/b.jsp</to-tree-id>
</navigation-case>
</navigation-rule>
<navigation-rule>
<from-tree-id>/b.jsp</from-tree-id>
<navigation-case>
<to-tree-id>/a.jsp</to-tree-id>
</navigation-case>
</navigation-rule>
The first navigation-rule element specifies the target for
a.jsp. It contains the navigation-case element with a
to-tree-id sub-element, without a from-outcome or a
from-action-ref sub-element. This means that, regardless of the outcome,
the target page (b.jsp) will be displayed. The second navigation
rule specifies the target for b.jsp. From b.jsp, the
user will definitely go to a.jsp.
Note: the original page will be re-displayed if there is an error processing it.
Both a.jsp and b.jsp use the ValueBean in Listing 2.
Listing 2. The ValueBean class
package jsfArticle;
public class ValueBean {
private String value;
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
The bean must be registered in the Application Configuration file given in Listing 3.
Listing 3. ValueBean in the Application Configuration file
<managed-bean>
<managed-bean-name>ValueBean</managed-bean-name>
<managed-bean-class>jsfArticle.ValueBean</managed-bean-class>
<managed-bean-scope>session</managed-bean-scope>
</managed-bean>
The a.jsp contains a UIInput component and a
validator that enforce the user to type four or more characters into the
UIInput component. The a.jsp page is given in
Listing 4.
Listing 4. a.jsp
<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h"%>
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f"%>
<html>
<head>
<title>First Page</title>
</head>
<body>
<f:use_faces>
<h:form formName="myForm">
Please enter your user id (Your user id must be at least 4
characters long) :
<h:input_text valueRef="ValueBean.value">
<f:validate_length minimum="4"/>
</h:input_text>
<br/>
<h:command_button commandName="submit" label="submit"/>
<br/>
<hr/>
<h:output_errors/>
</h:form>
</f:use_faces>
</body>
</html>
The b.jsp page contains a UIOutput component that
displays the value entered by the user to the UIInput component in
the a.jsp page. The b.jsp page also has a command
button for the user to go back to the a.jsp page. The
b.jsp page is given in Listing 5.
Listing 5. b.jsp
<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h"%>
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f"%>
<html>
<head>
<title>Second Page</title>
</head>
<body>
<f:use_faces>
<h:form formName="myForm">
The user id you have entered is <h:output_text
valueRef="ValueBean.value"/>
<br/>
<h:command_button commandName="back"
label="Back to Previous Page"/>
</h:form>
</f:use_faces>
</body>
</html>
You can invoke the a.jsp page using the following URL (assuming your web container is using port 8080, and that you are running the browser on the same machine that hosts the applications):
http://localhost:8080/jsfPageNav/faces/a.jsp
You will then see something similar to Figure 1.

Figure 1. The a.jsp page
Now, type and submit a string of four or more characters. Your browser will now look like the one in Figure 2.

Figure 2. The b.jsp page
If you click the Back button in b.jsp, you will see the a.jsp page again.
Note that if you type fewer than four characters into the
UIInput component in a.jsp page, the validator in
a.jsp will add a Message object to the
FacesContext instance, canceling the navigation. As a result, you
will see the a.jsp page again, with an error message, just like
the screenshot in Figure 3.

Figure 3. Failed navigation