Introduction to JavaServer Faces
Pages: 1, 2
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:
- Restore View (previously "Restore Component Tree") -- restores a tree of components.
- Apply Request Values -- applies data from the request.
- Process Validations -- executes any validations.
- Update Model Values -- updates values of model.
- Invoke Application -- executes application.
- Render Response -- generates a response to the user.
For additional information about the JSF actions at each phase of the cycle, consult the details of the JSF specification.
A JSF Example
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.