This looks like a fine idea, so we can have several pluggable ClassLoader Architecture options, sounds very interesting.

I need to think about how I might also utilise this pluggable architecture before I get back to you. See if I can achieve the required functionality with the existing interface, or whether I'd need to add a method.

Cheers,

Peter.

Gregg Wonderly wrote:

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