1. Added ContextFactory.getApplicationClassLoader()/initApplicationClassLoader() for simpler class loader customization.

2. Context.getApplicationClassLoader() now uses ContextFactory.getApplicationClassLoader() and also tries ContextFactory subclass as the last resort of loader guessing.
This commit is contained in:
igor%mir2.org 2005-06-26 22:57:31 +00:00
parent 58ff31852c
commit 01a323d63b
3 changed files with 68 additions and 25 deletions

View File

@ -2090,22 +2090,29 @@ public class Context
public final ClassLoader getApplicationClassLoader()
{
if (applicationClassLoader == null) {
// If Context was subclassed, the following gets the loader
// for the subclass which can be different from Rhino loader,
// but then proper Rhino classes should be accessible through it
// in any case or JVM class loading is severely broken
Class cxClass = this.getClass();
ClassLoader loader = cxClass.getClassLoader();
ClassLoader threadLoader
= VMBridge.instance.getCurrentThreadClassLoader();
if (threadLoader != null && threadLoader != loader) {
if (testIfCanUseLoader(threadLoader, cxClass)) {
ContextFactory f = getFactory();
ClassLoader loader = f.getApplicationClassLoader();
if (loader == null) {
ClassLoader threadLoader
= VMBridge.instance.getCurrentThreadClassLoader();
if (threadLoader != null
&& Kit.testIfCanLoadRhinoClasses(threadLoader))
{
// Thread.getContextClassLoader is not cached since
// its caching prevents it from GC which may lead to
// a memory leak and hides updates to
// Thread.getContextClassLoader
return threadLoader;
}
// Thread.getContextClassLoader can not load Rhino classes,
// try to use the loader of ContextFactory or Context
// subclasses.
Class fClass = f.getClass();
if (fClass != ScriptRuntime.ContextFactoryClass) {
loader = fClass.getClassLoader();
} else {
loader = getClass().getClassLoader();
}
}
applicationClassLoader = loader;
}
@ -2120,27 +2127,13 @@ public class Context
applicationClassLoader = null;
return;
}
if (!testIfCanUseLoader(loader, this.getClass())) {
if (!Kit.testIfCanLoadRhinoClasses(loader)) {
throw new IllegalArgumentException(
"Loader can not resolve Rhino classes");
}
applicationClassLoader = loader;
}
private static boolean testIfCanUseLoader(ClassLoader loader, Class cxClass)
{
// Check that Context or its suclass is accesible from this loader
Class x = Kit.classOrNull(loader, cxClass.getName());
if (x != cxClass) {
// The check covers the case when x == null =>
// loader does not know about Rhino or the case
// when x != null && x != cxClass =>
// loader loads unrelated Rhino instance
return false;
}
return true;
}
/********** end of API **********/
/**

View File

@ -143,6 +143,7 @@ public class ContextFactory
private final Object listenersLock = new Object();
private volatile Object listeners;
private boolean disabledListening;
private ClassLoader applicationClassLoader;
/**
* Listener of {@link Context} creation and release events.
@ -290,6 +291,38 @@ public class ContextFactory
return new DefiningClassLoader(parent);
}
/**
* Get ClassLoader to use when searching for Java classes.
* Unless it was explicitly initialized with
* {@link #initApplicationClassLoader(ClassLoader)} the method returns
* null to indicate that Thread.getContextClassLoader() should be used.
*/
public final ClassLoader getApplicationClassLoader()
{
return applicationClassLoader;
}
/**
* Set explicit class loader to use when searching for Java classes.
*
* @see #getApplicationClassLoader()
*/
public final void initApplicationClassLoader(ClassLoader loader)
{
if (loader == null)
throw new IllegalArgumentException("loader is null");
if (!Kit.testIfCanLoadRhinoClasses(loader))
throw new IllegalArgumentException(
"Loader can not resolve Rhino classes");
if (this.applicationClassLoader != null)
throw new IllegalStateException(
"applicationClassLoader can only be set once");
checkNotSealed();
this.applicationClassLoader = loader;
}
/**
* Execute top call to script or function.
* When the runtime is about to execute a script or function that will

View File

@ -104,6 +104,23 @@ public class Kit
return null;
}
/**
* Check that testClass is accesible from the given loader.
*/
static boolean testIfCanLoadRhinoClasses(ClassLoader loader)
{
Class testClass = ScriptRuntime.ContextFactoryClass;
Class x = Kit.classOrNull(loader, testClass.getName());
if (x != testClass) {
// The check covers the case when x == null =>
// loader does not know about testClass or the case
// when x != null && x != testClass =>
// loader loads a class unrelated to testClass
return false;
}
return true;
}
/**
* If initCause methods exists in Throwable, call
* <tt>ex.initCause(cause)</tt> or otherwise do nothing.