2

I have a Struts based web application that has a structure similar to the one shown below. (Not this is just an example)

$TOMCAT_HOME/webapps/myapp
            |-css
                |-myapp.css
            |-js
                |-myapp.js
            |-forum
                |-index.jsp
                |-list.jsp
                |-users.jsp
            |-Articles
                |-index.jsp
                |-ListArticles.jsp
            |-Guestbook
                |-viewGuestBook.jsp
                |-AddnewEntry.jsp
            |-WEB-INF
                |-classes
                    com
                     |-myapp
                        |-forum
                            |-DisplayForum.class
                            |-ListUsers.class
                        |-article
                            |-ArticleList.class
                            |-AddArticle.class
                        |-guestbk
                            |-LoadGuestBook.class
                            |-ProcessGuestBook.class

Currently, the application is built using ANT and deployed to the Tomcat application server as a single war file (named myapp.war). I would like to separate the application so that it is deployed using multiple war files for each module. (i.e. forum.war, articles.war and guestbook.war). The contents of the new war file will only contain files related to the module. For example, the forum.war file will contain

$TOMCAT_HOME/webapps/forum              
            |-forum
                |-index.jsp
                |-list.jsp
                |-users.jsp             
            |-WEB-INF
                |-classes
                    com
                     |-myapp
                        |-forum
                            |-DisplayForum.class
                            |-ListUsers.class

There are a couple of things i am not sure about with this approach.

Shared static resources

The *.css and *.js files are common across each war file. If i have different war files i will have a copy of the css files in each war file. Is there any way i can deliver the resource files (css, js, static files) in a common approach so that they are shared. I am thinking that maybe i should include a new war file called common.war and include the shared static data. (I think the other war files can access these files using the URL as they are static resources. right?)

Shared classes

There are some classes that are shared globally. As an example, there is a class called UserSession. When the user logs-on to the application, the UserSession object is created and stored in a Hashtable and the user's session id as the key for the Hashtable. Anytime a user tries to acess any part of the application, the session id is checked against the sesion id's in the Hashtable.

The UserSession object does a number of things - such as

  • Validating user login
  • Track user's activity
  • Log user login history to the database
  • And more...

I need all war files (applications/modules) to have access to the UserSession object but that only one is associated with each session. How should i architect this so that the user's session spans across the different war files?

I have been reading around about how to share objects and came up with two options

  • Shared object via JNDI
  • Shared object via Tomcat ServletContext

As i understand it, if an object is stored in the ServletContext, it can be accessed by any application (i.e. war file). How would this work though if i want a different instance per user session. For example,

User1 logs on - UserSession stored in ServletContext User2 logs on - Where do i store User2's UserSession object?

At the moment i store the sessionID in HTTPSession and the UserSession object in a HashTable.

HttpSession session = request.getSession(true);
UserSession userSession = getUserSession(session.getId());

Does User1 get the same sessionId regardless of the war file he/she is accessing? If so Could i Store another List object in ServletContext that contains the sessionIDs?

I have also seen references to object sharing using JNDI. I am not very familiar with JNDI. I have used JNDI for DataSources but that is as far as it goes. How exactly would it work? I would appreciate if someone can point me to an example showing how JNDI can be used for sharing data. Is it true that JNDI is the better approach and why?

And finally, where would the UserSession.class file reside? I know i can put it in a jar file in $TOMCAT_HOME/lib but this is usually not recommended. The problem though is if it is in the WEB-INF/lib folder of one of the war files it cant be accessed by any other war file.

Would appreciate some input/suggestions. I would be interested to know what strategy you use to deploy an application made up of multiple war files.

Thanks

Edit

Ok i forgot to mention why i want to split the war file. Basically, we have several teams of developers. We have had situations where one team is working on a specific area of the application and another team is working on a different area.

For example assume the following scenario -

Team1 is working on the Forums module due to be released next month. Team2 has been asked to deliver a change for the Articles and should be released next week.

If Team1 has checked in their code and are performing system/integration tests which will take more than a week, Team2 is stuffed as they have to wait.

These kinds of problems are usually solved using Branching but we tend to avoid branching as it introduces a lot of complications with merging that we decided to avoid Branching.

The other reason is that we have an older application that i am considering to reuse with this application. The older application based on pure HTTPServlet. I.e not based on any framework (i.e. structs, spring etc). If i want to integrate it with my existing app i will need to use the session/servletcontext.

Also, a lot of people are skeptical of the fact that if you make a simple change (e.g. you add a new stylesheet definition to a single css file), you have to rebuild and redeploy the whole application.

Other reasons include

  • Could Simplify scalability/load balancing - (possibly?) Not sure about this one. I am thinking in terms of deploying each war file to a different server/cluster.
  • Reduces PERMGEN memory requirements
  • etc...
ziggy
  • 15,677
  • 67
  • 194
  • 287

2 Answers2

2

I'm not sure if you understood correctly, but the HttpSession is different for each user (browser session), and for each application as well, AFAIK, so you can't use it to share data.

Basically, you need communication between your web applications. You could have one war to act as data manager for your UserSession, and all other wars communicating to this one. The data manager application needs to expose a service, e.g. UserSessionManager that can be accessed via other applications.

JNDI is a traditional solution for this. Spring has some helpers for this, but the JNDI API is not too complicated either. In the data manager war, you could do something like this in an initialization method:

DataManager mgr = new DataManagerImpl(...);
InitialContext ic = new InitialContext();
ic.rebind("java:global/env/datamanager", mgr);

The interface and the data objects you use needs to be put in a jar that is shared in all 'client' wars, the implementation is only in the data manager war. In your client wars, you can then do:

InitialContext ic = new InitialContext();
DataManager mgr = (DataManager)ic.lookup("java:global/env/datamanager");

Hope this helps, Geert.

GeertPt
  • 16,398
  • 2
  • 37
  • 61
  • How is the object refered to from JNDI initialized? – ziggy Feb 13 '12 at 16:21
  • Some servlet or servlet context listener should initialize the service and bind it to JNDI as part of servlet init or listener contextInitialized method. – GeertPt Feb 13 '12 at 21:56
  • Would you be able to point me to any example that shows how to initialise the object in JNDI using either a servlet, servlet context listener or contextInitialised method. Thanks – ziggy Feb 25 '12 at 15:22
1

If Team1 has checked in their code and are performing system/integration tests which will take more than a week, Team2 is stuffed as they have to wait.

These kinds of problems are usually solved using Branching but we tend to avoid branching as it introduces a lot of complications with merging that we decided to avoid Branching.

Well, there's your problem right there. This is exactly what branching is for. If it's giving you problems, then the answer is to solve those problems, not to avoid branching entirely. It might be as simple as switching to a better VCS. (Which one are you using right now?)

Also, a lot of people are skeptical of the fact that if you make a simple change (e.g. you add a new stylesheet definition to a single css file), you have to rebuild and redeploy the whole application.

That's the nature of Java web apps. If you put the CSS files into a separate war, then you still have to rebuild and redeploy that war. And with multiple wars, the process will become more complicated, not less.

Anyway, every Java IDE lets you do this with a single key press, so I don't see what the big deal is.

Could Simplify scalability/load balancing - (possibly?)

Possibly. But you know what they say about premature optimization.

Community
  • 1
  • 1
Mike Baranczak
  • 8,291
  • 8
  • 47
  • 71
  • With regards to rebuilding the war file that includes the CSS files, that is exactly what we want. I.e. only build the necessary war file - Not the jsp pages, the java files etc. Im afraid introducing branching is not possible. :) – ziggy Feb 13 '12 at 16:16