You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by Arthur Ash <ar...@epropose.com> on 2001/02/02 00:07:00 UTC

Servlet ClassLoader

Hi Folks,

I'm having a general issue with the app-specific classpath (WEB-INF/classes 
and WEB-INF/lib/*.jar).

Here is the scenario as I understand it:
I have an MVC servlet/bean framework that is installed in the primordial 
classpath.  It contains a single dispatcher servlet which instantiates 
handler classes (which function like servlets) using Class.forName().   My 
intention is to to put these app-specific handler classes in 
WEB-INF/classes or WEB-INF/lib in order to be a good J2EE citizen.

However, since the dispatch servlet has been loaded with the primordial 
class loader (ie, the Tomcat code first tried and succeeded to load it 
using the default class loader), when it itslef calls Class.forName(), it 
gets this same (primordial) ClassLoader.  It cannot see anything that is in 
WEB-INF, since this is visible to only to the servlet class loader (ie, 
com.apache.tomcat.loader.AdaptiveClassLoader).

Am I just screwed or is there some cool trick that I am missing?  Of course 
I could change the deployment scheme to put a copy of the dispatcher 
servlet into each apps WE-INF/classes, but this seems a bit clunky.

thanks
Arthur


mod_jk static build

Posted by Avery Buffington <av...@fundsxpress.com>.
Just wondering if there would be any drawbacks to installin mod_jk as a
static module instead of a DSO?  I'd like to use it as a static module,
but I thought that maybe there was a reason that a makefile was not
included to build it in this manner.  Before I start making my own
Makefile for a static build I figured I ask the experts. 

thanks,


-Avery

Re: Servlet ClassLoader

Posted by cm...@yahoo.com.
> WEB-INF/lib.  In the 2.3 model, Y will override X.  In the standard delegation
> model (i.e. Tomcat 3.2) you'd get the classes from X no matter what you did.

If you add a library to the CLASSPATH before starting tomcat 3.x - it'll
be used and no webapplication can override or change it. 

But this is a configuration choice - if you start tomcat with nothing in
CLASSPATH the webapplication can define anything it wants. 

The delegation module ensure that trusted code has preference over
untrusted code, and parent loader has precedence over child loader - if
you want to make sure that a class is loaded with _your_ code and is not
overriden.

Again - the model is fine, the implementation in 3.2 is bad ( because
parser.jar, etc is added to the CLASSPATH before starting tomcat ). The
fix in 3.3 is simple - start tomcat with Main.java ( in the main branch ),
put in CLASSPATH or parent loader ( if you embed tomcat ) what you want to
take precedence and not be overriden, set "useApplicationLoader" option 
in the loader interceptor.

( you can also set "useNoParent" option - and the webapps will have the
null parent - i.e. the system class loader, with rt.jar and ext/ in it )

 
Costin


Re: Servlet ClassLoader

Posted by "Craig R. McClanahan" <Cr...@eng.sun.com>.
Gudmundur Hafsteinsson wrote:

> > | You're right about the normal delegation model for Java2.
> > However, the Servlet
> > | 2.3 Spec (Proposed Final Draft) gives a servlet container
> > the option to "look
> > | before delegating" -- see Section 9.6.2.  Tomcat 4.0 does this.
> >
> > I've been wondering quite some time: how can this be a
> > "option"? I find
> > that very disturbing! Wouldn't that make tons of portability
> > problems? The
> > classloading isn't exactly something that's the easies thing
> > with Java to
> > grasp, and when things change from container to container,
> > thing start to
> > get really frustrating..
> >
> > | The intention of this language is that you can have version
> > X of a library
> > | installed as a shared resource, and version Y of the
> > library available in
> > | WEB-INF/lib.  In the 2.3 model, Y will override X.  In the
> > standard delegation
> > | model (i.e. Tomcat 3.2) you'd get the classes from X no
> > matter what you did.
> >
> > Yes, and this sounds much more sensible. Why not take away
> > the "option"
> > part of that section?!
> >
> > I know that you don't personally have the sole responsibility for that
> > spec, but I just wondered why it is like this!
>
> I agree! This is a very intuitive approach for loading classes
> in webapps, and should be specified without options.
> I don't know the community process that well, and I don't know
> the exact status of 2.3, but is it too late to remove that option and
> make it mandatory?
>

Servlet 2.3 is currently in "Proposed Final Draft" status.  The expert group
is currently considering several clarifications and minor changes.  Feedback
suggesting anything else should be sent to
"servletapi-feedback@eng.sun.com".

On the particular issue of class loaders, this is an area where existing
container implementations differ substantially already.  In fact, there is
no guarantee that any particular container provides for shared JAR files at
all (it is not specified behavior), so it would be difficult to impose this
kind of a restriction without going to the effort to define a lot more about
how shared class loaders work to ensure portability.

Applications that wish to protect themselves from class loader differences
need only follow two rules:
* Don't use any "shared library" capability of your servlet
  container.
* Place all the library JARs you need into WEB-INF/lib.

The challenge, of course, is dealing with things that the container itself
makes available in a shared manner.  For Tomcat, that issue shows up with
the XML parser, which is needed by Jasper to parse TLD files, as well as
pages in XML syntax.  One of the things we definitely need to look at is
migrating the parser that Jasper uses into a separate Jasper-only
classloader, so that it does not "pollute" the class loader space of web
apps.

>
> Reg,
> Gummi Haf

Craig McClanahan




RE: Servlet ClassLoader

Posted by Gudmundur Hafsteinsson <gu...@dimonsoftware.com>.
> | You're right about the normal delegation model for Java2.  
> However, the Servlet
> | 2.3 Spec (Proposed Final Draft) gives a servlet container 
> the option to "look
> | before delegating" -- see Section 9.6.2.  Tomcat 4.0 does this.
> 
> I've been wondering quite some time: how can this be a 
> "option"? I find
> that very disturbing! Wouldn't that make tons of portability 
> problems? The
> classloading isn't exactly something that's the easies thing 
> with Java to
> grasp, and when things change from container to container, 
> thing start to
> get really frustrating..
> 
> | The intention of this language is that you can have version 
> X of a library
> | installed as a shared resource, and version Y of the 
> library available in
> | WEB-INF/lib.  In the 2.3 model, Y will override X.  In the 
> standard delegation
> | model (i.e. Tomcat 3.2) you'd get the classes from X no 
> matter what you did.
> 
> Yes, and this sounds much more sensible. Why not take away 
> the "option"
> part of that section?!
> 
> I know that you don't personally have the sole responsibility for that
> spec, but I just wondered why it is like this!

I agree! This is a very intuitive approach for loading classes
in webapps, and should be specified without options.
I don't know the community process that well, and I don't know
the exact status of 2.3, but is it too late to remove that option and
make it mandatory?

Reg,
Gummi Haf

Re: Servlet ClassLoader

Posted by Endre Stølsvik <En...@Stolsvik.com>.
On Fri, 2 Feb 2001, Craig R. McClanahan wrote:

| > > -----Original Message-----
| > > From: Craig R. McClanahan [mailto:Craig.McClanahan@eng.sun.com]
| > >* Java asked the webapp class loader to find the
| > >  controller servlet class
| > >* The webapp class loader did not find the class
| > >  so it delegated to the shared class loader
| > >* The shared class loader (which reads from $CATALINA_HOME/lib
| > >  in Tomcat 4.0 -- the corresponding loader in Tomcat 3.2 reads
| > >  from the system classpath) and finds your class
| > >
| > > Now, when your controller servlet calls Class.forName(), it
| > > starts from its
| > > *own* class loader, and looks either there, or upwards.  Of
| > > course, if your
| > > components are under WEB-INF/classes or WEB-INF/lib, they are not
| > > visible ...
| >
| > The Java2 class loading model is for a loader to "delegate first" to it's
| > parent loader.  Only if the parent loader (that also delegates first to it's
| > parent) can't find the class will the original loader try to load it.
| >
| > The description above shows the webapp loader attempting to load the class
| > first and only delegating if that fails.  Is this really the case?
| >
|
| Sorry ... I should have been more explicit here.
|
| You're right about the normal delegation model for Java2.  However, the Servlet
| 2.3 Spec (Proposed Final Draft) gives a servlet container the option to "look
| before delegating" -- see Section 9.6.2.  Tomcat 4.0 does this.

I've been wondering quite some time: how can this be a "option"? I find
that very disturbing! Wouldn't that make tons of portability problems? The
classloading isn't exactly something that's the easies thing with Java to
grasp, and when things change from container to container, thing start to
get really frustrating..

| The intention of this language is that you can have version X of a library
| installed as a shared resource, and version Y of the library available in
| WEB-INF/lib.  In the 2.3 model, Y will override X.  In the standard delegation
| model (i.e. Tomcat 3.2) you'd get the classes from X no matter what you did.

Yes, and this sounds much more sensible. Why not take away the "option"
part of that section?!

I know that you don't personally have the sole responsibility for that
spec, but I just wondered why it is like this!

-- 
Mvh,
Endre


Re: Servlet ClassLoader

Posted by "Craig R. McClanahan" <Cr...@eng.sun.com>.

Marc Saegesser wrote:

> > -----Original Message-----
> > From: Craig R. McClanahan [mailto:Craig.McClanahan@eng.sun.com]
> >* Java asked the webapp class loader to find the
> >  controller servlet class
> >* The webapp class loader did not find the class
> >  so it delegated to the shared class loader
> >* The shared class loader (which reads from $CATALINA_HOME/lib
> >  in Tomcat 4.0 -- the corresponding loader in Tomcat 3.2 reads
> >  from the system classpath) and finds your class
> >
> > Now, when your controller servlet calls Class.forName(), it
> > starts from its
> > *own* class loader, and looks either there, or upwards.  Of
> > course, if your
> > components are under WEB-INF/classes or WEB-INF/lib, they are not
> > visible ...
>
> The Java2 class loading model is for a loader to "delegate first" to it's
> parent loader.  Only if the parent loader (that also delegates first to it's
> parent) can't find the class will the original loader try to load it.
>
> The description above shows the webapp loader attempting to load the class
> first and only delegating if that fails.  Is this really the case?
>

Sorry ... I should have been more explicit here.

You're right about the normal delegation model for Java2.  However, the Servlet
2.3 Spec (Proposed Final Draft) gives a servlet container the option to "look
before delegating" -- see Section 9.6.2.  Tomcat 4.0 does this.

The intention of this language is that you can have version X of a library
installed as a shared resource, and version Y of the library available in
WEB-INF/lib.  In the 2.3 model, Y will override X.  In the standard delegation
model (i.e. Tomcat 3.2) you'd get the classes from X no matter what you did.

Craig



RE: Servlet ClassLoader

Posted by cm...@yahoo.com.
> The Java2 class loading model is for a loader to "delegate first" to it's
> parent loader.  Only if the parent loader (that also delegates first to it's
> parent) can't find the class will the original loader try to load it.
> 

The code in the main branch is doing exactly that - the class loader
for "core" and the  class loader for "webapps" are siblings, with the
embeding application class loader as parent ( and of course, we delegate 
to parent first ). 

( For "trusted" applications the webapp loader is a child of the core,
that's a special exception. )

The code is not 'enabled' - it requires switching from Tomcat.java to
Main.java to start tomcat ( the LoaderInterceptor has all the code in it,
but Nacho mentioned few fixes that are also needed ). 

It'll happen, but right now sorting the bugs and fixing few urgent ones (
like self-test and watchdog failures in sandboxed mode ) is more
important. 

The fact that we don't have regression tests for most bugs that are
reported and fixed is really bad, and it's important to fix this in the
first place - the nightly run of watchdog and sanity and passing all tests
in all supported modes is the most important thing for me.

I'll repeat that a lot in the next weeks: if you have a bug and want to
have it fixed fast - write and send a regression test for that ( a
serlvet/jsp/whatever and a <gtest> fragment ), we'll include it in the
sanity and it'll have a fix ( that will hold and be tested nightly ). 


-- 
Costin


RE: Servlet ClassLoader

Posted by Marc Saegesser <ma...@apropos.com>.
> -----Original Message-----
> From: Craig R. McClanahan [mailto:Craig.McClanahan@eng.sun.com]
>* Java asked the webapp class loader to find the
>  controller servlet class
>* The webapp class loader did not find the class
>  so it delegated to the shared class loader
>* The shared class loader (which reads from $CATALINA_HOME/lib
>  in Tomcat 4.0 -- the corresponding loader in Tomcat 3.2 reads
>  from the system classpath) and finds your class
>
> Now, when your controller servlet calls Class.forName(), it
> starts from its
> *own* class loader, and looks either there, or upwards.  Of
> course, if your
> components are under WEB-INF/classes or WEB-INF/lib, they are not
> visible ...

The Java2 class loading model is for a loader to "delegate first" to it's
parent loader.  Only if the parent loader (that also delegates first to it's
parent) can't find the class will the original loader try to load it.

The description above shows the webapp loader attempting to load the class
first and only delegating if that fails.  Is this really the case?


Re: Servlet ClassLoader

Posted by "Craig R. McClanahan" <Cr...@eng.sun.com>.
Arthur Ash wrote:

> Hi Folks,
>
> I'm having a general issue with the app-specific classpath (WEB-INF/classes
> and WEB-INF/lib/*.jar).
>
> Here is the scenario as I understand it:
> I have an MVC servlet/bean framework that is installed in the primordial
> classpath.  It contains a single dispatcher servlet which instantiates
> handler classes (which function like servlets) using Class.forName().   My
> intention is to to put these app-specific handler classes in
> WEB-INF/classes or WEB-INF/lib in order to be a good J2EE citizen.
>

The Struts framework <http://jakarta.apache.org/struts> follows essentially the
same model.  However, due to classloader issues (more discussion below) the
controller servlet class itself must also be in WEB-INF/classes or WEB-INF/lib
for this to work correctly.

>
> However, since the dispatch servlet has been loaded with the primordial
> class loader (ie, the Tomcat code first tried and succeeded to load it
> using the default class loader), when it itslef calls Class.forName(), it
> gets this same (primordial) ClassLoader.  It cannot see anything that is in
> WEB-INF, since this is visible to only to the servlet class loader (ie,
> com.apache.tomcat.loader.AdaptiveClassLoader).
>

Class loaders are arranged in a hierarchy.  For Tomcat 4.0, the details are
discussed in a developer document ("catalina/docs/dev/classloaders.html) in the
source tree.  I will use that to illustrate what's going on because I'm more
familiar with it - Tomcat 3.2 currently follows a simplified version of the
same basic idea.

                      Bootstrap
                          |
                       System
                          |
                       Common
                      /      \
                 Catalina   Shared
                           /     \
                       Webapp1  Webapp2 ...

Each class loader has a reference to its parent, but not to its children.  So,
when your controller servlet is initially loaded (from a shared library
directory), what actually happened is:
* Java asked the webapp class loader to find the
  controller servlet class
* The webapp class loader did not find the class
  so it delegated to the shared class loader
* The shared class loader (which reads from $CATALINA_HOME/lib
  in Tomcat 4.0 -- the corresponding loader in Tomcat 3.2 reads
  from the system classpath) and finds your class

Now, when your controller servlet calls Class.forName(), it starts from its
*own* class loader, and looks either there, or upwards.  Of course, if your
components are under WEB-INF/classes or WEB-INF/lib, they are not visible ...

>
> Am I just screwed or is there some cool trick that I am missing?  Of course
> I could change the deployment scheme to put a copy of the dispatcher
> servlet into each apps WE-INF/classes, but this seems a bit clunky.
>

It's not clunky -- its required by virtue of the fact that classloaders know
how to delegate upwards but not downwards.  For lots of security related
reasons, that is actually a Good Thing.

>
> thanks
> Arthur
>

Craig McClanahan



RE: Servlet ClassLoader

Posted by cm...@yahoo.com.
> I have another question, which has been nagging me for
> a while: Why does the class loader for a web-app "see"
> the classes in the lib folder of the servlet engine
> (or the classpath of the java engine).

The problem will be resolved in the main tree ( most of the
code is there, I think Nacho was going to do it, or I ).

We use URLClassLoader - with no "trick". 

The problem is that all files in lib/ are included in 
CLASSPATH by the starter.
The solution is to use a different startup script,
 and construct a different class loader hierarchy - 
i.e. the webapplications will still have a parent loader 
including the files in CLASSPATH / embeding application, but the
core/modules will be in a separate ( paralel ) loader.


The change is not difficult, but requires changing the 
startup scripts and tomcat.startup. 

Costin



RE: Servlet ClassLoader

Posted by Gudmundur Hafsteinsson <gu...@dimonsoftware.com>.
> Am I just screwed or is there some cool trick that I am 
> missing?

As far as I know, this is not possible.

I have another question, which has been nagging me for
a while: Why does the class loader for a web-app "see"
the classes in the lib folder of the servlet engine
(or the classpath of the java engine).
For example if a servlet engine is using an XML parser
(say Xerces, some old version like 1.0.x) and includes
the SAX and DOM interfaces, but only version/level 1.
Now my cool web-app wants to use Xerces 1.3.0 and take
advantage of the new version/level 2 of the interfaces,
I have to fiddle with the lib folder of the servlet
engine (something I don't want to do), and even in
this example I'm doomed, because interface changes in
Xerces between these two versions make them incompatible!
(I know Tomcat does not use Xerces, this was just a
fictious example)

Now I pose the same question as Arthur Ash:
Am I just screwed or is there some cool trick that I am 
missing?

If I'm right about the problem I suggest separating the
classloaders for the servlet engine on one hand, and
the web-apps on the other hand, using a common classloader
for the servlet interface and other common servlet stuff.
Is this possible?

Regards,
Gummi Haf