Welcome!

Java Authors: Liz McMillan, Walter H. Pinson, III, Maureen O'Gara, Yakov Werde, Tony Bishop

Related Topics: Java

Java: Article

JavaServer Faces: The Importance of Components

How JSF and reusable components can shorten your development time

JavaServer Faces has established itself as the leading framework for JEE development. In spite of its rising popularity, many development teams are unfamiliar with its use of components: so let's begin with a description of JSF components and what they have to offer.

At its most basic, a component begins as a new tag, sometimes called a "custom tag" that you can add to a JavaServer Page (JSP). When the JSP is compiled, the tag is converted to a more complicated HTML-base structure. For example a simple tag like <mylib:emailSearch> might be converted to an entire HTML form to look up someone's e-mail, maybe something like:

<form method-"post" action="goGetEmails">
Enter User Name: <input type="text" name="uname" /><br />
<input type="submit" value="lookup" />
</form>

This code is generated from a Java class: the JSP compiler locates this class via a processing instruction that's placed at the top of the file, like this: <%@ taglib prefix="f" uri="http://java.sun.com/jsf/core"%>.

If you've been working with JSPs you're probably familiar with the JSP Standard Template Library (JSTL) that uses this technique to dynamically generate HTML. Although the JSTL is useful, most of its tags are quite simple and none, as we'll see, rise to the level of a "component." Developers tend to overlook JSTL largely because its syntax follows XML rules rather than Java, and many of its features are rather obscure.

Central to the use of JSTL is the JSP expression language. The "EL," as it's called, makes server-side data available to the JSTL tags as they are being compiled. For example this tag, <c:out value="${sessionScope.userName}" default="Smith" /> will look in the current session for an attribute called "userName" and print out its value. If there's no session, or if the session doesn't contain this attribute, the tag will simply print out "Smith."

While this is great for dynamically displaying data, it falls short when you're working with data that the user needs to change. JSTL gives you a way to put data into the browser, but no way to detect changes to that data. This is where JSF comes in. The JSF framework can track all the data that is passed between the browser and server, validate it, and convert the simple text strings that the server gets from the browser into proper Java objects.

JSF ships with a set of component tags built in. Let's use one for another example. The inputText tag creates an input field whose data can be tracked, validated and converted.

<h:inputText id="uname1" required="true" value="#{myBean.userName}" maxlength="25" />

This tag will produce an HTML input type="text" field. Assuming that this line is part of a form, here's how JSF will handle it.

  1. Since the attribute required is set to true, form processing won't be allowed to occur if the user doesn't enter a name. Instead, JSF will provide an error message that can be displayed elsewhere on the page via the <h:message> tag.
  2. The initial value of the input field will be provided from the userName attribute of a server-side bean called myBean. Notice that JSF has its own expression language. The JSF EL is similar to the JSP EL, but uses a prepended # instead of a $.
  3. The entry the user makes in this field will be used to automatically update the userName attribute in the server-side bean. If there are errors elsewhere in the form, JSF will keep the user on the page until all the data is acceptable, but all data the user has entered is kept up to date automatically - the developer doesn't have to provide any further coding.
  4. Because of the maxlength attribute, the user won't be allowed to enter more than 25 characters.

Attributes like reaquired and maxlength are called "validators." JSF provides a solid core of validators for commonly used data constraints. You can examine them at http://java.sun.com/javaee/javaserverfaces/1.1_01/docs/tlddocs/index.html.

Let's briefly examine one before we move on. The Long Range validator lets you check that the data in an input field is a valid number and that it falls between some minimum and maximum value. Suppose we want to accept numeric input between the values 199 and 4042. We would code our tags as:

<h:inputText id="counter" required="true" value="#{myBean.myCounter}">
<f:validateLongRange minimum="199" maximum="4042" />
</h:inputText>

If the user enters non-numeric data, he'll get a message that the data isn't the correct type. If he enters a number that's out of range, he'll get a message that tells him so.

So What About Components?
Like everything else in Java, the JSF framework is extensible. JSF was designed with the specific intention of letting people develop their own JSF-based tags. This has worked out quite well, and several companies are marketing tag libraries that offer much more sophisticated abilities than those available in JSF itself. Let's take a big step up and look at a component for building HTML tables quickly and easily. The component we'll use comes from Infragistics, Inc. and is part of the NetAdvantage for JSF product.

This component requires a collection of beans that it will convert to rows in an HTML table. The data in the table will be sortable, pageable, and editable. For this example let's assume an EmployeeBean that stores the following data:

Strings: firstName, lastName
Dates: hireDate, birthDate
Float: salary

Let's further assume that our employee data has been put in this Bean and collected into an ArrayList called employees. So to set up our table we'd start with:

<ig:webGrid
dataSource="#{myExampleClass.employees}"
styleClass="igGrid"
topPagerRendered="true"
pageSize="10"
>

The pageSize attribute specifies that only 10 rows will be displayed at a time. The topPagerRendered attribute causes a paging subcomponent to be rendered at the top of the grid. The dataSource attribute indicates the server-side bean that will supply the data.

Next we'll add tags to specify the columns in the table.

<ig:column sortBy="lastName">
<f:facet name="header">
<h:outputText value="Last Name" />
</facet>
<h:outputText value="#{DATA_ROW.lastName}" />
</ig:column>

The sortBy attribute makes this column sortable on the employees' last names - no other code is needed for this. The facet tag adds a header to the column. The outputTExt tag after the facet adds the data to the column.

All remaining columns would be added in the same manner.

In the browser, the table would resemble the following image, taken from the company's Web site.

Hopefully this example helps clarify the power and reusability of a component. To use these tags with another set of data, you'd need to change only the dataSource and values of the outputText value attributes.

While this approach to generating tables is easy and powerful, it's only one example of component usage. There are dozens of components from companies that make it easy to build rich interactive interfaces.

I think it's clear that what we've seen so far can, by itself, speed up the development of Web 2.0-style interfaces, but we've really just scratched the surface of what's possible. Next, we'll look at techniques for changing attribute values dynamically using the example data table we examined above. After that we'll see how to generate entire components from server-side Java objects.

When writing EL expressions for JSF we're normally referring to the accessor methods of plain Java Beans. In an expression like #{myExampleClass.employees}myExampleClass refers to a class. The name itself is specified in a faces-config.xml configuration class: here you'll see the name set up much as a servlet name is set up in web.xml.

The employees node refers to a public ArrayList getEmployees() method inside the class. You'll recall that I explained that JSF automatically updates all data values when a page is submitted. Typically (there are several way to manage this) all those values will be available to the bean that contains the getEmployees method. That means that getEmployees can make decisions about what to display based on other values on the page. So the user can make choices that affect what is displayed back to them.

Let's work through an example. Imagine a page that will display the employees of a company (see Figure 1). The user contains a set of radio buttons that lets him select on "Hourly," "Salaried," or "Both." There's also a submit button to send their choice to the server. Based on their selection, the page will show the correct set of employees (hourly, salaried, or both) in a table below the radio and submit buttons.

When the submit button is pressed the form is sent to the server where the JSF framework starts examining the data. The getEmployees method can then check the state of the radio buttons to decide which data to return to the grid. The code would resemble this:

public ArrayList getEmployees() {

GridDataDAO x = new GridDataDAO();

if(tableChoices.getValue().equals("hourly"))
return x.getHourlyData();
else if(tableChoices.getValue().equals("salaried"))
return x.getSalariedData();
else return x.getAllData();
}

If you read this code carefully, you'll probably find yourself wondering where tableChoices came from. tableChoices is the server-side component that mirrors the radio button list in the HTML. Setting it up is easy. In the same class that holds the getEmployees method, declare private UIInput tableChoices = null; and generate accessor (get/set) methods for it.

To associate the UIInput object with the radio button list, add a "binding" to the latter in your JSP like this:

<ig:radioButtonList
id ="choices"
dataSource="#{myExampleClass.tableDisplayChoices}"
binding="#{myExampleClass.tableChoices}" />

Notice in getEmployees that we can extract the selected value of the radio button list as a string with a simple getValue call.

This gives us a simple data filter: the user has some control over what he wants to see, and we can provide a different data source to the component based on the user's choice. The component in this page can be used with different data sources without any JSP recoding. However, in the example above, this only works as long as the different ArrayLists that are sent to the JSP always contain the same type of data bean.

Suppose, instead, that we want to display a completely different table based on user choices. For example, the user might want to select between commercial and residential real estate properties. To do this we'll use the "rendered" attribute of the data table. This attribute, which is a part of every JSF component, allows you to set whether or not a particular component is drawn on the page. So, to display different tables based on a user choice, we'll include tags for two different tables but set their rendered attribute to true or false based on user actions.

The value of the rendered attribute will be set via an EL:

<ig:webGrid
rendered="#{myExampleClass.drawingTableOne}"
dataSource="#{myExampleClass.commercial}"
styleClass="igGrid"
topPagerRendered="true"
pageSize="10"
>

The columns for the table remain the same.

We must add our second table. In the JSP we can simply place it directly after the first table.

<ig:webGrid
rendered="#{myExampleClass.drawingTableTwo}"
dataSource="#{myExampleClass.residential}"
styleClass="igGrid"
topPagerRendered="true"
pageSize="10"
>

Back in the server class, we'll use methods for each of these ELs.

public boolean isDrawingTableOne() {
if(userChoice.getValue().equals("commercial")) {
return true;
else return false;
}

public boolean isDrawingTableTwo() {
if(userChoice.getValue().equals("residential")) {
return true;
else return false;
}

The userChoice node should be bound to a component - a radio button, dropdown list. etc. So each table has its own data source, but only the one the user selects will be appear in the browser.

Let's pause for a moment and consider what would have been required to do this without the JSF framework. For each table, a lengthy method for generating the HTML would have to be coded and the code that accepts the user choice would have to decode the data from the radio buttons before it could be acted on.

Further Benefits of Components
Having looked at the procedure for working with the grid component, I'd like to spend a few minutes discussing the other features available in it. I'll stick with the grid (from Infragistics) that we've been using, but you should understand that all the vendors that are building components for JSF pack as much functionality as they can into each one. This works well for the JSF user, as he gets many additional features with little or no additional code.

Using built-in JavaScript, the Infragistics Web grid includes columns that can be moved (reordered in the grid) and resized via mouse drags. Any cell in the grid can be converted to an editable field with a mouse click, and the editable field can be any JSF component. There's more, but you get the idea. As these features pile up, the additional coding needed to support them increases exponentially. With JSF, though, it doesn't matter. A component vendor builds out all the supporting code and the JSF developer simply inserts the tag with the correct attributes and EL expressions, and then writes a little supporting code on the server.

Using AJAX with JSF
AJAX fits in with the JSF framework very naturally. However, the early JSF specifications (1.0, 1.1, and 1.2) don't address AJAX. One of the consequences is that each vendor of JSF components has built its own AJAX engine and the various engines aren't always compatible. Although this issue is being addressed in the upcoming 2.0 specification, for the time being, component users are basically forced to choose components from only one vendor if they want to use AJAX.

This doesn't include the simple components included with JSF, which aren't AJAX-enabled anyway.

Summary
In this article, I've tried to approach JSF use from a different perspective than most other articles on JSF. Most of the papers I've read stress the framework's server-side structure. Instead I've shown how JSF provides a basis for building Web 2.0 applications quickly and easily. Components are at the heart of JSF's appeal, and there are dozens of vendors offering them at many different levels of power and complexity.

JSF is now included in the JEE core implementation. As JEE users upgrade to EE5 (and up) they'll find that they already have JSF installed and ready to use. More and more shops are moving to JSF from both Model 2- and Struts-based applications. I hope this article has helped you see why.

More Stories By Jim Cook

Jim Cook is Java Product Manager at Infragistics.

Comments (0)

Share your thoughts on this story.

Add your comment
You must be signed in to add a comment. Sign-in | Register

In accordance with our Comment Policy, we encourage comments that are on topic, relevant and to-the-point. We will remove comments that include profanity, personal attacks, racial slurs, threats of violence, or other inappropriate material that violates our Terms and Conditions, and will block users who make repeated violations. We ask all readers to expect diversity of opinion and to treat one another with dignity and respect.