How to share session between web modules in WebSphere 6.1.
I recently had the *pleasure* of attempting to integrate a second Java web application module into an existing Enterprise application. Throughout what became a mere exercise, I ran into several problems that were not well documented on the web. I found enough documentation to wade my way through to a solution but thought it would be helpful to document my experience for others’ benefit. This post is a brief discussion of the actions you have to perform to share session amongst multiple web modules within a single Java Enterprise application.
The environment is a run-of-the-mill Java Enterprise business web application. The JEE version used is 1.4, Java SDK 1.5 (IBM implementation), running on IBM WebSphere 6.1 application server (fixpack 17 in case that matters). The application is deployed as an EAR with a single WAR. Also important to note is that the application server and web module class loaders are set to load from the application up (inverted, or “parent last”). The IDE being used is the WebSphere Development Studio Client version 7.
The desire was to separate a web service client from the one WAR in the EAR and deploy the client as a second WAR inside the EAR. It was necessary for servlets in the two web modules to share session state. In other words, I wanted to have all the web modules in my EAR use one, and only one, session. The two web modules would also be sharing some common code where each module maintained its own copies of the JAR files.
To meet these requirements there are multiple steps you must take. The requirement to focus on here, especially if your situation is not exactly like mine, is sharing session amongst multiple web modules. Sharing session is not a part of the servlet specification and so leads to some traps. Each step is explained below.
Step 1: Turn on the Shared Session Context IBM extension in the enterprise application configuration.
A big problem with wanting to share session state between web modules or applications in a servlet container is that the official servlet specification forbids it. You can read it for yourself in the Session Scope section of the version of the servlet specification you are using. IBM overcomes this limitation with a non-standard (a.k.a. proprietary) extension that you can toggle called Shared Session Context. How to toggle this extension is documented here. You simply flip on this switch and WebSphere starts sharing session state across web modules.
Remember that, if you decide to use this IBM extension, it is non-standard and it is then unlikely that your web application will be portable to other application servers. For sure, you will not be able to run your application on Apache Tomcat since that container adheres strictly to the servlet specification.
Step 1a: Work around a bug in Rational Application Developer (RAD) IDE for WebSphere.
NOTE: If you are using another IDE such as Eclipse, NetBeans, or IntelliJ IDEA, you can probably skip this step.
There is a bug in certain versions of Rational Application Developer (RAD) and WebSphere Developer Studio Client (WDSC) that must be worked around in order to perform Step 2 without error. Before you continue you should read the IBM bug report and determine if your IDE is affected. If not, skip straight to Step 2. If you are affected, follow the directions in the bug report. If you do have to work around the bug you may notice some side effects that I noticed after doing so. The side effects were acute with my application because it has a large number of files in it (approximately 150MB). You may not experience these problems with your application.
Side effects I experienced after using the work-around in the IDE bug:
- The Integrated Solutions Console for WebSphere took minutes to load some pages.
- Publishing my application to my development server took ~90 minutes each time.
- I lost the option to change class loading order from Parent_First to Parent_Last.
Step 2: Change the class loader policy from Multiple to Single.
Turning on Shared Session Context in Step 1 immediately reveals another problem related to class loading. By default, WebSphere uses unique class loaders for each WAR within an application. So even though two WARs might instantiate the exact same class, the Java runtime does not consider the resulting objects as compatible because they were loaded by different class loaders. The problem when trying to share session across WARs is that an object placed into session by one WAR will not be usable by another WAR. IBM has documented this part of their WebSphere architecture here.
For example, consider the situation where a web application installed in WebSphere is comprised of two web modules: AppA and AppB. Assume that the WebSphere server has been set up as in Step 1 above. If the two web modules are sharing session then it’s going to be common for a servlet in one to place an object in session for a servlet in the other module to retrieve. For instance, consider that AppA places an instance of java.lang.String into session for AppB to use as shown below.
String stringPutIntoSessionByAppA = “appA stuff.”;
When AppB pulls this object out of session as below,
String appBString = (String) session.getAttribute(“stringPutIntoSessionByAppA”);
which only works because of turning on the non-standard option Shared Session Context, an exception like this will be thrown:
ClassCastException: java.lang.String is incompatible with java.lang.String.
This error illustrates that the two classes, whose package and class name match exactly, are not considered to be the same class by the JVM at runtime because each one was loaded by a different class loader.
To fix this problem you have configure the web application to use a single class loader for all web modules within it. This class loader setting is changed through the WebSphere Integrated Solutions Console (a.k.a. the administration console). With the server running, log into the Integrated Solutions Console and click on Applications –> Enterprise Applications and then click on the name of the application whose settings you are changing. Under the Detail Properties section click on Class loading and update detection. Finally, you have two choice as shown below.
In the section WAR Class Loader Policy choose the option Single class loader for application. Click the OK button and then save the configuration. This setting will cause everything (all WARs and EJBs) in the EAR to be loaded under one class loader and allow session to be truly shared between two WARs.
If you want to write a web application for WebSphere 6.1 consisting of multiple web modules and you want all of the modules to share session you will have to do some configuration. The first step, turning on Shared Session Context, is an IBM proprietary extension to the servlet specification. Turning on this feature causes other problems and forces you to change your class loader settings on the server in order to get session sharing fully functional.
From → Uncategorized