8007004: nashorn script engine should not use thread context class loader as script 'application loader'
Reviewed-by: attila, hannesw
--- a/nashorn/src/jdk/nashorn/api/scripting/NashornScriptEngine.java Mon Jan 28 18:10:16 2013 +0530
+++ b/nashorn/src/jdk/nashorn/api/scripting/NashornScriptEngine.java Mon Jan 28 21:29:05 2013 +0530
@@ -74,27 +74,18 @@
// default options passed to Nashorn Options object
private static final String[] DEFAULT_OPTIONS = new String[] { "-scripting", "-af", "-doe" };
- NashornScriptEngine(final NashornScriptEngineFactory factory) {
- this(factory, DEFAULT_OPTIONS);
+ NashornScriptEngine(final NashornScriptEngineFactory factory, final ClassLoader appLoader) {
+ this(factory, DEFAULT_OPTIONS, appLoader);
}
@SuppressWarnings("LeakingThisInConstructor")
- NashornScriptEngine(final NashornScriptEngineFactory factory, final String[] args) {
+ NashornScriptEngine(final NashornScriptEngineFactory factory, final String[] args, final ClassLoader appLoader) {
this.factory = factory;
final Options options = new Options("nashorn");
options.process(args);
// throw ParseException on first error from script
final ErrorManager errMgr = new Context.ThrowErrorManager();
- // application loader for the context
- ClassLoader tmp;
- try {
- tmp = Thread.currentThread().getContextClassLoader();
- } catch (final SecurityException se) {
- tmp = null;
- }
- final ClassLoader appLoader = tmp;
-
// create new Nashorn Context
this.nashornContext = AccessController.doPrivileged(new PrivilegedAction<Context>() {
@Override
--- a/nashorn/src/jdk/nashorn/api/scripting/NashornScriptEngineFactory.java Mon Jan 28 18:10:16 2013 +0530
+++ b/nashorn/src/jdk/nashorn/api/scripting/NashornScriptEngineFactory.java Mon Jan 28 21:29:05 2013 +0530
@@ -31,6 +31,7 @@
import javax.script.ScriptEngine;
import javax.script.ScriptEngineFactory;
import jdk.nashorn.internal.runtime.Version;
+import sun.reflect.Reflection;
/**
* JSR-223 compliant script engine factory for Nashorn. The engine answers for:
@@ -136,7 +137,7 @@
@Override
public ScriptEngine getScriptEngine() {
- return new NashornScriptEngine(this);
+ return new NashornScriptEngine(this, getAppClassLoader());
}
/**
@@ -146,7 +147,7 @@
* @return newly created script engine.
*/
public ScriptEngine getScriptEngine(final String[] args) {
- return new NashornScriptEngine(this, args);
+ return new NashornScriptEngine(this, args, getAppClassLoader());
}
// -- Internals only below this point
@@ -176,4 +177,44 @@
private static List<String> immutableList(final String... elements) {
return Collections.unmodifiableList(Arrays.asList(elements));
}
+
+ private static ClassLoader getAppClassLoader() {
+ if (System.getSecurityManager() == null) {
+ return ClassLoader.getSystemClassLoader();
+ }
+
+ // Try to determine the caller class loader. Use that if it can be
+ // found. If not, use the class loader of nashorn itself as the
+ // "application" class loader for scripts.
+
+ // User could have called ScriptEngineFactory.getScriptEngine()
+ //
+ // <caller>
+ // <factory.getScriptEngine()>
+ // <factory.getAppClassLoader()>
+ // <Reflection.getCallerClass()>
+ //
+ // or used one of the getEngineByABC methods of ScriptEngineManager.
+ //
+ // <caller>
+ // <ScriptEngineManager.getEngineByName()>
+ // <factory.getScriptEngine()>
+ // <factory.getAppClassLoader()>
+ // <Reflection.getCallerClass()>
+
+ // So, stack depth is 3 or 4 (recall it is zero based). We try
+ // stack depths 3, 4 and look for non-bootstrap caller.
+ Class<?> caller = null;
+ for (int depth = 3; depth < 5; depth++) {
+ caller = Reflection.getCallerClass(depth);
+ if (caller != null && caller.getClassLoader() != null) {
+ // found a non-bootstrap caller
+ break;
+ }
+ }
+
+ final ClassLoader ccl = (caller == null)? null : caller.getClassLoader();
+ // if caller loader is null, then use nashorn's own loader
+ return (ccl == null)? NashornScriptEngineFactory.class.getClassLoader() : ccl;
+ }
}