Liferay’s session sharing mechanism has always been a bit of a mystery. As with most things Liferay, documentation is minimal, and leaves a lot of questions to be answered. I’d like to share with you what I’ve learnt after testing a bunch of scenarios, and hopefully this will be good reference material for all of you developing portlets on Liferay.
My scenarios focus on how Liferay’s sessions behave for different combinations of the private-session-attributes settings; between the portal, portlets (in the same WAR, and across different WARs) and the servlets in these WARs. This also means that only APPLICATION_SCOPE attributes are relevant to the discussion.
Testing was performed on Liferay 4.3.6, and consisted of basic JSR-168 portlets , and basic Servlet Spec servlets. To emulate code running in the portal scope, a simple servlet Filter was configured on the Portal application.
Private Session True
This is the default setting, in which each WAR has its own session. The session within each WAR is private, and nothing is shared between individual WARs. Portlets and Servlet within the same WAR file will be able to share the session, because they are in the same context. So far, this conforms to the Servlet spec.
Liferay provides an additional functionality under this setting. As the official FAQ states, it also allows shared (namespaced) attributes set by the portal to be visible from portlets. Any session attribute with the configured prefix (e.g. LIFERAY_SHARED_) will be copied over and be visible by the portlets, hence granting private portlets read-access to session attributes set by the portal. This is illustrated in diagram 1.Diagram 1
Private Session False
All portlets under this setting will share the same session, and also share this same session with the portal. This is the easiest way for portlets in individual WAR files to communicate with each other.
However, the downside to this is that servlets in these WAR files will not be able to communicate with the portlets at all. (This is a question often raised in the forums, and one I struggled with for a while to figure out). The most convenient way to think of this is that portlets with this setting use the portal session, and have no access to the WAR session. This is illustrated in diagram 2.Diagram 2
Diagram 3 depicts the interaction between a private and non-private portlet in individual WAR files. Portlet A, being non-private, has full communication with the portal, but cannot talk to Servlet A. Portlet B, being private, has full communication with Servlet B, but only has read-only access to Portal shared attributes.
You will notice arrow from Portlet A to Portlet B is dotted because this communication happening indirectly through the portal session. Portlet A is using the portal session, so any shared attributes that it sets will also be copied over to Portlet B, and can be read.Diagram 3
Diagram 4 expands on diagram 3, and adds another private portlet to WAR B. Both of the portlets in B are private, meaning they are using the WAR session, so they can freely communicate with each other and the servlet. Same as the previous example, they will be able to read shared attributes set by the portal, or by any non-private portlet like Portlet A.Diagram 4
Diagram 5 is a bit more interesting. Here, Portlet B has been changed to non-private, meaning it will use the portal session. That is why it can now freely communicate with the portal and Portlet A. However, just like anything else using the Portal session, it cannot read the WAR session of B anymore, even though it is in the same WAR! While this may seem a little counter-intuitive, it is consistent with the behaviour we have seen so far.Diagram 5
Copying shared attributes to a Servlet
Update: Liferay has a built in mechanism for calling servlets from the portal context, giving them access to the portal session.
You may have noticed so far that the servlets cannot directly read the shared attributes of the portal session. But you can get around this by using a private portlet as a proxy. Diagram 6 shows the flow of how a shared attribute x, set by non-private Portlet A, will be stored in the portal session and subsequently copied to private Portlet B. Portlet B, having write access to WAR session B, can set another attribute y to the same value as x, and y can be read by the servlet.Diagram 6
Overwriting shared attributes from private portlets?
We know that any session attributes set by private portlets cannot be seen by the portal, or by any other non-private portlets. But what happens if the private portlet sets an attribute of the same key as the shared attribute?Diagram 7
In Diagram 7, the flow is depicted more accurately by showing two sessions – the Portal session and the WAR session of B. I will walk through the numbered scenario as follows:
- Non-private Portlet A sets a session attribute LIFERAY_SHARED_foo to “alice” . This is stored in the portal session.
- Private Portlet B reads the attribute LIFERAY_SHARED_foo. Since this is a shared attribute, it has read access, and returns the value “apple” .
- Private Portlet B2 now sets the same session attribute LIFERAY_SHARED_foo to “bob” . Because it is a private portlet, the value is written to the WAR session.
- When Portlet B tries to read the attribute again, it returns the value “bob”. This shows that values in the WAR session override those copied from the portal. If at this point Portlet A were to set the attribute again, Portlet B cannot see the change.
- Portlet B2 now removes the session attribute LIFERAY_SHARED_foo
- When Portlet B tries to read the attribute again, it returns the value “alice” from the portal session.
This example shows that when private portlets tries to read an attribute, it will first read the attribute from the WAR session. If it can’t be found, it will try to read from any shared attributes copied from the Portal session.
I am not a core Liferay developer, so I’m not sure what the underlying implementation really is. However, my observations are consistent with the following summary:
- Non-private portlets read and write to the Portal session.
- Private portlets write to their own WAR session.
- Private portlets try to read from their own WAR session first, then looks up any shared attributes copied from the Portal session.
- Servlets only have access to the WAR session, and cannot directly access the Portal session. In order to read shared session attributes, servlets need a private portlet in the same WAR file to copy it for them. Or you can configure your servlet to use the portal session by using Liferay's PortalDelegateServlet mechanism.
I hope this has helped you in your understanding of Liferay’s session sharing mechanism. If you are a core Liferay developer, please let me know if I have made any mistakes, or if you have anything else to add. I’d be keen to know if this is still relevant to Liferay 4.4.x