users@glassfish.java.net

Re: Contexts and JSTL imports

From: <Jan.Luehe_at_Sun.COM>
Date: Mon, 02 Jul 2007 18:19:13 -0700

ITVGuy2000 wrote:

>Jan.Luehe wrote:
>
>
>>This is expected to work, and is working for me.
>>
>>You've deployed your webapp at "/messingaround/MyGlossaryOneFive",
>>and "ShowXMLDefs.jsp" resides at the top-level directory of your webapp,
>>right?
>>
>>Is there anything else deployed underneath "/messingaround"?
>>
>>Jan
>>
>>
>>
>
>Thanks for looking at this.
>
>- I have deployed my webapp at /messingaround/MyGlssaryOneFive
>- ShowXMLDefs.jsp at the top level of my webapp at,
>/messingaround/MyGlossaryOneFive/web/ShowXMLDefs.jsp
>- Yes there are many other applications deployed under messingaround, and
>messingaround is itself a context.
>Thus I have (or I should say had) the following applicaiton contexts:
>/messingaround
>/messingaround/MyGlossaryOneFive
>/messingaround/MySimpleGlossary
>/messingaround/PetSQLStruts
>/messingaround/PetSQLStrutsiBATIS
>/messingaround/manymanymanyothers
>
>As I said, these all work great. Its just when I want to do an JSTL import
>from a foreign context that things go wrong.
>
>One other thing... the import is done in the file
>/messingaround/xml/xml.jsp. This is under the /messingaround context.
>
>

OK, I think I understand what is going on: You've uncovered a
long-standing bug in the web container! :)

o.a.c.core.ApplicationContext.getContext(String uri), which provides
the impl of javax.servlet.ServletContext.getContext() and which is what
<c:import> ends up invoking by passing in the value of its "context"
attribute, has code like this (in abbreviated form):

    String contextPath = context.getPath();
    if (uri.startsWith(contextPath)) {
        return (this);
    }

where context is the underlying o.a.c.core.StandardContext to which
o.a.c.core.ApplicationContext delegates.

Now, if a servlet contained in a context deployed at "/123" invokes
this code:

    ServletContext sc = getServletContext().getContext("/123/456");
    RequestDispatcher rd = sc.getRequestDispatcher("/test.txt");
    rd.include(req, res);

where "test.txt" exists only in the webapp deployed at "/123/456", but
not in the webapp deployed at "/123", the returned servlet context
will be that of the webapp deployed at "/123" (because "/123/456"
starts with "/123", see the above condition in
ApplicationContext.getContext()), which does not have the requested
resource "test.txt", causing rd.include() to return a 404.

If the above servlet had been contained in a context deployed at any
context root different from "/123", the correct servlet context (i.e.,
the one deployed at "/123/456") would have been returned, and
rd.include() would have succeeded.

In summary, o.a.c.core.ApplicationContext.getContext(String uri)
really should return the context with the *longest matching* context
path. This would be consistent with how the request mapping algorithm
works. According to the servlet spec ("Use of URL Paths"):

  The web application selected must have the longest context path
  that matches the start of the request URL.

(I recommend that javax.servlet.ServletContext.getContext(String uripath),
which currently has these javadocs:

    * The given path must be begin with "/", is interpreted relative
    * to the server's document root and is matched against the context
roots of
    * other web applications hosted on this container.

also be clarified to mention that the context with the longest matching
path be returned.)

Please go ahead and log a bug in IssueTracker, or else, let me know if you
would like me to take care of this.

Thanks!!


Jan


>Thanks,
>
>ITVGuy2000
>
>