Some reader favorites:
EJB fundamentals and session beans
Create a scrollable virtual desktop in Swing
Wizard API updated!
Tim Boudreau has released a new version of the Swing Wizard library (version 0.997) that fixes the WizardException bug reported in JavaWorld's recent Open Source Java Project profile. The article's examples have been reworked to test out the new, improved WizardException. Thanks, Tim, for this helpful fix!
Open Source Java Projects: The Wizard API
Page 2 of 6
JSF components also maintain a list of attributes. Those attributes store component-specific information. For example, you may want to store the URL associated with an image used by a component; so you could store that URL—or the image itself—in the component's list of attributes. Component attributes are stored by name in a hash map.
All JSF components perform three fundamental tasks:
JSF components can render themselves or delegate rendering to a renderer. The boolean UIComponent.rendersSelf() method tells the JSF implementation whether or not a component renders itself; if not, the JSF implementation obtains a reference
to the component's renderer with the UIComponent.getRendererType() method's help and then calls on the renderer to produce markup for the component.
JSF component event handling can also be managed directly by a component, or components can delegate to an event handler. One or more event handlers can be registered for a component, typically by a component's renderer or the component itself, during the JSF lifecycle's Apply Request Values phase.
Finally, JSF components can have one or more validators that validate input. Those validators, which are usually created by the JSF implementation, are stored by components in an array list.
Now that we have a basic understanding of JSF components, let's look at implementing a custom validator and associating it with a component.
In Part 1, we discussed using built-in validators to validate input for JSF components. If you use JSP for your Web application's views—which
is typically the case—you can specify validators for JSF components with a <faces:validator> tag, like this:
<faces:textentry_input id='name'> <faces:validator className='javax.faces.validator.RequiredValidator'/> </faces:textentry_input>
The code fragment attaches a validator to a text field; you just specify the validator's class name with the <faces:validate> tag's className attribute. The validator specified above is a JSF built-in validator that checks to make sure a component's value is not
null. As discussed in Part 1, JSF provides a handful of built-in validators, but you can also implement your own validators and
associate them with a JSF component. For example, the application shown in Figure 3 uses a custom validator to validate a
username.
Figure 3. Use a custom validator. Click on thumbnail to view full-size image.
The JSP page displayed in Figure 3 is listed in Listing 1.
<!DOCTYPE HTML PUBLIC '-//W3C//DTD HTML 4.0 Transitional//EN'>
<html>
<head>
<title>A Simple JavaServer Faces Application</title>
</head>
<body>
<%@ taglib uri='http://java.sun.com/j2ee/html_basic/' prefix='faces' %>
<font size='4'>Please enter your name and password</font>
<faces:usefaces>
<faces:form id='simpleForm' formName='simpleForm'>
<table>
<tr>
<td>Name:</td>
<td>
<faces:textentry_input id='name'>
<faces:validator
className='com.sabreware.validators.NameValidator'/>
<faces:validator
className='javax.faces.validator.LengthValidator'/>
<faces:attribute
name='javax.faces.validator.LengthValidator.MINIMUM'
value='3'/>
</faces:textentry_input>
</td>
<td>
<faces:validation_message componentId='name'/>
</td>
</tr>
<tr>
<td>Password:</td>
<td>
<faces:textentry_secret id='password'/>
</td>
</tr>
</table>
<p><faces:command_button id='submit' commandName='Log In'/>
</faces:form>
</faces:usefaces>
</body>
</html>
Like the code fragment shown at the beginning of this section, the preceding JSP page uses <faces:validator> tags to attach validators to a JSF component. In this case, the validators are a custom validator that authenticates a username
and a JSF built-in validator that checks to make sure the username is at least three characters long.
The custom validator used in Listing 1 is listed in Listing 2.
package com.sabreware.validators;
import java.util.Iterator;
import javax.faces.component.UIComponent;
import javax.faces.component.AttributeDescriptor;
import javax.faces.context.FacesContext;
import javax.faces.context.Message;
import javax.faces.context.MessageImpl;
import javax.faces.validator.Validator;
public class NameValidator implements Validator {
public AttributeDescriptor getAttributeDescriptor(String attributeName) {
return null;
}
public Iterator getAttributeNames() {
return null;
}
public void validate(FacesContext context, UIComponent component) {
String name = (String)component.getValue();
if(!"phillip".equalsIgnoreCase(name)) {
context.addMessage(component,
new MessageImpl(Message.SEVERITY_ERROR, "bad username",
"The username " + name + " is invalid"));
}
}
}
The preceding validator implements the javax.faces.validator.Validator interface, which defines the methods listed below:
void validate(FacesContext, UIComponent)Iterator getAttributeNames(String)AttributeDescriptor getAttributeDescriptor(String)The validate() method performs the actual validation for a given component. The other two methods, defined by the Validator interface, are used by tools to discover attributes (and their descriptions) associated with a particular validator. In this
case, we don't have any attributes for our validator, so the getAttributeDescriptor() and getAttributeNames() methods simply return null.
A validator's validate() method does nothing if the component's values are valid; if those values are invalid, the validator() method creates messages and adds them to the JSF context. All of that happens during the JSF lifecycle's Process Validations phase. If a component fails validation—meaning messages have been added to the JSF context—the JSF implementation proceeds
directly to the Render Response phase; otherwise, the lifecycle proceeds to the Apply Model Values phase. (Refer to Figure 1 for more information about the JSF lifecycle phases.)
In a Model-View-Controller (MVC) architecture, views, which are typically JSP pages for Java-based Web applications, display values contained in a model. JavaServer Faces makes it easy to connect UI components to fields stored in model objects. As we saw in the last section, if a request's values are all valid, the JSF lifecycle moves from the Process Validations phase to the Apply Model Values phase. During the latter phase, the JSF implementation copies component values to the model objects associated with those components. The HTML text fields shown in Figure 4a are connected to a model object. When the Log In button activates, the JSF implementation forwards control to a JSP page that uses that model object to display a personalized greeting (Figure 4b).
Figure 4a. HTML text fields connected to a model object. Click on thumbnail to view full-size image.
Figure 4b. Personalized greeting. Click on thumbnail to view full-size image.
Listing 3 shows the JSP page illustrated in Figure 4a.
SUBHEAD2: Listing 3. /index.jsp
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title>A Simple JavaServer Faces Application</title>
</head>
<body>
<%@ taglib uri="http://java.sun.com/j2ee/html_basic/" prefix="faces" %>
<font size="4">Please enter your name and password</font>
<!-- We use jsp:useBean to create a model object, but
real applications typically create model objects elsewhere:
JSP pages are purely views of the model -->
<jsp:useBean id='user' class='com.sabreware.beans.User'
scope='session'/>
<faces:usefaces>
<faces:form id="simpleForm" formName="simpleForm">
<table>
<tr>
<td>Name:</td>
<td><faces:textentry_input id="name"
modelReference="${user.name}"/></td>
</tr>
<tr>
<td>Password:</td>
<td><faces:textentry_secret id="password"
modelReference="${user.password}"/></td>
</tr>
</table>
<p><faces:command_button id="submit" commandName="Log In"/>
</faces:form>
</faces:usefaces>
</body>
</html>
The preceding JSP page creates a session-scope variable of type com.sabreware.beans.User. JSP pages typically do not create model objects; instead, business objects, such as a servlet or a servlet filter, usually
create model objects. The preceding JSP page uses the <faces:textentry_input> tags' modelReference attribute to specify a field in the user object. For example, the name field is associated with the user object's name property, and the password field is associated with the user object's password property.
The User class is demonstrated in Listing 4.
package com.sabreware.beans;
public class User {
private String name = null, password = null;
public void setName(String name) { this.name = name; }
public String getName() { return name; }
public void setPassword(String pwd) { this.password = pwd; }
public String getPassword() { return password; }
}
The User class is a simple JavaBean that stores a name and password. Here's the JSP page shown in Figure 4b:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title>A Simple JavaServer Faces Application</title>
</head>
<body>
<%@ taglib uri='http://java.sun.com/jstl/core' prefix='c' %>
Welcome to JavaServer Faces, <c:out value='${user.name}'/>!
</body>
</html>
The preceding JSP page accesses the name property of the user object created by the JSP page listed in Listing 3. That property is accessed with the JSP Standard Tag Library (JSTL). Note the exact same syntax is used in Listing 3 to specify
user properties with the modelReference attribute.
By itself, JavaServer Faces does not provide much support for internationalization; instead, JSF relies on JSTL for internationalization and localization support.
Java-based Web applications typically localize messages (and format or parse numbers, currencies, percents, and dates) in JSP pages. It's also common to localize messages in a Java class. A validator, for example, may localize error messages. This section discusses both approaches using JSTL to internationalize the Web application discussed in the previous "Model Objects at Work" section.
First, we store all localized text in a properties file:
login.window-title=Internationalization Javaserver Faces
login.name=Name
login.password=Password
login.submit=Log In
errors.bad-username=Bad username
errors.bad-username-details=The username {0} is invalid
Then we rewrite Listing 3's JSP page to localize all text displayed to the user. Listing 7 shows that rewritten JSP page.
<!DOCTYPE HTML PUBLIC '-//W3C//DTD HTML 4.0 Transitional//EN'>
<html>
<head>
<%@ taglib uri='http://java.sun.com/jstl/fmt' prefix='fmt' %>
<fmt:setLocale value='en-US' scope='application'/>
<fmt:setBundle basename='messages' scope='application'/>
<title><fmt:message key='login.window-title'/></title>
</head>
<body>
<%@ taglib uri='http://java.sun.com/j2ee/html_basic/' prefix='faces' %>
<font size='4'>Please enter your name and password</font>
<jsp:useBean id='user' class='com.sabreware.beans.User'
scope='application'/>
<faces:usefaces>
<faces:form id='simpleForm' formName='simpleForm'>
<table>
<tr>
<td><fmt:message key='login.name'/></td>
<td><faces:textentry_input id='name'
modelReference='${user.name}'>
<faces:validator className=
'com.sabreware.validators.NameValidator'/>
</faces:textentry_input>
</td>
<td>
<faces:validation_message componentId='name'/>
</td>
</tr>
<tr>
<td><fmt:message key='login.password'/></td>
<td><faces:textentry_secret id='password'
modelReference='${user.password}'/></td>
</tr>
</table>
<p><faces:command_button id='submit' commandName='Log In'/>
</faces:form>
</faces:usefaces>
</body>
</html>
The preceding JSP page uses two tags from the JSTL formatting library to set a locale and resource bundle base name (<fmt:setLocale> and <fmt:setBundle>, respectively) and a third tag (<fmt:message>) to display localized messages stored in the specified resource bundle.
The validator listed below localizes error messages, also using JSTL.
package com.sabreware.validators;
import java.util.*;
import java.text.MessageFormat;
import javax.servlet.ServletContext;
import javax.servlet.jsp.jstl.core.Config;
import javax.servlet.jsp.jstl.fmt.LocalizationContext;
import javax.faces.component.UIComponent;
import javax.faces.component.AttributeDescriptor;
import javax.faces.context.FacesContext;
import javax.faces.context.Message;
import javax.faces.context.MessageImpl;
import javax.faces.validator.Validator;
public class NameValidator implements Validator {
public AttributeDescriptor getAttributeDescriptor(String attributeName) {
return null;
}
public Iterator getAttributeNames() {
return null;
}
public void validate(FacesContext context, UIComponent component) {
String name = (String)component.getValue();
if(!"phillip".equalsIgnoreCase(name)) {
ServletContext app = context.getServletContext();
LocalizationContext lc = (LocalizationContext)
Config.get(app, Config.FMT_LOCALIZATION_CONTEXT);
if(lc == null) {
context.addMessage(component,
new MessageImpl(Message.SEVERITY_ERROR, "bad username",
"The username " + name + " is invalid"));
}
else {
ResourceBundle rb = lc.getResourceBundle();
Object[] args = new Object[] { new String(name) };
String cs = rb.getString("errors.bad-username-details");
String s = MessageFormat.format(cs, args);
context.addMessage(component,
new MessageImpl(Message.SEVERITY_ERROR,
rb.getString("errors.bad-username"), s));
}
}
}
}
JSTL maintains a localization context that contains a resource bundle and the locale used to locate that resource bundle. That localization context is available
through the JSTL Config class. The preceding JSP page uses the context's resource bundle to localize messages.
Before we move on to JSF custom components, you should note that internationalization support for JSF is not complete. In
Listing 7, the text displayed by the Submit button is not localized because the JSF <command_button> tag does not support text localization. We could have internationalized the text with a scriptlet, but that involves ugly
code that should not exist in a JSP page. Internationalization support will be complete by JSF 1.0's release.
Note: Detailed coverage of JSTL internationalization is beyond the scope of this article. For more information about JSTL, see Resources.
Besides providing a standard set of components, a render kit that renders those components in HTML, and a set of corresponding JSP tags, JavaServer Faces also lets you create custom components. The application below contains two instances of a JSF custom component. That custom component keeps track of two images. When you click on the component, it toggles the image it currently displays.
Figure 5a. Two custom components display their primary images. Click on thumbnail to view full-size image.
Figure 5b. Application changes after user clicks on left-hand component. Click on thumbnail to view full-size image.
Figure 5c. Application changes again after user clicks on right-hand component. Click on thumbnail to view full-size image.
Figure 5a shows the application after it starts; the two custom components display their primary images. Figure 5b shows the application after the user clicks on the left-hand component, and Figure 5c shows the application after the user subsequently clicks on the right-hand component. If you click on the components a second time, the components will display their original image.
These custom components might seem trivial and somewhat useless; however, even though the former is true (the components are purposely trivial to illustrate JSF component implementation), the latter is not necessarily valid—this custom component can be used as part of any component that contains clickable images. For example, this custom component could be used in a tree control to expand or shrink nodes displayed in the tree.
Listing 9 lists the JSP page shown in Figure 5a.
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title>Creating Custom Components with JavaServer Faces</title>
</head>
<body>
<%@ taglib uri="http://java.sun.com/j2ee/html_basic/" prefix="faces" %>
<%@ taglib uri="/WEB-INF/tlds/example.tld" prefix="sabreware" %>
<faces:usefaces>
<sabreware:toggleGraphic id='bananaKiwi'
imageOne='/graphics/banana.jpg'
imageTwo='/graphics/kiwi.jpg'/>
<sabreware:toggleGraphic id='pineappleStrawberry'
imageOne='/graphics/pineapple.jpg'
imageTwo='/graphics/strawberry.jpg'/>
</faces:usefaces>
</body>
</html>
The preceding JSP page is simple—it uses a custom tag to create two instances of our custom component. For completeness, the
tag library descriptor (TLD) associated with the <sabreware:toggleGraphic> tag is listed in Listing 10.
<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE taglib
PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN"
"http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd">
<taglib>
<tlib-version>1.0</tlib-version>
<jsp-version>1.2</jsp-version>
<short-name>JSF Example</short-name>
<display-name>A Simple JSF Example Tag</display-name>
<description>This library contains one simple custom JSF tag</description>
<tag>
<name>toggleGraphic</name>
<tag-class>com.sabreware.tags.ToggleGraphicTag</tag-class>
<body-content>JSP</body-content>
<description>A simple tag for a custom JSF component</description>
<attribute>
<name>imageOne</name>
<required>true</required>
<rtexprvalue>false</rtexprvalue>
</attribute>
<attribute>
<name>imageTwo</name>
<required>true</required>
<rtexprvalue>false</rtexprvalue>
</attribute>
<attribute>
<name>id</name>
<required>true</required>
<rtexprvalue>false</rtexprvalue>
</attribute>
</tag>
</taglib>
The <sabreware:toggleGraphic> tag has three attributes: an identifier and the component's two images. Listing 11 shows the tag handler.
Free Download - 5 Minute Product Review. When slow equals Off: Manage the complexity of Web applications - Symphoniq
![]()
Free Download - 5 Minute Product Review. Realize the benefits of real user monitoring in less than an hour. - Symphoniq