tomcat-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Alan Newberger" <>
Subject RE: shell connector
Date Fri, 11 Jan 2002 18:51:51 GMT
thanks for your reply, I still feel there is a problem with ContainerServlets from arbitrary
packages even when placed in $CATALINA_HOME/server/lib, see below...

> From: Craig R. McClanahan []
> I committed some Ant custom tasks yesterday that talk to 
> Manager ... they
> might be useful to you.

I'll check them out, thanks.

> So that one can write servlet-based services that need access 
> to Catalina
> internals.  Existing examples include:
> * Manager servlet (needs to install, remove, and reload webapps)
> * Invoker servlet (needs to create new Wrapper instances on the fly)
> * Administration servlet (will provide web-based user interface for
>   updating pretty much all of the things in server.xml).
> The third thing is in the "admin" webapp in the HEAD branch.

That also sounds really useful, I'm going to have to take a close look at the HEAD branch
:) Hopefully it's capable of persisting changes back into server.xml...

> In order to execute a ContainerServlet that has access to the 
> internals of
> Tomcat 4, the following rules must all be followed:
> * Your servlet must implement the org.apache.catalina.ContainerServlet
>   interface.
> * Your servlet, and all the code it depends on, must be 
> loaded from the
>   "server" classloader.  That means it needs to be installed 
> as unpacked
>   classes under $CATALINA_HOME/server/classes or in JAR files in
>   $CATALINA_HOME/server/lib.  (Classes in common/classes and 
> common/lib
>   are also visible to these components.)
> No changes to Tomcat code, or to standard server.xml settings, are
> required.

IF a servlet which implements ContainerServlet is loaded by the Catalina class loader, everything
will work fine, i.e. it will have its 'setWrapper()' command called by StandardWrapper.load().
 The problem is in the way StandardWrapper decides which classloader to use to load the servlet.
 It uses its private 'isContainerServlet(string)' method, which only looks at the String representation
of the className and checks if it starts with 'org.apache.catalina'.  So, if I have a servlet
implementing ContainerServlet in some package, say '', and put it in a jar
$CATALINA_HOME/server/lib, and create some webapp with a web.xml with
as a 'server-class' for a servlet, things will still fail.  The StandardWrapper.isContainerServlet(string
classname) method will return false, so the StandardWrapper.load() method will try to load
the class from the webapp classloader, which of course will not find the class since it is
not in the webapp classpath.  You can put the in the
common/lib folder and it will load correctly, but things will break because no catalina classes
will be visible to it (an object instance cannot see other objects loaded in _child_ classloaders,
only _parent_ classloaders).

The solution to this isn't trivial -- you want all ContainerServlets to be loaded in the catalina
classloader, but how do you know whether a servlet is a ContainerServlet by its classname
alone, before actually loading it and doing something like 'instanceof' or 'isAssignableFrom()'?
 I'm sure this was why the StandardWrapper.isContainerServlet() method was written but it
just doesn't do the right thing.  I think the way to a nicer solution is through the 'privileged'
attribute for a Context in servlet.xml (evaluated in ServletWrapper via the isServletAllowed()
function).  I suggest that if a Context is designated as privileged, the context's wrapper
should attempt to load servlets via the catalina classloader.  If the class isn't found, catch
the exception and attempt to load it via the webapp classloader.  If the class is loaded,
check if it implements ContainerServlet; if so, call setWrapper() on it and continue, if not
destroy the class object and attempt to load it in the webapp classloader.  This is a bit
more expensive way of loading classes than what is done now, but if only performed in Contexts
marked 'privileged', most Context will be unaffected and privileged Contexts would actually
work :)  I'm fairly sure I'm right about this, I've read the code pretty carefully and tested
out the above behavior (i.e. I've previously tried doing the two things you outline as necessary
above and things failed, it was a mystery until I delved into StandardWrapper source). I'd
be happy to code up these proposed changes into StandardWrapper if you're interested.


To unsubscribe, e-mail:   <>
For additional commands, e-mail: <>

View raw message