Sharing session data between contexts HOW-TOIntroduction |
written by Johannes Fiala, johannes.fiala@fwd.at in May 2003
This HOW-TO covers my experiences how to share session data between different contexts.
I'll cover the following aspects step by step:
- Ways to pass a sessionid of a Context to another Context
- Using a "shared" Context to store session data
- Using persistent storage to store session data
I'll first describe how a sessionid can be passed from one Context to another Context (e.g. be shared).
Next, I'll describe a basic technique to store objects into a central Context to be retrieved from other
Context.
Finally, I'll touch the area of making shared session data persistent to share it easily with other Contexts.
This scenario is certainly the way to go in a clustered environment.
After reading this HOWTO, you should be able to share sessions across Contexts.
Note: This guide should apply to all J2EE containers.
|
Update history |
Update 2003-05-31:
Brushed up the whole HOWTO with examples, finished the shared Context part.
Update 2003-05-26:
Entered first ideas.
|
Tested configurations |
I tested the following configurations:
- Tomcat 4.1.24 with JDK 1.4 on Win 2K Professional/Win NT 4.0
- Tomcat 4.1.12 with JDK 1.3.1 on IBM AIX 4.3
|
Prerequisites |
To use this document, you should download and install (=unzip) the following components:
|
Ways to pass a sessionid of a Context to another Context |
According to the J2EE specification, every Context has his own session management.
The statement above may sound unspectacular first, but may turn out to be cumbersome. Since every Context
manages his own session, you don't know anything about other sessions the user may have at other Contexts of
your J2EE container.
This means if a user comes across Context A and gets sessionid A and then clicks to Context B he'll get a
sessionid B. However, how will Context B know that the same user has another session running at Context A?
If you plan to create bigger webapps, you'll surely notice that it makes sense to set up individual WAR files
for individual applications. We had such a scenario for a portal which will eventually include three different
WAR files, one for services, one for forms to be filled in and one for managing the content of the portal.
Thus we knew right from the beginning that we will have session data to be shared across contexts.
But how to pass the session id from one Context to another Context easily?
I think there are two possible ways:
- Passing the original sessionid along using an URL parameter
- Passing the original sessionid along using a Cookie
The first approach using the URL is applicable to all browsers. However, you'll have to pass a 32 character string
along with each request which will switch to another Context. If you already include the jsessionid from
your current Context, you'll soon have to live with really long URLs (32 chars from the Context's sessionid and
32 chars from the original Context).
If you can bear that, this is your choice.
The second approach using Cookies is a bit more tricky, so I'll spend the next paragraph on it:
Using a Url parameter to share the sessionid |
Using a url parameter is quite easy, all you have to do is to add the parameter to all links to other Contexts
you want to share the original sessionid with:
e.g.
/mycontext/myservlet?ssosessionid=XXX
|
Summary |
So we're now able to pass the sessionid of Context A to Context B using a Url or a Cookie (which is in my opinion the
more elegant approach).
|
|
Using a "shared" Context to store session data |
Next, we want to read the session data of Context A from Context B. Since we know the sessionid, it
should be straightforward you might think. This is when the J2EE spec comes into our way:
Reading the session data of another Context has been deprecated for security reasons as of Java Servlet API 2.1.
Link: Javadoc reference
So we'll have to find another way to share data between Contexts.
I came up with three major options: use a Context itself, use a database or use a file resource (e.g. XML file).
Putting shared objects into a Context - Advantages & Drawbacks |
The bigggest advantage of using a Context to store your shared session data is that you don't have to
serialize your objects. You only have to put it into the Context and you're done.
The biggest drawback certainly is that sessions could be transferred automatically between servers in a
clustered Tomcat environment. If you ever plan to cluster your Tomcats, use an external resource (database or file) to
store your shared session data. Additionally, you have to make sure that the database or file system will be
available to all Tomcat servers running in your cluster.
|
How to put shared data into a Context |
Imagine the following scenario: I have an authentication Context (Context A) which will perform some basic checks and then
will store some user info (roles, groups, ...).
The sessionid A which will be automatically assigned when the user accesses Context A is used as the shared
sessionid (ssosessionid = single signon sessionid).
I used the following approach to store shared session data:
First, I store the ssosessionid into a Cookie at the root path to make it available to all Contexts.
Next, I store the shared data (user roles and groups in my case) into an Hashtable using the ssosessionid as the key.
Then, this Hashtable in turn gets stored into the Context.
To make everything clearer, here are some lines of code:
 |  |  |  |
public synchronized static void storeDataInContext
(ServletContext context, String sessionid, Vector userroles) {
// load the shared_userroles from the context
Hashtable shareddata = (Hashtable)context.getAttribute("shared_userroles");
// if not yet available, create a new one
if (shareddata==null) {
shareddata = new Hashtable();
}
// store the userroles of the current session
shareddata.put(sessionid, userroles));
// store the shareddata back into the Context
context.setAttribute("shared_userroles", shareddata);
}
|  |  |  |  |
Please note that I marked the routine synchronized to prevent simultaneous updates of the shared Context data.
|
|
Using persistent storage to store shared session data |
If you expect to have a clustered J2EE environment sometime in the future, you'll certainly want
to make shared session data available to multiple servers.
This certainly prevents you from storing shared session data into a shared Context as outlined above. You'll
want to make shared session data available to all interested applications. This means you have to use a
resource which is accessible to all Tomcat servers in your clustered environment.
Making Java objects persistent - some thoughts |
The problem with making data persistent in a database or an XML file is the serialization/deserialization process.
To store an object and to revoke it from the shared session datastore, you'll have to serialize and deserialize it.
Here are the options I think you might have:
- Using the serializable interface to serialize objects and store them in files
- Using the same technique as Apache Axis/Soap to serialize objects into XML files
- Using the same technique as JDO to serialize objects into a JDBC database or object-oriented database
|
|
Open issues |
Using persistent storage - example
I haven't yet used persistent storage in a clustered environment to serialize the shared session data.
|
Credits |
- Yoav Shapira: thx for your extensive support at the userlist.
- Tomcat userlist: thx for sharing ideas.
- XML/XSLT layout: The XSLT layout has been copied and adapted from the original Tomcat project.
|
|