ziggy
ziggy

Reputation: 15876

Getting two servlets to use the same object using Servlet context

I am trying to write a simple program where i can put a HashMap on an application scoped session and get two applications/contexts deployed as two war files access the HashMap.

Servlet 1

public void doGet(HttpServletRequest request, HttpServletResponse response)
    throws IOException{
        PrintWriter out = response.getWriter();

        HashMap<String ,String> hm = new HashMap<String, String>();
        hm.put("1", "1");

        this.getServletContext().setAttribute("usermanager", hm);
        this.getServletConfig().getServletContext().setAttribute("usermanager2", hm);   
    }

Servlet 2

public void doGet(HttpServletRequest request, HttpServletResponse response)
throws IOException{

    HashMap newMap2 = (HashMap) this.getServletConfig().getServletContext().getAttribute("usermanager"); 
    HashMap newMap3 = (HashMap) this.getServletContext().getAttribute("usermanager2"); 

    System.out.println("newmap2 size " + newMap2.size());
    System.out.println("newmap3 size " + newMap3.size());   
}

To test this i restarted Tomcat 6 then run access Servlet 1 first so that it initializes the Hashmap object. When i subsequently access Servlet 2 i get a NULL-POINTER error which is pointing at the line number where i tried to call newMap2.size()

What am i doing wrong?

java.lang.NullPointerException
    at com.TestServlet.doGet(TestServlet.java:24)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:617)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:291)
    at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:859)
    at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:602)
    at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:489)
    at java.lang.Thread.run(Thread.java:619)

Upvotes: 1

Views: 4708

Answers (2)

home
home

Reputation: 12538

As @Peter Cetinski already mentioned a Servlet Context always relates to exactly one web application (WAR file). Nevertheless, the Servlet API provides a way to access 'foreign' Servlet Contexts by calling javax.servlet.ServletContext.getContext(uriPath).

So if you really want/need to spread your Servlets across different WARs and communication between them is required, you can do this.

Assuming that Servlet 1 is located in web application warA, Servlet 2 located in web application warB, and the applications context path is the same as the web application name (e.g. http://myserver/warA and http://myserver/warB), the code for Servlet 2 could look like this:

/* retrieve foreign context */
ServletContext ctxWarA = this.getServletContext().getContext("warA");

/* ... and work with it */
Map<String, String> map = (Map<String, String>) ctxWarA.getAttribute("usermanager");

There are some constraints:

  • you must explicitly allow warB to access the foreign context by specifying this in the applications' context.xml: <Context crossContext="true"/>

  • this setup is proprietary (I cannot tell you how this works in other application servers/servlet engines)

  • if you want to share custom classes they must be shared between the applications (place them in <tomcat>/lib

  • in the standard setup you work with different classloaders for warA and warB, you should be aware of that

  • Tomcat does not guarantee a certain startup sequence (there is no way to configure this). In your case warB must be able to handle this and expect warA to be not yet started

If you need to share objects/information between web applications, I'd consider those alternative approaches:

  • a shared singleton located in Tomcat/lib (I know a singleton, but it works)

  • an object located in the JNDI tree (Tomcat documentation)

  • information required to build the cache in a shared data store (file, database, etc.) and each applications loads the data at startup

Upvotes: 7

Peter Cetinski
Peter Cetinski

Reputation: 2336

ServletContext is shareable only within a web application. If you are deploying in 2 different WARs then you have 2 web applications.

Upvotes: 1

Related Questions