8024619: JDBC java.sql.DriverManager is not usable from JS script
authorsundar
Fri, 13 Sep 2013 16:45:11 +0530
changeset 19895 965b12eb322e
parent 19894 195477810711
child 19896 02a23209f384
8024619: JDBC java.sql.DriverManager is not usable from JS script Reviewed-by: jlaskey, lagergren, attila
nashorn/make/build.xml
nashorn/src/jdk/nashorn/internal/runtime/Context.java
nashorn/src/jdk/nashorn/internal/runtime/NashornLoader.java
nashorn/src/jdk/nashorn/internal/runtime/ScriptLoader.java
nashorn/src/jdk/nashorn/internal/runtime/StructureLoader.java
nashorn/test/script/basic/JDK-8024619.js
nashorn/test/src/META-INF/services/java.sql.Driver
nashorn/test/src/jdk/nashorn/api/NashornSQLDriver.java
--- 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();
+    }
+}