Chapter 6. InterPortlet Communication (IPC)
Prev |  | Next

## Chapter 6. InterPortlet Communication (IPC)

### Roy Russo

`<roy@jboss.org>`

## 6.1. Introduction

The first version of the Portlet Specification (JSR 168), regretfully, did not cover interaction between portlets on a page. The side-effect of diverting the issue to the subsequent release of the specification, has forced portal vendors to each craft their own proprietary API to achieve interportlet communication. This chapter covers the JBoss Portal Interportlet Communication API, and its ability to allow a developer to create links to other portal pages and affect behaviour in other portlets.

### Note

For the remainder of this chapter, the sample available here , will be used to cover the API.

### Warning

JBoss Portal IPC enables a one-to-one relationship between portlets! Do not attempt to affect behaviour of more than one portlet per action, as it will not work!

## 6.2. Configuration

### 6.2.1. Service Descriptor

IPC requires that a listener be available to intercept requests and respond appropriately. To enable the listener, it has to be declared as an mbean in your service descriptor, as in our example under helloworldipcportlet.sar/META-INF/jboss-service.xml :

    <server>
       <mbean code="org.jboss.portal.core.event.PortalEventListenerServiceImpl"
              name="portal:service=ListenerService,type=ipc_listener"
              xmbean-dd=""
              xmbean-code="org.jboss.portal.common.system.JBossServiceModelMBean">
          <depends optional-attribute-name="Registry" proxy-type="attribute">portal:service=ListenerRegistry</depends>
          <xmbean/>
          <attribute name="RegistryId">ipc_listener</attribute>
          <attribute name="ListenerClassName">org.jboss.portlet.hello.HelloWorldPortletB$Listener</attribute>
       </mbean>
    </server>

It is important to note here, that you will most likely not have to change any of these values, except for the following:

- name: Both the mbean type and the RegistryId value must match.
- ListenerClassName: Full path to the listening portet's inner class that acts as the listener.

### 6.2.2. Portal Descriptor

Enabling IPC, also requires that the listener be declared in the *-object.xml, so the Portal recognizes it. The declaration happens at the page level, as in our example:

    <deployments>
       <deployment>
          <parent-ref>default</parent-ref>
          <if-exists>overwrite</if-exists>
          <page>
             <page-name>IPC</page-name>
             <listener>ipc_listener</listener>
             <properties/>
    ...

### Note

The listener value must match the name values in your service descriptor!

### 6.2.3. The Listener

Now that the listener is configured in the service descriptor and the portal can recognize it, we must create the appropriate listener class within our portlet.

In our example, Portlet A will be modifying the behaviour of Portlet B. So then we will declare the listener in Portlet B, the recipient portlet.

       public static class Listener implements PortalNodeEventListener
       {
          public PortalNodeEvent onEvent(PortalNodeEventBubbler bubbler, PortalNodeEvent event)
          {
             PortalNode node = event.getNode();

             // Get node name
             String nodeName = node.getName();

             // See if we need to create a new event or not
             WindowActionEvent newEvent = null;
             if(nodeName.equals("HelloWorldPortletAWindow") && event instanceof WindowActionEvent)
             {
                // Find window B
                WindowActionEvent wae = (WindowActionEvent) event;
                PortalNode windowB = node.resolve("../HelloWorldPortletBWindow");
                if(windowB != null)
                {
                   // We can redirect and modify the view/mode as well!
                   newEvent = new WindowActionEvent(windowB);
                   newEvent.setMode(wae.getMode());
                   //newEvent.setWindowState(WindowState.MAXIMIZED);
                   newEvent.setParameters(wae.getParameters());
                }
             }

             if(newEvent != null)
             {
                // If we have a new event redirect to it
                return newEvent;
             }
             else
             {
                // Otherwise bubble up
                return bubbler.dispatch(event);
             }
          }
       }

It is important to note here some of the important items in this listener class. Logic used to determine if the requesting node was Portlet A.:

    nodeName.equals("HelloWorldPortletAWindow")

Get the current window object so we can dispatch the event to it:

    PortalNode windowB = node.resolve("../HelloWorldPortletBWindow");

Set the original parameter from Portlet A, so Portlet B can access them in its processAction():

    newEvent.setParameters(wae.getParameters());

Modify Portlet B windowmode and/or windowstate (ie, Maximize and place in Edit Mode):

                   newEvent.setMode(wae.getMode()); // wae.setMode(Mode.EDIT);
                   newEvent.setWindowState(wae.getWindowState()); // WindowState.MAXIMIZED

## 6.3. Communicating with another Portlet

Creating a link from Portlet A to Portlet B occurs in the same way you would normally create a PortletURL:

             html.append("<form action=\"" + resp.createActionURL() + "\" method=\"post\">");
             html.append("<input type=\"text\" name=\"sometext\"><br/>");
             html.append("<select name=\"color\">");
             html.append("<option>blue</option>");
             html.append("<option>red</option>");
             html.append("<option>black</option>");
             html.append("</select>");
             html.append("<input type=\"submit\"/>");
             html.append("</form>");

As you can see from the code above, we are creating a simple HTML form with an ActionURL from within Portlet A. It will target itself, but be intercepted by the listener, created in Portlet B. This form passes some text and a color value from input fields.

Now, in Portlet B, our listener innerclass will trigger the processAction() in Portlet B, reading in the parameters from the Portlet A form:

       public void processAction(JBossActionRequest request, JBossActionResponse response) throws PortletException, PortletSecurityException, IOException
       {
          String color = request.getParameter("color");
          String text = request.getParameter("sometext");
          if(color != null && text != null)
          {
             response.setRenderParameter("color", color);
             response.setRenderParameter("sometext", text);
          }
       }

Setting the render parameters, it will now pass them on to the Portlet B, doView();

## 6.4. Communicating with another Page

As seen in the included NavigationPortlet (tabs found at the top of the default layout), we are able to create links to Portal Pages. Included in the download sample , you can see the basics of creating a link to a Portal Page. I have added comments in-line to explain the code sample below:

    // Get the ParentNode. Since we are inside a Window, the Parent is the Page
    PortalNode thisNode = req.getPortalNode().getParent();

    // Get the Node in the Portal hierarchy tree known as "../default"
    PortalNode linkToNode = thisNode.resolve("../default");

    // Create a RenderURL to the "../default" Page Node
    PortalNodeURL pageURL = resp.createRenderURL(linkToNode);

    // Output the Node's name and URL for users
    html.append("Page: " + linkToNode.getName() + " -> ");
    html.append("<a href=\"" + pageURL.toString() + "\">" + linkToNode.getName() + "</a>");

Prev | Up | Next
Chapter 5. Security | Home | Chapter 7. Layouts and Themes