Monday, October 26, 2009

JSR286 : Action scope request attribute

Introduction

The core features of any Internet portal are content aggregation from different information sources, web-page personalization and single sign-on. Java portlets act as the building blocks of any J2EE based portal implementation. Java portlets are very similar to Java servlets in many ways. They too are web components, managed by a container, that generate dynamic content. Java Portlet Specification v1.0 (JSR 168) defines the portlet API, container-portlet contract and packaging requirements for Java portlets. The recent Java Portlet Specification 2.0 final draft (JSR 286) facilitates implementing portlets with more advanced capabilities. This article illustrates the use of action scoped request attributes runtime option, which facilitates Java objects created during action phase being accessible during render phase in the form of request attributes.

Portlet Spec v1.0 (JSR 168): Action phase and Request attributes

As defined in the portlet specification v1.0, the portlet lifecycle is split into two distinct phases: Render and Action. When the portlet is rendered in a web page for the first time, it is said to be in render phase in which it returns the initial HTML fragment to be displayed. The portal aggregates this HTML fragment with the fragments of other portlets to form a complete web page. When the user takes an action (form submission for example), it enters action phase in which it processes the request and update its internal state (data).

To reflect the state changes in the user interface, the portlet enters render phase again. This means every action phase is followed by at least one render phase invocation. The portlet might receive additional render requests under various circumstances like when the user refreshes the browser or when he/she makes a request on some other portlet on the same page. This refined request-handling model is required with portlets since they generate only segments of the web page and are hosted along with other portlets in the same page (alternatively, in the servlet model the implementation of service() method takes care of both request processing and response rendering; also it renders the entire web page).

The interface javax.portlet.Portlet abstracts the portlet API and has render() and processAction() methods to represent render and action phases respectively. The portlet container is responsible for invoking these methods as appropriate. During action(), you can call ActionResponse.setRenderParameter() method to set any String values and retrieve the same using RenderRequest.getParameter() in the following render calls. However there is no similar mechanism in case of request attributes. For example, the following portlet will not print the request attribute that is set in processAction().

package samples.actionscope;


import javax.portlet.*;
import java.io.IOException;
import java.util.Date;

public class DateTimePortlet extends GenericPortlet {

public void doView(RenderRequest req, RenderResponse res) throws IOException, PortletException {
Object actionAttribute = req.getAttribute("datetime");
res.getWriter().println("Date Time:" + (actionAttribute != null ? actionAttribute :"Unavailable"));
res.getWriter().println("
");
PortletURL u = res.createActionURL();
res.getWriter().println("Trigger an action.");
res.getWriter().close();
}

public void processAction(ActionRequest req, ActionResponse res) throws PortletException {
req.setAttribute("datetime",new Date());
}
}

Below is a screenshot of the resultant portlet window after clicking Trigger an action action URL.

With MVC-based web applications, you are very likely to create view objects after request processing, set them as request attributes and use the same for display purposes. Due to the separated action and rendering model, the action request attributes will not be available in any of the view components that are included in the render phase (JSP, Servlet etc).

The only workaround is to use HTTP session (javax.portlet.PortletSession interface) to store and retrieve the attribute explicitly during action and render phases respectively. The problem with this approach is that you, not the container, are responsible for managing session attributes. The attributes are scoped only to the current action request and following render requests and, must be cleaned up when the portlet receives next action request. If you don’t code it properly, you might end up retaining lot of unused objects in the session, thus causing performance issues (IBM Struts Portlet Framework and Apache Struts Portal Bridge also use session as the underlying mechanism). Won’t it be good if the container itself takes care of managing the attributes thus relieving portlet/frameworks from doing the same?

JSR 286 Container Runtime Options

With JSR 286 compliant portlet containers, you can specify additional runtime behavior. The specification defines the following options:

  1. javax.portlet.escapeXml
  2. javax.portlet.renderHeaders
  3. javax.portlet.servletDefaultSessionScope
  4. javax.portlet.actionScopedRequestAttributes

Support for the first three are optional whereas the last one is required, which is the one we are interested in.

javax.portlet.actionScopedRequestAttributes

As the name implies, the purpose of this runtime option is to provide the portlets with the action scoped request attributes during render phase. You specify this option in the portlet deployment descriptor (portlet.xml) at either portlet level or application level.

Portlet level (only this portlet):





DateTimePortlet
Date Time Portlet
samples.actionscope.DateTimePortlet


javax.portlet.actionScopedRequestAttributes
true
numberOfCachedScopes
10




Application Level (All the portlets in the application):





DateTimePortlet
Date Time Portlet
samples.actionscope.DateTimePortlet




javax.portlet.actionScopedRequestAttributes
true
numberOfCachedScopes
10



This specification instructs the portlet container to retain the action request attributes across requests and make them available in all the following render requests. The attributes are valid until a new action occurs or session timeout. Internally, portlet containers use an action scope id to keep track of the action scope, thus associating the attributes with it.

Below is a screenshot of the portlet running the same code with javax.portlet.actionScopedRequestAttributes specified after clicking Trigger an action action URL.

This feature makes the request attributes lifecycle model same as it is in Servlets. It can now be taken advantage to pass form beans back to JSPs in case of errors, resultant objects after processing a request or any object that is used for display. There is no need to manage the session attributes within portlet/framework. Note that the internal implementation mechanism will most likely use an HTTP session only. Hence , best practices related to keeping the session size to the minimum should be followed. For example, you have to design specific view data beans containing only information that is absolutely required (instead of using existing complex objects) to render the web page.

Along the same lines, javax.portlet.servletDefaultSessionScope runtime option can override the visibility of session attributes in the JSP/Servlets. By default, included JSP/Servlets have access to session attributes stored within application scope. Unless the portlet stores session objects at the application scope, they are not visible within JSP/Servlets. This option can be used to change this behavior to portlet scope.




javax.portlet.servletDefaultSessionScope
PORTLET_SCOPE


Portlet containers may choose not to support this runtime option, as this is not required according to the v2.0 specification.

Conclusion

As we saw, the Java Portlet Specification 2.0 has added the new container runtime option to support action scoped request attributes. In addition, it includes many features including events, public render parameters, serving resources, and new servlet features like cookies, lifecycle listeners, filters etc thus facilitating porting of existing servlet based applications into portal environment easily. Currently Sun Java System Application Server 9.1 (GlassFish v2) provides a Java Portlet Specification 2.0-compliant container that can be used to develop portlets leveraging new features.