Starting with this post, I would like to describe a new script interface called XMLPortletRequest. The intent of this interface is to provide a means for portlets to implement asynchronous and/or partial page updates within the portal/portlet paradigm, and yet remain compatible with Ajax toolkits and portlet bridges (JSF, Struts, Spring MVC etc.). I developed this approach several months ago, and the portlet-related specification groups, viz., JSR-286 in the Java-land, and WSRP in the language-agnostic web services land, are actively considering this interface as the basis for building Ajax-related solutions. Some specifics of this model are still being debated in these groups, but the semantics of the model are more or less finalized. Please read on for some background and details.

Before looking into XMLPortletRequest, its semantics, and how it is related to the XMLHttpRequest, it is worth looking into some of the peculiarities of using Ajax in portlets.

Problem 1: Reacting to XMLHttpRequest

Portlets are like widgets, and are meant to be aggregated in a portal page. For instance, if you think of the various modules on a Google home page, each module is like a portlet, and is designed to be rendered in a page containing other modules as well as other Google-generated markup.

JSR-168 provides a programming model for developing portlets. Alternatively, you can use frameworks like JSF, Struts, Spring MVC etc to build web apps and deploy those as portlets via portlet bridges. These bridge portlets translate respective framework API calls/life cycle into portlet API calls/life cycle.

The JSR-168 API is designed such that all user interactions go through the portal, which then invokes portlets. When you create a URL using this API (such as an action URL or a render URL), the URLs generated point to the portal. When you send a HTTP request to a portal using such a URL, the portal processes the request first, then goes through the lifecycle of each portlet, and at the end of this process, generates a full page and sends it back to the browser. This model works as long as you are using regular GET and POST submissions with action and render URLs over HTTP. When you bring in XMLHttpRequest into this picture, funny things start to happen. See Figure 1 from the paper titled Best Practices for Applying AJAX to JSR 168 Portlets.

The figure best illustrates one of the key assumptions that portals make regarding rendering. Most portals are designed to re-render the complete page upon each request. However, when a portlet uses XMLHttpRequest in some JavaScript to send a request, what it expects is some data (as text or JSON or XML) or some HTML fragment generated by a portlet. Instead, since the portal renders its complete page, XMLHttpRequest's responseXML or responseText fields would contain a page generated by the portal.

Oops - I got the portal page - what is it anyway?

If the script tries replace the content of some div with the responseText value of XMLHttpRequest, it would be inserting the full portal page within that div, leading the to a “portal in portal page” picture in the above reference. If the script does something else, like trying to eval() the responseText thinking that the response is JSON, it would get a JavaScript error. In essence, the page returned by the page makes little or no sense to the portlet's script that initiated the XMLHttpRequest.

XMLPortletRequest is designed such that a portal can deliver what the portlet generated on the server side.

Problem 2: Coordination aka Inter-Portlet Communication

In most cases, portlets are self-contained and do not effect each other. Such portlets can be added/removed at will without effecting other portlets on a page. This decoupled nature makes portlet development and deployment easy. But the down side is that, for the end user, the UI looks less interesting. Silos are not not the best way to present UI in a browser.

The upcoming JSR-286, and WSRP 2.0 specifications allow an exception to this. These specifications add an ability for portlets to communicate with each other in a loosely-coupled manner. One of the key mechanisms for doing this is by using events. Events are named, and can optionally have a payload with them. Using this mechanism, based on some user interaction, one portlet could fire an event that other portlets can handle. Upon handling the event, those portlets can fire more events, and the chain can continue until some system limit occurs. In this model, portlets don't send events directly to each other, and the portal acts as a coordinator for event distribution. During event processing, portlets can change their own state (e.g. change some back-end data). After the event chain completes, the portal renders each portlet with their latest state. In this way, portlets can still remain loosely coupled, and yet influence each other. In essence, events make it possible for a user interaction with one portlet to change the view of not just the portlet that the user is interacting with, but other portlets on a portal page as well. In some cases, the portal itself may want to handle some events, and its own markup may change.

Here is an example. Let's say, a portal page is aggregating two portlets, viz A and B. A submits an XMLHttpRequest to the server, which then invokes portlet A. As part of processing the request, A fires an event that B can handle. The portal dispatches the event to B. A then generates some JSON data to be returned via the responseText field of the XMLHttpRequest. While processing the event, portlet B changes its state, and its view in the browser becomes stale. The portal then needs to render B as well, and update its UI in the browser.

How to update multiple UI fragments on a page

Portlet A's script that started the XMLHttpRequest does not know much about portlet B, and hence the portal can not simply return portlet A's JSON data and portlet B's HTML view in the same response to portlet A. It needs do something special. Again, the XMLPortletRequest interface is designed to solve this problem such that (a) portlet A can receive its JSON data, and (b) the portal can update portlet B's view independently. The approach is not limited to events. Depending on how the portal is implemented and the features it supports, it can update any part of the portal page when several fragments of a page needs to be updated in response to a portlet's XMLHttpRequest.

Problem 3: Toolkits and Bridges

Toolkits and portlet bridges are not problems, but solutions that need to be accommodated within the portlet programming model. These two greatly influence the nature of the solution. First of all, most web developers today rely on toolkits like Dojo, DWR, GWT etc for Ajax. These toolkits simplify Ajax programming either by hiding the JavaScript completely behind a Java API (e.g. as in GWT), or provide higher level JavaScript APIs (e.g as in Dojo). However, these toolkits are portlet-agnostic. Since most web developers are already using these toolkits for their Ajax use cases, it does not help if we design a new portlet-specific Java/JavaScript API. Doing so would raise the bar for portlet development.

The second one the use of of web frameworks such as JSF, Struts, Spring MVC etc to write portlets. The APIs provided by these frameworks are not aware of the portlet API. Even if we design a new portlet-specific Java/JavaScript API, apps written using these frameworks will be agnostic to that API and cannot take advantage of it. So, the solution should be such that the portlet bridge layer can do the necessary translation.

Component libraries like ICEFaces share both flavors. ICEFaces is an Ajax toolkit, but uses JSF as the programming interface, and hence can be used via a JSF portlet bridge.

The XMLPortletRequest API is designed to minimize the amount of translations to be done in bridges and adoption of Ajax toolkits like Dojo easy.

I will discuss more about this interface in my next post.

TrackBacks

TrackBack URL for this entry: http://mt4.subbu.org/mt-tb.cgi/16

» Update on JSR-286 and Ajax from subbu.org

Early this year I have blogged about the problems related to portlets using Ajax to update their UI from the client side, and my attempts at addressing those. See here and here. As I mentioned in those posts, I also tried to make the model a part of th... Read More

Comments

Mohan Radhakrishnan said:

Is there any way we can use this now ? I am trying to use this in the themes of my Portal but the issue seems to be the same.

The themes should not refresh but the portlet associated with the node that I click to appear. I am using code like this.

function getXMLReq( url ){
var objXMLHttp=null
if (window.XMLHttpRequest){
objXMLHttp=new XMLHttpRequest()}
else if (window.ActiveXObject){
try {
objXMLHttp = new ActiveXObject("Msxml2.XMLHTTP");
} catch (e) {
try {
objXMLHttp = new ActiveXObject("Microsoft.XMLHTTP");
} catch (e) {}
}
}
alert( "Asynch Submit ");
objXMLHttp.open("POST", url, false);
objXMLHttp.send();
}

Leave a comment