8007004: nashorn script engine should not use thread context class loader as script 'application loader'
authorsundar
Mon, 28 Jan 2013 21:29:05 +0530
changeset 16197 1a5414cce91a
parent 16196 58f6f046bb5e
child 16198 1cfb1fbab2dc
8007004: nashorn script engine should not use thread context class loader as script 'application loader' Reviewed-by: attila, hannesw
nashorn/src/jdk/nashorn/api/scripting/NashornScriptEngine.java
nashorn/src/jdk/nashorn/api/scripting/NashornScriptEngineFactory.java
--- 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;
+    }
 }