JSF Central - Developing Unwired JSF Components
JSF Central

 
 Home 
 
 News 
 
 FAQ 
 
 Products 
 
 Articles & Books 
 
 Resources 
 
Developing Unwired JSF Components
by Marcel Urbanek
20 Sep 2005 02:45 EDT

Learn how to develop JSF components that render for WAP and desktop browsers.


The proliferation in recent years of web-enabled devices has brought tremendous challenges to application developers, with the need to develop components that can work across various platforms. For example, extending an application built for a standard web browser to work on a WAP device may require components of your web application to be rendered in more than one way.

It is tempting to think that if you use JSF it will be a simple matter to extend an application built for a standard web browser to work on a WAP 2.0 device, requiring adjustment only for screen size. However, some components (such as a table) are not viewable on mobiles, while other components don’t work because of the bugs in WAP browsers (which are more common than is usually recognised).

Thankfully there is a solution. We can use JSF to extend WAP with self-programmed components supported by render kits. This article will show you how to implement JSF components that use different renderers depending on the device used. This is achieved by separating the rendering from the rest of the component.

Renderers defined

A renderer is a type of interacting class that creates the client-side representation of a component, typically the generation of HTML. A renderer can also take input from the client and transform it into values the component can understand. In normal applications, components render themselves. This can create difficulties because if the component is to be used on different devices, it may need to be programmed differently for each one. Alternatively, if you implement encoding method that renders in any language, the source code becomes unreadable. So, the solution is to develop separate renderers for the component. Any JSF component can make use of renderers, with each different one rendering the component in a special language or style. In the case of WAP devices, we would probably use renderers to create HTML for desktop web browsers and HTML-MP for the WAP devices.

Let the Renderer do the heavy lifting

Developing a component that uses a renderer is different than developing a component that renders itself. Figure 1 shows a JSF component without an external renderer.

  Figure 1. UML diagram of a component that renders itself (this is called the <I> direct implementation </I> rendering model).
Figure 1. UML diagram of a component that renders itself (this is called the direct implementation rendering model).

This illustration shows that with a normal JSF component you have a tag that is accessible from the JSP. The component class which should be used for this tag is determined by the outcome from the getComponentType() method, and will be instantiated and given as a parameter to the setProperties() method of the tag class. The setProperties() method will then hand over all tag properties to the component class. JSF can then render the component by invoking the encodeBegin(), encodeEnd(), and decode() methods (there is also an encodeChildren() method).

Render kits extend this model, as shown in the following illustration.

  Figure 2. UML diagram of component development with a renderer (this is called the <I> delegated implementation </I> rendering model).
Figure 2. UML diagram of component development with a renderer (this is called the delegated implementation rendering model).

It can be seen that the model is extended by one or more rendering classes, and instead of calling the encoding method of the component, JSF invokes the encoding methods of the renderer. The outcome of the component’s getRenderer() method determines which renderer (defined in the XML file faces-config.xml) will be used.

Implementation

In this section we will illustrate how to implement a JSF component that uses a renderer. We will use the example of a menu bar. Web applications often have menu bars with different items at the top of the page. They consist of buttons, each with text or an icon, as shown in figure 3.

  Figure 3. Menu bar rendered for an HTML browser. This example has been generated with the button generator this discussed in this article.
Figure 3. Menu bar rendered for an HTML browser. This example has been generated with the button generator this discussed in this article.

Our goal is to implement a JSF component that dynamically renders such buttons not only for the standard web browsers but also for WAP applications. The latter would be similar to the one above, but a lot smaller with a font of 4*3 pixels.

  Figure 4. Menu bar rendered for WAP.
Figure 4. Menu bar rendered for WAP.

We will first examine how this component is usually implemented, then describe how the button generation works.

A number of attributes will be required, some of which are pretty obvious, such as:

  • text (which text should be rendered into the button)
  • action (which action to take when the button is clicked)

These two attributes would probably be enough to program a working button component, although we might also want to consider whether the menu items are activated or deactivated. This may be necessary if, for example, you are using form validators to test whether form data entered by the user is correct. If the user doesn’t enter any data and tries to submit the form, an error may be generated because there is no data to validate. In this situation, an attribute may be required to set the validators to skip, with some JavaScript attributes (e.g. “onclick”) to toggle the validators on and off.

  • active (specifies if the button should be rendered active or not)
  • description (renders a tooltip for the button)
  • immediate (specifies if form validators should be processed or not)
  • onClick (renders JavaScript "onclick")
  • onMouseOver (renders JavaScript "onMouseOver")

The next step is to generate a tag class. A tag class extends javax.faces.webapp.UIComponentTag, and has set/get methods to set the parameters necessary to render the component. Further, we will need to implement a setProperties() method, which passes the attributes to the component. The following excerpt from the class ButtonTag illustrates this point:

[...]

public void setProperties(UIComponent component)
{
        ButtonComponent buttonComponent=(ButtonComponent)component;
        //If the attribute isn't set we simply replace it with an empty
        //string.
        if (description==null)
        {
                description="";
        }
        //If the attribute value is a valuebinding, a valuebinding will 
        //be instantiated and stored.
        if (isValueReference(description))
        {
                ValueBinding vb = getFacesContext()
                .getApplication().
                createValueBinding(description);
                buttonComponent.setValueBinding("description", vb);
        }
        //If the attribute value is a normal value (no valuebinding), 
        //it is simply set as-is.
        else
        {
                buttonComponent.getAttributes().put("description", 
                                                     description);
        }
[...]

public String getComponentType()
{
        return ButtonComponent.COMPONENT_TYPE;
}
[...]

As can be seen in the setProperties() method, the attribute values are handed over to the component. If the attribute value (in this case "description") is null, it is set to an empty string (""). If the attribute value is a value binding (that is, it starts with "#{", ends with "}") a new ValueBinding will be instantiated and stored in the component. If the attribute is not a valu ebinding, the component will store the attribute value as-is. (If you're wondering why this code doesn't set component properties, remember that setting a component's attribute automatically sets the corresponding property, if one exists. So, if there is a description property for this component, the setting the description attribute will automatically set the description property).


Download: source code (ZIP; 2MB)


RSS feed(all feeds)

The Editor's Desk
JSF 2 Group Blog
Inside Facelets
In the Trenches

Site version 1.83  Report web site problems

Copyright (C) 2003-2007 Virtua, Inc. All Rights Reserved. Java, JavaServer Faces, and all Java-based marks are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries. Virtua, Inc. is independent of Sun Microsystems, Inc. All other trademarks are the sole property of their respective owners.