This section explains about the steps to develop Inter Portlet Communication (IPC) sample portlets. The topics include:
Inter Portlet Communication API
Event Generation and Subscription
Event Handling Life Cycle
Infinite Event Cycle Detection
Deterministic Behavior
Failure and Exception Handling
Portlets can communicate with each other even if they are in different web applications. It is assumed that all the sample portlets are on the same instance of a Portal Server. The Inter Portlet Communication API uses event generation and notification to convey the information or data among portlets. The event notification occurs for the portlets, which are registered themselves for listening to that particular event.
The IPC API is located in the com.sun.portal.portlet package. Portlets that are interested in receiving an event implements a single interface, PortletEventListener.
public interface PortletEventListener { public void handleEvent(EventRequest ereq, EventResponse eres) throws PortletException; }
You can use EventRequest to obtain the event name and event payload data. You can obtain Event payload data either by getting the event stream and reading from it or by calling getEventData() method which returns an Object and then casting it appropriately. If getEventData() is called after getting the event stream an IllegalStateException is thrown. Similarly, if getEventStream() is called after getEventData() an IllegalStateException is thrown.
public interface EventRequest() { public String getEventName(); public InputStream getEventStream(); public Object getEventData(); }
You can use EventResponse to set the render parameters, so that the information can be passed on to the render method after processing the event received in the handleEvent() method.
public interface EventResponse() { public void setRenderParameters(Map parmMap); public void setRenderParameter(String key, String value); public void setRenderParameter(String key, String[] values); }
The portlets can generate events only from within the handleEvent() or processAction() methods. Event can be generated by instantiating PortletEventBroker and calling createEvent() method on it. The PortletEventBroker constructor throws an IllegalStateException if you call from methods other than the handleEvent() or processAction().
public class PortletEventBroker { //Make sure that the call is coming from handleEvent() or from processAction() public PortletEventBroker(PortletRequest pr); //to create an event ... public PortletEvent createEvent(String eventName) throws EventNotRegisteredException; }
You can then use the PortletEventBroker instance to create an event by calling the createEvent() method.
public interface PortletEvent { public String getEventName(); public OutputStream getEventStream(); public void setEventData(Serializable s); public void fire(); }
You can set the event data can on the event stream which can be obtained by calling getEventStream() method. Alternatively, event data can be set by calling setEventData() method. If after obtaining the event stream, attempt to call setEventData() throws the IllegalStateException exception. Similarly, after calling setEventData() an attempt to call the getEventStream() throws the IllegalStateException exception. The event is then fired by calling the fire() method.
All the portlets which are interested in listening or generating an event must declare it in the sun-portlet.xml file as shown below:
<portlet> <portlet-name>NAME</portlet-name> . <!-- Other declarations --> . <events> <generates-event>NAME</generates-event> <generates-event>NAME</generates-event> . . . <consumes-event>NAME</consumes-event> <consumes-event>NAME</consumes-event> . . . </events> </portlet>
If a portlet requests an event, which it has not declared in the sun-portal.xml file, an exception NotRegisteredException is thrown. Wildcards cannot be used for declaring the events that are generated. Portlets interested in consuming all the events can use wildcard character (*) as shown below:
<portlet> <portlet-name>NAME</portlet-name> . <!-- Other declarations --> . <events> <generates-event>NAME</generates-event> <generates-event>NAME</generates-event> . . . <consumes-event>*</consumes-event> </events> </portlet>
The event cycle starts with the response to user interaction from the inside processAction method. These are Generation 1 events. These events are placed in the event queue by the Portlet Container and dispatched in the order they are created. The dispatching of the events continue, until all the events in the event queue are dispatched to appropriate portlets.
Dispatching of the events amount to calling the handleEvent methods of the appropriate portlets. Portlets can generate events in the handleEvent method which are Generation next events. If a portlet has subscribed to events which are generated in different generations, it will receive the events in proper order. It means that the handleEvent will be called with Generation ith event first and upon completion of that method, handleEvent will be called with event from Generation i+1.
Events are generated in response to the user interaction (Generation 1) or in response to other events (Generation next). This could lead to create more generations. To control the number of generations, the maxEventGenerations parameter in the desktopConfig.properties file can be configured for maximum number of generations of events per request. When the event creation exceeds the specified maximum number, a failure event, eventHandlingFailed will be sent to all the participating portlets.
If a portlet generates events X and Y in that order, then events X and Y are delivered to the portlets in that same order. If portlet A and B are interested in Event X, either A or B can get event X first. If portlets A and B are interested in Event X, and upon receipt of that event, generate events Y and Z respectively. If portlet C is interested in Event Y and Z, then portlet C can receive events Y and Z in any order.
In case of failure, handleEvent() method may throw PortletException. Container will catch that exception and stop sending the events from the event queue. Container then sends another event called eventHandlingFailed to all the portlets participating in that particular interaction. Container does not take any action if the PortletException is thrown while processing eventHandlingFailed event. Portlets can not generate and send any events while handling the event eventHandlingFailed. The portlet developer has the responsibility to take appropriate action needed.