Thanks again James.

I think I understand now.

First question - what VM are you using ? JDK1.1.8 ( Sun and IBM ) seem to
have handlers for jar protocol ( even if it's not standard AFAIK ). Long
time ago I tested with kaffe and it worked - but I'm not sure I tested
getResource().

The real problem is not in DependClassLoader, but SimpleClassLoader, where
getResource() is implemented. Even if we 'hack' DCL to not call
getResource(), I think it would be better, as you sugest, to add code to
support the jar protocol.

The problem is in SCL.getResource(), the code is:

        // a jar:-URL *could* change even between minor releases, but
        // didn't between JVM's 1.1.6 and 1.3beta. Tested on JVM's from
        // IBM, Blackdown, Microsoft, Sun @ Windows and Sun @ Solaris
        if( r.zipEntry != null ) {
            try {
                return new URL("jar:file:" +
                               r.repository.getPath() + "!/" +
                               name);
            } catch(java.net.MalformedURLException badurl) {
        ....


One thing you can try ( and may work ) is to replace this with

new URL("jar", null, r.repository.getPath() + "!/" + name );

This will avoid calling the handlers ( which are used to parse the local
part ).

I agree the right solution is to add the dummy handler ( or a 'real' jar
handler ! ) in the compat package. It must at least parse the URL,
otherwise it'll brake reloading ( since getFile() is used to add the jar
location to the list of files that are checked for modifications ).

Costin



On Fri, 7 Sep 2001, James THOMAS wrote:

>
>
> Thanks for the great info Costin.
>
> Just an FYI, I did implement another solution, which was to implement a
> "Handler" class for the "jar" protocol.  Interestingly enough, it was
> sufficient to only have a class that is responsible for the "jar" protocol.
> The implementation of the class could be crap because it is never used.
> The explanation behind this is implementation of the DependClassLoader:
>
> Basic Algorithm of "loadClassInternal":
> 1) If class is already loaded, return it.
> 2) obtain the class as a resource from "parent" (but will don't construct
> the "Class" yet).  If the resource is not found, then throw a
> ClassNotFoundException.  This is where we are failing today because the
> "jar" protocol does not have a handler in JDK 1.1
> 3) load the class from "parent2" and return it if found.
> 4) no create the class from the resource loaded in step 2
>
> By having a handler for the "jar" protocol, we get a non-null URL in step
> 2, thus avoiding the ClassNotFoundException.  And in my testing, "parent2"
> was always able to load the class requested.  Thus, the resource (i.e. URL)
> obtained from step 2 was never used.
>
>
> ===============================================================================
> ===============================================================================
>
>
> Thanks James, I'm very happy to see your contributions. ( and my
> appologies for not testing with 1.1 often enough ).
>
> >
> 
>jakarta-tomcat-3.3-dev-src\src\share\org\apache\tomcat\util\depend\DependClassLoader.java
>
> > ======================================================================
> > The method "loadClassInternal" appears to be incorrect.  When loading a
> > class, the code first retrieves the class as a resource from the "parent"
> > class loader.  But, the return value from the "getResource" is not used
> > because the code then delegates the class loading to the "parent2" class
> > loader ("parent2.loadClass(name)").  When running with JDK 1.1, the
> > "getResource" returns null because the "jar" protocol is not valid (the
> > exception message "unknown protocol: jar" is thrown from
> SimpleClassLoader
> > where a java.net.URL is constructed).  This causes the
> "loadClassInternal"
> > method to throw a "ClassNotFoundException" prematurely because the class
> > can successfully be loaded by one of the the parent class loaders.  Below
> I
> > offer a solution but I think it would be best if someone with a more
> > in-depth understanding of the code can validate this solution.
>
> The code is a bit tricky. 3.3 uses normal URLClassLoaders for loading, but
> in order to support reloading we use an additional wrapper (
> DependClassLoader ) that will collect dependencies ( since a servlet/jsp
> can depend on multiple jars/classes ).
>
> For DCL, "parent" is the webapp class loader. "parent2" is the
> applications class loader, parent of all webapp loaders.
>
> The code tries to make DependClassLoader as non-intrusive as possible (
> i.e. the behavior of using DCL should be as close as possible to 'normal'
> ).
>
> If a class can be loaded by parent2 ( the common app loader ), then we
> just delegate to it ( that's the normal delegation that would be used if
> no DCL was present ). We don't delegate to parent because then all classes
> loaded as result of resolving the current class would not be registered as
> depends ( parent will do all the loading without any notification ).
>
> If not, we'll use parent to get the bytes - then load them. The reason we
> have DependClassLoader12 is to support the security context - I couldn't
> find any other way ( like via jdkcompat ) since we need to call a
> protected method in super.
>
>
> >       // check parent class
> >       if( parent != null ) {
> >          try {
> >             c = parent.loadClass( name );
>
> ^^^ That will not brake part of reloading - parent will load all classes
> that are requested by the current class, and we'll not be able to record
> that...
>
> I'll try to find another fix ( nice try ! :-).
>
> Costin
>
>
>
>

Reply via email to