Tapestry Training -- From The Source

Let me help you get your team up to speed in Tapestry ... fast. Visit howardlewisship.com for details on training, mentoring and support!

Friday, June 11, 2004

More on Tapestry and JSF

A recent article at OnJava, Improving JSF by Dumping JSP has been the source of some interesting discussions. The author, Hans Bergsten, is on the JSF expert group and is quite aware of Tapestry ... he even modified the Hangman example from chapter two of Tapestry in Action for this article.

Limitations of JSF/JSP

Interestingly, the JSF component tree is built initially during the JSP render, the first time a page is accessed. That means components early in a page may not be able to reference or interact with components later in the page on that first render, which results in some oddities. He gives an example of a label component and an input field component, where the label does not appear the first time a page is rendered. Whoops! That a violation of the consistency principal to me.

Then it turns out the JSF mandates lots of limitation on how you write your JSP. For example, in most cases, you must use a <h:outputText> tag rather than literal text to output literal text ... otherwise the text tends to end up in the wrong place!

Almost two years ago, I was on a quest to mix and match Tapestry and JSP, such that a Tapestry page could use a JSP instead of an HTML template to render its response. I made a lot of progress but hit some complex cases where I could not merge the two models together, and I instead went outside the box to create Tapestry 3.0 (which has JSP-like features, such as implicit components).

Apparent the JSF team hit the same snags and, because they are blessed by the powers that be, simply said "Thou shalt not do the things that make JSF break. If you do, it is your fault, not ours.". Wish I had it so easy!

Now, as much as the JSF leaders might say that the limitations discussed in Hans' article are merely the result of using JSPs, and that JSF transcends JSPs ... well, any non-JSP implementation of JSF is going to be proprietary, and non-portable or lack the IDE tool support that justifies JSF in the first place. This should sound familiar, its the same set of promises that came out five years ago for EJBs (tools will fix everything!), and the same pattern of complexity, lock-in, and inefficiency that resulted.

Stepping closer to Tapestry

Hans' article continues with a discussion of how to use JSF with a custom ViewHandler that mimics Tapestry's HTML templates and page specifications. That's great I suppose ... but what I'd rather see is a comparison to chapter six which rebuilds the simple Hangman example using custom components. Creating new components in JSF is very involved ... lots of classes, lots of XML, lots of fiddly bits. Components in Tapestry are streamlined and easy ... and powerful, in that they can have their own HTML templates. So as complimentary as this article is to Tapestry, it is also an unfair comparison.

More observations

A JSF application can act as an inversion-of-control container, creating and configuring managed beans. This is a feature of Tapestry as well, primarily through the <bean> element of the page and component specifications. I think this is a better solution, to keep the beans associated with the page (or component) and for the names to be local to the page (or component). A lot of thought in Tapestry has gone into allowing different developers to work on different parts of an application without conflict. Anything global is a measured risk ... in Tapestry, the only true globals are the names of the pages.

It was interesting to the the <component> tags for selectForm and selections, where selections was nested inside selectForm (this also meant that in the template, the selections component was referenced as selectForm:selections. In Tapestry, the two components would be peers (both children of the containing page) and the relationship (that the form encloses the selections) would be determined at runtime, during the render. This is important, because in Tapestry a Form cannot know statically about all the form element components that will be rendered inside its body ... those components may be in the body of the Form (the most typical case), or inside components within the body of the Form ... or, with clever use of Block and RenderBlock, potentially on an entirely different page of the application! Tapestry doesn't care, which is why artifacts such as form control ids must be allocated dynamically.

Now I may be nitpicking here, and I'm not sure which of these is related to the JSF standard, and which to Hans' ViewHandler implementation. The HTML template includes the same kind of previewable HTML as Tapestry, but its not clear how or if it is discarded. Additionally, the javax.faces.Command/javax.faces.Link combination (used to render the link around each letter) has a rendered parameter similar to Tapestry's disabled parameter ... but neccessitates a duplication of the javax.faces.Graphic to cover the cases where the link is not rendered (because that particular letter has already been guessed).


I just don't see JSF aspiring to any of Tapestry's guiding principals: Simplicity, Consistency, Efficiency, or Feedback. It's very gratifying that the JSF experts are looking to Tapestry for inspiration ... this is quite similar to the situation with the EJB 3.0 specification and Spring.

There has been some discussion of what Tapestry can do that JSF can't. That's a silly question ... there's nothing Tapestry can do that JSF can't. There's nothing either framework can do that a servlet can't, or a Perl script for that matter. It's a question of how easy it is to get it working, and how well it works at runtime, and how maintainable it is in the long run.

Based on everything I've seen, JSF still faces an uphill battle in these areas. Yes, FUD. Yes, I'm biased. But last night at the NEJUG, I coded two simple applications while explaining Tapestry and fielding questions and where I messed up, Spindle or Tapestry itself helped me fix my problems. I doubt I could have accomplished the same things using the JSF RI (even if I had the necessary experience) in the time available. I suspect, over time, we'll be seeing some better shoot-outs between Tapestry, WebWork and JSF. Struts, at this time, is turning into an also-ran kept around for legacy purposes. In the meantime, I repeat the rallying cry: Results Not Standards.


Hans Bergsten said...

Howard, thanks for your feedback on my article. This is exactly the kind of public communication I hoped my article would inspire.

I very much appreciate Tapestry's guiding principals: Simplicity, Consistency, Efficiency, and Feedback. They are all important, and I want to ensure that future versions of the JSF specification follows them. In my article, I describe how using JSP as a combination of both view specification and template makes it impossible to do so, for instance the Consistency principle, as you point out.

What I also describe is that JSF is extremely pluggable; you can replace pretty much all parts of the JSF infrastructure with custom classes, such as the Tapestry-inspired ViewHandler in the article. This was very much a guiding principle in the JSF design, to allow existing, similar frameworks to over time add support for JSF components in the hope of creating a much larger pool of reusable, powerful web application UI components. Without a shared component model, the wheel has to be reinvented for each framework, and no one benfits from such fragmentation.

You're only partly right about that replacing infrastructure pieces like the ViewHandler creates portability problems. The JSF specification explicitly allows you to do so, so no matter how many pieces you've replaced, the JSF application is still portable between JSF implementations. If you use a custom ViewHandler, however, you can no longer use JSF RAD tools based on JSP pages and the default ViewHandler. But getting rid of the JSP-related problems was the whole point, so that's not necessarily bad.

I admit I don't know a whole lot about the Tapestry internals, but I very much like the overall model of clean separation of template and component declarations. Another great Tapestry feature is the ease with which you can combine components into a custom compound component, bound to its own template. The JSF ViewHandler described in the article doesn't have that feature, but as I also say, I make no claims whatsoever that the example matches Tapestry's feature set; it's only intended to show that there are more attractive ways to use JSF than with the default JSP layer. I'm fairly sure that the ViewHandler can be extended to support the equivalent of Tapestry compound component specifications. When I get a change, I'll probably take you up on the challenge to give the chapter six version of Hangman a try.

The most important goal I had writing this article, though, was to get some experiements started that can eventually be fed back into the next JSF specification version. I intend to learn a lot more about Tapestry, and I hope the Tapestry community will learn a lot more about JSF, and that together we can create something beautiful. There's already some support within the JSF EG for blessing alternatives to JSP in the next version, so by starting experiements in the open along these lines now, we can bring a great, thoroughly tested alternative to the table when it's time to write the spec language for the next version.

Patrick Ranger said...

I am currently shopping for the framework that will best suit my needs for the brand new web application I'm about to develop. Of course, none have everything, so it all comes down to your priorities and needs. As for mine, there are no matches for Tapestry and JSF. While separating component and presentation is inspiring, the tools available for JSF are outstanding.

To this extend, I don't see the point in comparing. It only depends on ones preferences: the greatest framework or the better tools?

I have been pleased to read such discussion. Hans' open mindness should be more widespread among developpers. How can you improve without admitting your weaknesses?

I am touched. I hope you guys will work together. I would like to see JSF based on Tapestry, so that the stupid tools/model dilemma no longer be. You're right, Howard: tools don't fix a model's weakness. But it does help productivity and ease of development. And you're right, Hans: there is no point in reinventing the wheel everytime a new framework is created. That's what OS is all about! So why not just admit Tapestry's model is better, stop trying to ducktape Tapestry-inspired add-ins into JSF and integrate Tapestry in the next JSF version?

Anyways, thanks for your devotion.