TechSpellBound
TechSpellBound

Reputation: 2555

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

I have a Tomcat 6 instance running on my local machine.

I have made the following changes in its configuration:

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.

Upvotes: 7

Views: 13945

Answers (3)

Ravi K Thapliyal
Ravi K Thapliyal

Reputation: 51711

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)

Upvotes: 5

Glen Best
Glen Best

Reputation: 23105

Think OO & java EE platform standards + security.

The first call returns the definitive servlet context for the current app, with all operations supported.

The second call returns a copy of the servlet context that could be for any app. As stated (rather vaguely!) in the javadoc, it's purpose is to allow you to obtain a RequestDispatcher, so you can dispatch to pages of other apps. It's other major but implicit requirement is to do this securely and to respect the Java EE specs, which do not allow sharing of session state or servlet context between apps. Imagine the terrible damage "rogue App B" could do to "good App A" if it could just change (or read) Servlet Context data by brute force. That's why it's a copy.

Hence, setting attributes on the copy, does not result in changes to the original. You could argue that the copy should throw some "Operation Not Supported Exception". Alternatively, you could argue that getRequestDispatcher should be refactored either to another class, or to allow an App Context URL to be passed in. ... But, unfortunately, neither of these things are true. B^)

Upvotes: 3

Eswar
Eswar

Reputation: 49

Absolutely those two context objects are different from another.. Context1 object gives current web application servlet context obj. ( ServletContext context1 = session.getServletContext();)

and

context2 object gives the servletcontext obj of specified web application (ServletContext context2 = session.getServletContext().getContext("/SampleProject");)

you are setting object in one context and trying to retrieve using another context, so it is not possible to get attribute from another web application context by putting it in current application context. But you can get attribute resides in another web application context by using second method.

Upvotes: 3

Related Questions