Showing posts with label portletevent. Show all posts
Showing posts with label portletevent. Show all posts

Wild cards in process supported-processing-event or supported-publishing events

In the Patterns in ProcessEvent annotation entry i talked about how you can use . as wild card character while annotating methods that should be used for handling the event. But the concept of wild card also applies to the supported-processing-event or supported-publishing-event. This is what the Portlet Specification says

"The portlet is encouraged to organize the local part of the event names in the event-definition element in a hierarchical manner using the dot ‘.’ as separator. A trailing '.'tells the Consumer that this is not the end of the hierarchy and the Portlet is interested in all events with names in this branch of the hierarchy. The portlet must not specify events with the same name but different types. Event names in the event-definition element hould not end with a trailing “.” character as wildcards are not supported in the event 0 definition level. Wildcards should only be used in the supported-processing-event or supported-publishing-event elements and should be able to be resolved by the portlet container to an event definition without wildcards in the event-definition element by matching event names ending with a "." character to any event whose local name starts with the characters before the "." character and also specifies the same namespace. If the wildcard string should match a part of a hierarchy two dots are required at the end of the wildcard string: one to denote the hierarchy and one for the wildcard: “foo.bar..”."

Basic idea is while declaring event you will have to specify fully qualified name of the event and you should use a hierarchical name such as say com.webspherenotes.events.contact, com.webspherenotes.events.address, com.webspherenotes.events.phone But while declaring which portlets can publish or subscribe the event you can use wild character like this com.webspherenotes.events..

Take a look at this sample portlet.xml

<?xml version="1.0" encoding="UTF-8"?>
<portlet-app xmlns="http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd"
version="2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd">
<portlet>
<portlet-name>ProcessEventAnnotationPortlet</portlet-name>
<display-name>Process Event Annotation Portlet</display-name>
<portlet-class>com.webspherenotes.portlet.jsr286.ProcessEventAnnotationPortlet</portlet-class>
<expiration-cache>0</expiration-cache>
<supports>
<mime-type>text/html</mime-type>
<portlet-mode>view</portlet-mode>
<portlet-mode>edit</portlet-mode>
</supports>
<portlet-info>
<title>Process Event Annotation Portlet</title>
<short-title>Process Event Annotation Portlet</short-title>
<keywords>Process Event Annotation Portlet</keywords>
</portlet-info>
<supported-processing-event>
<name>com.webspherenotes.events.</name>
</supported-processing-event>
<supported-publishing-event>
<name>com.webspherenotes..</name>
</supported-publishing-event>

</portlet>

<default-namespace>http://wpcertification.blogspot.com</default-namespace>
<event-definition>
<name>com.webspherenotes.events.contact</name>
<value-type>com.webspherenotes.portlet.events.Contact</value-type>
</event-definition>
<event-definition>
<name>com.webspherenotes.events.address</name>
<value-type>com.webspherenotes.portlet.events.Address</value-type>
</event-definition>
<event-definition>
<name>com.webspherenotes.events.phone</name>
<value-type>com.webspherenotes.portlet.events.Phone</value-type>
</event-definition>

</portlet-app>


The ProcessEventAnnotationPortlet can process all events starting with com.webspherenotes.events but it can publish all the events starting with com.webspherenotes

Patterns in ProcessEvent annotation

In the ProcessEvent annotation entry i built a sample portlet to demonstrate how we can use @ProcessEvent annotation.

When the processEvent() method in GenericPortlet gets invoked, first it checks if there there is exact match of event name and the value of name attribute of @ProcessEvent annotation. If it does not find exact match it tries to find the longest possible match using following rule

"If the local part of the event name has a wildcard at the end (“.”) the GenericPortlet will try to match the received event either to the same wildcard event name or to the longest matching event name for this wildcard. E.g. if an event with the local part of the event name of "a.b.c.d" is being received and there are methods annotated for handling "a.b." and "a.b.c." events in this portlet, the GenericPortlet will dispatch the event to the method annotated with "a.b.c."

Lets say this is how portelt.xml of my target portlet looks like


<?xml version="1.0" encoding="UTF-8"?>
<portlet-app xmlns="http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd"
version="2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd">
<portlet>
<portlet-name>ProcessEventAnnotationPortlet</portlet-name>
<display-name>Process Event Annotation Portlet</display-name>
<portlet-class>com.webspherenotes.portlet.jsr286.ProcessEventAnnotationPortlet</portlet-class>
<expiration-cache>0</expiration-cache>
<supports>
<mime-type>text/html</mime-type>
<portlet-mode>view</portlet-mode>
<portlet-mode>edit</portlet-mode>
</supports>
<portlet-info>
<title>Process Event Annotation Portlet</title>
<short-title>Process Event Annotation Portlet</short-title>
<keywords>Process Event Annotation Portlet</keywords>
</portlet-info>
<supported-processing-event>
<name>com.webspherenotes.events.contact</name>
</supported-processing-event>
</portlet>
<default-namespace>http://wpcertification.blogspot.com</default-namespace>
<event-definition>
<name>com.webspherenotes.events.contact</name>
<value-type>com.webspherenotes.portlet.events.Contact</value-type>
</event-definition>


</portlet-app>


The ProcessEventAnnotationPortlet can consume com.webspherenotes.events.contact event. So these are some of the @ProcessEvent combination that i can use to handle this event


  1. @ProcessEvent(qname="{http://wpcertification.blogspot.com}com.webspherenotes.events.contact"): Fully qualified event name

  2. @ProcessEvent(qname="{http://wpcertification.blogspot.com}com.webspherenotes."): Fully qualified event name, so this method can handle all the events starting with com.webspherenotes.*, it could be com.webspherenotes.events.contact,com.webspherenotes.events.hello

  3. @ProcessEvent(name = "com.webspherenotes."): Means it can handle all the events where local name starts with com.webspherenotes.*

ProcessEvent annotation

This is how the default implementation of the processEvent() method in GenricPortlet looks like,

public void processEvent(EventRequest request, EventResponse response) throws PortletException, IOException {
String eventName = request.getEvent().getQName().toString();
try {
// check for exact match
Method eventMethod = processEventHandlingMethodsMap.get(eventName);
if (eventMethod != null) {
eventMethod.invoke(this, request, response);
return;
} else {
// Search for the longest possible matching wildcard annotation
int endPos = eventName.indexOf('}');
int dotPos = eventName.lastIndexOf('.');
while (dotPos > endPos) {
String wildcardLookup = eventName.substring(0, dotPos + 1);
eventMethod = processEventHandlingMethodsMap.get(wildcardLookup);
if (eventMethod != null) {
eventMethod.invoke(this, request, response);
return;
}
if (dotPos == 0) {
break;
}
dotPos = eventName.lastIndexOf('.', dotPos - 1);
}
}
} catch (Exception e) {
throw new PortletException(e);
}
// if no event processing method was found just keep render params
response.setRenderParameters(request);
}


First it tries to figure out if there is a method with @ProcessEvent annotation, that matches current event, if yes it forwards control to that method if not it sets the current render parameters as new render parameters.

You can annotate a method use ProcessEvent annotation using two different approaches

  • Using QName: You can specify the fully qualified name of the event using "{" + Namespace URI + "}" + local part format. Ex. @ProcessEvent(qname="{http://wpcertification.blogspot.com}hello")

  • Using local Name:For using only the local part of the event name and leverage the default namespace defined in the portlet deployment descriptor with the default-namespace element the following alternative is provided: @ProcessEvent (name=), where the event name is only the local part.



You can download the sample portlet that i built to demonstrate how to use @ProcessEvent from here


package com.webspherenotes.portlet.jsr286;

import java.io.IOException;

import javax.portlet.Event;
import javax.portlet.EventRequest;
import javax.portlet.EventResponse;
import javax.portlet.GenericPortlet;
import javax.portlet.PortletException;
import javax.portlet.ProcessEvent;
import javax.portlet.RenderRequest;
import javax.portlet.RenderResponse;

import com.webspherenotes.portlet.events.Contact;

public class ProcessEventAnnotationPortlet extends GenericPortlet {

protected void doView(RenderRequest request, RenderResponse response)
throws PortletException, IOException {
System.out.println("Entering ProcessActionAnnotationPortlet.doView()");
response.setContentType("text/html");
Contact contact = (Contact) request.getPortletSession().getAttribute(
"contact");
if (contact != null) {
response.getWriter().println(
"First Name " + contact.getFirstName() + "
Last Name "
+ contact.getLastName() + "
Email "
+ contact.getEmail());
} else {
response.getWriter().println("Contact not found in session ");
}
System.out.println("Exiting ProcessActionAnnotationPortlet.doView()");
}

//@ProcessEvent(name = "hello")
@ProcessEvent(qname="{http://wpcertification.blogspot.com}hello")
public void handleContactEvent(EventRequest request, EventResponse response)
throws PortletException, IOException {
System.out
.println("Entering ProcessActionAnnotationPortlet.handleContactEvent()");
Event event = request.getEvent();
System.out.println("Event Name " + event.getName());
System.out.println("Event Value " + event.getValue());
Contact contact = (Contact) event.getValue();
System.out.println("Contact First Name " + contact.getFirstName());
System.out.println("Contact Last Name " + contact.getLastName());
System.out.println("Contact Email " + contact.getEmail());
request.getPortletSession().setAttribute("contact", contact);
System.out
.println("Entering ProcessActionAnnotationPortlet.handleContactEvent()");
}

}


The ProcessEventAnnotationPortlet can act as target of hello event. It has a handleContactEvent method that can be used for handling the hello event. I can annotate it using either only local name like this @ProcessEvent(name = "hello") or using fully qualified name like this @ProcessEvent(qname="{http://wpcertification.blogspot.com}hello")

This is the portlet.xml for my Sample portlet

<?xml version="1.0" encoding="UTF-8"?>
<portlet-app xmlns="http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd"
version="2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd">
<portlet>
<portlet-name>ProcessEventAnnotationPortlet</portlet-name>
<display-name>Process Event Annotation Portlet</display-name>
<portlet-class>com.webspherenotes.portlet.jsr286.ProcessEventAnnotationPortlet</portlet-class>
<expiration-cache>0</expiration-cache>
<supports>
<mime-type>text/html</mime-type>
<portlet-mode>view</portlet-mode>
<portlet-mode>edit</portlet-mode>
</supports>
<portlet-info>
<title>Process Event Annotation Portlet</title>
<short-title>Process Event Annotation Portlet</short-title>
<keywords>Process Event Annotation Portlet</keywords>
</portlet-info>
<supported-processing-event>
<name>hello</name>
</supported-processing-event>

</portlet>
<default-namespace>http://wpcertification.blogspot.com</default-namespace>
<event-definition>
<name>hello</name>
<value-type>com.webspherenotes.portlet.events.Contact</value-type>
</event-definition>

</portlet-app>

Reading the portlet.xml file everytime

When i was playing with Portlet Event on WebSPhere Portal Server, i noticed that if you add new events in the portlet.xml file after deploying portlet, that event does not get picked up.

Ex. First i did add hello event in portlet.xml and deployed it, created a wire and then i did add greeting event in both source and target and deployed them on WPS. After that when i tried creating wire the new events were not showing up in the Portlet Wiring Tool portlet. Only way i could get it working was by first uninstalling and then reinstalling the portlet. So i started looking for solution for what i can do to avoid this reinstalling of portlet application for my new events to show up.

It seems that when we deploy portlet on WPS for first time then portal reads the portlet.xml and caches information like events, preferences,... After that when we update the portlet it does not read the portlet.xml. You can change this behavior by changing value of cleanup.deployment.descriptors property in DeploymentService.


#
# If you set this property to true, all existing settings are cleared and deleted,
# and only the new settings found in the portlet.xml are created.

# Default = false
#cleanup.deployment.descriptors = false


After changing value of cleanup.deployment.descriptors to true like this i could see my changes in portlet.xml getting reflected with uninstall-reinstalling portlet again.

Handling portlet events in Spring Portlet MVC Framework

The Spring Portlet MVC Framework has concept of EventAwareController that can be implemented by your Controller class to indicate that it can handle events.

I built two sample portlets one is SpringSourcePortlet and other is SpringTargetPortlet to demonstrate how you can send and receive events in Spring Portlet MVC framework application. You can download the sample code from here

  1. Contact

  2. SpringSourcePortlet

  3. SpringTargetPortlet



I followed these steps to create my sample application

  • First create Contact.java in separate Java project like this

    package com.webspherenotes.portlet.events;

    import java.io.Serializable;
    import javax.xml.bind.annotation.XmlRootElement;

    @XmlRootElement
    public class Contact implements Serializable{
    private static final long serialVersionUID = -1637774642655976822L;
    private String firstName;
    private String lastName;
    private String email;
    public Contact(){
    }
    public Contact(String firstName, String lastName, String email) {
    super();
    this.firstName = firstName;
    this.lastName = lastName;
    this.email = email;
    }
    public String getFirstName() {
    return firstName;
    }
    public void setFirstName(String firstName) {
    this.firstName = firstName;
    }
    public String getLastName() {
    return lastName;
    }
    public void setLastName(String lastName) {
    this.lastName = lastName;
    }
    public String getEmail() {
    return email;
    }
    public void setEmail(String email) {
    this.email = email;
    }
    }


    The Contact.java implements Serializable object and has @XmlRootElement annotation to indicate that this object can be passed either locally or using WSRP

  • Create SpringSourcePortlet using Spring Portlet MVC Framework. In that create ViewModeController.java like this

    package com.webspherenotes.portlet.spring;

    import javax.portlet.ActionRequest;
    import javax.portlet.ActionResponse;
    import javax.portlet.RenderRequest;
    import javax.portlet.RenderResponse;

    import org.springframework.web.portlet.ModelAndView;
    import org.springframework.web.portlet.mvc.AbstractController;

    import com.webspherenotes.portlet.events.Contact;

    public class ViewModeController extends AbstractController{

    public void handleActionRequest(ActionRequest request,
    ActionResponse response) throws Exception {
    System.out.println("Entering ViewModeController.handleActionRequest");
    String fName = request.getParameter("fName");
    String lName = request.getParameter("lName");
    String email = request.getParameter("email");
    Contact contact = new Contact(fName, lName, email);
    response.setEvent("hello", contact);
    request.getPortletSession().setAttribute("contact", contact);
    System.out.println("Exiting ViewModeController.handleActionRequest");
    }

    public ModelAndView handleRenderRequest(RenderRequest request,
    RenderResponse response) throws Exception {
    System.out.println("Entering ViewModeController.handleRenderRequest");
    response.setContentType("text/html");
    ModelAndView modelAndView = new ModelAndView("source");
    if (request.getPortletSession().getAttribute("contact") != null) {
    modelAndView.addObject("contact", request.getPortletSession()
    .getAttribute("contact"));
    }
    System.out.println("Exiting ViewModeController.handleRenderRequest");
    return modelAndView;
    }
    }


    The handleRenderRequest() method of the ViewModeController, forwards control to source.jsp for generating markup. The source.jsp displays a form to user.

    The handleActionRequest() method of ViewModeController gets called when user enters values on Contact form and clicks submit. Inside this method i am reading values submitted by user, then creating a Contact object and passing it as value of the event.

  • This is how my SpringSourcePortlet-portlet.xml file looks like

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xsi:schemaLocation="
    http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
    <bean id="viewController"
    class="com.webspherenotes.portlet.spring.ViewModeController" />
    <bean id="portletModeHandlerMapping"
    class="org.springframework.web.portlet.handler.PortletModeHandlerMapping">
    <property name="order" value="1" />
    <property name="portletModeMap">
    <map>
    <entry key="view">
    <ref bean="viewController" />
    </entry>
    </map>
    </property>
    </bean>
    <bean id="viewResolver"
    class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <property name="viewClass">
    <value>org.springframework.web.servlet.view.JstlView</value>
    </property>
    <property name="prefix">
    <value>/WEB-INF/jsp/</value>
    </property>
    <property name="suffix">
    <value>.jsp</value>
    </property>
    </bean>
    </beans>

    The SpringSourcePortlet has only one controller class which is ViewModeController and it is set as a default VIEW mode controller

  • Next create SpringTargetPortlet and inside that create ViewModeController.java like this

    package com.webspherenotes.portlet.spring;

    import javax.portlet.Event;
    import javax.portlet.EventRequest;
    import javax.portlet.EventResponse;
    import javax.portlet.RenderRequest;
    import javax.portlet.RenderResponse;

    import org.springframework.web.portlet.ModelAndView;
    import org.springframework.web.portlet.mvc.AbstractController;
    import org.springframework.web.portlet.mvc.EventAwareController;

    import com.webspherenotes.portlet.events.Contact;

    public class ViewModeController extends AbstractController implements EventAwareController{
    public ModelAndView handleRenderRequest(RenderRequest request,
    RenderResponse response) throws Exception {
    System.out.println("Entering ViewModeController.handleRenderRequest");
    response.setContentType("text/html");
    Contact contact = (Contact) request.getPortletSession().getAttribute(
    "contact");
    if (contact != null) {
    response.getWriter().println(
    "First Name " + contact.getFirstName() + "
    Last Name "
    + contact.getLastName() + "
    Email "
    + contact.getEmail());
    } else {
    response.getWriter().println("Contact not found in session ");
    }
    System.out.println("Entering ViewModeController.handleRenderRequest");
    return new ModelAndView();
    }


    public void handleEventRequest(EventRequest request, EventResponse response)
    throws Exception {
    System.out.println("Entering ViewModeController.handleEventRequest");
    Event event = request.getEvent();
    System.out.println("Event Name " + event.getName());
    Contact contact = (Contact) event.getValue();
    System.out.println("Contact First Name " + contact.getFirstName());
    System.out.println("Contact Last Name " + contact.getLastName());
    System.out.println("Contact Email " + contact.getEmail());
    request.getPortletSession().setAttribute("contact", contact);
    System.out.println("Exiting ViewModeController.handleEventRequest");
    }

    }

    The ViewModeController.java implements EventAwareController interface to indicate that it can be used for handling events. It has a handleEventRequest method that will get called when it receives event. Inside this method we get access to EventRequest and EventResponse object. I am reading Contact object which was passed as event payload and setting it as attribute in the PortletSession.

    The handleRenderRequest() method reads the value of Contact object from the PortletSession and then displays those values to the user

  • This is how the SpringTargetPortlet-portlet.xml file of SpringTargetPortlet looks like

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xsi:schemaLocation="
    http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
    <bean id="viewController"
    class="com.webspherenotes.portlet.spring.ViewModeController" />
    <bean id="portletModeHandlerMapping"
    class="org.springframework.web.portlet.handler.PortletModeHandlerMapping">
    <property name="order" value="1" />
    <property name="portletModeMap">
    <map>
    <entry key="view">
    <ref bean="viewController" />
    </entry>
    </map>
    </property>
    </bean>
    <bean id="viewResolver"
    class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <property name="viewClass">
    <value>org.springframework.web.servlet.view.JstlView</value>
    </property>
    <property name="prefix">
    <value>/WEB-INF/jsp/</value>
    </property>
    <property name="suffix">
    <value>.jsp</value>
    </property>
    </bean>
    </beans>

    The SpringTargetPortlet has only one ViewModeController and it is set as default controller for the VIEW mode.

Passing Complex Events in WSRP

In the Passing complex objects in portlet events entry i talked about how you can pass complex/custom objects as event payload.

You can download the sample code for this project from here

  1. Contact

  2. EventSource

  3. EventTarget



But you will have to make some additional changes to your portlet if you want to pass these object between portlets installed on different severs using WSRP. In case when objects are hosted on different server then portal server will serialize the complex object using JAXB and then send it to consumer. I changed my existing Contact object like this to make it work in WSRP


package com.webspherenotes.portlet.events;

import java.io.Serializable;
import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement
public class Contact implements Serializable{
private static final long serialVersionUID = -1637774642655976822L;
private String firstName;
private String lastName;
private String email;
public Contact(){
}
public Contact(String firstName, String lastName, String email) {
super();
this.firstName = firstName;
this.lastName = lastName;
this.email = email;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}


I had to annotate the Contact object by adding @XmlRootElement this. You will have to copy the contact.jar in shared library of both producer and consumer. Also make sure that Contact class has no-arg constructor.


When my Contact.java class did not had constructor i was getting error like this.


[5/19/10 9:48:13:456 PDT] 00000071 PropertyDispa E com.ibm.wps.propertybroker.dispatch.PropertyDispatcherImpl dispatchSourceEvents EJPKB1002E: The propertybroker encountered an error while dispatching the source event {http://wpcertification.blogspot.com}hello from portlet window Control@1598316356 (SourcePortlet, [ObjectIDImpl '7_VVILMKG1009800I2DO701500G7', NAVIGATION_NODE, VP: 0, [Domain: rel], DB: 0000-FFCB6A290C00240480140D1F100A00F0], [ObjectIDImpl '6_VVILMKG10G4K30I2A4E1UM2007', CONTENT_NODE, VP: 0, [Domain: rel], DB: 0000-FFCB6A290C00123A80148AB8E0AD00E0], 100 with value com.webspherenotes.portlet.events.Contact@212c212c.
com.ibm.portal.propertybroker.exceptions.CommunicationTargetDispatchException: EJPKB1001E: An Error occurred while dispatching to the communication target

process.{http://wpcertification.blogspot.com}hello
11_VVILMKG1009800I2DO701500O3

{http://wpcertification.blogspot.com}hello
com.ibm.wps.pe.pc.util.JAXBEventPayloadWrapper
{http://wpcertification.blogspot.com}hello


for window Control@1605918648 (TargetPortlet, [ObjectIDImpl '7_VVILMKG1009800I2DO70150040', NAVIGATION_NODE, VP: 0, [Domain: rel], DB: 0000-FFCB6A290C00240480140D1F100A0004], [ObjectIDImpl '6_VVILMKG10G4K30I2A4E1UM2007', CONTENT_NODE, VP: 0, [Domain: rel], DB: 0000-FFCB6A290C00123A80148AB8E0AD00E0], 200.
at com.ibm.wps.propertybroker.standard.filter.JsrEventActionDispatcherPluginImpl.buildTargetJsrEventInformation(JsrEventActionDispatcherPluginImpl.java:263)
at com.ibm.wps.propertybroker.standard.filter.JsrEventActionDispatcherPluginImpl.dispatchCommunicationTarget(JsrEventActionDispatcherPluginImpl.java:106)
at com.ibm.wps.propertybroker.dispatch.PropertyDispatcherImpl.dispatchCommunicationTarget(PropertyDispatcherImpl.java:658)
at com.ibm.wps.propertybroker.dispatch.PropertyDispatcherImpl.dispatchCommunicationTargets(PropertyDispatcherImpl.java:611)
at com.ibm.wps.propertybroker.dispatch.PropertyDispatcherImpl.dispatchPropertyValues(PropertyDispatcherImpl.java:256)
at com.ibm.wps.propertybroker.dispatch.PropertyDispatcherImpl.dispatchSourceEvent(PropertyDispatcherImpl.java:138)
at com.ibm.wps.pe.pc.waspc.services.information.WaspcInformationProviderImpl$PortletEventProviderImpl.add(WaspcInformationProviderImpl.java:373)
at com.ibm.ws.portletcontainer.PortletContainerImpl.publishEventsToEventProvider(PortletContainerImpl.java:431)
at com.ibm.ws.portletcontainer.PortletContainerImpl.doAction(PortletContainerImpl.java:215)
at com.ibm.ws.portletcontainer.PortletContainerInvokerCollaboratorChainImpl.doCollaborator(PortletContainerInvokerCollaboratorChainImpl.java:78)
at com.ibm.ws.portletcontainer.ext.ExtCollaborator.doAction(ExtCollaborator.java:55)
at com.ibm.ws.portletcontainer.PortletContainerInvokerCollaboratorChainImpl.doCollaborator(PortletContainerInvokerCollaboratorChainImpl.java:65)
at com.ibm.ws.portletcontainer.cache.CacheInvokerCollaborator.doAction(CacheInvokerCollaborator.java:76)
at com.ibm.ws.portletcontainer.PortletContainerInvokerCollaboratorChainImpl.doCollaborator(PortletContainerInvokerCollaboratorChainImpl.java:65)
at com.ibm.ws.portletcontainer.PortletContainerImpl.processPortletAction(PortletContainerImpl.java:152)
at com.ibm.ws.portletcontainer.pcinvoker.PortletInvokerImpl$1.run(PortletInvokerImpl.java:59)
at java.security.AccessController.doPrivileged(AccessController.java:246)
at com.ibm.ws.portletcontainer.pcinvoker.PortletInvokerImpl.invokeProcessAction(PortletInvokerImpl.java:55)
at com.ibm.wps.pe.pc.waspc.core.impl.PortletInvokerImpl$3.invoke(PortletInvokerImpl.java:115)
at com.ibm.wps.pe.pc.waspc.core.impl.PortletInvokerImpl.invoke(PortletInvokerImpl.java:175)
at com.ibm.wps.pe.pc.waspc.core.impl.PortletInvokerImpl.invokeProcessAction(PortletInvokerImpl.java:113)
at com.ibm.wps.pe.pc.waspc.event.ActionEvent.execute(ActionEvent.java:78)
at com.ibm.wps.pe.pc.waspc.event.EventQueueManager.processEventLoop(EventQueueManager.java:112)
at com.ibm.wps.pe.pc.waspc.PortletContainerImpl.performEvents(PortletContainerImpl.java:206)
at com.ibm.wps.pe.pc.PortletContainerImpl.performEvents(PortletContainerImpl.java:298)
at com.ibm.wps.engine.phases.WPActionPhase.processPortlets(WPActionPhase.java:2644)
at com.ibm.wps.engine.phases.WPActionPhase.execute(WPActionPhase.java:668)
at com.ibm.wps.state.phases.AbstractActionPhase.next(AbstractActionPhase.java:130)
at com.ibm.wps.engine.Servlet.callPortal(Servlet.java:855)
at com.ibm.wps.engine.Servlet.doGet(Servlet.java:617)
at com.ibm.wps.engine.Servlet.doPost(Servlet.java:888)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:763)
at com.ibm.wps.engine.Servlet.doFilter(Servlet.java:1257)
at com.ibm.wps.resolver.servlet.ContentHandlerCleanup.doFilter(ContentHandlerCleanup.java:648)
at com.ibm.wps.resolver.servlet.AbstractFilter.doFilter(AbstractFilter.java:93)
at com.ibm.wps.engine.Servlet.service(Servlet.java:1248)
at com.ibm.ws.webcontainer.servlet.ServletWrapper.service(ServletWrapper.java:1146)
at com.ibm.ws.webcontainer.servlet.ServletWrapper.service(ServletWrapper.java:1087)
at com.ibm.ws.webcontainer.filter.WebAppFilterChain.doFilter(WebAppFilterChain.java:145)
at com.ibm.wps.engine.ExtendedLocaleFilter.doFilter(ExtendedLocaleFilter.java:113)
at com.ibm.ws.webcontainer.filter.FilterInstanceWrapper.doFilter(FilterInstanceWrapper.java:190)
at com.ibm.ws.webcontainer.filter.WebAppFilterChain.doFilter(WebAppFilterChain.java:130)
at com.ibm.wps.resolver.friendly.servlet.FriendlySelectionFilter.doFilter(FriendlySelectionFilter.java:191)
at com.ibm.ws.webcontainer.filter.FilterInstanceWrapper.doFilter(FilterInstanceWrapper.java:190)
at com.ibm.ws.webcontainer.filter.WebAppFilterChain.doFilter(WebAppFilterChain.java:130)
at com.ibm.wps.mappingurl.impl.URLAnalyzer.doFilter(URLAnalyzer.java:352)
at com.ibm.ws.webcontainer.filter.FilterInstanceWrapper.doFilter(FilterInstanceWrapper.java:190)
at com.ibm.ws.webcontainer.filter.WebAppFilterChain.doFilter(WebAppFilterChain.java:130)
at com.ibm.wps.engine.VirtualPortalFilter.doFilter(VirtualPortalFilter.java:88)
at com.ibm.ws.webcontainer.filter.FilterInstanceWrapper.doFilter(FilterInstanceWrapper.java:190)
at com.ibm.ws.webcontainer.filter.WebAppFilterChain.doFilter(WebAppFilterChain.java:130)
at com.ibm.wps.state.filter.StateCleanup.doFilter(StateCleanup.java:94)
at com.ibm.ws.webcontainer.filter.FilterInstanceWrapper.doFilter(FilterInstanceWrapper.java:190)
at com.ibm.ws.webcontainer.filter.WebAppFilterChain.doFilter(WebAppFilterChain.java:130)
at com.ibm.ws.webcontainer.filter.WebAppFilterChain._doFilter(WebAppFilterChain.java:87)
at com.ibm.ws.webcontainer.filter.WebAppFilterManager.doFilter(WebAppFilterManager.java:837)
at com.ibm.ws.webcontainer.filter.WebAppFilterManager.doFilter(WebAppFilterManager.java:680)
at com.ibm.ws.webcontainer.servlet.ServletWrapper.handleRequest(ServletWrapper.java:588)
at com.ibm.ws.wswebcontainer.servlet.ServletWrapper.handleRequest(ServletWrapper.java:524)
at com.ibm.ws.webcontainer.webapp.WebApp.handleRequest(WebApp.java:3517)
at com.ibm.ws.webcontainer.webapp.WebGroup.handleRequest(WebGroup.java:269)
at com.ibm.ws.webcontainer.WebContainer.handleRequest(WebContainer.java:818)
at com.ibm.ws.wswebcontainer.WebContainer.handleRequest(WebContainer.java:1478)
at com.ibm.ws.webcontainer.channel.WCChannelLink.ready(WCChannelLink.java:125)
at com.ibm.ws.http.channel.inbound.impl.HttpInboundLink.handleDiscrimination(HttpInboundLink.java:458)
at com.ibm.ws.http.channel.inbound.impl.HttpInboundLink.handleNewInformation(HttpInboundLink.java:387)
at com.ibm.ws.http.channel.inbound.impl.HttpInboundLink.ready(HttpInboundLink.java:267)
at com.ibm.ws.tcp.channel.impl.NewConnectionInitialReadCallback.sendToDiscriminators(NewConnectionInitialReadCallback.java:214)
at com.ibm.ws.tcp.channel.impl.NewConnectionInitialReadCallback.complete(NewConnectionInitialReadCallback.java:113)
at com.ibm.ws.tcp.channel.impl.AioReadCompletionListener.futureCompleted(AioReadCompletionListener.java:165)
at com.ibm.io.async.AbstractAsyncFuture.invokeCallback(AbstractAsyncFuture.java:217)
at com.ibm.io.async.AsyncChannelFuture$1.run(AsyncChannelFuture.java:205)
at com.ibm.ws.util.ThreadPool$Worker.run(ThreadPool.java:1497)
Caused by: com.sun.xml.bind.v2.runtime.IllegalAnnotationsException: 1 counts of IllegalAnnotationExceptions
com.webspherenotes.portlet.events.Contact does not have a no-arg default constructor.
this problem is related to the following location:
at com.webspherenotes.portlet.events.Contact

at com.sun.xml.bind.v2.runtime.IllegalAnnotationsException$Builder.check(IllegalAnnotationsException.java:66)
at com.sun.xml.bind.v2.runtime.JAXBContextImpl.getTypeInfoSet(JAXBContextImpl.java:389)
at com.sun.xml.bind.v2.runtime.JAXBContextImpl.(JAXBContextImpl.java:236)
at com.sun.xml.bind.v2.ContextFactory.createContext(ContextFactory.java:76)
at com.sun.xml.bind.v2.ContextFactory.createContext(ContextFactory.java:55)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:79)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:618)
at javax.xml.bind.ContextFinder.newInstance(ContextFinder.java:210)
at javax.xml.bind.ContextFinder.find(ContextFinder.java:381)
at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:574)
at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:522)
at com.ibm.wsspi.portletcontainer.util.EventFactory.serializeJAXB(EventFactory.java:285)
at com.ibm.wsspi.portletcontainer.util.EventFactory.serializeJAXB(EventFactory.java:166)
at com.ibm.wps.propertybroker.standard.filter.JsrEventActionDispatcherPluginImpl.buildTargetJsrEventInformation(JsrEventActionDispatcherPluginImpl.java:226)
... 72 more

Passing Complex Objects using portlet events

In the Hello Portlet Events entry, i built a sample to demonstrate how you can pass simple String using as value of event from one portlet to another. But if you want to pass a custom/ complex object and source and target portlets are not packaged in the same .war file then you will have to follow some additional steps.

I built 2 sample portlets to demonstrate how you can pass complex object from one portlet to another. The EventSourcePortlet passes object of com.webspherenotes.portlet.events.Contact type to TargetSourcePortlet.

You can download the sample code for this project from here

  1. Contact

  2. EventSource

  3. EventTarget



I had to follow these steps


  1. I started by creating Contact Java project, this project has Contact.java class like this

    public class Contact implements Serializable{
    private static final long serialVersionUID = -1637774642655976822L;
    private String firstName;
    private String lastName;
    private String email;
    public Contact(){
    }
    public Contact(String firstName, String lastName, String email) {
    super();
    this.firstName = firstName;
    this.lastName = lastName;
    this.email = email;
    }
    public String getFirstName() {
    return firstName;
    }
    public void setFirstName(String firstName) {
    this.firstName = firstName;
    }
    public String getLastName() {
    return lastName;
    }
    public void setLastName(String lastName) {
    this.lastName = lastName;
    }
    public String getEmail() {
    return email;
    }
    public void setEmail(String email) {
    this.email = email;
    }
    }

    The Contact class is simple POJO class and it implements Serializable interface. That is because the setEvent() method takes object of Serializable type as argument for event value

  2. Compile the Contact java source into contact.jar and copy it into shared library of your portal. In case of WebSphere portal it will be WebSphere/PortalServer/shared/app

  3. Create EventSourcePortlet project and in that create EventSourcePortlet.java like this

    public class EventSourcePortlet extends javax.portlet.GenericPortlet {
    public void init() throws PortletException {
    super.init();
    }
    protected void doView(RenderRequest request, RenderResponse response)
    throws PortletException, IOException {
    System.out.println("Entering SourcePortlet.doView()");
    response.setContentType("text/html");
    if (request.getPortletSession().getAttribute("contact") != null) {
    request.setAttribute("contact", request.getPortletSession()
    .getAttribute("contact"));
    }
    getPortletContext().getRequestDispatcher("/source.jsp").include(
    request, response);
    System.out.println("Exiting SourcePortlet.doView()");
    }
    public void processAction(ActionRequest request, ActionResponse response)
    throws PortletException, IOException {
    System.out.println("Entering SourcePortlet.processAction()");
    String fName = request.getParameter("fName");
    String lName = request.getParameter("lName");
    String email = request.getParameter("email");
    Contact contact = new Contact(fName, lName, email);
    response.setEvent("hello", contact);
    request.getPortletSession().setAttribute("contact", contact);
    System.out.println("Exiting SourcePortlet.processAction()");
    }
    }

    The doView() method of the EventSourcePortlet is forwarding control to contact.jsp for rendering. The contact.jsp displays a simple form to user where user can input firstName, lastName and email.

    The processAction() method of EventSourcePortlet gets control when user enters values on the form and clicks submit. In this method, I am reading values submitted by user and then creating a Contact object and then setting and event with name equal to hello and value equal to the Contact object.


  4. Create EventTargetPortlet and inside that create EventTargetPortlet.java like this

    public class EventTargetPortlet extends javax.portlet.GenericPortlet {
    protected void doView(RenderRequest request, RenderResponse response)
    throws PortletException, IOException {
    System.out.println("Entering TargetPortlet.doView()");
    response.setContentType("text/html");
    Contact contact = (Contact) request.getPortletSession().getAttribute(
    "contact");
    if (contact != null) {
    response.getWriter().println(
    "First Name " + contact.getFirstName() + "
    Last Name "
    + contact.getLastName() + "
    Email "
    + contact.getEmail());
    } else {
    response.getWriter().println("Contact not found in session ");
    }
    System.out.println("Exiting TargetPortlet.doView()");
    }

    public void processEvent(EventRequest request, EventResponse response)
    throws PortletException, IOException {
    System.out.println("Entering TargetPortlet.processEvent");
    Event event = request.getEvent();
    System.out.println("Event Name " + event.getName());
    Contact contact = (Contact) event.getValue();
    System.out.println("Contact First Name " + contact.getFirstName());
    System.out.println("Contact Last Name " + contact.getLastName());
    System.out.println("Contact Email " + contact.getEmail());
    request.getPortletSession().setAttribute("contact", contact);
    System.out.println("Exiting TargetPortlet.processEvent");
    }
    }

    The processEvent() method of the EventTargetPortlet get control whenever it receives event, in this method it is reading the Contact object that was sent as event payload and then setting it as attribute in PortletSession.
    In the doView() method it reads the Contact object from PortletSession and prints those values

  5. This is how the portlet.xml file for the EventSourcePortlet looks like

    <?xml version="1.0" encoding="UTF-8"?>
    <portlet-app xmlns="http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd" version="2.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd"
    id="com.webspherenotes.portlet.event.EventSourcePortlet.1a884b6b82">
    <portlet>
    <portlet-name>EventSourcePortlet</portlet-name>
    <display-name xml:lang="en">EventSourcePortlet</display-name>
    <display-name>EventSourcePortlet</display-name>
    <portlet-class>com.webspherenotes.portlet.event.EventSourcePortlet</portlet-class>
    <init-param>
    <name>wps.markup</name>
    <value>html</value>
    </init-param>
    <expiration-cache>0</expiration-cache>
    <supports>
    <mime-type>text/html</mime-type>
    <portlet-mode>view</portlet-mode>
    </supports>
    <supported-locale>en</supported-locale>
    <resource-bundle>com.webspherenotes.portlet.event.nl.EventSourcePortletResource</resource-bundle>
    <portlet-info>
    <title>EventSourcePortlet</title>
    <short-title>EventSourcePortlet</short-title>
    <keywords>EventSourcePortlet</keywords>
    </portlet-info>
    <supported-publishing-event>
    <name>hello</name>
    </supported-publishing-event>
    </portlet>
    <default-namespace>http://wpcertification.blogspot.com</default-namespace>
    <event-definition>
    <name>hello</name>
    <value-type>com.webspherenotes.portlet.events.Contact</value-type>
    </event-definition>
    </portlet-app>

    As you can see the value-type of the event is com.webspherenotes.portlet.events.Contact to indicate that we want to send object of Contact class as event payload

Hello Portlet Events

The Portlet Specification 2.0 has concept of Events, that can be used for portlet to portlet communication. I built this sample HelloEventsPortlet to demonstrate how to create simple portlet events communication

The HelloEventsPortlet application has two portlets SourcePortlet, which will display Action URL to the user in VIEW mode and when user clicks on the ActionURL it will set hello event in the processAction method, the TargetPortlet will act as consumer for the event and in the processEvent method it will read value of the event and set it as render parameter and display that value to the user in VIEW mode markup. Follow these steps to create events portlet


  • First create SourcePortlet.java like this


    package com.webspherenotes.portlet.events;

    import java.io.IOException;

    import javax.portlet.ActionRequest;
    import javax.portlet.ActionResponse;
    import javax.portlet.GenericPortlet;
    import javax.portlet.PortletException;
    import javax.portlet.RenderRequest;
    import javax.portlet.RenderResponse;

    public class SourcePortlet extends GenericPortlet{

    protected void doView(RenderRequest request, RenderResponse response)
    throws PortletException, IOException {
    System.out.println("Entering SourcePortlet.doView()");
    response.setContentType("text/html");
    getPortletContext().getRequestDispatcher("/source.jsp").include(request, response);
    System.out.println("Exiting SourcePortlet.doView()");
    }

    public void processAction(ActionRequest request, ActionResponse response)
    throws PortletException, IOException {
    System.out.println("Entering SourcePortlet.processAction()");
    response.setEvent("hello", "Hello event from the SourcePortlet");
    System.out.println("Exiting SourcePortlet.processAction()");
    }

    }

    The SourcePortlet has doView() and processAction() methods, in doView() method it is forwarding control to source.jsp for generating markup, the source.jsp generates a simple ActionURL.
    In the processAction() method it is calling response.setEvent("hello", "Hello event from the SourcePortlet"), which is used for publishing hello event.


  • This is how my TargetPortlet.java looks like

    package com.webspherenotes.portlet.events;

    import java.io.IOException;

    import javax.portlet.Event;
    import javax.portlet.EventPortlet;
    import javax.portlet.EventRequest;
    import javax.portlet.EventResponse;
    import javax.portlet.GenericPortlet;
    import javax.portlet.PortletException;
    import javax.portlet.RenderRequest;
    import javax.portlet.RenderResponse;

    public class TargetPortlet extends GenericPortlet implements EventPortlet{

    protected void doView(RenderRequest request, RenderResponse response)
    throws PortletException, IOException {
    System.out.println("Entering TargetPortlet.doView()");
    response.setContentType("text/html");
    response.getWriter().println("Hello from TargetPortlet.doView() " + request.getParameter("helloEvent"));
    System.out.println("Exiting TargetPortlet.doView()");
    }

    public void processEvent(EventRequest request, EventResponse response)
    throws PortletException, IOException {
    System.out.println("Entering TargetPortlet.processEvent");
    Event event= request.getEvent();
    System.out.println("Event Name " + event.getName());
    String eventValue =(String)event.getValue();
    System.out.println("Event Value " + eventValue);
    response.setRenderParameter("helloEvent", eventValue);

    System.out.println("Exiting TargetPortlet.processEvent");
    }

    }

    The TargetPortlet is implementing EventPortlet to indicate that it can act as consumer of event. The TargetPortlet has doView() and processEvent() methods, in doView() it is simply reading value of helloEvent render parameter and displaying it to user.

    The portlet container will call processEvent() method to give TargetPortlet chance to consume the event, it will get called before the render phase. You can call EventRequest.getEvent()method inside the processEvent() method to get the Event object and once you have the event object you can call its getName() and getValue() methods to read name and value of the event. After reading the value of event i am setting it as render parameter for the portlet.


  • This is how my portlet.xml file looks like

    <?xml version="1.0" encoding="UTF-8"?>
    <portlet-app xmlns="http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd"
    version="2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd">
    <portlet>
    <portlet-name>SourcePortlet</portlet-name>
    <display-name>Events Source Portlet</display-name>
    <portlet-class>com.webspherenotes.portlet.events.SourcePortlet</portlet-class>
    <expiration-cache>0</expiration-cache>
    <supports>
    <mime-type>text/html</mime-type>
    <portlet-mode>view</portlet-mode>
    <portlet-mode>edit</portlet-mode>
    </supports>
    <portlet-info>
    <title>Event Source Portlet</title>
    <short-title>Event Source Portlet</short-title>
    <keywords>Event Source Portlet</keywords>
    </portlet-info>
    <supported-publishing-event>
    <name>hello</name>
    </supported-publishing-event>

    </portlet>
    <portlet>
    <portlet-name>TargetPortlet</portlet-name>
    <display-name>Events Target Portlet</display-name>
    <portlet-class>com.webspherenotes.portlet.events.TargetPortlet</portlet-class>
    <expiration-cache>0</expiration-cache>
    <supports>
    <mime-type>text/html</mime-type>
    <portlet-mode>view</portlet-mode>
    <portlet-mode>edit</portlet-mode>
    </supports>
    <portlet-info>
    <title>Event Target Portlet</title>
    <short-title>Event Target Portlet</short-title>
    <keywords>Event Target Portlet</keywords>
    </portlet-info>
    <supported-processing-event>
    <name>hello</name>
    </supported-processing-event>

    </portlet>
    <default-namespace>http://wpcertification.blogspot.com</default-namespace>
    <event-definition>
    <name>hello</name>
    <value-type>java.lang.String</value-type>
    </event-definition>

    </portlet-app>

    There are three components in the portlet.xml

    1. event-definition: Element is declared at the portlet application level and it defines name of the event and the type of the event. In my case name of the event is hello and type is java.lang.Style

    2. supported-publishing-event: Element is used for declaring what all events can be published by this portlet

    3. supported-processing-event: Element is used for defining what all events can be consumed by this portlet



  • After developing this portlet deploy it in WebSphere Portal server and add them to a portal page

  • Now create a wire between consumer and producer using Portlet Wiring Portlet like this




Now you can test this portlet by clicking on the Action URL in the Source Portlet, you will notice that the TargetPortlet is displaying the value of event to user

What are Portlet Events

Portlet events are intended to allow portlets to react to actions or state changes not directly related to an interaction of the user with the portlet. Events could be either portal or portlet container generated or the result of a user interaction with other portlets. The portlet event model is a loosely coupled, brokered model that allows creating portlets as stand-alone portlets that can be wired together with other portlets at runtime. In response to an event a portlet may publish new events that should be delivered to other portlets and thus may trigger state changes on these other portlets.

In order to receive events the portlet must implement the EventPortlet interface in the javax.portlet package. The portlet container will call the processEvent method for each event targeted to the portlet with an EventRequest and EventResponse object. Events are targeted by the portal / portlet container to a specific portlet window in the current client request.

Events are a life cycle operation that occurs before the rendering phase. The portlet may issue events via the setEvent method during the action processing which will be processed by the portlet container after the action processing has finished. As a result of issuing an event the portlet may optionally receive events from other portlets or container events. A portlet that is not target of a user action may optionally receive container events, e.g. a portlet mode changed event, or events from other portlets, e.g. an item was added to the shopping cart event.