Converting the WorldClock portlet from the IBM Portlet API to the JSR 168 portlet API

This article shows how to convert a portlet that was originally developed for the IBM® WebSphere® Portal proprietary Portlet API to one using the JSR 168 standard portlet API. It describes the main issues in performing such a portlet conversion. If you need to convert a portlet from the IBM Portlet API to the JSR 168 API, this article serves as a good model for your doing so.

Franziska Paeffgen is software developer within the portlet container development team, that is responsible for providing a portlet runtime environment. Her work responsibilities are the communication between WebSphere Portal and Application Server and the portlet and portlet application deployment.

Birga Rick is software developer within WebSphere Portal development team at the IBM Boeblingen Lab in Germany. In 2003, she was part of the team implementing the reference implementation of the JSR 168 Portlet API, which is known as open source project Pluto today. Today she is jointly responsible for the portlet runtime environment of WebSphere Portal.

Introduction

The Java™ Portlet Specification (JSR 168) defines how local portlets plug into portals. This standardized portlet API was needed since, over the last few years, different portal vendors had defined different APIs, none of them interoperable. The effort to create this standard was co-lead by IBM and Sun, within the Java Community Process. The specification enables interoperability between local portlets and portals, offers portlet developers a simple programming model, provides portability and interoperability with other Java technologies, and leverages and aligns the portlet API with J2EE technologies.

Before the creation of JSR 168, IBM had provided a proprietary API within WebSphere Portal.
However, with the advent of JSR 168, it is recommended that portlet developers use the new standardized portlet API. The process of converting a portlet that uses the IBM Portlet API to one that uses the JSR 168 API needs to cover several aspects. There are significant differences within the portlet descriptors, the JSPs and their tags, and the main portlet methods. There are different method parameters and the flow of actions, and some functionality needs to be rewritten completely because there is no one-to-one match from one API to the other.

This article describes how to convert the WorldClock portlet, which was developed for IBM`s WebSphere Portal, from the IBM Portlet API to the JSR 168 API. This example covers the main issues to be addressed when when performing such a portlet conversion and applies to WebSphere Portal version 5 and above. Note that the code snippets shown here are not necessarily best practices; the goal in this conversion was simply to convert the portlet with minimal effort.

IBM WebSphere Portlet API compared to JSR 168 API

The IBM Portlet API and the JSR 168 API are similar in their major aspects. The IBM Portlet API is richer in functionality, since it was defined a few years ago and has been enhanced since then. This implies that there may be some difficulties when converting portlets using the IBM Portlet API to JSR API portlets, as the JSR 168 API might not provide all functionality required by the original portlet. More functionality is being added to the JSR 168 API so that, in time, there will be fewer and fewer difficulties. Nevertheless IBM provides extensions to the JSR 168 portlet API in order to provide at least the same functionality as the traditional IBM portlet API.

Request and response objects are the same for action and render phase with IBM`s portlet API, but different for JSR portlet API.

Portlets may store attributes in the action phase in the request and retrieve it in render. This is not possible with the JSR 168 Portlet API.

Portlet Application entities

Portlet Entities

The WorldClock portlet

The WorldClock portlet used as an example for the conversion is a simple portlet with basic portlet functionality and thus provides a good example of a conversion. This portlet allows users to set their local time zone and view the current time in that time zone. Users can view the current local time in several time zones around the world at the same time. Users can also quickly search for the current local time in an individual time zone. The portlet is dependent on the time provided by the server machine that is running WebSphere Portal to make its calculations.

Figure 1. Sample WorldClock Portlet

How to convert the WorldClock Portlet

The next sections describe a step-by-step conversion of the WorldClock portlet from the IBM Portlet API to the JSR 168 API. For a better overview about the code differences that result from this conversion, we provide sample source code of both WorldClock portlets. The conversion steps are divided into the following sections:

Each section provides code comparisons between the original and converted portlets. Most of the examples are also linked to fuller examples of the code, allowing you to see the code in the context of the appropriate method within the portlet.

There are general steps that need to be performed when converting a portlet from the IBM Portlet API to the JSR 168 API. These steps include changes to the import statements and the renaming and restructuring of methods.

General portlet conversion issues

The imported packages of the IBM Portlet API contain all the required interfaces and implementations of classes a portlet needs to be fully functional. Within the package javax.portlet.*; of the JSR 168 API, these required interfaces and classes have been packaged together, containing, for example, the interfaces for the portlet's action request and response, render request and response, configuration, and so on. Refer to the Portlet API Javadoc for WebSphere Portal 5.0 and the JSR 168 Portlet Specification API for a complete listing of the package contents.

With the IBM Portlet API the PortletAdapter provides a default implementation for the Portlet interface. The ActionListener interface is an addition to the Portlet
interface. If an object wishes to receive action events in the portlet, this interface must be implemented in addition to the Portlet interface.

For JSR 168 portlets, the GenericPortlet class provides a default implementation for the Portlet interface. It provides an abstract class which must be subclassed to create portlets. The GenericPortlet class allows you to implement the
processAction method, which handles action processing, provided within the ActionListener interface of the IBM portlet API.

The init method can throw the UnavailableException under both the JSR 168 API and the IBM Portlet API specifications. However, under JSR 168, it can also throw the generic exception PortletException,
when it is unable to perform its operation successfully.

Within the IBM Portlet API, there is no difference between a render request and response and an action request and response. The JSR 168 API, however, differentiates between whether the following action requires a re-rendering of the portlet's content or the processing of an action. Only the render request and response are passed as parameters within the doView method of JSR 168 API portlets.

The IBM proprietary portlet API does not conform to the Model-View-Controller (MVC) pattern.
During the render phase of a portlet, its state can still be changed. This is not true for the JSR 168 portlet API, which does differentiate, by the two different requests (render and action), whether the portlet's state can be modified, or the portlet's content is just being displayed. The doView method of the JSR 168 specific portlet API represents the view component of the MVC pattern.
The portlet content may provide links to an action URL that causes the actionPerformed method to be called.
The portlet's state can only be changed within this method using the action request. This part represents the controller part of the MVC pattern.

JSR 168 API

The IBM Portlet API defines action handling to be processed separately via ActionListener interface and its implementing classes. A standard implementation for action handling is already provided within the GenericPortlet class of the JSR 168. Since the JSR 168 API differentiates between an action request and response and a render request and response, the processAction method receives ActionRequest and ActionResponse objects as parameters.

There are detailed steps that may be necessary when converting a portlet from the IBM Portlet API to the JSR 168 API. A deeper understanding of both APIs is required for these changes. Those detailed steps that were necessary to convert the WorldClock portlet are described in this section.

The IBM Portlet API provides the basic configuration information about a portlet via a PortletSettings object, while the personalized information for each portlet instance is provided by aPortletData object.
Within the JSR 168 API, this information is provided by only one object called PortletPreferences. There are two major differences that need to be taken into account when manipulating preference attributes instead of portlet settings or portlet data:

The preference attributes of PortletPreferences allows NULL values.
Therefore the JSR 168 API differentiates whether a value is set or not by specifying a default value that is returned if no value is set.

The reset method of PortletPreferences removes or resets the preference value to a predefined default value, if available. The IBM Portlet API implements this functionality using the remove method of the PortletData object.

Within the IBM Portlet API, an external resource is included in the PortletContext directly using the include method. Under the JSR 168 API, a PortletRequestDispatcher object is provided by PortletContext; the include method of this object is then used to include a resource.

The generation of a Unified Resource Locator (URL) is different between the two APIs. To create a URL that invokes an action event within the IBM Portlet API, a URI needs to be created and extended by a PortletAction that identifies the action to occur.
Using the JSR 168 API, the method createActionURL directly returns a URL that invokes the action method to be called. To identify the action, a parameter can be set.

The IBM Portlet API allows the next portlet mode to be defined within event processing by specifying the ModeModifier of the portlet request. Using the JSR 168 API, the setPortletMode method of the action response is used to change to any arbitrary portlet mode. During conversion between the two portlet APIs, bear in mind that the createReturnURI method of the IBM Portlet API changes the portlet mode back to the mode that the portlet was in before the current one (typically changing it from EDIT mode to VIEW mode). To have the same behavior under JSR 168, the createReturnURI call needs to be replaced by RenderResponse.createActionURL. Within the method here called processAction, the portlet VIEW mode can be explicitly set at the action response.

Both, the IBM Portlet API and the JSR 168 API provide access to the logging facility via PortletContext. However, instead of using a PortletLog returned by the PortletContext.getLog method, the JSR 168 Portlet API provides a log method within the portlet context itself.

Deployment descriptor differences

A portlet deployment descriptor (portlet.xml) is used to describe the portlets packaged in a web archive; this deployment descriptor must be provided in addition to the web deployment descriptor (web.xml), which must be provided in order for the web archive to be valid. The JSR 168 Portlet API does not use the web.xml for portlet information. Therefore the web.xml file of a JSR 168 Portlet application may be empty.

There are detailed steps that must be performed when converting the portlet deployment descriptor from the IBM specific Portlet API to the JSR 168 API. A deeper understanding of both portlet descriptors is required for these changes. Because the portlet deployment descriptors provide the information about the portlet in a very different structure, only those differences that are present in the portlet.xml file of the WorldClock portlet are listed here.

The portlet.xml file describes a portlet application as defined within the IBM portlet Document Type Definition (DTD) or the JSR 168 portlet XML Schema Definition (XSD).
While the IBM Portlet API divides a portlet application definition into a portlet-app and a concrete-portlet-app, the JSR 168 API
defines only one portlet-app. Therefore the first step in converting portlet.xml is to change the portlet application tag, including the reference to the XML Schema definition of the portlet deployment descriptor.

Each portlet is defined by a <portlet> tag within the portlet application; this is common to both APIs.

IBM Portlet API

JSR 168 API

<servlet-class> ... </servlet-class>

<portlet-class> ... </portlet-class>

In the IBM Portlet API, the fully-qualified class name of the portlet is specified within the web.xml file in the same way as it is done for servlets. Since the JSR 168 API portlets are components of their own and not specific servlets, the fully qualified class name of the portlet is defined by the <portlet-class> tag within portlet.xml.

The portlet modes that are supported by the portlet are indicated within a <supports> block. the IBM Portlet API specifies the supported markup by a <markup> tag; the JSR 168 API uses the <mime-type> tag. The portlet modes that are defined by IBM's proprietary mode tags (for example, <view>, <edit>, <help>) need to be changed to the <portlet-mode> tag of the JSR 168 API. Since the configure mode is defined as optional within the JSR 168 API, this portlet mode must also be defined by a <portlet-mode> tag within a <custom-portlet-mode> tag.

For portlets using the IBM Portlet API, the title is defined for each concrete portlet. Since the JSR Portlet API does not use the same concept of a concrete portlet, the information is defined once per portlet by a <portlet-info> tag within the portlet definition. To support different settings depending on the locale, this information can be specified in a resource bundle instead, using the JSR 168 specific keys (for example, javax.portlet.title, javax.portlet.short-title, and javax.portlet.keywords).
Then the resource bundle must be defined once per portlet by a <resource-bundle> tag within the portlet definition.

Both versions of the WorldClock portlet contain four JSPs, which are used to display its content.

JSP differences

BidiInclude.jsp

The BidiInclude JSP is to make BIDI support a little easier. The variables defined within the JSP are meant to supplement the <bidi> tag.

WorldClockEdit.jsp

The WorldClockEdit JSP is used to modify the WorldClock portlet and change its settings or preferences.

WorldClockHelp.jsp

The WorldClockHelp JSP represents a JSP to display the help page of the WorldClock portlet.

WorldClockView.jsp

The WorldClockView JSP is used to display the WorldClock portlet`s content.

There are some differences between the JSPs for the IBM and the standard WorldClock portlet.
The JSPs used by the WorldClock portlet, BidiInclude.jsp, WorldClockEdit.jsp, and WorldClockView.jsp use the Portlet API specific JSP tags. The portlet tag library enables JSPs that are included from portlets to have direct access to portlet specific elements such as the portlet request and response. It also allows JSPs to access portlet functionality such as creation of portlet URLs. Within the JSPs, a tag element is always referenced by its defined prefix (for example, portletAPI).

The JSPs reference the IBM-specific portlet tags as follows:

<%@ taglib uri="/WEB-INF/tld/portlet.tld" prefix="portletAPI" %>

.

The JSR JSPs reference the tag library like this:

<%@ taglib uri="http://java.sun.com/portlet" prefix="portletExt" %>

WebSphere Portal provides an additional tag for use in JSR 168 portlets. To make this tag available in a JSP, the following directive is required:

The class implementing the functionality represented by this tag writes a localized string to the output stream. When no resource bundle can be found, the text between start and end tags is written to the output stream. The tag parameters are:

bundle (mandatory) - name of the resource bundle

key (mandatory) - key to be found in the resource bundle

There is currently no corresponding JSTL JSP tag available that reflects this functionality.

bidi

The class implementing the functionality represented by this tag supports text for bidirectional languages. Bidirectional languages are those which are typically read from right to left except when left-to-right text strings are displayed (for example, URLs, code samples, or directory and file names).
There is currently no corresponding JSTL JSP tag available that reflects this functionality, but an IBM extension, as explained above.

encodeURI

The class implementing the functionality represented by this tag creates the PortletResponse object and executes the encodeURI method.
The following portlet tags specified by the JSR 168 API provide equivalent behavior: <actionURL> and <renderURL>.

The following tag elements are used within the already mentioned JSPs of the JSR 168 WorldClock portlet:

defineObjects

The defineObjects tag must define the following variables in the JSP page:

renderRequest

renderResponse

portletConfig

These variables must reference the same JSR 168 API objects stored in the request object of the JSP. A JSP using the defineObjects tag may use these variables from scriptlets throughout the page. An example of a JSP using the defineObjects tag is:

After using the defineObjects tag, the JSP invokes the setTitle method of the RenderResponse to set the title of the portlet.

actionURL

The portlet actionURL tag creates a URL that must point to the current portlet and must trigger an action request with the supplied parameters. Parameters may be added to the URL by including the param tag between the actionURLstart and end tags. The following non-required attributes are defined for this tag:

windowState (Type: String, non-required) -- indicates the window state that the portlet should have when this link is executed.

portletMode (Type: String, non-required) -- indicates the portlet mode that the portlet must have when this link is executed, if no error condition occurred.

var (Type: String, non-required) - name of the exported scoped variable for the action URL.

secure (Type: String, non-required) -- indicates if the resulting URL should be a secure connection (if the value is set to "true") or an insecure one (if the value is set to "false").

renderURL

The portlet renderURL tag creates a URL that must point to the current portlet and must trigger a render request with the supplied parameters. Parameters may be added by including the param tag between the renderURL start and end tags. The same non-required attributes as already listed for the actionURL tag are defined for this tag as well.

namespace

This tag produces a unique value for the current portlet. This tag should be used for named elements in the portlet output (such as JavaScript functions and variables). The name spacing ensures that the given name is uniquely associated with this portlet and avoids name conflicts with other elements on the portal page or with other portlets on the page.

param

This tag defines a parameter that may be added to a actionURL or renderURL.The param tag must not contain any body content. The following required attributes are defined for this tag:

name (Type: String, required) - the name of the parameter to add to the URL. If name is null or empty, no action is performed.

value (Type: String, required) - the value of the parameter to add to the URL. If value is null, it is processed as an empty value.

Source code for the WorldClock portlets

This section compares relevant parts of the source code of the WorldClock portlet written using the IBM Portlet API with the converted portlet that uses the JSR 168 Portlet API. The highlighted code indicates changes in the context of the conversion.

WorldClock portlet doEdit method using IBM Portlet API

/**
* Edit functionality.
* Allow the user to adjust the local time and
* time zone. They can also pick the other time
* zones in the world to display in view mode.
*/
public void doEdit (PortletRequest request,
PortletResponse response)
throws PortletException, IOException
{
.....
// include JSP for extended search
getPortletConfig().getContext().include
("/WEB-INF/worldclock/WorldClockEdit.jsp",
request, response);
....
}

WorldClock portlet doEdit method using JSR 168 API

/**
* Edit functionality.
* Allow the user to adjust the local time and
* time zone. They can also pick the other time
* zones in the world to display in view mode.
*/
public void doEdit (RenderRequest request,
RenderResponse response)
throws PortletException, IOException
{
.....
// include JSP for extended search
PortletRequestDispatcher dispatcher =
getPortletConfig().getPortletContext().
getRequestDispatcher
("/worldclock/html/WorldClockEdit.jsp");
dispatcher.include(request, response);
....
}

WorldClock portlet actionPerformed using IBM Portlet API

/**
* Implements the save action for the portlet's
* edit mode. The action is executed as part of
* the submit URI before doView gets control. The
* parameters that have been set by the user in the
* edit form are retrieved from the request and
* written to the portlet database through PortletData.
*/
public void actionPerformed(ActionEvent anEvent)
throws PortletException
{
DefaultPortletAction pAction =
(DefaultPortletAction)anEvent.getAction();
String action = pAction.getName();
PortletRequest request = anEvent.getRequest();
.....
// save parameters to the user's config data
PortletData data = request.getData();
.....
// go back to edit view
request.setModeModifier(Portlet.ModeModifier.CURRENT);
....
}

WorldClock portlet actionPerformed method using JSR 168 API

/**
* Implements the save action for the portlet's
* edit mode. The action is executed as part of
* the submit URI before doView gets control. The
* parameters that have been set by the user in the
* edit form are retrieved from the request and
* written to the portlet database through PortletData.
*/
public void processAction(ActionRequest request,
ActionResponse response) throws PortletException
{
String action = request.getParameter(COMMAND);
.....
// save parameters to the user's config data
PortletPreferences data = request.getPreferences();
....
}

Conclusion

This article demonstrated a simple way to convert a portlet originally developed with the IBM Portlet API into a portlet that conforms to JSR 168. Although not all differences between the APIs were covered, this conversion example addresses common issues of such a conversion,without covering best practices of a JSR 168 portlet programming model. This example gives developers a better understanding about the main differences between the APIs and the how to change functionality from a portlet that uses one API to the other.

The first time you sign into developerWorks, a profile is created for you. Information in your profile (your name, country/region, and company name) is displayed to the public and will accompany any content you post, unless you opt to hide your company name. You may update your IBM account at any time.