river-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Gregg Wonderly <gr...@wonderly.org>
Subject Re: Separating out RMIClassLoader dependencies
Date Mon, 19 Oct 2009 22:24:24 GMT
Niclas Hedhman wrote:
> Some time ago, it was said that the classloader of a class could be
> retrieved by calling a static method. I have tried to point out that
> this is fairly "impossible" in OSGi without collaboration with the
> OSGi framework implementation, as multiple (even fully compatible, or
> even exact same versions) instance of the same classes can be present
> in different class spaces within the OSGi framework, and which package
> got resolved to which bundle (and hence the classloader) is an
> implementation detail in OSGi. There is no theory around that fact. I
> am speaking of "locating a classloader of an existing class already
> present", and not how to locate one externally to the JVM and OSGi
> framework.

The primary issue that my previous posting was trying to sort out, was the fact 
that inside of the core of River class loading, is the use of several methods on 
the RMIClassLoader class, which then results in calls to the configured and 
loaded instance of the RMIClassLoaderSpi implementation.  In containers and IDE 
environments, where classloading is customized and managed very differently than 
what JSE does by itself, getting an RMIClassLoaderSpi instance to be used 
through the normal means, can be nearly impossible.

So, I am investigating not using the RMIClassLoaderSpi mechanisms that are 
accessed through RMIClassLoader.

Instead, I have an interface defined (this is what I have so far) as follows:

public interface CodebaseClassAccess {
     public Class loadClass(String codebase, String name )
		 throws IOException, ClassNotFoundException;
     public Class loadClass(String codebase, String name,
				  ClassLoader defaultLoader )
		throws IOException,ClassNotFoundException;
     public Class loadProxyClass(String codebase, String[] interfaceNames,
				       ClassLoader defaultLoader )
		 throws IOException,ClassNotFoundException;
     public String getClassAnnotation( Class cls );
     public ClassLoader getClassLoader(String codebase) throws IOException;
     public ClassLoader createClassLoader( URL[] urls,
					    ClassLoader parent,
					    boolean requireDlPerm,
						AccessControlContext ctx );
     public ClassLoader getParentContextClassLoader();
     public ClassLoader getSystemContextClassLoader( ClassLoader defaultLoader );
}

This is an SPI interface.  There is a class with static methods that mirrors 
this interface.  That class has a setter on it to set the implementation of this
interface to use.  Without a call to the setter, the default is the use of 
RMIClassLoaderSpi.

I have an implementation that I am using in my netbeans development that is 
shown below.

There are three important issues that this covers.

1)  It covers the fact that the use of null as a "default" parent classloader is 
not going to work in many cases, because the jini/river jars are likely not in 
the JVM system class loader.
2)  My changes for allowing "never-preferred" classes to prohibit downloading
     jars until services will be activated, need to know what loader to use for
     non-preferred classes since it is not usually going to be the JVM system
     class loader.
3)  Class.forName( name ) will only use the preferred class loader or system
     class loader and in some cases, there is more control needed.

In the end, I am making changes that start to allow other class 
loading/packaging/platforming to be plugged into the PreferredClassLoader.  I'm 
doing this, because I think that if we want Jini to work in other places, we 
have to be able to also honor the ability to plugin Jini services that need 
preferred classes to work as part of their bug fixing strategy.

I've got some stuff working now, but there is still more work to do to provide a 
useful package to try out.

Gregg Wonderly

public class NetbeansCodebaseClassLoaderAccess
               implements CodebaseClassAccess {
     public static PreferredClassProvider provider = new PreferredClassProvider();

     public @Override ClassLoader getParentContextClassLoader() {
         return Lookup.getDefault().lookup(ClassLoader.class);
     }

     public @Override Class loadClass( String codebase,
                   String name,
                   ClassLoader defaultLoader ) throws IOException, 
ClassNotFoundException {
         return provider.loadClass( codebase, name, defaultLoader );
     }

     public @Override Class loadProxyClass(String codebase, String[] interfaceNames,
              ClassLoader defaultLoader) throws IOException, 
ClassNotFoundException {
         return provider.loadProxyClass( codebase, interfaceNames, defaultLoader );
     }

     public @Override String getClassAnnotation( Class cls ) {
         return provider.getClassAnnotation( cls );
     }

     public @Override ClassLoader getClassLoader(String codebase) throws 
IOException {
         return provider.getClassLoader( codebase );
     }

     public @Override Class loadClass(String codebase, String name)
                 throws IOException, ClassNotFoundException {
         return provider.loadClass( codebase, name,
             Thread.currentThread().getContextClassLoader() );
     }

     public @Override ClassLoader createClassLoader( final URL[] urls, final 
ClassLoader parent,
             final boolean requireDlPerm, final AccessControlContext ctx) {
         return AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() {
                 public ClassLoader run() {
                     return new PreferredClassLoader(urls, parent, null, 
requireDlPerm);
                 }
             }, ctx );
     }

     public ClassLoader getSystemContextClassLoader( ClassLoader defaultLoader ) {
         // defaultLoader will be the PreferredClassLoader instance.  We need to 
just
         // return that loader instead of the 
defaultLoader.getClass().getClassLoader()
         // business that usually occurs.  That business would change the class 
loading
         // scope to completely remove all view of the system and the codebase 
classes.
         return defaultLoader != null ? defaultLoader :
             Lookup.getDefault().lookup(ClassLoader.class);
     }
}


Mime
View raw message