JSR 286 allows portlets to fire events and consume events. An event is first fired from the processAction method. Portlet container notifies a consumer portlet by invoking its processEvent method. A consumer portlet can also fire an event from the processEvent method.
There is no way to fire an event during the rendering phase.
For the event mechanism to work, you need to follow a few ground rules. This article discusses those.
Defining an Event
An event is first defined in portlet.xml. This definition has to exist for the portlet application of both the publisher and consumer.
An event has a namespace qualified name and a payload data type. For example:
<portlet-app …>
…
<event-definition>
<qname xmlns_x="https://www.webagesolutions.com">x:was</qname>
<value-type>com.mycom.address.model.Address</value-type>
</event-definition>
</portlet-app>
In this example, the qualified name of the event is as follows:
– Namespace URL is “https://www.webagesolutions.com”
– The local part is “was”
The Java class for the payload data is com.mycom.address.model.Address. We will discuss the requirements for this class shortly.
You can also define an event using a simple name instead of a qualified name.
<event-definition>
<name>AddressEvent</name>
<value-type>com.mycom.address.model.Address</value-type>
</event-definition>
This is not recommended. To avoid any naming conflict, you should always use the qualified name approach.
The Payload Class
The event payload class is declared using the <value-type> element in portlet.xml. This class can be a Java primitive class, such as String and Integer. If you wish to use your own class, it must conform to a few rules:
- Must implement java.io.Serializable
- Must have a JAXB binding. To quickly do that, use the @XmlRootElement annotation.
For example:
@XmlRootElement
public class Address implements Serializable {
//…
}
Firing an Event
The publisher portlet needs to declare all the events it will fire in portlet.xml.
<portlet>
…
<supported-publishing-event>
<qname xmlns_x="https://www.webagesolutions.com">x:was</qname>
</supported-publishing-event>
</portlet>
The local part and namespace URL must be exactly as stated in the event definition.
To fire an event, you need to call the setEvent method of either the ActionResponse or EventResponse object.
For example:
public void processAction(ActionRequest request, ActionResponse response)
throws PortletException, java.io.IOException {
//…
Address a = new Address();
response.setEvent(
new QName("https://www.webagesolutions.com", "was"), a);
}
Note how the namespace URI and local part of the QName object matches the event definition.
Consuming an Event
The consumer side needs to declare all the events it is interested in consuming.
<portlet>
…
<supported-processing-event>
<qname xmlns_x="https://www.webagesolutions.com">x:was</qname>
</supported-processing-event>
</portlet>
The namespace and local part must match the event definition. Otherwise, the consumer will not be notified.
Develop the processEvent method. This will be automatically called when a matching event is fired.
public void processEvent(EventRequest request, EventResponse response)
throws PortletException, IOException {
Event e = request.getEvent();
logger.info("Got an event.");
logger.info("QName: " + e.getQName());
logger.info("Name: " + e.getName());
logger.info("Value type: " + e.getValue().getClass().getName());
Address a = (Address) e.getValue(); //Get the payload
}
This method will print out something like this:
INFO: QName: {https://www.webagesolutions.com}was
INFO: Name: was
INFO: Value type: com.mycom.address.model.Address
In Conclusion
You need to be extra careful in making sure that the qualified name of an event is correct in every place. Otherwise, events will not be dispatched to the right consumer. Also make sure that the payload type is serializable and has a JAXB binding.