From 01a323d63bfb219b3802ab18afe334e94f12ffca Mon Sep 17 00:00:00 2001 From: "igor%mir2.org" Date: Sun, 26 Jun 2005 22:57:31 +0000 Subject: [PATCH] 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. --- .../src/org/mozilla/javascript/Context.java | 43 ++++++++----------- .../mozilla/javascript/ContextFactory.java | 33 ++++++++++++++ js/rhino/src/org/mozilla/javascript/Kit.java | 17 ++++++++ 3 files changed, 68 insertions(+), 25 deletions(-) diff --git a/js/rhino/src/org/mozilla/javascript/Context.java b/js/rhino/src/org/mozilla/javascript/Context.java index 94b4538842a5..f799936c922c 100644 --- a/js/rhino/src/org/mozilla/javascript/Context.java +++ b/js/rhino/src/org/mozilla/javascript/Context.java @@ -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 **********/ /** diff --git a/js/rhino/src/org/mozilla/javascript/ContextFactory.java b/js/rhino/src/org/mozilla/javascript/ContextFactory.java index 423eae9c29f7..50300fd5cedb 100644 --- a/js/rhino/src/org/mozilla/javascript/ContextFactory.java +++ b/js/rhino/src/org/mozilla/javascript/ContextFactory.java @@ -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 diff --git a/js/rhino/src/org/mozilla/javascript/Kit.java b/js/rhino/src/org/mozilla/javascript/Kit.java index d44a98c59341..a80495768620 100644 --- a/js/rhino/src/org/mozilla/javascript/Kit.java +++ b/js/rhino/src/org/mozilla/javascript/Kit.java @@ -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 * ex.initCause(cause) or otherwise do nothing.