Developing Java-based Web applications is becoming easier every day. In spite of that, developing Java-based Web applications is time-consuming if you compare it with developing rich UI applications using Swing or .NET.
The Java Community Process (JCP) has come up with a specification called JavaServer Faces (JSF), which attempts to standardize the way we develop Java Web applications and provides a set of rich ready-to-use UI components. JSF is a step in the right direction toward rapidly developing rich Web applications. In this article, I'll discuss the JSF technology and why it is necessary.
Web application's architecture
As shown in Figure A, almost all Web-based UI applications have an n-tier architecture, which can be divided into:
- Presentation tier—This tier handles the presentation user interface and the logic for creating the dynamic user interface.
- Business Logic tier—This tier consists of business objects and rules for data manipulation and transformation. Session facade objects and servlets fall under this tier.
- Data Access tier—This tier normally handles interfaces to the database tier and hides all data access from the business logic tier. Typically, entity beans or data access object frameworks fall under this tier.
- Data tier—This tier controls data storage and performance optimization techniques.
|Web application's architecture|
Web user interfaces usually send a set of key/value pairs to the Web server. By manipulating and transforming this data, the server tries to identify client-side activities like mouse clicks, values changed, etc. Essentially, via data manipulation and transformation, the server tries to identify events generated on the UI side. Initially, Web programmers used to write logic for manipulating and transforming data submitted by the client. Later, they wrote business logic routines for routing these events to appropriate server components (Servlet/JSP).
Then, the open source community came up with a framework for encapsulating some of the complexities of Web-based UI programming, such as wiring client actions (events) to server-side components or to reusable UI components (tag libraries).
You might have guessed that I am talking about the Struts framework. Struts provides highly configurable components for data transformation (ActionForm) and a framework for mapping client actions (events) to server-side components (ActionServlet).
Struts architecture is based on the classical Model View Controller (MVC) design paradigm. Because of its usability, Struts is highly popular and has become a sort of pseudo standard for designing Web-based UI applications.
JSF is inspired by the Struts framework and will provide the following components, some of which are similar to components you can find in the Struts framework:
- Server-side reusable components for creating user interfaces
- A set of JSP tags for accessing those components
- A framework for storing UI state information beyond the life of the server request
- A framework for developing custom UI components
- The wiring of client-side events to server-side components (FacesServlet)
- The opportunity for IDE vendors to develop standards for a Web application framework
JSF and Struts have many things in common. For example, JSF has FacesServlet for dispatching a request to appropriate components similarly to ActionServlet in Struts. JSF also provides standard UI components similar to Struts and the tag library components.
Lifecycle of JSF-based applications
To understand the JSF framework more closely, let's look at the JSF lifecycle shown in Figure B.
Faces request goes through nine total phases. Out of those nine, it goes through seven distinct phases, shown as bold solid rectangles. Dashed lines show Render Response from intermediate steps or some error conditions during data validation and conversion.
The Reconstitute Request Tree phase creates a component tree for the requested page. If that page previously displayed and JSF saved the page's state information, the state information is added to the request. This means that JSF automatically retains form information when a form redisplays; for example, when a user doesn't correctly fill out a form. This handy feature is a fundamental capability provided by Microsoft's WebForms, but is otherwise absent from J2EE.
During the Apply Request Values phase, the JSF implementation iterates over the components in the component tree and calls each component's decode() method. That method extracts information from the request and stores it in the component. Optionally, components may delegate decoding to a renderer.
In addition to decoding request information during the Apply Request Values phase, components or their renderer may create request events. Typically, request events signal a visual change for one or more components (e.g., clicking on a graphic in a tree control may expand a branch of the tree). Alternatively, an event in one component may update the visual representation of another component (e.g., clicking on a leaf node in a tree may cause an associated list to change its contents and redisplay). In either situation, a request event is generated and added to the JSF context.
Request events, which are generated during the Apply Request Values phase, are handled during the Process Events phase, during which the JSF implementation calls the processEvents() method for each component that has one or more request events. Components may handle request events themselves or they may choose to delegate event handling to an event handler. The processEvents() method is a Boolean() method. If that method returns false, the JSF lifecycle advances to the Process Validations phase; otherwise, the lifecycle processing advances directly to the Render Response phase.
During the Reconstitute Request Tree phase, the JSF implementation may register one or more validators for any of the components in the component tree. In the Process Validations phase, the JSF implementation invokes the validate() method for each validator. Validators perform correctness checks and return a Boolean value from their validate() method; if that method returns true, the JSF lifecycle proceeds normally; otherwise, the JSF implementation invokes the Render Response phase directly.
Each JSF user interface component can be associated with a field in a Java object (known as a model object). During the Update Model phase, component values are copied to the component's model object and a component's updateModel() method carries out the data transfer. Conversion errors can occur during this phase because request parameters are strings, but model values can represent any type of Java object. If a conversion error occurs, the JSF implementation invokes the Render Response phase directly.
In a JSF application, if you submit a form or click on a link (both of which must be represented by JSF components), the JSF implementation creates a form event or a command event, respectively. Those events are handled in the Invoke Application phase by an application-specific handler. During this phase, JSF handles any application-level events, such as submitting a form or linking to another page.
Finally, the Render Response phase creates a response component tree and forwards the response. When a user submits a form, clicks on a link, or otherwise generates a request, the cycle starts anew.
A big hit
The JSF specification is going to provide a standard framework for developing extensible Web-based UI applications with quick turnaround times. With a multitude of cool features, JSF is making its presence felt, and I feel that it's going to be a big hit with developers.