While JSF provides a powerful foundation for building user-interface components, it is a new standard, only just now being fully defined. Many other articles discuss what JSF is, and how it works, and the upcoming book “JSF in Action”, by author Kito Mann (Manning publications), gives a comprehensive description of how to put it to use effectively. Most web applications already in use today make use of a UI framework of some sort already, and many of these frameworks are highly capable in their own right. These frameworks are not going to go away, nor are developers going to readily discard all their learning and experience with them. Indeed, why should they? Just because a new standard has arrived is no reason to abandon not only the tried and true, but also the unique advantages of existing UI frameworks. The good news is that JSF is perfectly capable of working in conjunction with these frameworks, and has in fact been designed with easy integration in mind. In that light, lets have a look at how JSF can be used in conjunction with existing frameworks, as an enhancement, not a potential replacement.
While JSF supplies functionality at several levels of UI design, many of its components are designed to be “pluggable”, using the Factory pattern to provide the specific implementation at runtime. (Even the factories themselves are “pluggable”, in fact). This allows elements such as the FacesContext, the StateManager, the ExternalContext, and, perhaps most importantly for our discussion here, the LifeCycle handler and the RenderKits to be dynamically specified. This means that for each major piece of JSF, a special implementation of these elements can be provided that is “aware” of an external framework, and makes the connection point between this framework and JSF.
In addition to pluggable factories, JSF also provides the means to handle both “JSF requests” and “Non-JSF requests”, meaning a page prepared by another framework can trigger a page that will be handled entirely by JSF, in addition to the usual case where a page rendered by JSF itself triggers the next request.
Let’s examine how this might be accomplished using a few of the more popular UI frameworks as an example – please understand it is not my intention to lay out a development roadmap for integration with these frameworks here, just to examine the possibilities for such synergy, and to open the door to further exploration.
With somewhat of a leaning towards the use of JSP in any case, it is easy to see how JSF would make a good fit with Struts. Indeed, there is an effort already well underway to create such a connection. Both Struts and JSF already integrate well with the JSTL (Java Standard Tag Library), and Struts provides some unique functionality in that it delves a bit further into providing services for application logic than JSF does. Struts provides, for example, a database connection pool mechanism, which is a Model-oriented concern that JSF does not provide. Struts also includes the portlet-like Tiles tag library, which currently has no equivalent in JSF. Where the two frameworks do overlap entirely, it provides an opportunity for developers to transition gradually, where this is desirable, to JSF components. Where existing applications are being extended, this allows new pages to take advantage of JSF components, while existing Struts pages co-exist properly with them in the same application. A library and information about this integration is already available at the Apache Foundation’s website.
A powerful Avalon-based framework, with capabilities for much more than user-interface construction, Cocoon does however bring substantial power to the UI developer. Cocoon provides more than the normal request/response cycle processing, it brings the concept of “pipelines” to the web application. A typical pipeline begins with a matcher, which maps requests to the proper pipeline, then continues with actions, generators, transformers, and finally a serializer, which produces the finished markup for the browser (or other output device). Typically, the data flowing through this pipeline is XML, often taking advantage of XSL to produce the finished markup. JSF fits neatly into this structure in that it is straightforward to provide a RenderKit that will produce XML. The Action class in a pipeline is normally where application logic is executed. By providing a custom implementation of the JSF LifeCycle object (allowing us to “intercept” the JSF process flow at the proper pla!
ces), we can use the Action mechanism to provide the “connection point” for JSF and Cocoon, taking the output of the Action and producing a JSF view “tree”. JSF’s components are already organized into hierarchies, making it easy to map them to XML via the RenderKit, which then “inserts” this XML into the Cocoon pipeline. Cocoon’s processing then continues as normal, doing whatever it would normally do with the XML. Often this involves processing via one or more XSL stylesheets to produce markup. We can produce “standard” stylesheets that provide the mapping of the XML version of a rendered JSF component into, say, HTML (or PDF, WML, etc). As Cocoon already supports serializers for many different display formats, such as PDF, SVG, and so forth, these alternative markups are easily supported.
This is just one example of a connection between Cocoon and JSF – there are several other possibilities.
The Velocity framework provides a capable and flexible template language ideal for creating UIs (and very valuable for many other templating tasks, incidentally). It purposely avoids being a general-purpose programming language, neatly avoiding the temptation to embed business logic in the UI, which can happen with JSP, for example. Velocity’s template language does, however, have plenty of capability to render components managed by JSF. The renderkit in this case produces a nested structure of JavaBeans from the UIComponents as it traverses the JSF tree. Velocity’s template language allows easy access to both bean properties and methods directly from the template. By preparing a template “macro”, Velocity’s VTL (Velocity template language) can be extended, and a macro can be used to refer to each JSF component to be placed on the finished page. These macros then perform the same function as the JSF custom tag library does in the JSP implementation of JSF: they provide the translation from the non-visual JSF component to the finished markup.
The Tapestry framework (another Apache project) takes a different approach to its UI functionality, as well as providing much more than just a rendering technology. Conceptually, some parts of Tapestry are comparable to JSF, in that Tapestry uses a reusable component mechanism for building the user interface, and incorporates an event model for handling interaction between the UI and the underlying application model. Tapestry, however, uses the target markup (for instance HTML) as the “template language”, as opposed to imposing a new template language, making it far easier for web page designers to work directly with HTML, and have that same HTML, without changes, act as the template for a dynamic web application. Special anchor markers are used to simply denote where the Tapestry components are to be placed in the HTML page, and at runtime the framework handles the merging of the two, producing the finished markup. Each Tapestry page can have a corresponding component de!
finition, specifying for each of the referenced components what type they are, and how they interact with the page.
Tapestry already provides much of the functionality of JSF, but the standard UI components of JSF could still be used as an adjunct to Tapestry, by defining Tapestry component “wrappers” for the standard JSF UIComponent library. In this case, much of the “connection” would be made in Java code, as opposed to template markup, although a corresponding HTML (or other markup) snippet would be created for each component linked in this way. How much of the lifecycle management and model interaction functionality of JSF is suitable for combination with Tapestry is a different and more complex topic: Tapestry already provides many of these capabilities, and in some cases developers may decide they prefer the flow of processing provided by Tapestry over the request lifecycle supplied by JSF. Of course, the reverse is also true, and it is conceivable that a JSF component could be created that “encapsulates” any specified Tapestry component, thus allowing existing Tapestry component to be accessed from an application that is otherwise entirely JSF.
Of course, Tapestry also has one significant advantage of JSF as it stands today: the Spindle project, designed as an Eclipse plugin for Tapestry developers is something that JSF needs, and no doubt will get, but doesn’t have today.
We’ve only examined a few of the many powerful UI frameworks available in open source today, and have just scratched the surface of how these frameworks might be tied in to JSF (or vice versa). Hopefully though, this exploration of the possibilities is enough that you can see that JSF is not necessarily an “either/or” choice with existing UI tools and frameworks, but that to a large degree synergistic co-existence is possible. This has the potential to allow developers to take advantage of what’s good in JSF, and to come together on a single component standard over time, while at the same time not disrupting current development, nor losing the unique advantages of other UI frameworks.
So, if JSF can be used as a compliment to existing UI frameworks, how can tool-builders accommodate this? It will no doubt be easier for creators of development tools to write their visual design tools to support only JSP, indeed, JSP is an essential choice to support. However, it is not the only choice, and tool-makers who provide only JSP support are doing developers a disservice. By making it harder to use other UI frameworks at the rendering level, they are effectively putting those frameworks at a disadvantage as well, and failing to live up to the promise of flexibility offered by JSF itself. If instead tool vendors allow a choice of outputs from their JSF design tools, permitting the user to select the rendering technology used, there is no loss of flexibility. A page designer can ‘paint’ a UI page, choosing from a pallet of JSF components. The developer can then take this design and generate the UI template for their framework of choice – a Velocity template, a Struts JSP page, a Cocoon XSL stylesheet, and so forth. No, this will not be as easy for the tool vendor, but development tools are not judged by how easy they are to create, they are judged by how easy they are to create with them. As developers, we have a responsibility to throw our support behind those tools that give us choices, encouraging other tool-makers to do the same. In the development technology battle between J2EE and .NET, we must not fall prey to solving problems the easy way – by taking choices away, as Microsoft has done. We should instead rely on the superior flexibility of the Java platform to continue to give developers even greater choices, just as Java itself preserves our choice of platform.
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 [email protected]