53

We want to split a working application in two different .war files in order to be able to update one app without affecting the other. Each webapp will have different a UI, different users and different deploy schedule.

The easiest path seems to be sharing the same session, so if app A set session.setAttribute("foo", "bar") app B will be able to see it.

Is there a way to share the HttpSession state for both apps in the same Tomcat instance?

Our app is running on a dedicated Tomcat 5.5, there are no other apps running on the same tomcat instance, so any security concerns regarding the session sharing are not a problem. We're running multiple Tomcat instances, but the balancer is using sticky sessions.

If it's not possible or this session sharing is a really bad idea please leave a comment.

zb226
  • 9,586
  • 6
  • 49
  • 79
Serxipc
  • 6,639
  • 9
  • 40
  • 51

11 Answers11

27

You should not share HttpSession; but you can share other objects. For example, you can register an object via JNDI and access the same object in all your apps (databases use this to pool connections).

Aaron Digulla
  • 321,842
  • 108
  • 597
  • 820
23

One thing to be aware of is that two web apps will use different classloaders. If you want to share objects, they need to use the same version of the class from the same classloader (or else you will get LinkageErrors). That means either putting them in a classloader shared by both web apps (system classpath for example) OR using serialization to effectively drain and reconstitute the object in the right classloader with the correct version of the class.

Alex Miller
  • 69,183
  • 25
  • 122
  • 167
7

If you want to use Spring, there's a project called Spring Session: https://github.com/spring-projects/spring-session

Quoting: "HttpSession - allows replacing the HttpSession in an application container (i.e. Tomcat) neutral way"

Luís Soares
  • 5,726
  • 4
  • 39
  • 66
6

For Tomcat 8 I use the following configuration to share a session across 2 webapps:

conf/context.xml

<Context sessionCookiePath="/">
    <Valve className="org.apache.catalina.valves.PersistentValve"/>
    <Manager className="org.apache.catalina.session.PersistentManager">
        <Store className="org.apache.catalina.session.FileStore" directory="${catalina.base}/temp/sessions"/>
    </Manager>
    ...
</Context>

I deploy the same simple webapp twice log.war and log2.war:

/log
/log2

I can now log-in to /log and have the user displayed in /log2, this does not work with the tomcat default configuration.

enter image description here

The session value is set and read:

HttpSession session=request.getSession();  
session.setAttribute("name",name);

HttpSession session=request.getSession(false);  
String name=(String)session.getAttribute("name");  

I used this project as example: https://www.javatpoint.com/servlet-http-session-login-and-logout-example

Most examples/solutions use a in-memory database which requires more setup work:

flavio.donze
  • 7,432
  • 9
  • 58
  • 91
5

If the two webapps are so closely coupled that they need to share objects, why are you splitting it in two? Even if you manage them somewhat independently any decent build management system should be able to create a single WAR file for deployment.

A solution like Aaron suggest with JNDI will work, but only if both webapps are running on the same server. If the units are tightly coupled and you are going to be running it on the same server anyway ... might as well have a single WAR.

If you really do want them to stand independently I'd seriously examine the data exchange between the two. Ideally you'd want them to only share relevant data with one another. This data could be passed back and forth via POST (or GET if more appropriate) parameters, you might even consider using cookies.

mppfiles
  • 2,397
  • 1
  • 21
  • 16
Kris
  • 14,426
  • 7
  • 55
  • 65
  • 1
    We are splitting the webapps to be able to update one app without affecting the other. Each webapp will have different ui, different users and different deploy schedule. – Serxipc Mar 20 '09 at 14:44
  • Then you should definitely make sure they only communicate via some API, not by sharing class instances (unless via something like JMX). – Kris Mar 23 '09 at 10:24
  • 1
    other example would be providing multilanguage translated websites, i.e. es.example.com pt.example.com ru.example.com etc. Each multilanguage websites has their own servlet mappings, so it is a different app. But they might want to reuse some data, since the content is translated. – Mladen Adamovic Sep 26 '16 at 09:17
4

One way of doing this is described in this blog post: Session sharing in Apache Tomcat

Summary: Add emptySessionPath to the Connector configuration and crossContext to the Context

hooknc
  • 4,854
  • 5
  • 31
  • 60
Ray Hulha
  • 10,701
  • 5
  • 53
  • 53
  • 3
    This looks like a great solution, but you should really include some details of the implementation to be a valid answer, in case the referred link breaks. – beldaz Nov 13 '14 at 23:17
  • This does not work, as Tomcat webapps names are involved on storing and reading session data. – D.A.H May 13 '22 at 15:47
3

redison download

conf/context.xml

<Context sessionCookiePath="/">
  ...
  <Manager className="org.redisson.tomcat.RedissonSessionManager"
               configPath="${catalina.base}/conf/redisson.yaml"
               readMode="REDIS" />
</Context>

conf/redisson.yaml

singleServerConfig:
  address: "redis://<host>:6379"

sessionCookiePath="/" makes Tomcat use the same session id for different web apps. RedissonSessionManager makes session to be persisted in 'shared space'


I was not able to achieve desired result with org.apache.catalina.session.FileStore PersistentManager in shared context.xml, I faced issues with session deserialization in background expiration monitor thread. It failed to deseriazile the session because it was using common classloader without webapp serializable models in classpath. Theoretically PersistentManager could be configured for each web app separately (to have proper classpath) in WEB-INF/context.xml but I failed to make it work.

org.apache.catalina.session.JDBCStore PersistentManage was promising because it expose last_access column for the session so it is not required to deserialize session_data, but it was saving app_name all the time causing same session id to be written as different rows for diffrent web apps. Thus session data was not stored in the shared place.

Spring Session has it`s own way to create session id. I was not able to find solution to force Spring Session to create same session id for different web apps.

Solution with core tomcat session id generation (with ability to generate the same for different web apps and RedissonSessionManager, which store data using session id as the only key and has it's own expiration mechanism) finally worked for me. The solution works perfectly with @SessionScope spring beans.

Mike
  • 20,010
  • 25
  • 97
  • 140
  • 1
    As I understand all other options failed, except using RedissonSessionManager? Session sharing can be implemented by using RedissonSessionManager? – D.A.H May 13 '22 at 15:53
  • 1
    I did some testing and and JDBCStore requires that sessionAppCol="app_name" is defined. Without sessionAppCol it is unable to write session data. – D.A.H May 13 '22 at 16:01
  • This is the best and most accurate answer to the question how share session state between different applications in tomcat. Redis based solution works. You can found ready to use Redis packages here: https://redisson.org/articles/redis-based-tomcat-session-management.html – D.A.H May 13 '22 at 16:29
0

You can do by taking servlet context by your context root.

For retrieving variable.

request.getSession().getServletContext().getContext("/{applicationContextRoot}").getAttribute(variableName)

For setting variable:

request.getSession().getServletContext().getContext("/{applicationContextRoot}").setAttribute(variableName,variableValue)

Note: Both the applications should deployed in the same server.

Pls let me know if you find any problem

Pete
  • 57,112
  • 28
  • 117
  • 166
Qazi
  • 132
  • 1
  • 3
  • 11
  • This is not the session but the servlet context, it's different in scope and lifespan from the session, two things different. – Petros Makris Sep 05 '18 at 06:16
0

Tomcat 8 : i had to do : <Context crossContext="true" sessionCookiePath="/"> in conf/context.xml

more details on config attributes here

and then to set the value(like @Qazi's answer):

ServletContext servletContext =request.getSession().getServletContext().getContext("contextPath")
servletContext.setAttribute(variableName,variableValue)

to get the value:

ServletContext servletContext =request.getSession().getServletContext().getContext("contextPath")
servletContext.getAttribute("user"); 
rohith
  • 733
  • 4
  • 10
  • 24
0

I developed session state server for tomcat using python.

Due to this I don't need to change the code already written for creating/accessing and destroying session. Also as there is separate server/service which is handling and storing session so not master cluster is needed. There is no session replication (as in tomcat clustering) in this case, rather this is session sharing between web farming.

Amogh
  • 4,453
  • 11
  • 45
  • 106
-1

You should not split your app that way in order by have high availability. You could deploy the whole app on many tomcat instances.

cherouvim
  • 31,725
  • 15
  • 104
  • 153
  • 2
    It's not an availability problem. We want two different wars because each one will have it's own purpose, like an admin app and a users app. – Serxipc Mar 22 '09 at 11:59
  • 2
    @Serhii: fair enough. You didn't mention this in your question. Instead you said `in order to be able to update one app without affecting the other`. That was the basis of my answer. – cherouvim Dec 02 '14 at 05:34