Liferay Session Sharing Demystified
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
Mixed Scenarios
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
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.
Summary
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