Communicating Between JSF Portlets Using IPC

Liferay Faces Bridge supports Portlet 2.0 Inter Portlet Communication (IPC), using the JSR 329/378 approach for supporting Portlet 2.0 Events and Portlet 2.0 Public Render Parameters.

You can visit the Liferay Faces Demos home page to see portlets that demonstrate the IPC techniques described in this tutorial. At that location, you’ll also find portlets that implement Ajax Push for IPC, using ICEfaces+ICEPush and PrimeFaces+PrimePush.

For the first tutorial, you’ll learn how to use Portlet 2.0 Public Render Parameters.

Using Portlet 2.0 Public Render Parameters

The Public Render Parameters technique provides a way for portlets to share data by setting public/shared parameter names in a URL controlled by the portal. While the benefit of this approach is that it is relatively easy to implement, the drawback is that only small amounts of data can be shared. Typically the kind of data that is shared is simply the value of a database primary key. As required by the Portlet 2.0 standard, Public Render Parameters must be declared in the WEB-INF/portlet.xml descriptor.

This example excerpt from a WEB-INF/portlet.xml descriptor demonstrates setting a public render parameter for a customer ID, shared between a Customers portlet and a Bookings portlet:

<portlet>
    <portlet-name>customersPortlet</portlet-name>
    <supported-public-render-parameter>selectedCustomerId</supported-public-render-parameter>
</portlet>
<portlet>
    <portlet-name>bookingsPortlet</portlet-name>
    <supported-public-render-parameter>selectedCustomerId</supported-public-render-parameter>
</portlet>
<public-render-parameter>
    <identifier>selectedCustomerId</identifier>
    <qname xmlns:x="http://liferay.com/pub-render-params">x:selectedCustomerId</qname>
</public-render-parameter>

Fortunately, the JSR 329/378 standard defines a mechanism for you to use Portlet 2.0 Public Render Parameters for IPC in a way that is more natural to JSF development. Section 5.3.2 of this standard requires the bridge to inject the public render parameters into the Model concern of the MVC design pattern (as in JSF model managed-beans) after the RESTORE_VIEW phase completes. This is accomplished by evaluating the EL expressions found in the <model-el>...</model-el> section of the WEB-INF/faces-config.xml descriptor. The faces-config.xml descriptor excerpt below demonstrates using this mechanism for the example Customers and Bookings portlets:

<faces-config>
    <application>
        <application-extension>
            <bridge:public-parameter-mappings>
                <bridge:public-parameter-mapping>
                    <parameter>customersPortlet:selectedCustomerId</parameter>
                    <model-el>#{customersModelBean.selectedCustomerId}</model-el>
                </bridge:public-parameter-mapping>
                <bridge:public-parameter-mapping>
                    <parameter>bookingsPortlet:selectedCustomerId</parameter>
                    <model-el>#{bookingsModelBean.selectedCustomerId}</model-el>
                </bridge:public-parameter-mapping>
            </bridge:public-parameter-mappings>
        </application-extension>
    </application>
</faces-config>

Section 5.3.2 of the JSR 329/378 standard also requires that if a bridgePublicRenderParameterHandler has been registered in the WEB-INF/portlet.xml descriptor, then the handler must be invoked so that it can perform any processing that might be necessary. Optionally, you can implement and register a bridgePublicRenderParameterHandler for processing public render parameters.

For example, a BridgePublicRenderParameterHandler for processing public render params for the Bookings portlet’s currently selected customer could be stubbed out like the following class code:

package com.liferay.faces.example.handler;

import javax.faces.context.FacesContext;

import com.liferay.faces.bridge.BridgePublicRenderParameterHandler;

public class CustomerSelectedHandler
implements BridgePublicRenderParameterHandler {

    public void processUpdates(FacesContext facesContext) {
        // Here is where you would perform any necessary processing of public
        // render parameters
    }

}

For the BridgePublicRenderParameterHandler to be invoked, it must be registered in an <init-param> element within the portlet’s <portlet> element in the WEB-INF/portlet.xml descriptor:

<init-param>
    <name>javax.portlet.faces.bridgePublicRenderParameterHandler</name>
    <value>com.liferay.faces.example.handler.CustomerSelectedHandler</value>
</init-param>

Now that you’ve explored Public Render Parameters for JSF in IPC, you’ll learn about Events in IPC.

Handling Portlet 2.0 Events

In Portlet 2.0, you can leverage a server-side events technique that uses an event-listener design to share data between portlets. When using this form of IPC, the portlet container acts as a broker and distributes events and payload (data) to portlets. One requirement of this approach is that the payload must implement the java.io.Serializable interface since it might be sent to a portlet in another .war file running in a different classloader. In addition, the Portlet 2.0 standard requires the events to be declared in the WEB-INF/portlet.xml descriptors of the involved portlets.

The following example WEB-INF/portlet.xml descriptor snippets define an IPC event for when a Customer is edited in the example Bookings portlet. The bookingsPortlet portlet is registered as the event’s publisher (or sender). The customersPortlet portlet, on the other hand, is registered as a processor (or listener) for that event type. Consequently, when a Customer is edited in the bookingsPortlet portlet, that portlet publishes the event and the customersPortlet portlet is notified for processing the event.

Here’s a snippet from the Customers portlet’s portlet.xml descriptor:

<portlet>
    <portlet-name>customers</portlet-name>

    ...

    <supported-processing-event>
        <qname xmlns:x="http://liferay.com/events">x:ipc.customerEdited</qname>
    </supported-processing-event>
</portlet>


...

<event-definition>
    <qname xmlns:x="http://liferay.com/events">x:ipc.customerEdited</qname>
    <value-type>com.liferay.faces.demos.dto.Customer</value-type>
</event-definition>

The snippet from the Bookings portlet’s portlet.xml is similar, except it is specified as a publisher:

<portlet>
    <portlet-name>bookings</portlet-name>

    ...

    <supported-publishing-event>
        <qname xmlns:x="http://liferay.com/events">x:ipc.customerEdited</qname>
    </supported-publishing-event>
</portlet>

...

<event-definition>
    <qname xmlns:x="http://liferay.com/events">x:ipc.customerEdited</qname>
    <value-type>com.liferay.faces.demos.dto.Customer</value-type>
</event-definition>

Optionally, you can implement a BridgeEventHandler for an event type and register the handler in the WEB-INF/portlet.xml descriptor. If a BridgeEventHandler has been registered in the WEB-INF/portlet.xml descriptor, Section 5.2.5 of the JSR 329/378 standard requires that the handler must be invoked so that it can perform any event processing that might be necessary.

When the customer’s details (such as first name/last name) are edited in the Bookings portlet, the event named ipc.customerEdited is sent back to the Customers portlet and is processed by the following CustomerEditedEventHandler class:

...

import javax.faces.context.FacesContext;
import javax.portlet.Event;
import javax.portlet.faces.BridgeEventHandler;
import javax.portlet.faces.event.EventNavigationResult;

...

public class CustomerEditedEventHandler implements BridgeEventHandler {

        ...

        public EventNavigationResult handleEvent(FacesContext facesContext, Event event) {
                EventNavigationResult eventNavigationResult = null;
                String eventQName = event.getQName().toString();

                if (eventQName.equals("{http://liferay.com/events}ipc.customerEdited")) {
                    ...
                }

                return eventNavigationResult;
        }

        ...
}

And here’s the descriptor for registering the CustomerEditedEventHandler class as a bridge event handler for the Customers portlet. The following <init-param> belongs in the Customers portlet’s <portlet> element, in the WEB-INF/portlet.xml descriptor.

<init-param>
    <name>javax.portlet.faces.bridgeEventHandler</name>
    <value>com.liferay.faces.example.event.CustomerEditedEventHandler</value>
</init-param>

You’ve explored some common basic JSF portlet development topics dealing with IPC. These techniques should help launch you into development of your own JSF portlet development using IPC!

Related Topics

Contexts and Dependency Injection for JSF Portlets

Liferay Faces Alloy UI Components

Liferay Faces Bridge UI Components

Understanding Liferay Faces Bridge

Understanding Liferay Faces Portal

Understanding Liferay Faces Alloy

0 (0 Votes)
Localizing JSF Portlets Previous