7026898: DriverManager to now use CopyOnWriteArrayList
authorlancea
Thu, 17 Mar 2011 11:37:06 -0400
changeset 8797 e8507464a69d
parent 8796 604a43386301
child 8798 088871daae86
7026898: DriverManager to now use CopyOnWriteArrayList Reviewed-by: alanb, briangoetz
jdk/src/share/classes/java/sql/DriverManager.java
--- a/jdk/src/share/classes/java/sql/DriverManager.java	Wed Mar 16 18:54:50 2011 -0400
+++ b/jdk/src/share/classes/java/sql/DriverManager.java	Thu Mar 17 11:37:06 2011 -0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2011, 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
@@ -26,10 +26,10 @@
 package java.sql;
 
 import java.util.Iterator;
-import java.sql.Driver;
 import java.util.ServiceLoader;
 import java.security.AccessController;
 import java.security.PrivilegedAction;
+import java.util.concurrent.CopyOnWriteArrayList;
 
 
 /**
@@ -79,6 +79,27 @@
 public class DriverManager {
 
 
+    // List of registered JDBC drivers
+    private final static CopyOnWriteArrayList<Driver> registeredDrivers = new CopyOnWriteArrayList<Driver>();
+    private static volatile int loginTimeout = 0;
+    private static volatile java.io.PrintWriter logWriter = null;
+    private static volatile java.io.PrintStream logStream = null;
+    // Used in println() to synchronize logWriter
+    private final static  Object logSync = new Object();
+
+    /* Prevent the DriverManager class from being instantiated. */
+    private DriverManager(){}
+
+
+    /**
+     * Load the initial JDBC drivers by checking the System property
+     * jdbc.properties and then use the {@code ServiceLoader} mechanism
+     */
+    static {
+        loadInitialDrivers();
+        println("JDBC DriverManager initialized");
+    }
+
     /**
      * The <code>SQLPermission</code> constant that allows the
      * setting of the logging stream.
@@ -235,44 +256,33 @@
      */
     public static Driver getDriver(String url)
         throws SQLException {
-        java.util.Vector drivers = null;
 
         println("DriverManager.getDriver(\"" + url + "\")");
 
-        if (!initialized) {
-            initialize();
-        }
-
-        synchronized (DriverManager.class){
-            // use the read copy of the drivers vector
-            drivers = readDrivers;
-        }
-
         // Gets the classloader of the code that called this method, may
         // be null.
         ClassLoader callerCL = DriverManager.getCallerClassLoader();
 
-        // Walk through the loaded drivers attempting to locate someone
+        // Walk through the loaded registeredDrivers attempting to locate someone
         // who understands the given URL.
-        for (int i = 0; i < drivers.size(); i++) {
-            DriverInfo di = (DriverInfo)drivers.elementAt(i);
+        for (Driver aDriver : registeredDrivers) {
             // If the caller does not have permission to load the driver then
             // skip it.
-            if ( getCallerClass(callerCL, di.driverClassName ) !=
-                 di.driverClass ) {
-                println("    skipping: " + di);
-                continue;
+            if(isDriverAllowed(aDriver, callerCL)) {
+                try {
+                    if(aDriver.acceptsURL(url)) {
+                        // Success!
+                        println("getDriver returning " + aDriver.getClass().getName());
+                    return (aDriver);
+                    }
+
+                } catch(SQLException sqe) {
+                    // Drop through and try the next driver.
+                }
+            } else {
+                println("    skipping: " + aDriver.getClass().getName());
             }
-            try {
-                println("    trying " + di);
-                if (di.driver.acceptsURL(url)) {
-                    // Success!
-                    println("getDriver returning " + di);
-                    return (di.driver);
-                }
-            } catch (SQLException ex) {
-                // Drop through and try the next driver.
-            }
+
         }
 
         println("getDriver: no suitable driver");
@@ -292,23 +302,16 @@
      */
     public static synchronized void registerDriver(java.sql.Driver driver)
         throws SQLException {
-        if (!initialized) {
-            initialize();
+
+        /* Register the driver if it has not already been added to our list */
+        if(driver != null) {
+            registeredDrivers.addIfAbsent(driver);
+        } else {
+            // This is for compatibility with the original DriverManager
+            throw new NullPointerException();
         }
 
-        DriverInfo di = new DriverInfo();
-
-        di.driver = driver;
-        di.driverClass = driver.getClass();
-        di.driverClassName = di.driverClass.getName();
-
-        // Not Required -- drivers.addElement(di);
-
-        writeDrivers.addElement(di);
-        println("registerDriver: " + di);
-
-        /* update the read copy of drivers vector */
-        readDrivers = (java.util.Vector) writeDrivers.clone();
+        println("registerDriver: " + driver);
 
     }
 
@@ -321,37 +324,26 @@
      */
     public static synchronized void deregisterDriver(Driver driver)
         throws SQLException {
+        if (driver == null) {
+            return;
+        }
+
         // Gets the classloader of the code that called this method,
         // may be null.
         ClassLoader callerCL = DriverManager.getCallerClassLoader();
         println("DriverManager.deregisterDriver: " + driver);
 
-        // Walk through the loaded drivers.
-        int i;
-        DriverInfo di = null;
-        for (i = 0; i < writeDrivers.size(); i++) {
-            di = (DriverInfo)writeDrivers.elementAt(i);
-            if (di.driver == driver) {
-                break;
+        if(registeredDrivers.contains(driver)) {
+            if (isDriverAllowed(driver, callerCL)) {
+                 registeredDrivers.remove(driver);
+            } else {
+                // If the caller does not have permission to load the driver then
+                // throw a SecurityException.
+                throw new SecurityException();
             }
-        }
-        // If we can't find the driver just return.
-        if (i >= writeDrivers.size()) {
+        } else {
             println("    couldn't find driver to unload");
-            return;
         }
-
-        // If the caller does not have permission to load the driver then
-        // throw a security exception.
-        if (getCallerClass(callerCL, di.driverClassName ) != di.driverClass ) {
-            throw new SecurityException();
-        }
-
-        // Remove the driver.  Other entries in drivers get shuffled down.
-        writeDrivers.removeElementAt(i);
-
-        /* update the read copy of drivers vector */
-        readDrivers = (java.util.Vector) writeDrivers.clone();
     }
 
     /**
@@ -364,34 +356,22 @@
      * @return the list of JDBC Drivers loaded by the caller's class loader
      */
     public static java.util.Enumeration<Driver> getDrivers() {
-        java.util.Vector<Driver> result = new java.util.Vector<>();
-        java.util.Vector drivers = null;
-
-        if (!initialized) {
-            initialize();
-        }
-
-        synchronized (DriverManager.class){
-            // use the readcopy of drivers
-            drivers  = readDrivers;
-       }
+        java.util.Vector<Driver> result = new java.util.Vector<Driver>();
 
         // Gets the classloader of the code that called this method, may
         // be null.
         ClassLoader callerCL = DriverManager.getCallerClassLoader();
 
-        // Walk through the loaded drivers.
-        for (int i = 0; i < drivers.size(); i++) {
-            DriverInfo di = (DriverInfo)drivers.elementAt(i);
+        // Walk through the loaded registeredDrivers.
+        for(Driver aDriver : registeredDrivers) {
             // If the caller does not have permission to load the driver then
             // skip it.
-            if ( getCallerClass(callerCL, di.driverClassName ) != di.driverClass ) {
-                println("    skipping: " + di);
-                continue;
+            if(isDriverAllowed(aDriver, callerCL)) {
+                result.addElement(aDriver);
+            } else {
+                println("    skipping: " + aDriver.getClass().getName());
             }
-            result.addElement(di.driver);
         }
-
         return (result.elements());
     }
 
@@ -481,21 +461,22 @@
 
     //------------------------------------------------------------------------
 
-    // Returns the class object that would be created if the code calling the
-    // driver manager had loaded the driver class, or null if the class
-    // is inaccessible.
-    private static Class getCallerClass(ClassLoader callerClassLoader,
-                                        String driverClassName) {
-        Class callerC = null;
+    // Indicates whether the class object that would be created if the code calling
+    // DriverManager is accessible.
+    private static boolean isDriverAllowed(Driver driver, ClassLoader classLoader) {
+        boolean result = false;
+        if(driver != null) {
+            Class<?> aClass = null;
+            try {
+                aClass =  Class.forName(driver.getClass().getName(), true, classLoader);
+            } catch (Exception ex) {
+                result = false;
+            }
 
-        try {
-            callerC = Class.forName(driverClassName, true, callerClassLoader);
-        }
-        catch (Exception ex) {
-            callerC = null;           // being very careful
+             result = ( aClass == driver.getClass() ) ? true : false;
         }
 
-        return callerC;
+        return result;
     }
 
     private static void loadInitialDrivers() {
@@ -544,26 +525,17 @@
         });
 
         println("DriverManager.initialize: jdbc.drivers = " + drivers);
-        if (drivers == null) {
+
+        if (drivers == null || drivers.equals("")) {
             return;
         }
-        while (drivers.length() != 0) {
-            int x = drivers.indexOf(':');
-            String driver;
-            if (x < 0) {
-                driver = drivers;
-                drivers = "";
-            } else {
-                driver = drivers.substring(0, x);
-                drivers = drivers.substring(x+1);
-            }
-            if (driver.length() == 0) {
-                continue;
-            }
+        String[] driversList = drivers.split(":");
+        println("number of Drivers:" + driversList.length);
+        for (String aDriver : driversList) {
             try {
-                println("DriverManager.Initialize: loading " + driver);
-                Class.forName(driver, true,
-                              ClassLoader.getSystemClassLoader());
+                println("DriverManager.Initialize: loading " + aDriver);
+                Class.forName(aDriver, true,
+                        ClassLoader.getSystemClassLoader());
             } catch (Exception ex) {
                 println("DriverManager.Initialize: load failed: " + ex);
             }
@@ -574,7 +546,6 @@
     //  Worker method called by the public getConnection() methods.
     private static Connection getConnection(
         String url, java.util.Properties info, ClassLoader callerCL) throws SQLException {
-        java.util.Vector drivers = null;
         /*
          * When callerCl is null, we should check the application's
          * (which is invoking this class indirectly)
@@ -594,40 +565,32 @@
 
         println("DriverManager.getConnection(\"" + url + "\")");
 
-        if (!initialized) {
-            initialize();
-        }
-
-        synchronized (DriverManager.class){
-            // use the readcopy of drivers
-            drivers = readDrivers;
-        }
-
-        // Walk through the loaded drivers attempting to make a connection.
+        // Walk through the loaded registeredDrivers attempting to make a connection.
         // Remember the first exception that gets raised so we can reraise it.
         SQLException reason = null;
-        for (int i = 0; i < drivers.size(); i++) {
-            DriverInfo di = (DriverInfo)drivers.elementAt(i);
 
+        for(Driver aDriver : registeredDrivers) {
             // If the caller does not have permission to load the driver then
             // skip it.
-            if ( getCallerClass(callerCL, di.driverClassName ) != di.driverClass ) {
-                println("    skipping: " + di);
-                continue;
+            if(isDriverAllowed(aDriver, callerCL)) {
+                try {
+                    println("    trying " + aDriver.getClass().getName());
+                    Connection con = aDriver.connect(url, info);
+                    if (con != null) {
+                        // Success!
+                        println("getConnection returning " + aDriver.getClass().getName());
+                        return (con);
+                    }
+                } catch (SQLException ex) {
+                    if (reason == null) {
+                        reason = ex;
+                    }
+                }
+
+            } else {
+                println("    skipping: " + aDriver.getClass().getName());
             }
-            try {
-                println("    trying " + di);
-                Connection result = di.driver.connect(url, info);
-                if (result != null) {
-                    // Success!
-                    println("getConnection returning " + di);
-                    return (result);
-                }
-            } catch (SQLException ex) {
-                if (reason == null) {
-                    reason = ex;
-                }
-            }
+
         }
 
         // if we got here nobody could connect.
@@ -640,45 +603,7 @@
         throw new SQLException("No suitable driver found for "+ url, "08001");
     }
 
-
-    // Class initialization.
-    static void initialize() {
-        if (initialized) {
-            return;
-        }
-        initialized = true;
-        loadInitialDrivers();
-        println("JDBC DriverManager initialized");
-    }
-
-    /* Prevent the DriverManager class from being instantiated. */
-    private DriverManager(){}
-
-    /* write copy of the drivers vector */
-    private static java.util.Vector writeDrivers = new java.util.Vector();
-
-    /* write copy of the drivers vector */
-    private static java.util.Vector readDrivers = new java.util.Vector();
-
-    private static int loginTimeout = 0;
-    private static java.io.PrintWriter logWriter = null;
-    private static java.io.PrintStream logStream = null;
-    private static boolean initialized = false;
-
-    private static Object logSync = new Object();
-
     /* Returns the caller's class loader, or null if none */
     private static native ClassLoader getCallerClassLoader();
 
 }
-
-// DriverInfo is a package-private support class.
-class DriverInfo {
-    Driver         driver;
-    Class          driverClass;
-    String         driverClassName;
-
-    public String toString() {
-        return ("driver[className=" + driverClassName + "," + driver + "]");
-    }
-}