Monday, August 21, 2006

Imagining Using the Portlet 2.0 (JSR 286) Early Draft 1 Spec Release

I've done some projects which have used JSR 168 Portlets in the past. When I saw that the first public released draft of the new spec was out I thought I'd take a look. Here's my imaginings of how things would have been if we'd used this spec instead...

Lets describe my imaginary app. (The standard kind of portler app I've worked on.) The setup is simple. There are three portlets. A “search” portlet and two content portlets: “films” and “actors”. You can use the search portlets single search field, coupled with a radio button selection of the search type (c.f. google) to search for either actors or films. The results of your search are displayed in the same portlet as a clickable list.

Once a result in this list is clicked, wiring passes the actor or film id to the relevant portlet, which retrieves and displays the relevant content. If the other content portlet currently displays content, then a “reset” wire from the search portlet tells it to clear its contents.

Finally, content displayed in the actor portlet includes a list of films which they have appeared in. Clicking this link passes the film id to the films portlet which again retrieves and displays the relevant content. On this occasion there is no need to reset any other portlets. This functionality is also present from the films portlet to the actors portlet.

Clearly this is not at all possible using JSR 168 portlets alone. We were deploying to Websphere Portal Server 6.0 which gave us the ability to "wire" portlets together which were on the same page (inter page wiring has been added since then). This wiring was pretty darn complex (i've blogged about it before now) but once we got it going, we were able to get the kind of behaviour described above. In our case, even though we had all our portlets in a single war app, we passed all our parameters (such as film and actor ids) as request parameters and the wiring allowed an action in one portlet to call the processAction() method in another before all the following doView(). We only used the sessions for portlets to store their individual state, not to share it.

So how would things change if we now wanted to change to Portlet 2.0? Well the first point I'm happy to make is that we still have binary backwards compatability with 1.0 portlets. This means all our portlet code would still work. However, as the wiring was all proprietary, we would have to do something new to regain this functionality.

This is where the new "Portlet Co ordination" model comes in. The new spec (as I understand it) has added the concept of events which can be "thrown" (my terminology - almost in the same way as exceptions or events which are listened for in Swing apps is the impression that I get). These are then handled in an additional phase in the request action handling - rendering cycle which occurs after the relevant processAction() method is called, but before all the doView(), doEdit() etc. calls are made to generate the page fragments. As with wires, you can set attributes in the event (as standard types or even XML which is marshalled with JAXB - nice and flexible) which can then be picked up by those portlets which have elected (declaratively in the portlet.xml - again, nice and flexible) to react to specific
goings on which have happened (not only as a result of user interaction, but also emitted from the portal framework itself (c.f. pp. 75) The spec indicates that portlets can send what are termed "dynamic" events which are not declared in portlet.xml or, more usually static "declared" events. Finally I should note that a portlet can throw more than one event per processAction() call. Something which made things even more complicated with Websphere wires.

Clearly this is brilliant. How do we do it? Well, there's a new lifecycle interface for our portlet classes: javax.portlet.EventPortletInterface. This provides a new method which we must implement: processEvent(). To reinstate our old wired portlets, we need to take the Portlet classes we'd written, add the implementation of the interface, do some fairly hefty refactoring to move a lot of the code in many of the portlets processAction() methods to the new processEvent() method, declare our sending and receiving of events in the portlet.xml file and then deploy. Hooray! The complex WSDL for the exports and imports of data which WebSphere used for wiring is no longer required.

The final beauty of this new model is that the portal will now be happy to dynamically propagate any events as requested during operations. No more intervention is required after a successful deployment. (This is a vast improvement on WebSphere wiring jungle which would be remembered after subsequent deployments, but if you wanted to change a wire, you had to undeploy the entire portlet application and remove your portal pages again, then redeploy, put the pages back and then re wire using the admin GUI. If things still didn't work, then you'd have to undeploy, destroy and then repeat again. This wasted a lot of time.)

You should have guessed that I'm very happy that this has been added to the 2.0 spec. But while I do admit that it does seem a vast improvement on the way I have described above, I fear a few tricks have been missed in keeping this simple. Firstly, one of the few things I did like about the wiring method was that the wire effectively allowed you to call processAction() on one portlet, set a request parameter which would tell the wire to then call the processAction() on another portlet. It made sense to me and did not mean I had to understand (and debug) an increasingly complex class flow. Indeed, there could be multiple calls (as I outlined above where a click in a search result would get one portlet to display some detail and the other to reset itself) and each would follow the same route, initiated by the same original interaction from the user. The point I'm trying to make is that I'm not entirely convinced that there is a requirement for another portlet method, and its associated interface to implement. What is so vastly different between "actions" and "events" which means that they have to be handled separately?

Portlet development, even in the simplest sense is more complicated that it is with servlets - and rightly so, due to the slightly more complicated request - (action - render) - response cycle. But the aim should be to keep a sensible level of simplicity, otherwise potential developers will be driven away and the spec under used. Something JEE is only just recovering from. Consequently, it seems to me, that were the two new concepts of Portlet Co ordination and Shared Render Parameters (see below) to be linked and allow the proposed mechanism to call the processAction() methods rather than the additional processEvent() methods. The associated benefits of bookmarkable URLs (see below) could be leveraged and the present processing mechanism would be maintained. Code which was written for 1.0 could be simply updated (or in my case, little new would have to be done, we could just replace the wires with the new entries in portlet.xml to let on about who did the sending and who the receiving. Sorted.

Which brings me onto my second and final (and far shorter) area of feedback. I've already discussed what a nightmare getting the WebSphere wiring to work could be. It certainly seems vastly simpler with the "auto wiring" in the 2.0 spec, and the necessary xml configurations in portlet.xml are vastly simpler than the previous WSDL nightmare. But are the configurations necessary at all? Why do we still have to hack XML? - EJB3 showed us that annotations and sensible defaults can get us a great deal. I would also like to see the same sort of support in Portlet 2.0. Perhaps this is a way of implementing the (possibly necessary complexity) which led to the additional processEvent() step. As with EJB's, the Home, RemoteHome, and other interfaces are still there, it's just that the developer never needs to think about them, unless they choose to.

Before I close, I'd like to mention a few more quickies. Firstly, support for Java 5 - excellent - but why no support for JEE 1.5 rather than 1.4? Surely this would be an ideal to piggy back on what looks to be a storming, remarkably simplified and vastly more usable spec. The fact that the JPA can now be used outside an EJB container is a vast improvement. If portlets could then simply use this for the "M" in their MVC (we just used Hibernate and POJOs when we did our development) then everything done would be far more futureproof and allow portal implementations to run on Web Container only platforms.

Secondly, it is also very welcome to see the ability to share session state and render parameters. The possibililty of bookmarkable portlet URLs is an attractive one and will greatly increase usability and greatly simplify trying to handle the ever present threat of a user pressing the dreaded "back" button. The ability to share parameters outside the current portlet application is also a great improvement on a previously frustrating and seemingly arbitrary restriction.

All in all, I think this is a very promising looking 2.0 spec. I for one look forward to doing more portlet development in the future and coming up with even wilder ways to try and push the limits of what it can do.

NOTE: I haven't commented on the proposed AJAX or WSRP support. Both would be most welcome however and help the spec to be relevant to an even wider audience.

No comments: