Gerald Nunn's Blog

« Portlet Render Dependencies and CSS Image References | Main | Evil Overlord 101 »

Delivering Data from Portal Events to Page Flows

Friday, January 11, 2008

If you are working on a portlet project you likely will be familiar with inter-portlet communication (IPC) and Java Page Flows (JPFs). When creating IPC events, one option that is available is to invoke a JPF action in response to the event. One question that often arises though is how do you deliver data to that action?

For example, let's say you have an e-commerce portal and you have a portlet that displays an individual product. This portlet has an event that can be invoked by other portlets to display a selected product and the event that is fired contains a payload that holds the product name. So now the JPF action that is being invoked needs to get that product name in order to process it. A traditional way of doing this is to have a backing file unpack the payload and store it in the request or session where it can be retrieved by the JPF action. I've done it this way myself many times, but Nathan Lipke, one of our Portal engineers, pointed out an alternative way to handle this scenario.

It is not well documented, but if the event payload object extends the org.apache.struts.action.ActionForm object it can be delivered directly to the JPF action method without requiring the use of an intermediate backing file. Let's look at an example to make this clearer.

Using our previous example of selecting a product, here is a payload object that we define to allow one portlet to pass the selected product to another object.

public class ProductBean extends ActionForm implements Serializable {

    private String product;

    public ProductBean() {

    }

    public ProductBean(String product) {
        this.product = product;
    }

    public String getProduct() {
        return product;
    }

    public void setProduct(String product) {
        this.product = product;
    }

    @Override
    public String toString() {
        return super.toString()+"["+product+"]";
    }
}

Now we need to define an action in the JPF in our portlet to be notified when the event is fired as follows.

@Jpf.Action(forwards = { @Jpf.Forward(name = "success", path = "product.jsp") })
public Forward displayProduct(ProductBean bean) {
    this.product = bean.getProduct();
    return new Forward("success");
}

In the portlet itself, create an event handler as normal and add the invoke page flow action to the handler specifying the displayProduct action we created previously. Here is an example of how the XML would look in the .portlet file.

<netuix:handleCustomEvent event="displayProductEvent"
	eventLabel="handleDisplayProductEvent" fromSelfInstanceOnly="false"
	onlyIfDisplayed="false">
	<netuix:invokePageFlowAction action="displayProduct" />
</netuix:handleCustomEvent>

Finally in the other portlet we need to fire the event using the PortletBackingContext as follows:

PortletBackingContext pbc = PortletBackingContext.getPortletBackingContext(getRequest());
pbc.fireCustomEvent("displayProductEvent", new ProductBean(selectedProduct));

That's basically it, as mentioned previously the key to making this work is having the event payload extend the ActionForm object. Thanks again to Nathan Lipke for pointing this out to me.

Posted by Gerald Nunn at 4:01 PM | Categories: | Permalink