Explore the process of creating new JSF components, including common "gotchas" and guidelines for defining good componentsby Jonas Jacobi
May 25, 2005
The JavaServer Faces (JSF) specification provides a set of components with which application developers can build Java server applications. However, it is extremely likely that developers will want to extend JSF by creating custom components. Here we'll explore the process of creating new JSF components, highlighting common "gotchas" and providing guidelines for defining good components. We'll also look at the need for providing design-time metadata, so that component developers can ensure an excellent design-time experience for their custom components.
Before we start looking at components, it is worthwhile to elaborate on "why another framework?" When it comes to the architecture of JSF, it is not a new thing. For example, Apache's Tapestry and Oracle's ADF UIX framework have been around for quite some time and have proven to be very successful. JSF brings what other similar view technologies do not have: backing of a standard specification (JSR 127).
If we look at where we are today, most Web applications are stuck in the 1990s, when much too much effort was put into basic plumbing and not enough into high-level components. Basically, there is limited abstraction or no abstraction over the markup making development of Web applications cumbersome and the applications themselves hard to maintain. A lot of work is forced into the application to make it rich and interactive, with various technologies from applets, plug-ins (Flex), DHTML, and JavaScript. Together, these technologies can make up a very interactive and powerful Web application, but how do you maintain such an application? How do you reuse what you have built? Do you need multiple tools to achieve your goal of an interactive Web application?
These questions lead back to JSF and what it brings to the table—a best-of-breed J2EE framework—and the fact that every major J2EE tool vendor such as Oracle, IBM, Sun, and Borland is behind JSF.
Potential Beneficiaries
So, who in the IT community would gain from using, developing, and deploying JSF applications instead of using proven but nonstandard technologies such as Tapestry, Cocoon, and Struts? Let's have a look.
End users. End users will probably not notice much of what is happening behind the scene, but they will notice that Web applications are richer in functionality as we move ahead with JSF.
Business developers. JSF gives business developers the means to build powerful enterprise Web applications by using an open standard (Java) with the ease and productivity that Visual Basic has been providing to its developers. The fact that more components will be available on the market, free or for a fee, means that business developers will have access to richer components—including dynamic menus, scroll bars, tables, and so on—that have so far been available only to those with expertise in DHTML, JavaScript, and the like. These components will not only provide business developers with richer functionality but will also improve their productivity in building Web applications.
Component developers. Components, components, components: these are the golden nuggets that will make or break the success of JSF. Some vendors are already producing components for external use and for open source communities such as MyFaces (see Resources). But, for JSF adoption to increase we need more components—lots of them—and with richer functionality.
The dearth of existing components and the need for richer component sets mean that getting into the business of providing JSF components is a good opportunity. JSF also allows component authors to sell components based on a recognized J2EE-standard framework (instead of trying to convince customers to use a homegrown framework). Besides the business aspect of creating JSF components, there are also benefits to creating components by using JSF. JSF provides built-in support for aspects that are hard and cumbersome to implement, such as event handling, state saving, expression language, and a standard way to make custom components extensible.
Tool developers. Tool developers need a formal standard that not only makes life easier for end users but also allows the developers to design and develop tools that will ease development of Web applications, or as they are called in this early part of the twenty-first century, J2EE applications.
As you are probably aware, JSF uses different classes for providing component functionality and for rendering the component. Before getting your hands dirty building your first set of components, search the Web for existing components.
There should be a fair amount of components already out there, and in most cases, you can probably get away with writing a new renderer for an existing component. If the component you are looking for cannot be found, it is time to build your own. To build a new component, you should make sure it has distinct server-side behavior and introduces a new behavior, functionality, or definition. If the component exists and you need a new appearance, you just need to create a new renderer (see Figure 1).
Good and Bad of It
An example of good separation between behavior and appearance is the UISelectOne component provided by the JSF Reference Implementation. This component has a distinct behavior and three different renderer types: ListBox, Radio, and Menu. Potentially, you can add other types of renderers that have different appearances but the same behavior.
What distinguishes a good component from a bad component? A good component should have generic properties, event listeners, and specific behavior. The component should not contain markup-specific attributes, such as the "href" attribute; should not write markup or get request parameters; and should work with server events, not client events. It is important to isolate the presentation information from the underlying server-side component (see Table 1).
In addition to the Table 1 information, using JSF facets enhances business developers' user experience developing applications with JSF components. A facet is a kind of child component that has a specific purpose defined by its name. A facet can be viewed as an empty placeholder that can take one child component. A parent component can have multiple facets; an example is a component called panelPage provided by Oracle's ADF Faces component set. This component uses facets to render its children in predefined locations such as the corporate logo (CORPORATE_BRANDING facet) or the copyright statement (COPYRIGHT facet).
Renderers have their own classes and are therefore also subject to good and bad implementations. Writing a good renderer means basically reversing the list of dos for writing a good component. What is really important is that you do not give model access to the renderer. You should also try to use the ResponseWriter as often as possible, which will give tools a better chance of visualizing your component in a WYSIWYG editor. Here is an example of using the ResponseWriter:
public void encodeBegin(
FacesContext context,
UIComponent component) throws
IOException
{
ResponseWriter out =
context.getResponseWriter();
//Pass the component so that
//the ResponseWriter can use
//it.
out.startElement(
"span", component);
//Pass the "styleClass"
//attribute so that it can be
//matched.
Object style =
component.getAttributes().
get("styleClass");
out.writeAttribute("class",
style, "styleClass");
}
You also need to make sure you register your renderer with a render kit. The most widely used rendering language is HTML, but this characteristic doesn't mean that you must use the HTML render kit; you can use any rendering language of your choice, such as SVG or XML.
There are some areas that need improvement and a few areas or gotchas that are not yet covered or will not be covered by the JSF specification. One example is the lack of a strategy for a consistent look and feel. There is currently nothing in the specification that outlines or defines a standard for implementing "themes" or "skinning." An area of improvement would be to make it easier to write a renderer. Today you need to write Java code to create a renderer, but it should be possible to come up with a more declarative solution for writing renderers similar to what is available in ADF UIX.
There is also no support for registering a renderer with multiple render kits and no tool support for testing components across multiple implementations such as MyFaces or Sun's JSF Reference Implementation.
The Good, the Bad, and the Ugly
As a component developer or vendor, you are not locked into any IDE; in fact, if you prefer to use a text editor such as Emacs or VI, you can do so. JSF simplifies J2EE development because it will be easier for tool vendors to create a design-time experience for business developers similar to Visual Basic, using custom-designed and reusable components. Component developers may have the following questions: How do I get tools to support my custom components? Do I have to add anything beyond the required renderer so that my components can utilize all design-time features or display nicely in the tool's visual editor?
The good. As you probably already know, there are plenty of tools available today with various levels of JSF support, and all major tool players—Oracle, IBM, Sun Microsystems, and Exadel—are working feverishly to improve the support for JSF. The JSF expert group clearly thought about tool support when they designed the faces-config.xml file. This XML file is an invaluable source of information that contains, for example, available components and their properties and facets. Not only is the XML file format easily digestible by tools, but also tools can automatically detect the location of a faces-config.xml for a set of components. Tools can, based on information provided in the faces-config.xml file, expose the set of available components at design time.
The bad. The bad thing is that faces-config.xml and TLDs are not very expressive and cannot convey interesting constraints such as valid values, or component enumerations. An example is the Oracle ADF Faces component . This component has an attribute called messageType. The valid values for this attribute are "error", "warning", "info", and "none". Unfortunately, there is no way in faces-config.xml to express that constraint. The faces-config.xml file also cannot indicate relationships between components, such as what would be a valid child for a particular component—for example, a Table component might only accept a Column component as a valid child. These shortcomings can be dealt with by providing these constraints and relationships in design-time metadata.
The ugly. What could turn ugly is if tool vendors define their own proprietary ways of providing design-time metadata. Tool vendors are already asking for additional metadata from component authors so that components can fully utilize the design time, which will lead to component authors providing proprietary solutions for each tool vendor.
The hope. The hope is that the JSF community can agree on standard design-time metadata and that component authors will invest in providing metadata for their components. The most likely way of defining such a standard is through the Java Community Process (JCP). Oracle is working with other JCP members with the goal of proposing a new JSR that would define a standard set of design-time metadata items for JSF components and a mechanism for providing such metadata.
Although the faces-config.xml language allows a component author to express a great deal of information about their components and renderers, it only has standard syntax for expressing a very minimal set of design-time metadata (mainly display-name, description, and icon). Fortunately, the faces-config.xml language is designed with convenient extension points that can be used to hold additional information.
Strong Community
As previously discussed, there is not yet a standard mechanism for supplying additional design-time metadata. However, one proposed solution would utilize the extension points in faces-config.xml (see Listing 1). If you are interested in this issue, there is a thread on the Sun's JavaServer Faces Technology forum devoted to discussing design-time metadata for JSF components.
A crucial ingredient for the continuation of JSF's success and progress is a strong community. If you look at what ASP.Net has done and evaluate what makes this proprietary framework so successful, there is one thing that always pops up: the ASP community. Its community sites have forums with hundreds of daily posts as well as tutorials and content that are updated daily. There are component galleries with free hosting of custom components, which are integrated with the development tools. There are also free versions of basic tools supporting ASP development.
Some of this type of groundwork has already started with projects such as MyFaces and information sites such as JSFCentral, but this is not enough. We cannot hope that a small group or a single person can provide us with a complete set of community sites including daily posts, tutorials, and contents. Now is the time to get involved in Faces!
The JSF community needs one or more neutral hosting sites that provide content such as tutorials, forums, and announcements—and, of course, component galleries. Another area in which the community can provide help in is testing tools. In the spirit of Cactus and JUnit, the community could provide testing tools with a different approach, such as test components and not markup, and send simulated events. For anyone eager to get involved, this possibility would make a good open source project.
Skinning and themes are areas that noncoders could ideally participate in. Noncoders could provide style abstractions to mirror component abstractions using styles, icons, text/translations, and templating.
There is a future beyond HTML; eventually, component authors will provide higher-level components with better customization. These components will be based on other client-side technologies, such as DHTML, SVG, Flex, XUL, and Web Forms (see Figure 2).
The message here is, think components, not markup! JSF is not exclusively for HTML, it is not exclusive to hard-core developers, and it is not exclusive to business developers. There are plenty of opportunities for all types of developers. Finally, don't forget the metadata, and make sure you get involved early in the JSF community.
About the Author
Jonas Jacobi is a senior product manager for JDeveloper at Oracle.