This article is meant to acquaint the reader with JavaServer Faces, commonly known as JSF. JSF technology simplifies building the user interface for web applications. It does this by providing a higher-level framework for working with your web app, representing the page as event-aware components rather than raw markup.
At this time, there are two JSF variants: JSF early access 4 (which is included in the Java Web Services Developer Pack 1.3), and JSF 1.0 Beta. It's important to remember that JSF is a specification, much like J2EE. And like J2EE, there is a reference implementation from Sun, along with other implementations of the interface, such as the open source MyFaces. This article is concerned with the distinctive features of the JSF specification and its ideas, not with a particular implementation. After all, since JSF is not yet final, the specifics might yet change.
We assume the reader is already somewhat familiar with Java programming, servlets, JavaServer Pages (JSPs) and custom tag technologies. The reader should be experienced with servlet/JSP containers such as Tomcat, and design patterns such as model-view-controller (MVC).
In developing web applications, we often deal with the same problems. First off, the interface is the most frequently updated part of the application, so we want to simplify modification of the interface as much as possible. Secondly, those developing the application have significantly different skill sets — server-side programmers, HTML coders, graphic designers, etc. — and we want their work to be as independent as possible. This leads to a model-view-controller design to separate the roles.
In many organizations, the development of a web application works in a familiar manner. The designer creates a prototype, the HTML coder does everything in HTML, and the server-side programmer achieves his or her needed functionality in Java. This approach often fails badly. The designer, when creating the prototype, is limited only by his or her imagination, inadvertently causing problems for the other participants, often forcing them to start from scratch when developing a new application.
Even if the problem of role division can be solved in existing frameworks (for example, by using custom tags or XML/XSL transformations), there can still be a problem with code reuse. So what's so different between creating the GUI for a Swing application and a web application? It's obvious: in Swing, there is a set of standard GUI components and an entire infrastructure for tweaking and extending the functionality. A Swing developer works with the concept of a
Component — an element of the user interface, such as a panel, button, list, or table — and can either set values to use the default behavior or extend the component to provide new behavior.
Some of these components, specifically
Containers allow combinations of components, such as a panel with a table that contains buttons in some of its cells. As an added bonus, the developer gets to work with high-level concepts: when the button is clicked, an event is generated.
Meanwhile, for the web developer to know the button has been pressed, he has to analyze the HTTP request and try to determine what has happened. This is not ideal. The programmer shouldn't have to work so hard to figure out if a button, image, or hyperlink was clicked, or how these pieces were implemented in HTML. Ideally, the developer just wants to know that an event occurred. In other words, the developer needs to be able to see the web interface in terms of familiar high-level concepts.
This is the problem JSF aims to solve.
The following presentation of JSF concepts is based on the most recent specification (dated Dec. 18, 2003).
The core JSF architecture is designed to be independent of communication protocols or markup language specifics. However, it's also meant to solve the problems experienced working with HTML clients communicating via HTTP with a Java application server that supports Servlet/JSP applications. JSF aims to provide the following features to simplify application development:
Of course, when developing web applications today, everyone has to deal with these problems, and everyone solves them in their own way, increasing development time and hurting maintainability. JSF tries to offer a unified way to deal with these issues.
The specification understands the importance of dividing software development roles and assigns responsibilities to these roles.
Component writers (a.k.a. Component Developers) are responsible for creating reusable UI components. They are thus responsible for:
Application developers are responsible for the server-side tasks, such as creating an application's business logic, its persistence layer, etc. They should develop appropriate Java objects to represent the desired functionality, and make these objects accessible from servlets.
Tool providers supply tools like IDEs that facilitate creating JSF-based applications, or even higher-level frameworks that might use JSF to create their user interface.
JSF implementors are responsible for implementing all the required specifications of JSF. For example, they might provide a JSF implementation within their J2EE server.
Note that most developers will not perform either of the latter two roles. But they indicate the seriousness of Sun's intentions with respect to role-division: for JSF to succeed, it's necessary to follow the role-division guidelines.
Let's look in detail at what JSF provides us. As noted above, the highlight of JSF is the availability of reusable server components for creating GUI's. From JSF's point of view, all components should inherit from
javax.faces.component.UIComponent (note that in the EA4 release this was an interface). Any page or screen of the application will consist of a set of such components. A set of hierarchically ordered components is called the JSF Tree (EA4's term) or the View (1.0 beta's term). This tree of components represents the structure of the onscreen page. Each element of a tree is
UIComponent, with some components being composites and thus having child components.
In JSF there is a set of standard components. The UML diagram shows the notation structure of these standard components. The developer can create new components based on existing components (for example, by inheriting from
UIOutput), or by a completely new subclass of
UIComponent. To make creating components easier, it's possible to inherit from
UIComponentBase, which contains default implementations for the methods in
UIComponent along with some convenience methods.
If a hypothetical page will contain a form with an input field and a button, then the JSF components' structure will be of the form
UIForm → (
UICommand, where the "→" character is understood to show a parent-child relationship. This means the
UIViewRoot has a single child, a
UINamingContainer (used by JSF for automatic assignment of unique identifiers), which has a
UIForm child, which in turn has two children: a
UIInput and a
UICommand. Each component can find its parent with
getParent() and its children with
Figure 1 shows the relationship of the JSF component classes.
Figure 1. Standard JSF components.
The most interesting methods of
UIComponent are the following:
These methods are responsible for the translation of data from a request to a component and from forming a reply based on the state of a component. Naturally, implementations of these methods should be coordinated — if the
encode() stores the condition of a component, then
decode() should have an opportunity to read it. Despite the fact that these methods are in the components themselves, the responsibility for encoding and decoding is usually relegate to special classes inherited from
These renderer classes bear the responsibility for how a given component will be presented to the user. For example,
UICommand might be displayed as either a button or a link. This arrangement allows the
UICommand class to remain fairly constant, while its presentation varies with the associated
Renderer functionality can be united in a
For example, if you know that the client will be rendering HTML you can use the
HTMLRenderKit. In fact, there are multiple kits, including
SimpleHTMLRenderKit for browsers that don't fully support HTML 4.0, and
AdvancedHTMLRenderKit for modern browsers. Of course, this means a given page may look different in different browsers, but the page structure (the View) does not need to be modified. It's only necessary to define a rule to determine which
RenderKit to use.
However, this may not be enough in some cases. The important part is the component model, which encapsulates the data with which the component works. As an example, we'll consider the
javax.faces.model.DataModel that appeared in JSF 1.0 Beta. This abstract class is a wrapper for data representing Strings, accessed by index. If, for example, we needed to represent records in a database table, we could use JSF's
javax.faces.model.ResultSetDataModel, an implementation of
DataModel. This arrangement of a component in terms of a
Renderer and its
UIComponent represent the model, view, and controller from the familiar MVC pattern.
A component can generate events and notify all interested listeners. All event classes need to inherit from
javax.faces.event.FacesEvent, while all listeners implement
javax.faces.event.FacesListener. So, to track the change in a component's value, we have
javax.faces.event.ValueChangeEvent, which is handled by a
javax.faces.event.ValueChangeListener. A concrete
UIComponent provides an opportunity to register listeners on this type of event. For example,
javax.faces.component.UIInput contains the method
addValueChangeListener, which takes a
JSF also provides the concepts of a
Validator and a
Converter. The former is used to check the status of a component (for
UIInput), and in the case of an error it provides a message to be shown to the user, such as "invalid phone number" or "username should only contain letters and numbers." A
Converter is used to transform data from a String to some kind of object and back.
For example, a model may store a date as a
java.util.Date, but the Renderer changes it to a String at some stage of encoding, and at decoding time it's necessary to convert the String back into a
Date. For this common purpose, JSF provides the standard converter
JSF defines not only the possible actions involving components, but also the order of these actions. At the moment a request is received by
FacesServlet, the entry-point to JSF, a lifecycle of JSF request processing begins, which consists of a set of phases, each with its own specialization:
For additional information about the JSF actions at each phase of the cycle, consult the details of the JSF specification.
Currently, JSP is used as the basic mechanism for formatting a page. With special JSF custom tags, we can create the structure, the component tree, and the parameterization of each component. Here's what a basic JSF page looks like:
<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %> <%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %> <HTML> <HEAD> <title>Hello</title> </HEAD> <body bgcolor="white"> <h2>Enter number</h2> <f:view> <h:form > <h:graphicImage id="logo" url="/logo.gif" /> <h:inputText id="num" required="true" size="4"> <f:validateLength maximum="4" minimum="1" /> </h:inputText> <h:commandButton value="submit" action="success" title="Submit" /> </h:form> </f:view> </body> </HTML>
This page consists of a form in which we have a graphic image, an input field, and a submit button. We've also added a validator to the input field. Note that the form does not have an
ACTION attribute. This is because JSF has its own navigation system. The target where the form will be submitted is defined by the button, with help from a configuration file, faces-config.xml, which specifies that if a page transition is successful (i.e., the action = "success"), then we'll be redirected to a certain URL. Notice that this arrangement is similar to the Struts framework; developers already familiar with Struts will see the analogy between the JSF configuration file and struts-config.xml.
JSF was developed to handle everything required for developing web-oriented applications. It's meant to be an all-encompassing solution. But it's interesting to compare the technology to existing alternatives. Struts is a well-known web framework that is something of a standard for similar projects. Much like JSF, it is based on MVC principles. However, Struts itself doesn't provide a View construction mechanism. But to its credit, Struts has a nicely implemented concept of controllers. Thus, Struts is often used in combination with other frameworks that deal with the presentation.
Also, there are many frameworks available that are similar to JSF, such as UIX from Oracle. In fact, this particular framework is very similar to JSF and probably reflects Oracle's interest in web GUIs. The Oracle JDeveloper IDE supports UIX, but reportedly plans to add JSF support. IBM's WebSphere Application Developer also supports JSF. One other framework, similar in spirit to JSF, is Tapestry, in which we can see the concepts of a lifecycle, reusable components, and rigid division of roles.
In conclusion, my own opinion about JSF is that while it has incorporated the advantages of many custom tag libraries and frameworks, it has also inherited the difficulties of adjusting to a new way of coding. Granted, Struts arguably has the same problem. But since JSF isn't yet final, it's possible that it will be further improved before it's done.
Alexander Prohorenko is a certified professional, who holds Sun Certified System Administrator and Sun Certified Java Programmer certifications.
Olexiy Prokhorenko is a Sun Certified Enterprise Architect whose areas of interests include Web software architecture and development of software with frequently changing requirements.
Return to ONJava.com.
Copyright © 2009 O'Reilly Media, Inc.