The Many Faces of JavaServer Faces (JSF)

by Michael Nash

Determine if JavaServer Faces will help you build effective user interfaces.

No doubt the name at least is familiar: JavaServer Faces has been talked about a lot, and much anticipated, with good reason. For years there have been an ever-expanding choice of ways to take your web application's output and get it on a page (or on some other kind of display). The Servlet API did a lot to enable the first Java web applications - having created web applications for Java before Servlets, I can attest to how much it helped! The first web applications with Servlets cranked out HTML directly - pretty much everyone now agrees this was a bad plan, and hard to maintain to boot. Next came toolkits such as Apache's Element Construction Set that generated the HTML for you. A step in the right direction, but not far enough for most. Then came JSP: A hybrid, in some ways, between an HTML page and a Servlet. JSP was a significant step forward from Servlet-generated HTML - If you use it right (and that's a critical if), you can enforce a pretty clean separation of view and application logic. Better still, JSP's, particularly once tag libraries came along, were simple enough that non-programmers could help with the page layout process, particularly for HTML formatting.

Other UI technologies went in different directions, though: Apache's Velocity, similar and to some degree a successor to the popular WebMacro project, applied a simple but extensible template language to generating the UI portion of an application, reading JavaBean properties from the Servlet context (where the application logic put it). Tea, Maverick, WebWork2, Scope, Echo, FreeMarker, Barracuda, Cocoon - all took different, and in some cases radically different, approaches to getting the data from the application logic to the page.

Sometimes, as in the case of Barracuda, Cocoon, and several others, XML was involved, and potentially XSL transformations. Many of these frameworks also delved into the application logic side of the equation, proving much more than a UI system. Struts is perhaps the most widely known example, taking the JSP approach to a new level with a powerful custom tag library, and popularizing the concept and advantages of Model/View/Controller that Smalltalk old-timers were so familiar with. Over time, many common elements began to emerge between such frameworks, and it became clearer what the best practices were for UI technology in a web environment, what worked and what didn't. Developers realized that web applications that used HTML/HTTP as the basis of their UI were quite different animals from desktop or "thick" client applications using Swing or other such toolkits. The user, however, still wanted a rich and responsive UI experience. There was still a wide gap in the way the various frameworks produced the display from the data produced from the application logic, and techniques and UI elements created for one technology were not portable to the next. You couldn't take a custom JSP tag from Struts and use it in an application build with Scope, for example. You couldn't take UI components for Echo and easily apply them to an application built with Cocoon. This meant that anyone attempting to build tools to make it easier for page/UI designers to do their job had to back one horse, or write many different tools, neither of which was a very attractive option. As a result, Java and J2EE lacked the rich graphical tools to help build applications by comparison to an up-and-coming rival, .NET. While the hard-boiled "vi" crowd didn't see this as a problem, it did limit the adoption of Java and of many of these different frameworks in many organizations, where experienced developer resources were not available for creating Luis. Either the UI got short shrift - the results of which we can see on the web today in the many horrifying anti-examples of usability out there - or the development project went wildly over budget re-inventing the wheel, because there was no standard wheel to do UI development. The other choice was to commit to a single UI framework approach, and abandon any possibility of portability later on.

JSF should change all that - one of it's goals is to bring a single common standard that tool-creators can use to build their tools against, while still allowing many different options for rendering the finished UI. One JSF-based design tool should be able to be used on many different JSF implementations, and components should be portable from one implementation to the next, so that neat UI gizmo you built for one application really can be re-used on another.

Sounds great - but where's the beef? How is JSF going to accomplish these admittedly lofty goals? Let's look at JSF from several different perspectives, and talk about about where the rubber meets the road - how you'll be able to apply JSF from a practical perspective on your development projects, no matter what UI technology you're currently backing.

It's important to realize that JSF is not tied inextricably to JSP, even though the reference implementation demonstrates JSF with JSP. JSF defines non-visual UI components, which sounds like a contradiction in terms - the idea, however, is to separate the definition of a UI component from it's presentation. Much like dividing up UI and application logic, but at a finer level. Now we're talking about dividing up the UI into a non-visual representation and a rendering - a translation of that non-visual representation into an actual display. That rendering can be done in any number of ways, as we will see.

The set of UI components supplied with JSF is extensible - indeed, the extensions will no doubt outstrip the supplied components in short order, by extending and combining them into more sophisticated UI elements. Tool developers can now create UI-paint applications that manipulate JSF components, as opposed to framework-specific elements (such as tags or XSL elements), allowing the page designer to say "place one of this type of component here, bind it to the following property in the application". JSF components are associated with a value from the underlying application logic, and may also be associated with one or more "events" that are triggered when the component is manipulated by the user. These events (the equivalent of a "submit" operation in Servlet terms) trigger a chain of processing called the JSF life cycle. In brief, this life cycle applies the request parameters to the "tree" of non-visual components (creating one, if necessary), performs necessary validations and type conversions, then passes the values to the application logic and triggers the method associated with the event. This life cycle can be abbreviated by, for example, validation errors, causing the page to be re-displayed with all of the values intact (in addition, likely, to an error message telling the user why the validation failed). This avoids calling the application logic entirely, at least for simple validations. Assuming the validations and conversions were successful, the application did get called, the "tree" of components associated with this request is cached for later use, and the application goes on to the next logical step. Some events will return to the same logical page, so the ability to cache the page of components and their associated values allows the page to be modified and then re-displayed: for example, filling in a customer code might result in the customer name being displayed alongside it, while the remainder of the page remains the same. This kind of "state saving" helps build web-based applications that provide a more "traditional" UI experience for the user, while not imposing an additional burden on the application logic.

JSF, therefore, has very little impact on the application logic of your existing programs, assuming they were written in a fashion that employs model/view/controller separation. This allows JSF to be phased-in, as opposed to making it a "rip and replace" technology.

While some work is required to integrate the JSF life cycle into existing frameworks, it's API is factory and interface based, allowing just such integration. An effort is already underway to allow Struts to take advantage of JSF, as they have quite similar approaches in many ways even now. JSF's reference implementation includes a powerful tag library, where JSP pages can easily be created to pick elements from the UIView (the response "tree" of non-visual components) for display in specific locations on the finished page. Like any other JSP, the "decorative" portion of the page can be interlaced with these components as necessary to create an user-friendly layout.

What if you're not currently using Struts or even JSP, though, are you out in the cold as far as JSF is concerned? Not at all.

While it has been discussed a few times how it's quite possible to generate XML from JSP pages, then transform that XML via XSL, this many-layered approach has many hardened veterans in the web application business shaking their heads over the complexity. We'll try a more direct approach.

Let's look at an example of one of my favorite UI frameworks: Cocoon - (or the UI-handling portion of Cocoon, in any case, as Cocoon of course can do far more than render a UI). Cocoon does not expose a Servlet request and response directly to the application logic (or the controller Servlet) for manipulation. Instead, it uses the powerful approach of pipelines, where a pipeline begins (usually) with a generator, passes through one or more transformers, and then into a serializer. Another way to initiate a pipeline is through an action, which is the common way in Cocoon to invoke server-side application logic. This logic then deposits an XML fragment in the session context, which is in turn extracted by a special Generator, and on to the normal pipeline flow.

Let's see (at a high level) how JSF fits into this model: Pipelines deal (with few exceptions) with XML, so we need a way to Map the UIView produced by JSF into an XML document. This is the "RenderKit" portion of JSF - the layer where the non-visual component begins it's conversion into a concrete representation on the screen. Fortunately, the structured and hierarchical form of a UIView can easily be serialized into XML. With this approach, the UI does not "pick" elements from the UIView to be laid out on the page (or other display device), the entire UIView "tree" is available - so how do we format it into a user-friendly view? The most common mechanism for this in Cocoon is XSL transformation: our XML representation of the whole UIView can be passed through a stylesheet, taking advantage of the unique and powerful structure of XSL, to produce a proper rendering of the XML as needed for different displays. The most common output might be HTML, but nothing prevents us from applying a stylesheet to produce PDF, SVG, RTF, XSL or any other format we might care to imagine. Our stylesheets can even be hierarchical: we can have one "root" stylesheet that knows how to render all of the common elements, such as UISelectOne's, UIText, and so forth, then "import" that stylesheet and override selectively. On this page we want all UIText fields to have a green background? No problem, just override that one template. We can also drive *which* elements we render, doing the same kind of selective process as we might do in a JSP page, by overriding the top-level UIView template, then calling render templates one at a time for explicitly named elements. As you can see, JSF's power can easily be linked with a UI mechanism that is not JSP-oriented, while at the same time preserving the power of it's standardization.

While we've only examined one possible integration of JSF into an existing UI-rendering technology, there are of course many other possibilities. Each UI framework so far has had to come up with an answer to the issues addressed by JSF: how to map application logic to a non-visual representation, how to lay out components on a page, how to render a given component in the appropriate display language, and so forth. Ideally, each of the many different UI approaches can take advantage of the common backbone of JSF, allowing the goal of portability to be achieved not only between systems, but also between entire frameworks, while maintaining the unique advantages that set them apart from other UI technologies and approaches. This will require a willingness to set aside any "not invented here" syndrome in order to reap the advantages of standardization, thus enabling the entire Java industry to benefit, as well as the users of any one framework.

About the Author

Michael Nash is the president of JGlobal Limited, a software development, consulting, training and support company specializing in open source Java technologies. He is also a core developer of the Keel meta-framework, the author of two books and a number of articles and papers about next-generation web-application development with Java, and a member of the JSR-127 (JavaServer Faces) Expert Group. He can be reached at mnash@jglobal.com.
This article was originally published on Monday Jan 5th 2004
Mobile Site | Full Site