Difference between session.getServletContext() and session.getServletContext().getContext("/SampleProject")

java, servlets, tomcat

Solution

I feel your question was slightly misunderstood and that you already had the basic understanding of the API i.e. once a web-app sets its `crossContext="true"` it could use `getContext()` to get access to a context that corresponds to some other web-app deployed on the server.

getServletContext().getContext() equals NULL unless <Context crossContext="true">

From what I've understood, your question actually is that in `/SameWebApp` why

ServletContext context1 = session.getServletContext();
context1.setAttribute("contextAttribute", new Object());
ServletContext context2 = session.getServletContext().getContext("/SameWebApp");

System.out.println(context1.equals(context2)); // prints false, or 
System.out.println(context2.getAttribute("contextAttribute")); // prints null (at least they could have been clones)

In just one word, the answer is "Security". Imagine if you couldn't guarantee that an "adminEmail" context attribute has not been tampered with by an evil web-app having its `crossContext=true`. Your app could potentially help compromise itself as soon as that "Forgot Password" request comes! :)

A Dive into Tomcat internals

Tomcat 7 provides a `class ApplicationContext implements ServletContext` that returns from `getContext("/context-root")` as

    if (context.getCrossContext()) {
        // If crossContext is enabled, can always return the context
        return child.getServletContext();
    } else if (child == context) {
        // Can still return the current context
        return context.getServletContext();
    } else {
        // Nothing to return
        return (null);
    }

Here `context` belongs to current web-app and `child` represents the other web-app. But, hold on, what makes Tomcat call it a child?

These two actually aren't `ApplicationContext` but instances of `StandardContext` a class that `implements Context` but instead of servlet specific things holds Tomcat specific config settings for a web-app like crossContext, hostname, mimeMappings etc. `StandardContext.getParent()` gives you the `Container` and hence it has been referred to as a child above.

Anyways, we're interested in the case when `child == context` is true i.e. `getContext()` was called on the "/SameWebApp". The call is being delegated to `StandardContext.getServletContext()` which has been implemented to return a different instance of `ApplicationContext`.

This is why the attributes you set in `context1` are not found in `context2`.

But wait, there's some more to it. Why does `StandardContext.getServletContext()` return like

return (context.getFacade());

A Tomcat instance is basically executing two types of Java code:

- container provided, and

- user deployed

The container code is "Trusted" and may need to run with elevated privileges sometimes. The user code, on the other hand, is not trusted and needs to be restricted from compromising Tomcat internals.

One of the things that Tomcat does to achieve this is always wrap an `ApplicationContextFacade` around the `ApplicationContext` (and hence the `StandardContext` as well). So just to recap, what appears to be a simple `ServletContext` implementation is actually a `StandardContext` mapped to an `ApplicationContext` which is then wrapped within an `ApplicationContextFacade`.

For further information on how the `ApplicationContextFacade` works using Reflection in tandem with `Globals.IS_SECURITY_ENABLED` and `SecurityUtil.isPackageProtectionEnabled()` settings please take a look at Why do Servlets access Tomcat ApplicationContext through a Facade on SO.

References: Tomcat 7 Source Code (Download Link)

Problem

I have a Tomcat 6 instance running on my local machine. I have made the following changes in its configuration: In /conf/`context.xml` – changed the tag as follows ``` <Context crossContext="true"> ``` In /conf/`server.xml` – changed the tag as follows ``` <Connector port="8080" protocol="HTTP/1.1" emptySessionPath="true" connectionTimeout="20000" redirectPort="8443" /> ``` Suppose I have a WAR file named `SampleProject.war` deployed here which extract to folder `SampleProject`. In some servlet in this WAR, say `SampleServlet`, I write two blocks of code as follows : ``` ServletContext context1 = session.getServletContext(); ``` and ``` ServletContext context2 = session.getServletContext().getContext("/SampleProject"); ``` What is the difference between `context1` and `context2`? I thought that both refer to the application context. But if I set some attribute in `context1` and access in `context2`, I don't get the value in `context2`. Any help would be appreciated.

Original source