I'm using IBM's JDK 1.1.8
I feel almost certain that it does not have a "jar" protocol handler.

I tried your suggestion but I still get the exception:
java.net.MalformedURLException: unknown protocol: jar
        at java.lang.Throwable.<init>(Throwable.java:74)
        at java.lang.Exception.<init>(Exception.java:38)
        at java.io.IOException.<init>(IOException.java:38)
        at
java.net.MalformedURLException.<init>(MalformedURLException.java:38)
        at java.net.URL.<init>(URL.java:201)
        at java.net.URL.<init>(URL.java:222)

Looking at JDK 1.1.8 javadoc it seems that a URL Handler for the protocol
is created:
     "If this is the first URL object being created with the specified
protocol, a stream protocol handler object, an instance of class
URLStreamHandler, is created for that protocol:"


James


==================================================================================
==================================================================================


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