Search code examples
liferayportletjsr286

Using JSR-268 IPC for portlets on different pages in Liferay


I started developing a portlet based application using WebSphere Portal and now I am switching my development environment to Liferay. I am using the event system introduced with JSR-286 for inter-portlet communication, trying to avoid all non standardized features in order to serve both WebSphere Portal and Liferay as supported environments.

My events seem to work fine if the publishing portlet and the receiving portlet are on the same page, but I would like to place those portlets on different pages. On WebSphere there is a "Wiring" configuration page where portlets can be configured to send events to specific portlets on other pages and there is an option to automatically switch the page if such an event is fired.

How do I do that using Liferay?

Using: Liferay Portal Community Edition 6.1.0 CE (Paton / Build 6100 / December 15, 2011)


Solution

  • Olaf's answer gives you a good start. Just place a file called portal-ext.properties in your classpath with the content portlet.event.distribution=ALL. This will make sure that all portlets that care for the event will receive it, even if it is on a different page.

    Now for switching the pages: I suggest creating an interface that handles your events. This interface is basically a representation of the portlet.xml file's event-definition-tags in code. This additionally has the advantage that you just have to make sure that your interface and your portlet.xml is in sync. If the interface is not in sync with the remaining source code then this will oftentimes be a compile time error instead of a runtime error (such as wrong parameter types to an event).

    interface Events
    {
      public static final String EVENT_NAME_X ="eventX"; // as defined in portlet.xml
      public static final String EVENT_NAME_Y ="eventY";
      public void fireEventX(ActionResponse response, ParamType param);
      public void fireEventY(ActionResponse response, ParamType param);
    }
    

    Then you can have a simple implementation that fires your events that you can use with WebSphere:

    public class SimpleEvents implements Events
    {
        @Override
        public void fireEventX(ActionResponse response, ParamType param)
        {
            response.setEvent(EVENT_NAME_X, param);
        }
    
        @Override
        public void fireEventY(ActionResponse response, ParamType param)
        {
            response.setEvent(EVENT_NAME_Y, param);
        }
    }
    

    Then you can have another implementation for Liferay which looks like this:

    public class RedirectingEvents extends SimpleEvents
    {
      private String eventXRedirect;
      private String eventYRedirect;
    
        @Override
        public void fireEventX(ActionResponse response, ParamType param)
        {
            super.fireEventX(param);
            if (eventXRedirect != null)
              response.sendRedirect(eventXRedirect);
        }
    
        @Override
        public void fireEventY(ActionResponse response, ParamType param)
        {
            super.fireEventY(param);
            if (eventXRedirect != null)
              response.sendRedirect(eventYRedirect);
        }
        // setters & getters
    }
    

    Now if you are using Spring IoC (which I happen to know that you do), then you can can configure the implementation as follows in your application-context.xml file:

    <bean class="package.RedirectingEvents" primary="true">
      <property name="eventXRedirect" value="/page-after-X-event" />
      <property name="eventYRedirect" value="/page-after-Y-event" />
    </bean>
    

    Here is how you get the "value"-part for this xml snippet:

    Open the target page in liferay to which the user should be redirected after an event was fired, while beeing logged with appropriate privileges and click in the menu at the top of the page on Manage->page. There you can set a "Friendly URL". Copy the same URL you entered in the Friendly-URL field (without the unchangable prefix) into the application-context.xml snippet above.

    In your classes that fire events you can then just allow the Events-interface to be autowired and use it like this:

    @Controller
    class Foobar
    {
      @Autowired
      private Events portletEvents;
      @ActionMapping
      public void action(ActionRequest request, ActionResponse response)
      {
        portletEvents.fireEventX(someParam);
      }
      @EventMapping(Events.EVENT_NAME_Y)
      public void handleEventRequest(EventRequest request, EventResponse response)
      {
        Object value = request.getEvent().getValue();
        log.info("got Y event! Value is: " + value);
      }
    }
    

    If you deploy your application on WebSphere Portal, you simple exchange the xml snippet above with the following:

    <bean class="package.SimpleEvents" primary="true" />
    

    Now you you have a solution that allows you to send JSR-286 messages across pages, switching the pages at the same time, while still being able to deploy you application on both Liferay and WebSphere Portal without any change in code (just configuration needs to be adapted).