GWT, JSF, declarative markup, and lunch with Gavin
Just had an interesting lunch with Gavin King (original author of Hibernate and Seam), and came up with a somewhat crazy idea that needs more eyeballs on it.
EXECUTIVE SUMMARY
The GWT toolset lacks a way to do declarative markup. The only way to compose GWT components is through Java code. Joel Webber of the GWT team said at Google Developer Day 2007 that one of his personal ambitions for GWT is to build a declarative markup system.
The Seam toolchain lacks a way to build custom JSF widgets easily. Building a custom JSF widget with plain Javascript is extremely painful. The GWTJSF integration library goes partway towards addressing this, but doesn’t currently support building composable trees of GWT-based widgets.
What if we brought the two together? What if we could create a JSF-based and Facelets-based markup system that enabled composability of independently developed JSF widgets implemented in GWT? This could both leverage an existing declarative markup system (Facelets) for GWT’s purposes, and deliver a much better toolset for creating Seam applications with richer UI functionality.
That’s the basic idea. If you Get It, then please skip to the DETAILS section. Otherwise, read on.
BACKGROUND
The first chunk of lunch was walking through my Seam/GWT example, clarifying what it does and how it does it. Basically, as the page explains, it takes GWT modules and encapsulates them in JSF components. This allows GWT modules to exist within the context of a larger JSF / Seam application, leveraging other JSF page components and directly communicating with Seam components through GWT RPC.
The main use for this, it seemed to us, is taking existing GWT modules and wrapping them as JSF components, to enable their use in a larger JSF application. This was one of the original use cases that motivated the Exadel guys (Sergey Smirnov and Alex Smirnov) to create their GWTJSF integration library.
Where do we take it from here, though? Originally it seemed to us that if all you need is GWT, then this JSF integration isn’t of much use to you. Michael Neale has already landed — in the Seam 2.0 beta — a GWT integration that doesn’t require JSF at all, but just lets your GWT app communicate with Seam components. (He hasn’t, evidently, integrated my RPC refactoring in GWT 1.4, so it doesn’t yet support native GWT-style RPC, but that’ll be easy to do now that GWT 1.4rc1 is out.)
So, is the only use case for GWTJSF really for people who want to take existing GWT components and build them into JSF apps? Well, Gavin saw the code for the GWT module in my demo, and his feeling was, wow, this is a much better programming model than writing custom JSF components in Javascript. So what would it take to make GWTJSF better at creating reusable JSF components?
There are two main things that the current GWTJSF library lacks. One of them is support for Seam conversation propagation. This is important if you want to have GWT components that can participate in a Seam web application which uses both GWT-based AND non-GWT-based components. You want the GWT components to be able to carry the conversation state in RPCs, so they can participate in the Seam server-side conversation state management. (Yes, I know it is totally against the GWT religion to even mention the words “server-side session state.” This isn’t the main point, so don’t get hung up on that.)
But that’s actually not the most interesting possible extension.
THE DETAILS
The current Seam blogging example is basically a tree view of blog posts. Each tree node can be expanded to show the full text of a blog post, with an inline edit button that lets you edit the post’s text right there in the tree.
Here’s the GWT/JSF markup for instantiating this tree-view-blog-editing component:
<!– This is a JSF component encapsulating a GWT module. –>
<bloglist:component id=”main2″>
<!– This widget routes GWT RPC requests to the Seam component named “gwtBlog”. –>
<gwt:gwtListener serviceBean=”#{gwtBlog}”/>
</bloglist:component>
This creates a JSF component wrapping a GWT module. The GWT module exposes an interface which is implemented by the server-side Seam component named “gwtBlog”. So the GWT module uses a single interface to communicate with the server.
The GWT service interface is this:
public interface BlogService extends RemoteService {
public Blog getDtoBlog ();
public List getDtoBlogEntryList ();
public String getFormattedHTML (String wikiText);
public void updateBody (String id, String newBody);
}
This interface conflates operations on the whole list of posts (getDtoBlogEntryList) with operations on individual posts (getFormattedHTML, updateBody).
Overall, this widget is great and all, but it really consists of two orthogonal pieces: a tree view component, and an individual-post-editing component. They’re bound together in the current GWT code. This widget is monolithic; all it does is make a tree of blog posts. It can’t be repurposed by tweaking the JSF page.
When showing this to Gavin, his feeling was that it was not nearly generic enough. The typical Seam way of doing this would be something like (edited for brevity):
<!– Generic tree view, using a post-edit widget for each node. –>
<ice:tree id=”tree” value=”#{tree.model}” var=”item”>
<ice:treenode>
<ice:panelgroup style=”display: inline;”>
<ice:commandlink value=”#{ item.userObject.text}”>
</ice:commandlink>
</ice:panelgroup>
</ice:treenode>
</ice:tree>
This builds a JSF component tree that declaratively nests multiple widgets, using Seam expression language ( e.g. “#{tree.model}”, “#{item}”) to specify where the components get their data.
Now, here’s the rub. What if you could write JSF / Facelets markup that instantiated a tree of GWT widgets this way?
Something like this:
<gwt:tree id=”tree” value=”#{blogEntries}” var=”item”>
<gwt:blogpostedit value=”#{item.blogPost}”>
</gwt:blogpostedit>
What you’d be doing here is writing a JSF page that creates a component tree that is purely instantiated on the client. The only rendering would happen on the client via GWT. The GWT components would (WAVING HANDS MADLY) have some protocol for nesting themselves, and would have some data-binding style coupling to the server components from which they pull data. The RPC could be GWT-style RPC via service interfaces generic to each specific component.
This would essentially turn the JSF UI component tree into a structure that can be either rendered purely on the server (original-style JSF controls), or rendered partially on the server and refreshed using AJAX (the Ajax4JSF / RichFaces style of user interface), OR rendered entirely on the client (GWT-style widgets). This would also enable declarative construction of GWT-based interfaces, using the exact same syntax and UI component tree as used for other JSF interfaces.
This is good for Seam, because it enables a graceful path towards Seam-based JSF apps with lots of custom UI code, without losing the compositional good qualities of Facelets. And it’s good for GWT, because it gives a declarative framework for building GWT applications, with a great story for coupling to server-side business logic.
ARE YOU CRAZY?
This is not quite a half-baked idea yet. In fact I’d say it’s about 10% baked. But it’s definitely interesting, and it definitely bears more thinking about.
There are many issues with it, just a few of which are:
- This doesn’t really let you mix arbitrary non-GWT and GWT JSF widgets; the only allowable children of GWT JSF widgets would be other GWT JSF widgets. (Unless you get really sneaky with partial rendering invoked FROM GWT, which probably isn’t worth it….)
- I have no idea at all what Joel Webber (of GWT fame) has in mind for declarative markup, so this concept may be totally wrong for his use cases.
- On the face of it this idea seems to imply some kind of EL (expression language) parser implemented in GWT, which is no small chunk of work.
- Who exactly implements this is a totally open question; I still want to get back to the offline Blogger client done with GWT/Gears, which has basically nothing to do with this 😉
I don’t claim to have answers to these; this post is just a starting point.
I’m going to post in the GWT developers forum, in the Seam users forum, and in the Ajax4JSF developers forum to see what kind of reactions this idea provokes.
Discuss!
Leave a Reply