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.
For this one, you need to implement the SessionIDRetriever interface, which is itself quite simple: get the cross-context Session ID, somehow, from the provided PortletRequest.
Here are a few possible approaches I've tried - they work, but each has their own restrictions. You may need a different solution for your situation.
Use a Cookie
A cookie is theoretically available to all portlets in all portlet applications, and so can act as a shared source of information - a place to put the session id. (As we will see, the cookie is not a sensible place to put messages!) Firstly, there is the practical problem of how to access the cookie:
Reading the cookie: the PortletRequest doesn't provide us with an exact equivalent for HttpServletRequest.getCookies(). However, hopefully you will be able to get at the cookie using PortletRequest.getProperty("cookie"): I have only tried this on Jetspeed 1.6 so far.
Writing the cookie: Portlets can't set cookies, because they have no access to the page headers (which is where cookies are set). So there are 2 options I am aware of, both of which can only happen after the page finishes rendering:
JavaScript: have the portlet write out javascript which sets the cookie.
Servlet in IFRAME: have the portlet write out an IFRAME (probably invisible, zero size) which contains a servlet or JSP in your portlet application. This servlet or JSP can set the cookie.
Therefore, there are a few more problems/restrictions with usage:
You need to have a 'CookieSetter' portlet which appears only on the first page after login.
It's possible for cookies to stay around after a user's portal session has finished (e.g. if someone logs out of a portal, then a different user logs in using the same browser). You can deal with this case by having the CookieSetter portlet check the session to see if it's done its job yet, and if it hasn't it clears the cookie and sets a fresh one containing the new session ID.
As discussed above, cookies can only be set by the client, after the Render phase has completed, and until that has been set, there will not be enough information available for messaging portlets to initialise. Therefore no messaging portlets can appear before the CookieSetter portlet, nor should they be on the same page as it.
It's possible for people to set their client (browser) settings such that this method will not work at all. E.g. they can turn off cookies, or JavaScript, or some browsers may not support IFRAMEs.
Implementation:
Retrieval: CookieSessionIDRetriever will look for a cookie named "cookie_msg_session_id". Included in the messaging library.
Yes, this is a portal-specific solution. But it may well be worth it considering how messy the non-portal-specific cookie solution is. Also, you can still plug in the cookie solution if you need to switch to a different portal later - it's just one line in the properties file, and doesn't affect your portlets' code.
There is already an ideal identifier for the user's portal session: the Portal's session id. For example, if you log into Jetspeed, that creates a session for the /jetspeed application. The problem is that the portlets have no way of accessing that session.
However, if your portal is open source, you can modify the code to pass on this session ID, in a PortletRequest attribute named "message.portal_session_id". I've done this with Jetspeed 1.6.
Implementation:
RequestAttributeSessionIDRetriever will look for the PortletRequest attribute "message.portal_session_id". If you can get your portal to populate the "message.portal_session_id" PortletRequest attribute, you can reuse this class to retrieve it. Included in the messaging library.
Jetspeed 1.6: The modification I made was to org.apache.jetspeed.aggregator.impl.PortletRendererImpl.buildRenderingJob() (from Jetspeed 2 M3, which is included with 1.6), which is packaged in jetspeed-2.0-M3.jar.