diff --git a/core/src/main/java/io/apigee/trireme/core/Sandbox.java b/core/src/main/java/io/apigee/trireme/core/Sandbox.java index a84efa88..7cf8061f 100644 --- a/core/src/main/java/io/apigee/trireme/core/Sandbox.java +++ b/core/src/main/java/io/apigee/trireme/core/Sandbox.java @@ -27,6 +27,8 @@ import java.io.InputStream; import java.io.OutputStream; +import java.net.URL; +import java.net.URLClassLoader; import java.util.AbstractMap; import java.util.ArrayList; import java.util.List; @@ -55,7 +57,7 @@ public class Sandbox private boolean hideOsDetails; private ClassShutter extraClassShutter; private boolean allowJarLoading = true; - private ClassLoader classLoader = null; + private ClassLoaderSupplier classLoaderSupplier = null; /** * Create a new sandbox that will not affect anything in any way. @@ -85,7 +87,7 @@ public Sandbox(Sandbox parent) this.hideOsDetails = parent.hideOsDetails; this.extraClassShutter = parent.extraClassShutter; this.allowJarLoading = parent.allowJarLoading; - this.classLoader = parent.classLoader; + this.classLoaderSupplier = parent.classLoaderSupplier; if (parent.mounts != null) { this.mounts = new ArrayList>(parent.mounts); } @@ -279,15 +281,36 @@ public boolean isAllowJarLoading() { } /** - * Allows specifying the ClassLoader that will be used by the "trireme-support" module's - * "loadJars" method to load JAR files into the currently-running script. + * A Supplier that returns an instance of a ClassLoader to be used + * for loading Java classes into the currently-running script. + *

+ * The Supplier should return a new instance for every invocation of this method + * if it is desired that classes loaded by any one invocation of the + * "trireme-support" module's "loadJars" method are isolated from classes loaded + * from another invocation of the "loadJars" method. + *

+ * The Supplier may return the same instance for every invocation of this method + * if such isolation is not desired. */ - public Sandbox setClassLoader(ClassLoader classLoader) { - this.classLoader = classLoader; + public interface ClassLoaderSupplier { + ClassLoader getClassLoader(URL[] urlArray); + } + + /** + * Allows specifying the Supplier that will return an instance of a ClassLoader + * that will be used by the "trireme-support" module's "loadJars" method to load JAR files + * into the currently-running script. + */ + public Sandbox setClassLoaderSupplier(ClassLoaderSupplier classLoaderSupplier) { + this.classLoaderSupplier = classLoaderSupplier; return this; } - public ClassLoader getClassLoader() { - return classLoader; + /** + * Returns the ClassLoaderSupplier if set, null otherwise. + */ + public ClassLoaderSupplier getClassLoaderSupplier() { + return classLoaderSupplier; } + } diff --git a/core/src/main/java/io/apigee/trireme/core/modules/TriremeNativeSupport.java b/core/src/main/java/io/apigee/trireme/core/modules/TriremeNativeSupport.java index 445fff49..f24fdfcc 100644 --- a/core/src/main/java/io/apigee/trireme/core/modules/TriremeNativeSupport.java +++ b/core/src/main/java/io/apigee/trireme/core/modules/TriremeNativeSupport.java @@ -99,14 +99,18 @@ public static Object loadJars(Context cx, Scriptable thisObj, Object[] args, Fun throw Utils.makeError(cx, thisObj, "Cannot get URL for JAR file :" + e); } } + URL[] urlArray = urls.toArray(new URL[urls.size()]); Sandbox sandbox = self.runtime.getSandbox(); ClassLoader loader = null; if (sandbox != null) { // use custom class loader if specified - loader = sandbox.getClassLoader(); + Sandbox.ClassLoaderSupplier supplier = sandbox.getClassLoaderSupplier(); + if (supplier != null) { + loader = supplier.getClassLoader(urlArray); + } } if (loader == null) { // fallback - loader = new URLClassLoader(urls.toArray(new URL[urls.size()])); + loader = new URLClassLoader(urlArray); } // Load the classes in to the module registry for this script only. diff --git a/node10/node10src/src/test/java/io/apigee/trireme/node10/test/JarLoadingTest.java b/node10/node10src/src/test/java/io/apigee/trireme/node10/test/JarLoadingTest.java index ad1c067b..c27c1d18 100644 --- a/node10/node10src/src/test/java/io/apigee/trireme/node10/test/JarLoadingTest.java +++ b/node10/node10src/src/test/java/io/apigee/trireme/node10/test/JarLoadingTest.java @@ -106,7 +106,7 @@ public void testLoadingDisabled() public void testLoadingUsingCustomClassLoader() throws NodeException, InterruptedException, ExecutionException { - ArrayList urls = new ArrayList(); + final ArrayList urls = new ArrayList(); String[] jarNames = {"target/test-classes/testjar.jar", "target/test-classes/depjar.jar"}; for (String jn : jarNames) { File jarFile = new File(jn); @@ -121,9 +121,11 @@ public void testLoadingUsingCustomClassLoader() } } - Sandbox sb = new Sandbox().setClassLoader( - new URLClassLoader(urls.toArray(new URL[urls.size()])) - ); + Sandbox sb = new Sandbox().setClassLoaderSupplier(new Sandbox.ClassLoaderSupplier() { + public ClassLoader getClassLoader(URL[] urlArray) { + return new URLClassLoader(urls.toArray(new URL[urls.size()])); + } + }); NodeScript script = env.createScript("jarload.js", new File("target/test-classes/tests/jarload.js"), new String[]{"Foo", "25"}); @@ -139,8 +141,12 @@ public void testLoadingUsingCustomClassLoader() public void testLoadingFailsUsingInvalidCustomClassLoader() throws NodeException, InterruptedException, ExecutionException { - URL empty[] = new URL[0]; - Sandbox sb = new Sandbox().setClassLoader(new URLClassLoader(empty)); + final URL empty[] = new URL[0]; + Sandbox sb = new Sandbox().setClassLoaderSupplier(new Sandbox.ClassLoaderSupplier() { + public ClassLoader getClassLoader(URL[] urlArray) { + return new URLClassLoader(empty); + } + }); NodeScript script = env.createScript("jarload.js", new File("target/test-classes/tests/jarload.js"), new String[]{"Foo", "25"});