8024619: JDBC java.sql.DriverManager is not usable from JS script
Reviewed-by: jlaskey, lagergren, attila
--- a/nashorn/make/build.xml Thu Sep 12 22:16:40 2013 +0530
+++ b/nashorn/make/build.xml Fri Sep 13 16:45:11 2013 +0530
@@ -230,6 +230,10 @@
<compilerarg value="-Xlint:deprecation"/>
</javac>
+ <copy todir="${build.test.classes.dir}/META-INF/services">
+ <fileset dir="${test.src.dir}/META-INF/services/"/>
+ </copy>
+
<!-- tests that check nashorn internals and internal API -->
<jar jarfile="${nashorn.internal.tests.jar}">
<fileset dir="${build.test.classes.dir}" excludes="**/api/**"/>
@@ -238,6 +242,7 @@
<!-- tests that check nashorn script engine (jsr-223) API -->
<jar jarfile="${nashorn.api.tests.jar}">
<fileset dir="${build.test.classes.dir}" includes="**/api/**"/>
+ <fileset dir="${build.test.classes.dir}" includes="**/META-INF/**"/>
</jar>
</target>
--- a/nashorn/src/jdk/nashorn/internal/runtime/Context.java Thu Sep 12 22:16:40 2013 +0530
+++ b/nashorn/src/jdk/nashorn/internal/runtime/Context.java Fri Sep 13 16:45:11 2013 +0530
@@ -236,6 +236,10 @@
private static final ClassLoader myLoader = Context.class.getClassLoader();
private static final StructureLoader sharedLoader;
+ /*package-private*/ ClassLoader getSharedLoader() {
+ return sharedLoader;
+ }
+
private static AccessControlContext createNoPermAccCtxt() {
return new AccessControlContext(new ProtectionDomain[] { new ProtectionDomain(null, new Permissions()) });
}
@@ -254,7 +258,7 @@
sharedLoader = AccessController.doPrivileged(new PrivilegedAction<StructureLoader>() {
@Override
public StructureLoader run() {
- return new StructureLoader(myLoader, null);
+ return new StructureLoader(myLoader);
}
}, CREATE_LOADER_ACC_CTXT);
}
@@ -599,7 +603,7 @@
* @throws ClassNotFoundException if structure class cannot be resolved
*/
public static Class<?> forStructureClass(final String fullName) throws ClassNotFoundException {
- if (System.getSecurityManager() != null && !NashornLoader.isStructureClass(fullName)) {
+ if (System.getSecurityManager() != null && !StructureLoader.isStructureClass(fullName)) {
throw new ClassNotFoundException(fullName);
}
return Class.forName(fullName, true, sharedLoader);
@@ -792,12 +796,11 @@
static Context fromClass(final Class<?> clazz) {
final ClassLoader loader = clazz.getClassLoader();
- Context context = null;
- if (loader instanceof NashornLoader) {
- context = ((NashornLoader)loader).getContext();
+ if (loader instanceof ScriptLoader) {
+ return ((ScriptLoader)loader).getContext();
}
- return (context != null) ? context : Context.getContextTrusted();
+ return Context.getContextTrusted();
}
private Object evaluateSource(final Source source, final ScriptObject scope, final ScriptObject thiz) {
@@ -899,7 +902,7 @@
new PrivilegedAction<ScriptLoader>() {
@Override
public ScriptLoader run() {
- return new ScriptLoader(sharedLoader, Context.this);
+ return new ScriptLoader(appLoader, Context.this);
}
}, CREATE_LOADER_ACC_CTXT);
}
--- a/nashorn/src/jdk/nashorn/internal/runtime/NashornLoader.java Thu Sep 12 22:16:40 2013 +0530
+++ b/nashorn/src/jdk/nashorn/internal/runtime/NashornLoader.java Fri Sep 13 16:45:11 2013 +0530
@@ -38,10 +38,7 @@
import jdk.nashorn.tools.Shell;
/**
- * Superclass for Nashorn class loader classes. This stores Context
- * instance as an instance field. The current context can be
- * efficiently accessed from a given Class via it's ClassLoader.
- *
+ * Superclass for Nashorn class loader classes.
*/
abstract class NashornLoader extends SecureClassLoader {
private static final String OBJECTS_PKG = "jdk.nashorn.internal.objects";
@@ -69,27 +66,8 @@
};
}
- private final Context context;
-
- final Context getContext() {
- return context;
- }
-
- NashornLoader(final ClassLoader parent, final Context context) {
+ NashornLoader(final ClassLoader parent) {
super(parent);
- this.context = context;
- }
-
-
- /**
- * Called by subclass after package access check is done
- * @param name name of the class to be loaded
- * @param resolve whether the class should be resolved or not
- * @return Class object
- * @throws ClassNotFoundException if class cannot be loaded
- */
- protected final Class<?> loadClassTrusted(final String name, final boolean resolve) throws ClassNotFoundException {
- return super.loadClass(name, resolve);
}
protected static void checkPackageAccess(final String name) {
@@ -122,10 +100,6 @@
return permCollection;
}
- static boolean isStructureClass(final String fullName) {
- return fullName.startsWith(SCRIPTS_PKG);
- }
-
/**
* Create a secure URL class loader for the given classpath
* @param classPath classpath for the loader to search from
--- a/nashorn/src/jdk/nashorn/internal/runtime/ScriptLoader.java Thu Sep 12 22:16:40 2013 +0530
+++ b/nashorn/src/jdk/nashorn/internal/runtime/ScriptLoader.java Fri Sep 13 16:45:11 2013 +0530
@@ -33,17 +33,42 @@
*
*/
final class ScriptLoader extends NashornLoader {
+ private static final String NASHORN_PKG_PREFIX = "jdk.nashorn.internal.";
+
+ private final Context context;
+
+ /*package-private*/ Context getContext() {
+ return context;
+ }
+
/**
* Constructor.
*/
- ScriptLoader(final StructureLoader parent, final Context context) {
- super(parent, context);
+ ScriptLoader(final ClassLoader parent, final Context context) {
+ super(parent);
+ this.context = context;
}
@Override
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
checkPackageAccess(name);
- return super.loadClassTrusted(name, resolve);
+ try {
+ return super.loadClass(name, resolve);
+ } catch (final ClassNotFoundException | SecurityException e) {
+ // We'll get ClassNotFoundException for Nashorn 'struct' classes.
+ // Also, we'll get SecurityException for jdk.nashorn.internal.*
+ // classes. So, load these using to context's 'shared' loader.
+ // All these classes start with "jdk.nashorn.internal." prefix.
+ try {
+ if (name.startsWith(NASHORN_PKG_PREFIX)) {
+ return context.getSharedLoader().loadClass(name);
+ }
+ } catch (final ClassNotFoundException ignored) {
+ }
+
+ // throw the original exception from here
+ throw e;
+ }
}
// package-private and private stuff below this point
--- a/nashorn/src/jdk/nashorn/internal/runtime/StructureLoader.java Thu Sep 12 22:16:40 2013 +0530
+++ b/nashorn/src/jdk/nashorn/internal/runtime/StructureLoader.java Fri Sep 13 16:45:11 2013 +0530
@@ -34,7 +34,6 @@
/**
* Responsible for on the fly construction of structure classes.
- *
*/
final class StructureLoader extends NashornLoader {
private static final String JS_OBJECT_PREFIX_EXTERNAL = binaryName(SCRIPTS_PACKAGE) + '.' + JS_OBJECT_PREFIX.symbolName();
@@ -42,27 +41,17 @@
/**
* Constructor.
*/
- StructureLoader(final ClassLoader parent, final Context context) {
- super(parent, context);
+ StructureLoader(final ClassLoader parent) {
+ super(parent);
}
- @Override
- protected synchronized Class<?> loadClass(final String name, final boolean resolve) throws ClassNotFoundException {
- // check the cache first
- final Class<?> loadedClass = findLoadedClass(name);
- if (loadedClass != null) {
- if (resolve) {
- resolveClass(loadedClass);
- }
- return loadedClass;
- }
-
- return super.loadClassTrusted(name, resolve);
+ static boolean isStructureClass(final String name) {
+ return name.startsWith(JS_OBJECT_PREFIX_EXTERNAL);
}
@Override
protected Class<?> findClass(final String name) throws ClassNotFoundException {
- if (name.startsWith(JS_OBJECT_PREFIX_EXTERNAL)) {
+ if (isStructureClass(name)) {
return generateClass(name, name.substring(JS_OBJECT_PREFIX_EXTERNAL.length()));
}
return super.findClass(name);
@@ -75,11 +64,7 @@
* @return Generated class.
*/
private Class<?> generateClass(final String name, final String descriptor) {
- Context context = getContext();
-
- if (context == null) {
- context = Context.getContextTrusted();
- }
+ final Context context = Context.getContextTrusted();
final byte[] code = new ObjectClassGenerator(context).generate(descriptor);
return defineClass(name, code, 0, code.length, new ProtectionDomain(null, getPermissions(null)));
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8024619.js Fri Sep 13 16:45:11 2013 +0530
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * JDK-8024619: JDBC java.sql.DriverManager is not usable from JS script
+ *
+ * @test
+ * @run
+ */
+
+var DriverManager = Java.type("java.sql.DriverManager");
+var e = DriverManager.getDrivers();
+
+var driverFound = false;
+// check for Nashorn SQL driver
+while (e.hasMoreElements()) {
+ var driver = e.nextElement();
+ if (driver.acceptsURL("jdbc:nashorn:")) {
+ driverFound = true;
+ break;
+ }
+}
+
+if (! driverFound) {
+ fail("Nashorn JDBC Driver not found!");
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/src/META-INF/services/java.sql.Driver Fri Sep 13 16:45:11 2013 +0530
@@ -0,0 +1,1 @@
+jdk.nashorn.api.NashornSQLDriver
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/src/jdk/nashorn/api/NashornSQLDriver.java Fri Sep 13 16:45:11 2013 +0530
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.nashorn.api;
+
+import java.sql.*;
+import java.util.Properties;
+import java.util.logging.Logger;
+
+/**
+ * A dummy SQL driver for testing purpose.
+ */
+public final class NashornSQLDriver implements Driver {
+ static {
+ try {
+ DriverManager.registerDriver(new NashornSQLDriver(), null);
+ } catch (SQLException se) {
+ throw new RuntimeException(se);
+ }
+ }
+
+ @Override
+ public boolean acceptsURL(String url) {
+ return url.startsWith("jdbc:nashorn:");
+ }
+
+ @Override
+ public Connection connect(String url, Properties info) {
+ throw new UnsupportedOperationException("I am a dummy!!");
+ }
+
+ @Override
+ public int getMajorVersion() {
+ return -1;
+ }
+
+ @Override
+ public int getMinorVersion() {
+ return -1;
+ }
+
+ @Override
+ public DriverPropertyInfo[] getPropertyInfo(String url, Properties info) {
+ return new DriverPropertyInfo[0];
+ }
+
+ @Override
+ public boolean jdbcCompliant() {
+ // no way!
+ return false;
+ }
+
+ @Override
+ public Logger getParentLogger() throws SQLFeatureNotSupportedException {
+ throw new SQLFeatureNotSupportedException();
+ }
+}