Tuesday, February 14, 2006

JSF and JSP: A Mismatched Combination

Our company has recently been evaluating a whole series of technologies to use on Java-based web applications. So far we've liked what Hibernate and Spring bring to the table so we'll be using those on our next project. Now we've turned our minds to evaluating the front-end frameworks that will help build the UI, and our first stop was Java Server Faces (JSF), since it's now the "official" framework, courtesy of Sun.

While reading the JSF spec, I grew increasingly uncomfortable with what I was reading. It seemed to me that JSF was trying too hard to turn the web into a traditional client/server application. It gave me that save bad feeling that I got when I first read the EJB spec back in 1998. There was something fundamentally wrong with the idea, and I struggled to figure out what it was. After thinking about it for a while, I realized that the real problem was with attempting to use JSP as the view technology within JSF, not any fundamental flaw in JSF itself. I'm certainly not the first person to suggest that JSPs shouldn't be used with JSF, but it still seems like everyone who has used JSF on a real-world project has used JSP as the view. Here's one more potential reason not to use JSPs.

The Component Tree And The View in JSF
First, let's take a closer look at the inner workings of JSF. Central to the operation of JSF is the component tree, a collection of objects that represent the UI components that are on a page. This component tree is used not only to render the display to the requester, but also to hold the form values that the requester submits to the application. Also, type transformations and input validations are performed on the values in the component tree prior to updating the model, so the component tree is really the core of the JSF framework. The JSF lifecycle basically defines how the component tree is created and used.

The definition and construction of the component tree is delegated to the view itself. The view is responsible for indicating what components are within itself, instantiating those components, and then putting those components into a component tree for the rest of the JSF framework to use. This mimics the way that traditional client/server applications are built: typically, a Canvas or Panel UI component will directly instantiate any other UI components that are attached to it, which is then manipulated by the rest of the application.

JSF’s lifecycle dictates that the view will be called upon to build the component tree at the beginning of the lifecycle (during the “Restore View” phase), and then will be called upon to render the output back to the client at the end of the lifecycle (during the “Render Response” phase). This happens via a “ViewHandler” class that acts as the interface to the specific view technology. Again, this mimics the operation of traditional client/server applications: a Canvas/Panel/Window is instantiated, which causes all of its components to be built and initialized, and then that Canvas/Panel/Window is told to “paint” itself, which causes the components to be rendered and displayed.

The Role of JSPs in the JSF framework
Sun’s specification for Java Server Faces states that the framework is intended to be open with respect to the view technology that is used to build and display the component tree; The last chapter of Bergsten’s Java Server Faces book[1] describes several view options for use in JSF. However, the vast majority of his book, as well as the specification itself, describes how to use JSP as the view technology. The only view technology that vendors are required to integrate into any JSF implementation, and the only view technology that is integrated into Sun’s own reference JSF implementation, is JSP. For all intents and purposes, JSP is the default view technology for JSF.

This implies that the default “ViewHandler” implementation of JSF will use the JSP engine in order to have the component tree created during the “Restore View” phase, and will also use the JSP engine in order to have the component tree rendered for display during the “Render Response” phase. The JSP engine, in turn, will read in a JSP file to determine what UI components are on that page, and how to display those components to the user. The JSF spec provides custom JSP tags to facilitate this: the tags are internally mapped to a specific type of JSF UI component, and when the JSP engine executes a tag that is embedded in the JSP file, the tag manipulates its corresponding UI component within the component tree.

Practical Problems with JSPs as the View
The JSF 1.1 spec, when used in conjunction with JSP 2.0, has several well-documented problems related to how the JSP engine interacts with the JSF framework. One problem is that HTML text can get outputted out of sequence. For example, if HTML is interleaved with JSF tags, the JSP engine will have to render one component before the other, since JSF components ignore the interleaved text. Another problem is that certain components that don’t exist when a page is first loaded can magically appear if a page is refreshed, again due to the interaction between how the JSP engine parses JSP pages and the JSF tags on that page.

As of the time of this writing, Sun has completed revision 1.2 of the JSF spec, and also updated the JSP spec to revision 2.1, in an attempt to fix these types of issues. Their official release is being delayed due to the fact that these specs are tied to the overall update of J2EE, from version 1.4, to version 5. Once these changes are released, vendors will need to update their implementations and tools accordingly, and only then will these problems (hopefully) be solved.

The Fundamental Problem
While these practical problems are said to be fixed in the new versions of the JSF and JSP specs (1.2 and 2.1, respectively), the fact that changes to the JSP specification were required at all in order to interoperate properly with JSF brings up a more fundamental problem: JSP technology was never designed to fit into the JSF framework and specifically does not fit into the JSF lifecycle properly.

As previous stated, the JSF framework is based on the traditional client/server UI framework. In that framework, the view has separate instantiation and rendering phases in its lifecycle: The constructor of a Panel/Canvas/Window is responsible for instantiating the component and all subcomponents that it has, and the “paint” method (or equivalent method) is responsible for causing the component to render itself to the display. Correspondingly, in the JSF lifecycle there are separate instantiation and rendering steps (the “Restore View” and “Render Response” phases, respectively). In terms of the actual API, these two separate phases are embodied in the “ViewHandler” abstract class, which has separate “createView” versus “renderView” methods that map to each phase. The component tree is built by the “createView” method and returned to the JSF framework during the “Restore View” phase; that component tree is then passed in by the framework to the “renderView” method for use during the “Render Response” phase. It is this component tree that glues the two phases together by virtue of it being the output of one phase and the input to the other phase.

However, JSP technology was meant to output HTML to a browser, not to worry about building up or rendering component trees as part of some UI framework. When used as part of JSF, the JSP engine doesn’t even realize that it is building a component tree when it processes a JSP page, it is simply telling each custom tag it encounters to render itself. All it expects is for each custom tag to render HTML output. But when JSF custom tags are embedded into a JSP page, they will actually build up the component tree based on the parameters that are sent into them when they are executed by the JSP engine. The JSP engine is unaware of these activities, as far as it is concerned it is just calling a series of tags; the component tree is built as a byproduct of what the JSP engine does, not as its core functionality.

As a matter of fact, a typical JSP view handler implementation doesn’t even do anything during the “Restore View” phase of JSF. The implementation of the “createView” method in version 1.1.1 of MyFaces by Apache doesn't call the JSP engine at all and instead simply creates an empty component tree during the “Restore View” phase. Not until the implementation of the “renderView” method, during the “Render Response” phase of the lifecycle, is the JSP engine called to parse the JSP page, and the component tree actually built. The reason for this is that the JSP engine cannot separate the initialization of a component from the rendering of that component. The JSP “lifecycle” consists of only one externally accessible phase, which is the rendering of all the contents of a JSP file to the browser. Because of this, the first time a JSP page is parsed the component tree is empty, as none of the tags have been processed yet. As the JSP engine renders the JSP page by executing the tags embedded in the page, the component tree is built on the fly by each JSF custom tag. Thus, the UI components are initialized and rendered all in one step, during the “Render Response” phase of JSF. The “renderView” method is effectively performing both the “Restore View” and “Render Response” phases in one step. But the JSF lifecycle clearly expects these to be two separate steps, not one single step.

So JSP technology essentially violates the fundamental design of the JSF framework. Two of JSF’s phases have been compressed into one. It’s by clever engineering that the technology has been made to work with JSF. However, it’s clearly not an ideal fit, as JSP technology was never meant to perform the tasks that JSF requires of it as a view technology.

Possible Alternatives
It seems pretty clear to me that JSP technology, as it is currently defined, is not well-suited to work as the view technology for JSF. A view technology that features explicit instantiation versus rendering of its UI components is necessary in order for proper integration with JSF. I believe that eventually Sun will add such a view technology to the JSF specification in order to address this issue.

A simple approach might be for Sun to change the JSP engine so that it has an explicit “instantiate components” versus “render components” phase, and then use separate files for each phase. One file would define the components that should be on the page, and the other would specify the layout of those components. This would fix almost all of the core issues with using JSP technology as the view for JSF. However, it would be difficult to maintain backwards compatibility with existing JSP pages, and Sun has not indicated any desire to do this.

Outside of Sun, several attempts at building such an alternative view technology are already underway. Most are based on mimicking the functionality of Tapestry, which breaks apart the view into two separate files, one that defines the components on a page, and another that servers as the HTML template to enable those components to be laid out. One such alternative view is Facelets, which is being developed by one of the members of the Sun JSF implementation team. As such it has a good chance of eventually becoming a part of the spec. It breaks out the view into two separate files, a UI composition file where the components that make up the component tree are defined and initialized, and an HTML template file where the actual components are laid out for rendering. Another credible alternative is found in Apache’s Struts Shale project, which contains a technology called Clay that is meant to provide Tapestry-like HTML template capabilities as the view for their JSF implementation. Unfortunately it appears that the creator of Tapestry himself is not open to making Tapestry work with JSF.

Others have attempted to build a series of Swing-like objects for use as the view technology, effectively turning web application development into traditional client/server UI development. However there does not appear to be broad support for this approach, mostly due to the difficulty in having Java classes output HTML.

A final approach might be to utilize XML/XSLT to serve as the view technology. During the “Restore View” phase, an XML file could be read in that would then be converted into a component tree. Then during the “Render Response” phase the component tree could be converted back to XML and an XSL transformation performed on it to create the HTML output. This might be the simplest view technology to implement, but again, there have not been any suggestions to build such a view technology.

So the good news is that there are several attempts underway to replace JSP as the view technology for JSF. If JSF is the approach that you want to take for building web-based applications, I would encourage you to take a look at some of these alternatives rather than just automatically choosing to go with JSP.



 
[1] Java Server Faces, Bergsten, H., O’Reilly 2004

0 Comments:

Post a Comment

Links to this post:

Create a Link

<< Home