An Introduction to Java Server Faces

An Introduction to Java Server Faces

By Prithpal S. Bhogill, OCI Senior Software Engineer 

August 2003


Introduction

Web application development in Java has come a long way. We have matured from our yester year implementations using Java Servlets to render HTML code, to Element Construction Set (ECS) to modularize HTML rendering and representation, to using JavaServer Pages (JSP) technology to provide clean separation of business logic and presentation. Lately Model View Controller (MVC) frameworks like STRUTS have gained wide acceptance to rapidly develop complex web applications. What has been missing in the server side Java implementations is a presence of event driven frameworks to handle User Interface (UI) component interactions, input validations, handling page navigation and rendering.

JavaServerFaces (JSF) technology fills in this gap. JSF provides a set of APIs to represent UI components, manage their state, handle events, perform input validation and manage page navigation and internationalization. It decouples components from their presentation so they can be rendered in multiple ways and on different devices. In this article I attempt to run through all the pieces of the JSF architecture, discuss the different phases involved in the lifecycle of a JSF page and last but not the least discuss some implementation considerations.

JavaServer Faces Overview

JSF is a standard UI framework for Java Web applications. It is being led by Sun Microsystems as JSR 127 under the Java Community Process (JCP). It promotes rapid web application development by easily assembling UI components, plumbing them to the back end business logic components and wiring UI component generated events to server-side event handlers. The JSF API is composed of:

A JSF application typically runs on a web server and renders the UI back to the client. Its clean separation of UI components from their presentation allows the components to be rendered in different ways on different devices. A typical JSF application development team will primarily consist of three roles.

Let us take a quick look at a typical JSF page versus a standard JSP page in the code example below.

Example 1: Standard JSP Request Page quoteRequest.jsp

  1. <html>
  2. <head>
  3. <title>Handy Dandy Service Bureau</title>
  4. </head>
  5. <body bgcolor="white">
  6. <h2>Welcome to the Handy Dandy Service Bureau. Enter up to 2 stock symbols to get quotes</h2>
  7. <form method="get">
  8. <p><input type="text" name="stock1" size="4"/></p>
  9. <p><input type="text" name="stock2" size="4"/></p>
  10. <p><input type="submit" value="Submit"/>
  11. <input type="reset" value="Reset"/></p>
  12. </form>
  13. <%
  14. String stock1 = request.getParameter("stock1");
  15. String stock2 = request.getParameter("stock2");
  16. if ((stock1.length() > 0) (stock2.length() > 0)) {
  17. %>
  18. <%@include file="quoteResponse.jsp" %>
  19. <%
  20. }
  21. %>
  22. </body>
  23. </html>

Standard JSP Response Page: quoteResponse.jsp

  1. <jsp:stockBean id="StockQuoteBean" class="com.ociweb.model.StockQuoteBean" scope="request" ></jsp:stockBean>
  2. <html>
  3. <head><title>Handy Dandy Service Bureau</title></head>
  4. <body bgcolor="white">
  5. <h2>Welcome to the Handy Dandy Service Bureau. Here are your results: </h2>
  6. <p>Stock 1: <jsp:getProperty name="StockQuoteBean" property="Symbol1"></jsp:getProperty>
  7. Price: <jsp:getProperty name="StockQuoteBean" property="Price1"></jsp:getProperty>
  8. </p>
  9. <p>Stock 2: <jsp:getProperty name="StockQuoteBean" property="Symbol2"></jsp:getProperty>
  10. Price: <jsp:getProperty name="StockQuoteBean" property="Price2"></jsp:getProperty>
  11. </p>
  12. </body>
  13. </html>

Code Summary:

Example 2: Stock Quote JSF Request Page jsfQuoteRequest.jsp

  1. <html>
  2. <head> <title> Handy Dandy Service Bureau </title> </ head >
  3. <%@ taglib uri="http://java.sun.com/jsf/html" prefix="display" %>
  4. <%@ taglib uri="http://java.sun.com/jsf/core" prefix="main" %>
  5. <body bgcolor="white">
  6. <h2> Welcome to the Handy Dandy Service Bureau. Enter up to 2 stock symbols to get quotes</h2>
  7. <jsp:stockBean id="StockQuoteBean" class="com.ociweb.model.StockQuoteBean" scope="request" ></jsp:stockBean>
  8. <main:use_faces>
  9. <display:form id="quoteForm" formName="quoteForm" >
  10. <p>
  11. <display:input_text id="stock1" valueRef="StockQuoteBean.Symbol1"></display:input_text>
  12. </p>
  13. <p>
  14. <display:input_text id="stock2" valueRef="StockQuoteBean.Symbol2"></display:input_text>
  15. </p>
  16. <display:command_button id="submit" label="Submit" commandName="submit" ></display:command_button>
  17. </display:form>
  18. </main:use_faces>
  19. </body>
  20. </html>

Stock Quote JSF Response Page jsfQuoteResponse.jsp

  1. <html>
  2. <head> <title> Handy Dandy Service Bureau </title> </head>
  3. <%@ taglib uri="http://java.sun.com/jsf/html" prefix="display" %>
  4. <%@ taglib uri="http://java.sun.com/jsf/core" prefix="main" %>
  5. <body bgcolor="white">
  6. <main:use_faces>
  7. <display:form id="responseform" formName="responseform">
  8. <p>
  9. <display:output_text id="symbolLabel1" valueRef="StockQuoteBean.Symbol1" ></display:output_text> :
  10. <display:output_text id="symbolPrice1" valueRef="StockQuoteBean.Price1" ></display:output_text>
  11. </p>
  12. <p>
  13. <display:output_text id="symbolLabel2" valueRef="StockQuoteBean.Symbol2" ></display:output_text> :
  14. <display:output_text id="symbolPrice2" valueRef="StockQuoteBean.Price2" ></display:output_text>
  15. </p>
  16. <display:command_button id="back" label="Back" commandName="back" ></display:command_button><p>
  17. </display:form>
  18. </main:use_faces>
  19. </body>
  20. </html>

Code Summary:

The body section of this code can be easily changed to represent the same UI components in a different markup language like WML (Wireless Markup Language), though you would need a separate tag library for that.

JavaServer Faces Architecture

The JSF architecture is comprised of six different layers.

UI Component Model

The UI component model primarily defines the functionality of the components. It consists of JavaBean components representing various modes of input, selection, and grouping capabilities. The base class for all UI components is an abstract class that defines the state information and its associated behavioral contracts. Every component has a type, an identifier, local values and some generic attributes. The UI component model is extensible and you can easily create new components by extending or aggregating existing components. Their behavior is defined by events that tie them into the Event Model. Each UI component (or Java Server Faces component) can be associated with pluggable validators which validate user input in response to an event before any application logic can be invoked.

The existing set of UI component classes are:

Rendering Model

The rendering model defines the presentation aspects of a UI component. The same UI component can be rendered in different ways by creating multiple renderers. So a UISelectOne component can be rendered as a drop-down list with only a single selection permitted or as a group of radio buttons, from which only one can be selected. Also a UICommand component can be rendered as a button or as a hyperlink. Additional benefits are realized by decoupling the rendering from the component functionality, as the same component can be easily rendered to an HTML client (i.e. web browser) using an HTML Renderer or to a WML client (i.e. cell phone) by just switching to a WML Renderer. The rendering model uses what are called render kits. Render kits are to JSF applications what XSLT is to XML, i.e. content can be rendered differently for different devices.

Event Model

The JSF event model is similar to JavaBeans event design. It defines Listener and Event classes that a web 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 register it on the component that generates the event. When the user activates a component, such as clicking a button, an event is fired. This causes the JSF implementation to invoke the listener method that processes the event. This strong capability is commonplace with thick client (i.e. Java Swing) interfaces, so developers are very familiar with this event notification model. It has been missing so far in the web application arena. Loosely coupled web application can be designed using this model.

The JSF implementation supports two different kinds of events:

Validation Framework

The validation framework provides a mechanism by which 'Validators' can be registered with UI components. Validators are simple classes which can define data type validation (i.e. alpha or numerical input etc), range validation (i.e. valid between MIN and MAX values), or required field validation.

In its simplest form, for a class to act as a validator, it has to implement the Validator interface. The validator can be expressed and associated with a UI component in a JSP page using the core tag library <jsf-core> by nesting the <validate_validatortype> tag inside of the input component tag (<validate_required> can be used for required field validation).

Any validation errors resulting from user input can be renderered to the client using the <output_errors> tag.

The JSF implementation provides a set of validators which can be used for basic validations. You can also create custom validators to cater for different application needs. The validators provided by the implementation are:

RequiredValidator
Checks if the component value is null, or empty in the case of a text field
Expressed via the <validate_required> tag
LengthValidator
Checks if the component value length is within a defined range
Expressed via the <validate_length> tag
LongRangeValidator
Checks if the component long value is within a defined range
Expressed via the <validate_longrange> tag
DoubleRangeValidator
Checks if the component double value is within a defined range
Expressed via the <validate_doublerange> tag
StringRangeValidator
Checks if the component string value is within a certain range
Expressed via the <validate_stringrange> tag

Page Navigation Framework

The page navigation framework provides an easy declarative mechanism to specify the sequence of pages to be loaded without requiring any special code in the application. The navigation can be completely defined in the application resource file, a simple XML file, which contains navigation rules that define possible outcomes (e.g. successful outcome, failure outcome). Here is a sample navigation rule for our Stock Quote example above:

  1. <navigation-rule>
  2. <from-tree-id>/quote_request.jsp</from-tree-id>
  3. <navigation-case>
  4. <from-outcome>success</from-outcome>
  5. <to-tree-id>/quote_response.jsp</to-tree-id>
  6. </navigation-case>
  7. <navigation-case>
  8. <from-outcome>error</from-outcome>
  9. <to-tree-id>/error.jsp</to-tree-id>
  10. </navigation-case>
  11. </navigation-rule>

As you can see most of the application navigation can be defined using navigation rules. This decoupling helps in altering page navigation without modifying application code. You can also be finer grained in a navigation rule so it is activated based on a specific action. Some code modifications are required if additional processing is required to figure out the sequence of pages to be loaded.

Internationalization Framework

This framework provides an easy mechanism for localizing static data, dynamic data, and messages in applications. Static data can be localized using the standard tag library internationalization tags and providing resource bundles (properties files containing messages for different languages tied to key values) and associating specific data in JSP pages with keys. Internationalizing dynamic data on the other hand is a model bean function as the data is only available at run time. The JSF API provides a set of classes for localizing generic output and error messages. These include the Message, MessageResources, MessageResourceFactory, and ResourceBundle classes.

The JSF architecture is summarized in this diagram below.

JSF Architecture

JavaServer Faces Page Lifecycle

This section discusses the various phases involved in a typical JSF page lifecycle. At a high level, the lifecycle involves a request for a specific page submitted to a HTTP / Web Server (e.g. from a browser) followed by a response generated for a specific device (e.g. HTML for a browser). The standard lifecycle for a typical JSF page is expressed in the following phases:

Reconstruct Component Tree

This phase is initiated when a page request is submitted to the server (i.e a user clicks a submit button on a web page). During this phase the server creates a hierarchical tree of UI components which represent the elements constituting the page. The JSF engine parses this component tree and wires all the declared event handlers and validators to the specific components. All this information is finally persisted in a FacesContext. A faces context is nothing but a snapshot, an object tree representation of the incoming page. This information is utilized in the following phases until the response is rendered.

Apply Request Values

In this phase the JSF engine applies the values from the request object (parameters) to the respective components in the component tree (available from the current FacesContext) created in the previous phase. These values are stored locally in the UI components. In the event that conversion errors occur during storage of these values, they are queued up in the FacesContext, so they can be displayed when the content is finally rendered. If any event handlers were associated with specific components, they are notified of the relevant events.

Perform Validations

After the request values have been applied, the JSF page enters the validation phase, wherein all the registered validators are applied to relevant UI components. The locally stored values of these components are run through the associated validators and validation errors, if any, are queued in the FacesContext. If validation errors occur in this phase, the JSF engine skips the next two phases and the page enters the Render Response phase. The page is reconstructed from the component tree and displayed along with the validation errors and any errors or messages queued up in the FacesContext from the Apply Request Values phase. If no validation errors are detected, the page enters the Synchronize Model phase and any events generated at this point are broadcast to the interested event handlers.

Synchronize Model

In this phase any model objects associated with UI components are synchronized to the UI component's local value. If any conversion error occurs at this point, (e.g. a String value is mapped to an Integer property in a model object and cannot be parsed into an integer), the errors are queued in the FacesContext and the page enters the Render Response. The page is recreated from the component tree and rendered to the user displaying the conversion errors which occurred in this phase. Also any events generated at this point are broadcast to the interested event handlers.

Invoke Application Logic

After the model has been successfully synchronized, the page enters this phase. In this phase the JSF engine handles all application level events, such as linking to another page, performing updates to back end services, database updates, etc. When processing an application level event, a default ActionListener determines the outcome of the Action and passes the outcome to the NavigationHandler. The NavigationHandler then looks up the response to be generated from the navigation rule defined in the application configuration file, based on the outcome of the application logic, i.e. success or failure. The component tree for the next page to be generated is constructed and the page enters the final stage.

Render Response

In this phase the JSF engine renders the UI components in the component tree persisted in the FacesContext. If any errors or messages have been queued up from previous phases, they are rendered along with the page. This component tree is persisted so subsequent requests to this page can access it and it is readily available to the Reconstruct Component Tree phase.

Implementation Considerations

There is usually a tradeoff in trying to achieve abstraction and modularity versus implementing your application in a tightly coupled manner. With Java Server Faces, you can abstract out the navigation in the form of rules defined in a configuration file. The JSF implementation can render an input page with error(s) simply by using the component tree to recreate the page. All the interactions are event-driven and validators are pluggable. The UI component model separates the component functionality from its presentation, so the same component can be rendered differently on various devices. This provides a very flexible, loosely coupled and scalable solution. However, all this comes at a cost!

Memory and Duplication

The JSF engine primarily duplicates the component layout in the form of a component tree, which is persisted in the server memory, so it can be accessed for subsequent hits to the same page. This is okay when dealing with small forms having few fields. However, for complex pages with many fields, the cost of maintaining the component layout in memory is high. Also, if an error occurs in the any phase (more expensive if it happens in later phases), the same page is re-rendered with errors and the entire process is repeated. The data is again duplicated from the component local values to model object(s) so they can be in sync. In addition to the cost of persisting the component layout as an object tree, maintaining the UI Component and Model classes in memory is expensive.

Simple Components

The current implementation provides simple components like buttons, input text elements, drop down lists, check boxes, group controls etc. Complex components like Table or Tree are not yet available. Many of these complex components are necessary to provide a nice user experience.

Custom Renderers and Validators

The current implementation packages two Java Standard Tag libraries, core and html. Developers have to develop custom tag libraries for expressing these UI components in another display format e.g. WML for wireless devices. Custom components and validators developed in house or procured from vendors have to be supported and maintained. This incurs additional overhead.

New technology

Java Server Faces is a relatively new technology. It requires a lot of configuration. Few IDEs support it, so a lot of hand coding is required to write the tags in pages. Since the tags are new, the page authors will have some learning curve associated with the tag libraries. Few vendor supplied, customized components exist. As the technology matures and the user audience increases, more components and renderers will be available.

Summary

This article has covered the basics of Java Server Faces, providing insight into its architecture, discussed different team roles, typical lifecycle of a JSF page, and discussed some implementation considerations. Java Server Faces is a step in the right direction. It aims to provide a loosely coupled UI Component model, which provides event driven functionality on the server side. Different renderers can render the same component differently for various targetted devices. It provides a nice framework for web application development using the MVC architecture. With time and support from vendors we will hopefully see more JSF applications.

References



Software Engineering Tech Trends (SETT) is a regular publication featuring emerging trends in software engineering.


secret