This version of the messaging library supports communication between portlets in different portlet applications (that is, portlets which have been deployed in separate .war files, whose definitions are in different portlet.xml's).
However, it is a lot easier if you can restrict yourself to communication between portlets in the same application (which the library will do by default). If at all possible, do that and you won't need to bother with the rest...
The reason for the complications is that portlets in different portlet apps do not have access to any common session.
There are 2 main issues that have to be dealt with to get cross context communication working:
A MessageStore must be set up which is accessible to all portlets in any portlet application. (this is the most significant work)
The portlets need to be able to access an ID corresponding to the user's whole portal session.
Details of each, and some example implementations are given below.
You can plug in your chosen implementations: simply make the classes available in your portlet webapp, and configure them in this properties file: /WEB-INF/classes/message/PortletMessaging.properties.
# MessageStore class to use
# message.store=message.store.BasicMessageStore
message.store=message.store.EJBMessageStore
# SessionIDRetriever class to use
# (only important for cross-context portlet communication)
# session.id.retriever = message.retriever.NamespacedLocalSessionIDRetriever
session.id.retriever=message.retriever.PortletRequestSessionIDRetriever
The MessageHelper will use the specified classes behind-the-scenes when necessary - you should not refer to them in your portlet code. So you can change the MessageStore/SessionIDRetriever without needing to recompile your portlets.
If this properties file is not present, the messaging library will default to single-application communication (i.e. not cross-context), with the MessageStore in the portlet session (as in version 1 of the library). Default classes used are message.store.BasicMessageStore and message.retriever.NamespacedLocalSessionIDRetriever.
If you implement a new MessageStore or SessionIDRetriever, and would like to make it available to others, I'd be very happy to add it to this site :) Particularly as the ones I have done are mostly proof-of-concept so far.
Alternative MessageStore implementations
The MessageStore deals with both storage and access to the messages, and the mappings of local-global names. It is described by the MessageStore interface. See message.store.BasicMessageStore for an example implementation.
The MessageStore is kept within the portlet APPLICATION_SCOPE session, and therefore there is always one MessageStore object per portlet application. So for cross-context messaging, the MessageStore must not store the messages and mappings internally, but instead must be able to retrieve them from an external location.
This actual location where the messages and the mappings are stored must be accessible by any portlet application. Some portal-independent approaches would be:
As you can see, this will most likely add an external dependency to your portlets.
EJB Implementation (tested on JBoss):
I have made a quick, proof-of-concept EJB Message Store which I've tested with an EJB deployed on JBoss or Geronimo. However this implementation isn't very efficient (the EJB simply delegates to a BasicMessageStore object which it serialises and stores in a database), so for a production system you will probably want to code your own.
You can get it, and associated portlet webapps for testing, from the Download page.
SessionIDRetriever implementations
When a portlet goes to retrieve a message from the external MessageStore, it needs to be able to identify which user session it is participating in, to be able to retrieve the right messages. This session id needs to be available to all portlets, in all portlet applications. However, JSR168 doesn't give us an easy way of accessing an ID that serves this purpose, so we have to come up with workarounds.
The SessionIDRetriever interface is quite simple: get the cross-context Session ID, somehow, from the provided PortletRequest.
The best solution I've found so far is the PortletRequestSessionIDRetriever which uses PortletRequest.getRequestedSessionId() to get the real Portal session ID. This has the single but important limitation that it won't work on the very first request a client (browser) makes to the Portal - because, of course, at that point the client hasn't yet joined a session, and so can't send along its session ID to the server with its request! This means that you should avoid putting messaging portlets on the first Portal page, as they'll end up seeing 'null' session IDs (which may break/confuse your MessageStore and in any case won't work with the session that gets established later).
If for whatever reason this SessionIDRetriever doesn't work in your chosen Portal, you can have a look at some alternative SessionIDRetriever implementations - but these are generally more complex and fragile than the PortletRequestSessionIDRetriever above.
If you've got this far, you must be desperate for a cross-context solution ;-) Sorry that this probably isn't as simple to do as you'd like! Good luck, I'd like to hear how it goes.
Thanks to Cameron Purdy and Ganesh Prasad, whose discussions were very helpful in working out how to go about implementing this, and to Eric Peukert, who came up with this much-improved SessionIDRetriever approach.