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