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);
    }
}

Reply via email to