I'm trying to figure out the best-practice to allow two servlets that are deployed in two separate contexts to share an array of Java beans.
I'm working with WebSphere, and have a servlet that is to be shared by many different portlets that are defined by many different portlet-apps. Each portlet-app is deployed separately from the other portlet-apps, so they don't share the same session or servlet context like I thought that they might.
The basic idea was to have a portlet 'Pa' set a Java bean array attribute (keyed with 'paJavaBeans') onto its session, and then from that portlet's JSP, call servlet 'S' and have servlet 'S' get the same session attribute (using the key 'paJavaBeans') to process. Found out that the request.getSession() of servlet 'S' is different than the request.getSession() of 'Pa', so the 'paJavaBeans' attribute wasn't shareable via those session objects. I figured that would be too easy, but gave it a try anyway.
My main goal was to avoid having to deploy a copy of servlet 'S' with each webmodule, but instead deploy just one and have all other webmodules access and share it.
If anyone could point me in the right direction to the best-practice that could satisfy this request, I'd appreciate it.
How to share data between servlet contexts? I can think of these solutions:
Solutions based on standards, and which work in distributed environment and with mixture of app server offerings: 1. Using JNDI: Store the shared data in JNDI. Works even if each web app is deployed in a separate JVM or with different web container products, as long as the JNDI provider is hosted in a central server.
2. Using DB: Store the shared data in a DB. Has the advantage of being persistent and available.
3. Using HTTP parameters: Deploy just the servlet as another standalone web app. It'll get a separate standalone servlet context, which is used as a shared context. It stores and retries shared data from this servlet context. Other web apps use HTTP POST and GET to this servlet to add and retrieve data. Kind of like a RESTful service. Doesn't require any service other than servlet container.
4. Use an EJB layer and stateful session bean accessed through JNDI, to store shared data. Seems unnecessarily complicated for simply sharing passive data.
5. Using other app's SessionContext: Use the ServletContext.getContext(uri) method to access another app's servlet context, and access data that way. I'm not sure whether this will work for apps running in separate JVMs.
Use memory caching: Use a memory caching framework like EHCache.
Possible solution for colocated web apps (but not tried this out myself): Use a custom caching class that stores the data as static, and is configured to load in the system or common classloader (most ASes have a concept of classloader hierarchy - they're implemented differently by products with different levels and names, but most include a "common" classloader, that is shared by all web app classloaders. Hence, the static data also gets shared, atleast by colocated web apps in a single JVM.
Speaking for myself, I think I prefer the HTTP solution, then the JNDI one.
Thank you Karthik for the reply and multiple options. I went with the built-in WebSphere JNDI option that makes available a DistributedMap to all applications deployed on the server. I can set an attribute on this map from one app, then read it from another app. I'm not positive if it's the most efficient solution, but for now it's working. Here are the main steps I took.
From the servlet in the app that sets the attribute on the map:
AssignmentSummary assignmentsSummaries = new AssignmentSummary;
javax.naming.Context jndiContext = new javax.naming.InitialContext();
com.ibm.websphere.cache.DistributedMap dMap = (com.ibm.websphere.cache.DistributedMap)jndiContext.lookup("services/cache/distributedmap");
From the servlet in the app that reads the attribute from the map: