by Naresh Devnani

The Portlet Packet: Inter-portlet communication in Portlet 2.0

how-to
Nov 26, 200812 mins

Add dynamic interaction to your portal applications

The Portlet 1.0 spec didn’t do much to enable portlets to communicate, especially if they lived in different Web applications. Author Naresh Devnani shows you how all that has changed with the new Portlet 2.0 spec, with a new event model that makes it easier for portlets to talk — and listen. Level: Intermediate

Portlet 2.0 is the recently finalized latest version of the Java portlet specification. One of the shortcomings of the previous version of the spec (JSR168) was lack of support for inter-portlet communication. As a result, developers tasked with presenting dynamic interaction on Web portals had to resort to all kinds of fancy workarounds.

The Portlet Packet: 3-for-1

This article is about the new inter-portlet communication facilities found in Portlet 2.0. See these other articles in the JavaWorld Portlet Packet to round out your education — and look for future articles, too!

  • “A quick start guide to Portlet 2.0”
  • “Inter-portlet communication with the Dojo toolkit”

The Portlet 2.0 specification is designed to fill this gap with a revamped event model that allows portlets to publish and subscribe to events from other portlets. This article will explain the event model and walk you through some sample portlets that use this model to communicate.

Before you begin this article, you should already have some knowledge of portal programming. This article is intended for intermediate developers familiar with portlet development using the Portlet 1.0 spec, who want to learn about inter-portlet communication in Portlet 2.0.

The Portlet 2.0 event model

The portlet event model is a loosely coupled, brokered model that allows a portlet to react to state changes without direct user action with that portlet. These state changes may be generated from the container or from other portlets.

You could exchange information between portlets through portlet sessions in Portlet 1.0, but all those portlets would have to be part of same portlet application. With events, you can exchange information between portlets, even when they are not part of the same application. This is good, as enterprises use portlets from different sources (different vendors, for instance, or different development teams), and it becomes hard to contain them within same portlet application.

Examples and source code

In this article the Portlet 2.0 event model is introduced using a two sample Portlet 2.0 applications. The first application, jsrsample, has an event class that is created by a publishing portlet and consumed by a subscriber portlet. The second application, jsrsample2, only consumes the event created by jsrsample’s publish portlet. You can download the source for these applications anytime.

Events are not only used for portlet-to-portlet communication; the portlet container can also raise events that can be consumed by portlets. The Portlet 2.0 specification has some pre-defined container events, such as newWindowState and newPortletMode.

Event request handling

In Portlet 1.0, there were two types of request: action and render. All action requests would be handled by portlets first, and only after that would render requests kick in. Event requests in Portlet 2.0 fall between these two request types. In Portlet 2.0, after all the action requests have been completed, event requests kick in, and when event requests and response requests have been completed, render requests kick in. Figure 1 illustrates the sequence.

Figure 1. Event request handling diagram (click to enlarge)

Defining events

To define an event, you would have to declare it in portlet.xml, as shown in Listing 1.

Listing 1. Defining an event

<event-definition>
      <qname xmlns:mycomp='http://www.mycomp.com/jsr286'>mycomp:AppEvent</qname>
      <value-type>com.mycomp.portal.jsr286.WrapperEvent</value-type>
</event-definition>

The <event-definition> tag is a sibling of the <portlet> tag. Listing 1 defines an event named mycomp:AppEvent, where mycomp refers to the namespace and AppEvent is the local name. Its type is defined by the <value-type> tag. Here, the type is a custom Java class; it could have also been a primitive type or any standard class defined in the JAXB 2.0 specification (except java.lang.Object). These event definitions require you to use qname to uniquely identify the event. You can define multiple events in portlet.xml.

The next step is to add the events to specific portlets, which are either going to publish (generate) an event or process (consume) an event. You add this information to portlet.xml as well. You would define the publishing of an event using the <supported-publishing-event> tag, as in Listing 2.

Listing 2. Publishing an event

<portlet>
....
<supported-publishing-event>
         <qname xmlns:mycomp='http://www.mycomp.com/jsr286'>mycomp:AppEvent</qname>
</supported-publishing-event>
....
</portlet>

And you would define the processing of an event using the <supported-processing-event> tag, as in Listing 3.

Listing 3. Processing an event

<portlet>
....
<supported-processing-event>
         <qname xmlns:mycomp='http://www.mycomp.com/jsr286'>mycomp:AppEvent</qname>
</supported-processing-event>
....
</portlet>

Each portlet definition can have both publishing and processing tags, and you could define multiple events within each portlet definition. Apart from these event definitions, your portlet.xml would look exactly as it would under the Portlet 1.0 spec.

Take a look at the portlet.xml files for the sample applications. jsrsample’s portlet.xml file has event definition, publishing event, and processing event tags, as its portlets create and consume events. jsrsample2’s portlet.xml contains only definition and processing event tags, as the portlet in this application only consumes events.

Coding events

If you are going to use a custom Java class to define your event type, you start by coding the event class. Listing 4 illustrates an example.

Listing 4. An example event class

@XmlRootElement
public class WrapperEvent implements Serializable {
    ...
    public static final QName QNAME = new QName("http://www.mycomp.com/jsr286", "AppEvent");

    private String name;
        private String zipcode;
        ...
}

An event class must implement the Serializable interface and be annotated with @XmlRootElement. (For your IDE to process this annotation, you would need Java 6 or, if you are using Java 5, you would need the JAXB library in your build classpath. I am using Java 5, so I used jaxb-api-2.1.jar from the JBoss portlet container 2.0 lib directory; you can download JAXB from the Sun Website.) The class in Listing 4 defines a public variable for the QName object of this event, so other portlet classes can access this variable rather than creating their own QName objects. (This variable is not required by the spec.) This class is used as the Event class in both of the sample applications, and is present in both WAR files. You could make it available to both applications through your application server’s classpath as well, but one way or another, both sample applications need this class for their portlets.

You publish events in the processAction() method of the portlet code by calling setEvent() on the ActionResponse object. This setEvent() method takes two parameters: the QName of the event object and the type of object defined in portlet.xml. Listing 5 illustrates an example of the processAction() method.

Listing 5. processAction()

public void processAction(ActionRequest request, ActionResponse response) throws PortletException, IOException {
...
    WrapperEvent event = new WrapperEvent();
    ...
    response.setEvent(WrapperEvent.QNAME, event);
}

The method in Listing 5 is part of the PublishEventPortlet class in the jsrsample application. This method is executed when a user submits a form on the main view of this portlet.

A custom portlet extends from GenericPortlet, and GenericPortlet in Portlet 2.0 has been enhanced to implement the EventPortlet interface. This provides you with the optional processEvent() method to process events. This method allows you to process the events that have been defined in portlet.xml for that particular portlet. Once you get an event, you can compare it with a local name using getName(); alternately, you could use the getQName() method to compare an event to a fully qualified name. Once you have found the match, you can cast the event value to the appropriate class. Listing 6 shows processEvent() in action.

Listing 6. processEvent()

public void processEvent(EventRequest eventRequest, EventResponse response) throws PortletException, IOException {
        Event event = eventRequest.getEvent();
        if(event.getQName().equals(WrapperEvent.QNAME))
        {
            WrapperEvent wrapEvent = (WrapperEvent)event.getValue();
            ...
        }
}

The method in Listing 6 is part of the SubscribeEventPortlet class in the jsrsample application. This method is executed by the portlet container when it receives the event from PublishEventPortlet.

If you want to capture events in some method in your portlet class other than processEvent(), you could define an annotation on your custom method, as in Listing 7.

Listing 7. Capturing events with a custom method

@ProcessEvent(qname="{http://www.mycomp.com/jsr286}AppEvent")
public void processAppEvent(EventRequest request, EventResponse response) throws PortletException, java.io.IOException {
// process event AppEvent
Event event = request.getEvent();
WrapperEvent wrapEvent = (WrapperEvent)event.getValue();
}

The method in Listing 7 is part of the NewsEventPortlet class in the jsrsample2 application. This method is executed by the portlet container when it receives an event from PublishEventPortlet. The @ProcessEvent annotation makes sure that your method receives the correct event.

Now you’re ready to build an application that uses these events to exchange information.

Deploying the sample application

In the remainder of this article, you’ll go hands-on with the sample code to see how this works in practice. First, you’ll deploy jsrsample, a Portlet 2.0 application that, as noted, includes two portlets: one for publishing an event and the other for subscribing to an event. Next, you’ll deploy jsrsample2, a Portlet 2.0 application with one portlet, which subscribes to the event generated in the first application.

The example code that you can download assumes the presence of JBoss Portlet Container 2.0, which includes Tomcat. This is available under the LGPL open source license. (If you want to use the sample apps with other portlet containers, you may need to modify them somewhat, particularly the web.xml file; portlet.xml would remain the same no matter what container you use.) After you have installed and configured the container, look at its core Web application, called simple-portal. This Web application holds the framework that displays the portlets. You could either add your own page by modifying layouts/nav/main.jsp, or modify one of the existing pages. I modified one of the existing pages, demo/demo2.jsp, by removing its portlets and adding my own custom portlets. The JBoss portlet container uses a very simple tag library to include portlets, which requires the portlet name as defined in portlet.xml and the context name of the portlet Web application. Listing 8 shows how it’s done.

Listing 8. Defining a portlet in portlet.xml

<xportal:portlet name="pubEventPortlet" applicationName="jsrsample"/>

IPC-source.zip contains all of the sample code for this article. Once you’ve downloaded and unzipped it, walk through the following steps:

  • Deploy jsrsample.war by copying it to the Tomcat webapps directory.
  • Copy demo2-1st.jsp from the sample package to the demo directory under the simple-portal application and rename it to demo2.jsp. (Give the existing demo2.jsp file another name first.)
  • Restart the container.

The jsrsample application defines an event, called WrapperEvent, and includes two portlets, called PublishEventPortlet and SubscribeEventPortlet. The custom demo2.jsp has the appropriate tags to display both portlets.

The Publish portlet has a HTML form for accepting name and zip code values; when you submit the form, the portlet publishes the event through the processAction() method. The Subscribe portlet renders default values for name and zip code when you first load the portal page. After the Publish portlet has published its event, the Subscribe portlet receives the event in its processEvent() method and changes its output to display new values. Figure 2 shows a screenshot of these two portlets in action.

Figure 2. Two portlets running (click to enlarge)

Now deploy jsrsample2.war and substitute demo2-2nd.jsp for the demo2.jsp on the server, then restart the container. jsrsample2 defines one event, WrapperEvent (just as in the jsrsample application), and contains one portlet, NewsEventPortlet. The new version of demo2.jsp has one extra tag to display the News portlet.

The News portlet subscribes to the same WrapperEvent that is being published by Publish portlet. The News portlet displays a default zip code in the absence of any event; when it receives the event in its custom processAppEvent() method, it extracts the zip code from the event and uses the value in its render view. Figure 3 shows all three portlets in action.

Figure 3. Portlets from two different applications (click to enlarge)

As you can see, it’s quite easy for a portlet to receive events from another portlet, whether the two portlets reside in the same or separate Web applications. You just have to make sure to include the common event classes in all portlet Web applications. If you would like to deploy this application to an other Portlet 2.0 container, make sure to check that container’s requirements for web.xml, as some containers expect specific elements in the web.xml files of Portlet 2.0 applications.

In conclusion

In this article, you looked at the inner workings of the event model in Portlet 2.0. With that information under your belt, you will be able to modularize your complex portlet applications and use the new Portlet 2.0 event model to exchange information. For example, imagine that you’re developing an e-commerce solution on a portal and have to use third-party products for your product catalog, inventory status, and shopping cart functionality. If you were developing with the Portlet 1.0 spec, you would have to put all of these product libraries and related code in same portlet Web application so they could share the same session and data. With the Portlet 2.0 spec, you can create three separate portlet Web applications and encapsulate appropriate business logic in each applications, then use the event model to share data and state among all three applications.

Overall, the Portlet 2.0 spec can help make your code more modular and manageable. If you’re a portlet developer, you’ll want to investigate further to see if you should make the jump.

Naresh Devnani has 12 years of experience in the software industry, mostly in the Web world, out of which he has been using Java for close to 10 years. Currently, he is the managing director at Lean Management Group, where he is responsible for running the enterprise content management practice and also helps customers with architecture and design questions. Previously, he was chief architect in professional services at Vignette.