Using JSR-268 IPC for portlets on different pages

2019-06-13 16:54发布

问题:

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)

回答1:

There are a few properties that you can set in portal-ext.properties. Quoting with the comments on them (as they probably state the usage better than I could do myself:

##
## Portlet Coordination
##

#
# Set this property to specify how events are distributed. If the value is
# "layout-set", then events will be distributed to all portlets contained in
# a layout set. If the value is "layout", then events will be distributed to
# all portlets that are present in a layout.
#
portlet.event.distribution=layout

#
# Set this property to specify how public render parameters are distributed.
# If the value is "layout-set", then public render parameters will be
# distributed to all portlets contained in a layout set. This will only work
# correctly if the property "layout.default.p_l_reset" is set to false. If
# the value is "layout", then public render parameters will be distributed
# to all portlets that are present in a layout.
#
portlet.public.render.parameter.distribution=layout

.....

#
# Set the default value for the "p_l_reset" parameter. If set to true, then
# render parameters are cleared when different pages are hit. This is not
# the behavior promoted by the portlet specification, but is the one that
# most end users seem to prefer.
#
layout.default.p_l_reset=true

Hope that helps



回答2:

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).