You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by Bojan Smojver <bo...@binarix.com> on 2001/09/15 04:44:53 UTC

Weird Classloaders

I'm playing with Classloader issues in Tomcat 3.3 (but from what I hear
it's not much different in TC 4) and the whole thing behaves really,
really strange. This is what I can observe, with automatic reloading
enabled:

- a jar file in WEB-INF/lib will be picked up with no issues the very
first time the application is started
- if the jar file is changed, the application will reload (due to some
recent fixes there in DependClassLoader), but some resources might not
get loaded properly (for instance a properties file from within that
jar)
- if old version of the jar file, or a new jar file with the same binary
of the class is returned back to WEB-INF/lib, sometimes the app will
come back to normal after an automatic reload (not always though)
- if you keep replacing jar file long enough with different versions, it
will eventually fail even when loading class files from it and the whole
app will stop working (ClassNotFoundException)

I've checked the code in DependClassLoader and (unfortunately) it calls
the parent's equivalent methods for getResourceAsStream() and
getResource(), where parent is java.net.FactoryURLClassLoader. parent2
is the same as class as parent, but different object (ie. another
instance of the same thing). I'm guessing those things are part of the
JDK.

So, my real question here is, do any of you Sun guys (or any of you with
better knowledge of JDK) know what this java.net.FactoryURLClassLoader
actually does? Is it kind of 'caching' stuff and then it gets seriously
confused when there are changes? Or maybe I'm doing something I'm not
supposed to do...

My environment is JDK 1.3.1_01, Linux. In some other discussions, people
from TC 4 team mentioned that there are similar problems on Windows too.

And finally, do we just write a replacement for this (probably buggy)
method, or is there are known workaround or fix for this?

Bojan

Re: Weird Classloaders

Posted by Bojan Smojver <bo...@binarix.com>.
Remy Maucherat wrote:

> > My environment is JDK 1.3.1_01, Linux. In some other discussions, people
> > from TC 4 team mentioned that there are similar problems on Windows too.
> 
> TC 4 uses a 100% custom URLClassLoader clone, and it accesses the JARs
> directly (using JarFile objects). I'm really careful about properly closing
> these objects when the CL is dumped when reloading. However, there are still
> problems, at least under Windows (the symptoms are roughly what you
> describe). So it looks like the problems are with the java.util.jar package.
> 
> > And finally, do we just write a replacement for this (probably buggy)
> > method, or is there are known workaround or fix for this?
> 
> Nope :(
> 
> Remy

Just found this by searching the web (it's from TC 4 B5 release notes):

-------------------------------------------------------------
If you attempt to undeploy, then redeploy, an application from the same
web application archive file URL (where the URL refers to an actual WAR
file, not to a directory), the redeploy will fail with error "zip file
is
closed".  There appears to be a problem in the JDK's JarURLConnection
class
where JAR files are cached, even after they are closed, so that a
request
for a connection to the same URL returns the previous JarFile object
instead
of a new one.  As a workaround, you should do one of the following:
* Change the URL of the web application archive each time you redeploy.
* Deploy from an unpacked directory (on the same server) instead of from
a WAR file (this is often more convenient in a development environment
anyway).
-------------------------------------------------------------

Can this be related? I've noticed you use those inside the classloaders.
Is there another way to get to those files packed inside jars?

Now if FactoryURLClassLoader uses the above, I wonder if that's causing
such strange behaviour. There is a SimpleClassLoader in TC 3.3 which
kind of does everything by itself (for JDK 1.1 compatibility), but I was
still unable to figure out how to 'turn it on' in Java 2. It would be
interesting to see if that one suffers from the same problems. Any
suggestions from TC 3.3 experts more then welcome...

I checked IBM JDK for Linux. No difference (not surprising given that
both Sun and IBM build from the same source).

Bojan

Re: Weird Classloaders

Posted by Bojan Smojver <bo...@binarix.com>.
cmanolache@yahoo.com wrote:
> 
> On Sat, 15 Sep 2001, Bojan Smojver wrote:
> 
> > Remy Maucherat wrote:
> >
> > > TC 4 uses a 100% custom URLClassLoader clone, and it accesses the JARs
> > > directly (using JarFile objects). I'm really careful about properly closing
> > > these objects when the CL is dumped when reloading. However, there are still
> > > problems, at least under Windows (the symptoms are roughly what you
> > > describe). So it looks like the problems are with the java.util.jar package.
> >
> > After playing a bit more with the whole thing, it turns out that there
> > is an IOException thrown when bytes are read from
> > java.util.zip.ZipFile$1 (I'm guessing 1 is an internal class in ZipFile
> > which is actually an InputStream - do I see JDK people giving a nod?).
> > The ZipFile object is brand new after jar gets refreshed and yet it
> > seems to be reading something totally bogus data.
> >
> > One other somewhat interesting observation: if the jar grows, the class
> > file cannot be found. If it shrinks, class is found but properties files
> > packed in there are not. Really amusing...
> 
> Seems like a bug in JDK, if ZipFile is new it shouldn't use the old stuff.
> 
> It seems the ZipFile uses a native implementation... Can you try with a
> different VM ? Maybe IBM 1.3 ( well, it can be identical ) ?

Doesn't work with IBM as well.

> I think Ant has a good replacement for the whole zip, and we can certainly
> take a look. Creating a class loader using the different zip is also
> possilbe, and plugging it in is also easy.
> 
> However, I would mark this as LATER. The whole thing can take time, and I
> don't think we can/should put this into 3.3 ( because it'll be new
> untested code ).

How about I write a little section in the release notes of 3.3 (or
whichever other document you think is appropriate) and tell everyone
about the findings, so that there is no confusion as to why it doesn't
work as expected.

In the meantime, I'm posting a bug into Sun's bug database. I'm not sure
how fast they really are about those issues, but it might not be worth
writing a whole lot of new classloaders if they can fix it reasonably
quick (provided it really is a bug in JDK, of course).

Bojan

Re: Weird Classloaders

Posted by cm...@yahoo.com.
On Sat, 15 Sep 2001, Bojan Smojver wrote:

> Remy Maucherat wrote:
>
> > TC 4 uses a 100% custom URLClassLoader clone, and it accesses the JARs
> > directly (using JarFile objects). I'm really careful about properly closing
> > these objects when the CL is dumped when reloading. However, there are still
> > problems, at least under Windows (the symptoms are roughly what you
> > describe). So it looks like the problems are with the java.util.jar package.
>
> After playing a bit more with the whole thing, it turns out that there
> is an IOException thrown when bytes are read from
> java.util.zip.ZipFile$1 (I'm guessing 1 is an internal class in ZipFile
> which is actually an InputStream - do I see JDK people giving a nod?).
> The ZipFile object is brand new after jar gets refreshed and yet it
> seems to be reading something totally bogus data.
>
> One other somewhat interesting observation: if the jar grows, the class
> file cannot be found. If it shrinks, class is found but properties files
> packed in there are not. Really amusing...

Seems like a bug in JDK, if ZipFile is new it shouldn't use the old stuff.

It seems the ZipFile uses a native implementation... Can you try with a
different VM ? Maybe IBM 1.3 ( well, it can be identical ) ?

I think Ant has a good replacement for the whole zip, and we can certainly
take a look. Creating a class loader using the different zip is also
possilbe, and plugging it in is also easy.

However, I would mark this as LATER. The whole thing can take time, and I
don't think we can/should put this into 3.3 ( because it'll be new
untested code ).

Costin


Re: Weird Classloaders

Posted by Bojan Smojver <bo...@binarix.com>.
Remy Maucherat wrote:

> TC 4 uses a 100% custom URLClassLoader clone, and it accesses the JARs
> directly (using JarFile objects). I'm really careful about properly closing
> these objects when the CL is dumped when reloading. However, there are still
> problems, at least under Windows (the symptoms are roughly what you
> describe). So it looks like the problems are with the java.util.jar package.

After playing a bit more with the whole thing, it turns out that there
is an IOException thrown when bytes are read from
java.util.zip.ZipFile$1 (I'm guessing 1 is an internal class in ZipFile
which is actually an InputStream - do I see JDK people giving a nod?).
The ZipFile object is brand new after jar gets refreshed and yet it
seems to be reading something totally bogus data.

One other somewhat interesting observation: if the jar grows, the class
file cannot be found. If it shrinks, class is found but properties files
packed in there are not. Really amusing...

Anyone knows alternatives to java.util.zip/java.util.jar that come
without those 'features'?

Bojan

Embedded Tomcat

Posted by Eric Blenkush <bl...@ccs.neu.edu>.
Hi,

I am going to use tomcat in my java app but I only need a very limited set
of features. Specifically I dont need any server/networking stuff. All I
want to do is give tomact a JSP and get the output of its execution. Should
I use the Embedded class or since I dont need alot of features is there a
more efficient way to do this?

Thanks,
Eric Blenkush


Re: Weird Classloaders

Posted by Remy Maucherat <re...@apache.org>.
> I'm playing with Classloader issues in Tomcat 3.3 (but from what I hear
> it's not much different in TC 4) and the whole thing behaves really,
> really strange. This is what I can observe, with automatic reloading
> enabled:
>
> - a jar file in WEB-INF/lib will be picked up with no issues the very
> first time the application is started
> - if the jar file is changed, the application will reload (due to some
> recent fixes there in DependClassLoader), but some resources might not
> get loaded properly (for instance a properties file from within that
> jar)
> - if old version of the jar file, or a new jar file with the same binary
> of the class is returned back to WEB-INF/lib, sometimes the app will
> come back to normal after an automatic reload (not always though)
> - if you keep replacing jar file long enough with different versions, it
> will eventually fail even when loading class files from it and the whole
> app will stop working (ClassNotFoundException)
>
> I've checked the code in DependClassLoader and (unfortunately) it calls
> the parent's equivalent methods for getResourceAsStream() and
> getResource(), where parent is java.net.FactoryURLClassLoader. parent2
> is the same as class as parent, but different object (ie. another
> instance of the same thing). I'm guessing those things are part of the
> JDK.
>
> So, my real question here is, do any of you Sun guys (or any of you with
> better knowledge of JDK) know what this java.net.FactoryURLClassLoader
> actually does? Is it kind of 'caching' stuff and then it gets seriously
> confused when there are changes? Or maybe I'm doing something I'm not
> supposed to do...
>
> My environment is JDK 1.3.1_01, Linux. In some other discussions, people
> from TC 4 team mentioned that there are similar problems on Windows too.

TC 4 uses a 100% custom URLClassLoader clone, and it accesses the JARs
directly (using JarFile objects). I'm really careful about properly closing
these objects when the CL is dumped when reloading. However, there are still
problems, at least under Windows (the symptoms are roughly what you
describe). So it looks like the problems are with the java.util.jar package.

> And finally, do we just write a replacement for this (probably buggy)
> method, or is there are known workaround or fix for this?

Nope :(

Remy


Re: Weird Classloaders

Posted by Glenn Nielsen <gl...@voyager.apg.more.net>.
cmanolache@yahoo.com wrote:
> 
> On Sat, 15 Sep 2001, Bojan Smojver wrote:
> 
> > - if the jar file is changed, the application will reload (due to some
> > recent fixes there in DependClassLoader), but some resources might not
> > get loaded properly (for instance a properties file from within that
> > jar)
> 
> What do you mean ( i.e. how do you load the properties ) ? We create a new
> loader, and getting resources with the new loader should return the new
> stuff ( I'm not sure for Bundles, maybe they're caching something - need
> to check ).
> 

I have used Tomcat 4 with resource bundles, and when the manager does a reload
of a webapp the new property files are used.  All OK.


> > - if old version of the jar file, or a new jar file with the same binary
> > of the class is returned back to WEB-INF/lib, sometimes the app will
> > come back to normal after an automatic reload (not always though)
> 
> > - if you keep replacing jar file long enough with different versions, it
> > will eventually fail even when loading class files from it and the whole
> > app will stop working (ClassNotFoundException)
> 
> Again, need more details.
> 
> > I've checked the code in DependClassLoader and (unfortunately) it calls
> > the parent's equivalent methods for getResourceAsStream() and
> > getResource(), where parent is java.net.FactoryURLClassLoader. parent2
> > is the same as class as parent, but different object (ie. another
> > instance of the same thing). I'm guessing those things are part of the
> > JDK.
> 
> DependClassLoader is a wrapper around the real webapp loader - it's role
> is to record dependencies.
> 
> Parent is the real loader, parent2 is the grand-parent ( the parent of
> all webapps ). If a resource can be loaded by parent2, it is loaded
> ( to respect the delegation rules ). If not, we get the resource from
> parent  ( i.e. from the application WEB-INF ).
> 
> The class is created by DependClassLoader so class deps will also go
> to DCL ( and we can record them ).
> 
> URLClassLoader is the standard JDK1.2+ loader. It has some important
> features besides loading classes - it checks sealing, load the right
> security context, and many other things that are imporant.
> 
> You can of course replace it with anything you want - including
> SimpleClassLoader or replacement. All you need to do is replace
> LoaderInterceptor with your custom-made one.
> 
> > So, my real question here is, do any of you Sun guys (or any of you with
> > better knowledge of JDK) know what this java.net.FactoryURLClassLoader
> > actually does? Is it kind of 'caching' stuff and then it gets seriously
> > confused when there are changes? Or maybe I'm doing something I'm not
> > supposed to do...
> 
> If you can provide more details, I can take a look. Reloading seems to
> work fine for me ( but I'll try again ).
> 
> > And finally, do we just write a replacement for this (probably buggy)
> > method, or is there are known workaround or fix for this?
> 
> We must first find out which of the buggy methods we need to replace :-)
> 
> Costin

-- 
----------------------------------------------------------------------
Glenn Nielsen             glenn@more.net | /* Spelin donut madder    |
MOREnet System Programming               |  * if iz ina coment.      |
Missouri Research and Education Network  |  */                       |
----------------------------------------------------------------------

Re: Weird Classloaders

Posted by cm...@yahoo.com.
On Sat, 15 Sep 2001, Bojan Smojver wrote:

Could you file a bug in bugzilla and attach a very simple servlet and
instructions on how to reproduce ?

It would help a lot.

Costin



Re: Weird Classloaders

Posted by Bojan Smojver <bo...@binarix.com>.
cmanolache@yahoo.com wrote:
> 
> On Sat, 15 Sep 2001, Bojan Smojver wrote:
> 
> > - if the jar file is changed, the application will reload (due to some
> > recent fixes there in DependClassLoader), but some resources might not
> > get loaded properly (for instance a properties file from within that
> > jar)
> 
> What do you mean ( i.e. how do you load the properties ) ? We create a new
> loader, and getting resources with the new loader should return the new
> stuff ( I'm not sure for Bundles, maybe they're caching something - need
> to check ).

I'm loading the properties files (which can be any other type of file,
really) by calling getResourceAsStream() on the classloader of my
servlet. First time ever, all three of the properties files get pulled
in OK. I verified that by printing out the properties and passing them
to Velocity. Next time around (after the jar file gets updates), two
things can happen: properties files don't get pulled in correctly or the
class itself doesn't get pulled in correctly and I get
ClassNotFoundException (ie. app doesn't run at all).

> > - if old version of the jar file, or a new jar file with the same binary
> > of the class is returned back to WEB-INF/lib, sometimes the app will
> > come back to normal after an automatic reload (not always though)
> 
> > - if you keep replacing jar file long enough with different versions, it
> > will eventually fail even when loading class files from it and the whole
> > app will stop working (ClassNotFoundException)
> 
> Again, need more details.
> 
> > I've checked the code in DependClassLoader and (unfortunately) it calls
> > the parent's equivalent methods for getResourceAsStream() and
> > getResource(), where parent is java.net.FactoryURLClassLoader. parent2
> > is the same as class as parent, but different object (ie. another
> > instance of the same thing). I'm guessing those things are part of the
> > JDK.
> 
> DependClassLoader is a wrapper around the real webapp loader - it's role
> is to record dependencies.
> 
> Parent is the real loader, parent2 is the grand-parent ( the parent of
> all webapps ). If a resource can be loaded by parent2, it is loaded
> ( to respect the delegation rules ). If not, we get the resource from
> parent  ( i.e. from the application WEB-INF ).
> 
> The class is created by DependClassLoader so class deps will also go
> to DCL ( and we can record them ).
> 
> URLClassLoader is the standard JDK1.2+ loader. It has some important
> features besides loading classes - it checks sealing, load the right
> security context, and many other things that are imporant.
> 
> You can of course replace it with anything you want - including
> SimpleClassLoader or replacement. All you need to do is replace
> LoaderInterceptor with your custom-made one.

Aha, so that's what I need to change (not that I'm going to do it for
real - no security - just wanted to test). Thanks!

> > So, my real question here is, do any of you Sun guys (or any of you with
> > better knowledge of JDK) know what this java.net.FactoryURLClassLoader
> > actually does? Is it kind of 'caching' stuff and then it gets seriously
> > confused when there are changes? Or maybe I'm doing something I'm not
> > supposed to do...
> 
> If you can provide more details, I can take a look. Reloading seems to
> work fine for me ( but I'll try again ).

Even from jars stored in WEB-INF/lib? I found that part to behave in a
really erratic manner. When I have plain classes in WEB-INF/classes,
everything seems to behave much, much better.

bojan

Re: Weird Classloaders

Posted by cm...@yahoo.com.
On Sat, 15 Sep 2001, Bojan Smojver wrote:

> - if the jar file is changed, the application will reload (due to some
> recent fixes there in DependClassLoader), but some resources might not
> get loaded properly (for instance a properties file from within that
> jar)

What do you mean ( i.e. how do you load the properties ) ? We create a new
loader, and getting resources with the new loader should return the new
stuff ( I'm not sure for Bundles, maybe they're caching something - need
to check ).


> - if old version of the jar file, or a new jar file with the same binary
> of the class is returned back to WEB-INF/lib, sometimes the app will
> come back to normal after an automatic reload (not always though)

> - if you keep replacing jar file long enough with different versions, it
> will eventually fail even when loading class files from it and the whole
> app will stop working (ClassNotFoundException)

Again, need more details.


> I've checked the code in DependClassLoader and (unfortunately) it calls
> the parent's equivalent methods for getResourceAsStream() and
> getResource(), where parent is java.net.FactoryURLClassLoader. parent2
> is the same as class as parent, but different object (ie. another
> instance of the same thing). I'm guessing those things are part of the
> JDK.

DependClassLoader is a wrapper around the real webapp loader - it's role
is to record dependencies.

Parent is the real loader, parent2 is the grand-parent ( the parent of
all webapps ). If a resource can be loaded by parent2, it is loaded
( to respect the delegation rules ). If not, we get the resource from
parent  ( i.e. from the application WEB-INF ).

The class is created by DependClassLoader so class deps will also go
to DCL ( and we can record them ).

URLClassLoader is the standard JDK1.2+ loader. It has some important
features besides loading classes - it checks sealing, load the right
security context, and many other things that are imporant.

You can of course replace it with anything you want - including
SimpleClassLoader or replacement. All you need to do is replace
LoaderInterceptor with your custom-made one.


> So, my real question here is, do any of you Sun guys (or any of you with
> better knowledge of JDK) know what this java.net.FactoryURLClassLoader
> actually does? Is it kind of 'caching' stuff and then it gets seriously
> confused when there are changes? Or maybe I'm doing something I'm not
> supposed to do...

If you can provide more details, I can take a look. Reloading seems to
work fine for me ( but I'll try again ).

> And finally, do we just write a replacement for this (probably buggy)
> method, or is there are known workaround or fix for this?

We must first find out which of the buggy methods we need to replace :-)

Costin