As Published In

Oracle Magazine
March/April 2004
DEVELOPER: JSF

Facing Forward with JSF
By Budi Kurniawan

JavaServer Faces expedites development of Java applications.

JavaServer Faces (JSF) is a new technology for rapidly building Web applications using Java technologies. JSF expedites the development process by providing the following features: standard and extensible user interface (UI) components, easily configurable page navigation, components for input validation, automatic bean management, event-handling, easy error handling, and embedded support for internationalization.

This article demonstrates how to build an online pizza ordering system using JSF.

Project Description

The application is called PizzaRia, an online store that allows users to select pizzas and have them delivered. PizzaRia looks like other online stores in which users can browse the menu, add products to the shopping cart, and check out.

The user interface of this application is five JavaServer Pages (JSP) files named index.jsp, details.jsp, shoppingCart.jsp, checkOut.jsp, and order.jsp. Every user interface page includes three other pages: header.jsp, menu.jsp, and footer.jsp.

Figure 1

Figure 2

Figure 3

Figure 4

Figure 5

The Database

The application data is stored in three tables, Products, Orders, and OrderDetails. The Products table stores product information and has four columns: ProductId, Name, Description, and Price.

Each row in the Orders table stores an individual order, including the information about the contact name, delivery address, and credit card details. The Orders table has six columns: OrderId, ContactName, DeliveryAddress, CCName, CCNumber, and CCExpiryDate.

The items for each order are stored in the OrderDetails table. The OrderDetails table has four columns: OrderId, ProductId, Quantity, and Price. The Orders table has a one-to-many relationship with the OrderDetails table via the OrderId column. Note that the OrderDetails table holds the Price information at the time the user places the order. This price can be different from the current product price, which is stored in a Price field of the Products table.

The script file pizzaria-oracle.sql for creating the required tables in an Oracle database is in the pizzaria.zip file.

Business Objects

The following are the business objects used in the application:

ProductBean. Encapsulates a product. It has the following properties: id, name, description, and price. A ProductBean instance is automatically created by the JSF implementation every time the details.jsp page is accessed. The JSF implementation calls the ProductBean no-argument constructor to retrieve the corresponding data from the database and populate the fields.

ProductSummary. Represents the summary of a product. This class includes two properties:
id and name.

ShoppingItemBean. Represents a shopping item. This class includes four properties: productId, productName, price, and quantity.

ShoppingCartBean. Represents a shopping cart stored in the session object. This class allows you to add a shopping item (using the addShoppingItem method), get the list containing all shopping items (using the getShoppingItems method), and get the total value of the purchase (using the getTotal method).

OrderBean. Represents an order. This class has the following five properties: contactName, deliveryAddress, creditCardName, creditCardNumber, and creditCardExpiryDate.

MenuBean. Displays a menu of available products using the getMenu method. This method returns an HTML table containing the links to the product details.

DatabaseUtil. Provides three methods for accessing and manipulating the data:

  • GetProductSummaries. Returns an ArrayList containing the summaries of all products in the Products table. A product summary is represented by the ProductSummary class.
  • GetProductDetails. Returns a ProductBean object encapsulating the details of the product with the specified identifier.
  • InsertOrder. Inserts the customer order into the Orders and OrderDetails tables.

Application Context Listener

The application context listener (the AppContextListener class) reads in the initial parameters for database access from the web.xml file and writes them to the ServletContext object. The following initial parameters are used: jdbcDriver, dbUrl, dbUserName, and dbPassword. Edit these values in your web.xml file to reflect the real values for your database.

JSF Application Configuration

JSF allows programmers to configure applications easily through the application configuration file. This file, if present, must be named faces-config.xml and reside in the WEB-INF directory of your application.

You can configure many aspects of the application, including bean management, page navigation, custom UI components, custom validators, and message resources, in the faces-config.xml file. In the PizzaRia application, I use the faces-config.xml file for bean management and page navigation.

JavaBean management. For JavaBean management, use the managed-bean element in the faces-config.xml application configuration file. Each managed-bean element registers a JavaBean that JSF will instantiate and store in the specified scope. The managed-bean element is defined as follows:

<!ELEMENT managed-bean (description*, display-name*, icon*, managed-bean
name, managed-bean-class, managed-bean-scope, (managed-property* | map-entries |
list-entries))>

A managed-bean element must contain a managed-bean-name element, a managed-bean-class element, and a managed-bean-scope and can optionally contain any number of descriptions, display-name, icon, and managed-property/map-entries/list-entries elements.

The managed-bean-name specifies the name that will be used to refer to the JavaBean throughout the application. The managed-bean-class element contains the fully qualified class name for the JavaBean. The managed-bean-scope element defines the scope of the JavaBean. The possible values for this element are application, session, request, or none. If the value of the managed-bean-scope element is something other than none, the JavaBean created will be stored in the corresponding object. For example, if the value is "session," the JavaBean is stored in the session object of a given user.

In the PizzaRia application, I register four JavaBeans as shown in Listing 1.

Page navigation. Page navigation determines the control flow of a Web application. This section demonstrates how to set up page navigation in JSF.

JSF uses the navigation-rule element to define a rule for page navigation. Its definition is as follows:

<!ELEMENT navigation-rule 
  (description*, display-name*, icon*, from-view-id?, navigation-case*)>

The from-view-id element is the identifier of the page of origin. To describe the navigation rule for a JSP page called index.jsp, the following is the value of the from-view-id subelement:

<from-view-id>/index.jsp</from-view-id>

The navigation-case element represents a possible target. A navigation-rule element can have zero or several navigation-case subelements.

Each navigation-case element specifies the target page for a particular outcome of the from-view-id processing. An outcome can come from the action attribute of the UICommand component in the from-view-id element.

The navigation-case element is described as follows:

<!ELEMENT navigation-case 
(description*, display-name*, icon*, from-action?, from-outcome?, 
to-view-id, redirect?)>

The to-view-id element specifies the target page. The from-outcome value is the outcome of processing the from-view-id. This value comes from the action property of the UICommand component that triggered the ActionEvent in the from-view-id.

The from-action element also represents the outcome of processing the from-view-id. However, its value comes from the evaluation of the action property of the UICommand component that raised the ActionEvent.

Listing 2 shows the navigation-rule elements used in the PizzaRia application.

Using UI Components in JSP Pages

JSF provides two custom tag libraries to help you rapidly write Web applications: HTML and Core. The HTML custom tag library defines tags that represent UI components. The Core custom tag library defines core actions for registering event handlers, using validators with components, and so on. You use the tags from both libraries in the JSP pages of your JSF applications.

To use the HTML and Core custom tag libraries in a JSP page, you must include the following taglib directives in the page:

<%@ taglib uri="http://java.sun.com
/jsf/html/" prefix="h" %>
<%@ taglib uri="http://java.sun.com/
jsf/core/" prefix="f" %>

The prefix attribute values can be anything. However, by convention, you normally use h and f.

Writing the JSP pages in a JSF application is the responsibility of the page author. In addition to laying out components, this responsibility includes binding the components to model object data and adding Core tags (such as event listeners and validators) to component tags.

There are 25 tags in the HTML custom tag library. Each component is rendered as an HTML element, and many tags are rendered as the same HTML element. Table 1 lists the tags in the HTML custom tag library.

TagDescription
ColumnRepresents a column of data within a UIData component.
command_buttonRepresents a button to submit a form to the server.
command_linkRepresents a hyperlink to navigate to another page or a location on a page.
data_tableRepresents a table that supports data binding to a collection of data objects.
FormRepresents a form.
graphic_imageDisplays an image.
input_hiddenRepresents a hidden element.
input_secretRepresents a password box.
input_textRepresents an input box that accepts a string.
input_textareaRepresents a text area that accepts a multiline string.
MessageDisplays messages for a given component.
MessagesRepresents a component that obtains messages from FacesContext and displays them to the user.
output_labelDisplays text.
output_linkDisplays a hyperlink.
output_messageDisplays messages for a given component
output_textDisplays a line of text.
panel_gridDisplays a table.
panel_groupGroups a set of components.
selectboolean_checkboxRepresents a textbox.
selectmany_checkboxlistDisplays a set of check boxes from which the user can select multiple values.
selectmany_listboxRepresents a select box from which a user can select multiple items.
selectmany_menuRepresents a list of items from which a user can select multiple items.
selectone_listboxRepresents a select box from which a user can select one item.
selectone_menuRepresents a list of items from which a user can select one item.
selectone_radioRepresents a set of radio buttons.

Table 1. HTML Custom Tag Library

Using Validators

Validators make input validation simple and save developers hours of programming. JSF provides a set of validator classes for validating input values entered into input components. Alternatively, you can write your own validator if none of the standard validators suits your needs.

A validator is an implementation class that checks an input value and sends an error message if the input is invalid. You use a validator by nesting it inside an input component whose input needs to be validated. If the validator decides that the user's input is invalid, the JSF servlet redisplays the JSP page from which the form was submitted, without copying the local value to the JavaBean instance bound to the input component.

The JSF implementation provides three standard validators for common validation tasks, including checking that required fields have entries and that input meets length and range requirements. Table 2 lists the standard validators.

Validator ClassTagDescription
LengthValidatorvalidate_lengthEnsures that the length of a component's local value falls into a certain range. The value must be a string.
LongRangeValidatorvalidate_longrangeEnsures that a component's local value to within a certain range. The value must be convertible to a long.
DoubleRangeValidatorvalidate_doublerangeEnsures that a component's local value is within a certain range. The value must be convertible to a floating-point number

Table 2. JSF Standard Validators

In addition, the input_text and input_textarea tags in the HTML custom tag library have a required attribute. If you assign true to this attribute, users will be forced to enter a value to the input or textarea element before they can proceed.

In the PizzaRia application, the checkOut.jsp page uses the required attribute to guarantee that no field is empty.

Event Handling

JSF applications are event-driven. Handling events in JSF is surprisingly easy. Here are the steps:

  1. Write an event listener.
  2. Deploy the event listener in the WEB-INF/classes or WEB-INF/lib directory under the application directory.
  3. In the tag representing the component whose event is to be captured, use an action_listener or a valuechange_listener tag defined in the Core custom tag library.

Event objects in JSF. All event objects in JSF must extend the javax.faces .event.FacesEvent class for those events to be supported by the request processing lifecycle. The FacesEvent class is a subclass of the java.util.EventObject class and adds the getComponent method, which returns the UIComponent component that fired the event.

The FacesEvent class has two subclasses: ActionEvent and ValueChangeEvent. The ActionEvent class represents the activation of the UI component, such as a UICommand component.

The ValueChangeEvent class represents a notification that the local value of a UIInput component has been changed. However, if the new value was not validated successfully, the ValueChangeEvent notification will not be fired. Some of the important methods added to this class are getOldValue and getNewValue. The getOldValue method returns the old value of the component that fired the event. The getNewValue method returns the new value. The return type of both getOldValue and getNewValue is java .lang.Object.

Event listeners in JSF. To capture a JSF event, use an event listener. All listeners in JSF applications must implement the javax.faces.event.FacesListener interface. This interface extends the java.util.EventListener interface, which is the interface that must be implemented by all Java event listeners.

The FacesListener interface has two subinterfaces: ActionListener and ValueChangeListener. The ActionListener interface is the interface that must be implemented to capture an ActionEvent. This interface adds a new method—processAction—that will be invoked by the request processing lifecycle. This method is invoked when the ActionEvent for which the ActionListener is registered occurs. The processAction method has the following signature:

public void processAction(ActionEvent 
  event) 
 throws AbortProcessingException

The ValueChangeListener interface is the interface you implement to capture a ValueChangeEvent. This interface adds one method: processValueChange. This method is invoked when the ValueChangeEvent action observed by this listener occurs. Here is the signature of the processValueChange method:

public void processValueChange(ValueChangeEvent
  event) 
throws AbortProcessingException

Next Steps

DOWNLOAD
JavaServer Faces (JSF)

PizzaRia application

READ
more about JavaServer Faces
java.sun.com/j2ee/javaserverfaces/download.html
java.sun.com/webservices/downloads/webservicespack.html

In the PizzaRia application, you need an ActionListener called AppAction Listener. Its processAction method first obtains the local value from the getLocalValue method of the ActionEvent object passed to processAction. If the local value is "Buy," processAction obtains the ShoppingCartBean object associated with the user and adds the shoppingItem to the bean. If the local value is "Pay," then processAction obtains the OrderBean object and the ShoppingCartBean object from the session object and calls the insertOrder method of the DatabaseUtil object. Listing 3 describes the processAction method.

The AppActionListener class employs two useful methods: getValueBinding and getDatabaseUtil. The getValueBinding method accepts a string specifying an object name and returns a ValueBinding object that can be downcast to the object type. For example, to obtain the instance of a user's ShoppingCartBean that is registered in the application configuration file as shoppingCartBean, you call the getValueBinding method by passing "shoppingCartBean":

ShoppingCartBean cart = (ShoppingCartBean) 
getValueBinding("#{shoppingCartBean}").getValue(facesContext);

The following is the getValueBinding method:

private ValueBinding getValueBinding(String valueRef) {
  ApplicationFactory factory =
  (ApplicationFactory)FactoryFinder
.getFactory(FactoryFinder
.APPLICATION_FACTORY);
  Application application = factory.getApplication();
return
  application.createValueBinding
(valueRef);
  }

The getDatabaseUtil method returns a reference to the DatabaseUtil instance in the ServletContext:

private DatabaseUtil getDatabaseUtil() {
FacesContext facesContext = FacesContext.getCurrentInstance();
ServletContext servletContext = (ServletContext)
facesContext.getExternalContext()
.getContext();
return (DatabaseUtil) servletContext
.getAttribute("DATABASE_UTIL");
  }

Running the Application

This PizzaRia JSF application has been tested with the JSF reference implementation (JavaServer Faces [JSF] Beta 1.0). See the README.TXT file in the application zip file (pizzaria.zip) for details on deploying your PizzaRia application.


Budi Kurniawan (budi@brainysoftware.com) is an IT consultant specializing in internet and object-oriented programming. He is the author of Java for the Web with Servlets, JSP, and EJB (New Riders, 2001) and the upcoming How Tomcat Works (brainysoftware.com, 2004).


Please rate this document:

Excellent Good Average Below Average Poor

 
E-mail this page
Printer View Printer View
Oracle Is The Information Company About Oracle | Oracle RSS Feeds | Careers | Contact Us | Site Maps | Legal Notices | Terms of Use | Privacy