A portlet may have any number of inputs, and any number of outputs. It refers to these inputs and outputs using a local name in the portlet code (eg "person_name", "item_id"). Mappings of input/output names to global message boxes are defined externally to the portlet code - in the portlet preferences.
A message box can hold only one message at a time: sending a new message to it will overwrite the old one. The messages never expire, as we cannot know whether the interested portlets no longer need them (actually, this implementation stores them in the session, so when the user session expires they will be cleaned up). Messages can be any sort of Object, though it may be wise to make them Serializable.
A message input is mapped to a source message box, from which it reads its message.
A message output always sends its message to a local (namespaced to its own portlet instance) message box of the same name, but it may also publish it to any number of additional global message boxes.
Limitations
This version of the messaging library allows for messaging between portlets in different portlet applications. However, setting this up will require some configuration and probably coding, as the exact form of cross-context communication will depend on your situation. What you need to do is described in the Cross-Context messaging section.
Caching of portlet views is a problem: if you want the view of another portlet to update because an input message has changed, but the portlet is cached, the portal won't call its 'doView' and you have no way of forcing it to - that I know of, anyway. If you have enabled caching like this, I guess you'll have to add a 'refresh' link to the portlet so that the user can force a reload. However this isn't very user-friendly - another option which works is to disable view caching entirely by setting
<expiration-cache>0</expiration-cache>
for your portlets in portlet.xml. You will then need to ensure that your 'doView' is as lightweight as possible, as it will be called every time the page loads.
This is not critical, but something to be aware of: Portlets only 'register' their mappings when they first load. The provided mapping configuration form (for use in a portlet's Edit mode) lists message boxes available as sources or targets, but it will only be able to 'see' those that have already been registered in the current session's MessageCentre. So if you haven't visited a portlet's page, its message boxes won't appear yet in another portlet's Edit mode.
The portlet can read messages using MessageHelper.get(name), and send messages using MessageHelper.send(name). If you're sending messages, and want to avoid problems due to portlets loading out of order/in parallel on the page, make sure you send them in processAction - that way they'll be sent and ready by the time the other portlets get to doView.
Important step: configure the portlet's message mappings in its entry in portlet.xml. Each input has a Name (local, used in the portlet code), a SourceName, and a SourceNamespace. Each output has a Name (local, used in the portlet code), and any number of additional Publish destinations (which each consist of a PublishName and a PublishNamespace). Example settings for a portlet with one input and one output are shown below. Note that these are the defaults: as it is now, if you define a Publish target, and the user later tries to remove it, they won't be able to (although they would be able to re-map it).
Set up any wiring that is different from the defaults in portlet.xml:
If your portal structure will be fixed, and it allows you to directly set the preferences for each portlet instance somehow, you can do that to set up the wiring.
Or, write an Edit mode that lets the portlet user modify the inputs/outputs in the preferences. Once you've saved the preferences, reload the mappings by calling MessageHelper.setLoadedPrefs (to false) and then MessageHelper.loadPrefs
Or, if you want to use the full automatic wiring interface provided (see the screenshots):
Call MessageUtils.processMappingForm in processAction when you need to process the results of the edit mappings form. This will update the message mappings for the selected portlet, and save them in the portlet's preferences.
What's the Portlet ID?
Lots of the functions and classes in this messaging system require a portlet ID. For the messages to get to the right places, we clearly need a unique ID for each portlet instance. However I haven't yet found a consistent way of retrieving a portlet instance id that works across different portals (if there is one, please tell me!). For example, I've seen a suggestion to add a portlet parameter containing an id in the portlet.xml - but that will end up being the same on all instances of that particular portlet, so you still can't distinguish between them. Some portals have their own functions for retrieving an instance id, but then you'd be locked to using that particular portal.
I've settled for randomly generating portlet instance id's, and storing them in the local portlet's session. The function to do this is MessageHelper.getPortletID - you can use this, or implement your own solution; as long as each portlet instance has a unique ID, it can be any String.
What's the Session ID?
Use MessageHelper.getSessionID to retrieve it.
It's only really relevant for Cross-Context messaging, so if your portlets are all in the same application, just use the MessageHelper function and don't worry about it.
Messaging model: Message Centre keeps track of all the mappings between local message names and global message names, allowing dynamic reconfiguration of message 'routes' by the administrator or the portal user.
Three messaging portlets
Multiple instances of the same portlets: they have different mappings, defined in their parameters
Dynamically mapped portlets: initial state
Dynamically mapped portlets: all in Edit mode
Dynamically mapped portlets: sent message from 1st to 2nd
Dynamically mapped portlets: sent message from 2nd to 3rd
Dynamically mapped portlets: changed 3rd to read from author_name
Dynamically mapped portlets: 3rd now does search using author_name