src/share/classes/java/sql/DriverManager.java

Print this page

        

@@ -24,14 +24,14 @@
  */
 
 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;
 
 
 /**
  * <P>The basic service for managing a set of JDBC drivers.<br>
  * <B>NOTE:</B> The {@link <code>DataSource</code>} interface, new in the

@@ -77,10 +77,27 @@
  * @see Connection
  */
 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 static  Object logSync = new Object();
+
+    /**
+     * 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.
      * @since 1.3
      */

@@ -233,48 +250,37 @@
      * that can connect to the given URL
      * @exception SQLException if a database access error occurs
      */
     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 {
-                println("    trying " + di);
-                if (di.driver.acceptsURL(url)) {
+                    if(aDriver.acceptsURL(url)) {
                     // Success!
-                    println("getDriver returning " + di);
-                    return (di.driver);
+                        println("getDriver returning " + aDriver.getClass().getName());
+                    return (aDriver);
                 }
-            } catch (SQLException ex) {
+
+                } catch(SQLException sqe) {
                 // Drop through and try the next driver.
             }
+            } else {
+                println("    skipping: " + aDriver.getClass().getName());
+            }
+
         }
 
         println("getDriver: no suitable driver");
         throw new SQLException("No suitable driver", "08001");
     }

@@ -290,27 +296,20 @@
      *               <code>DriverManager</code>
      * @exception SQLException if a database access error occurs
      */
     public static synchronized void registerDriver(java.sql.Driver driver)
         throws SQLException {
-        if (!initialized) {
-            initialize();
-        }
-
-        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);
+        /* 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();
+        }
 
-        /* update the read copy of drivers vector */
-        readDrivers = (java.util.Vector) writeDrivers.clone();
+        println("registerDriver: " + driver);
 
     }
 
     /**
      * Drops a driver from the <code>DriverManager</code>'s list.

@@ -319,41 +318,30 @@
      * @param driver the JDBC Driver to drop
      * @exception SQLException if a database access error occurs
      */
     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 we can't find the driver just return.
-        if (i >= writeDrivers.size()) {
-            println("    couldn't find driver to unload");
-            return;
-        }
-
+        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 security exception.
-        if (getCallerClass(callerCL, di.driverClassName ) != di.driverClass ) {
+                // throw a SecurityException.
             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();
+        } else {
+            println("    couldn't find driver to unload");
+        }
     }
 
     /**
      * Retrieves an Enumeration with all of the currently loaded JDBC drivers
      * to which the current caller has access.

@@ -362,38 +350,26 @@
      * <CODE>d.getClass().getName()</CODE>
      *
      * @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());
     }
 
 
     /**

@@ -479,25 +455,26 @@
         }
     }
 
     //------------------------------------------------------------------------
 
-    // 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 {
-            callerC = Class.forName(driverClassName, true, callerClassLoader);
+                aClass =  Class.forName(driver.getClass().getName(), true, classLoader);
+            } catch (Exception ex) {
+                result = false;
         }
-        catch (Exception ex) {
-            callerC = null;           // being very careful
+
+             result = ( aClass == driver.getClass() ) ? true : false;
         }
 
-        return callerC;
+        return result;
     }
 
     private static void loadInitialDrivers() {
         String drivers;
         try {

@@ -542,29 +519,20 @@
                 return null;
             }
         });
 
         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,
+                println("DriverManager.Initialize: loading " + aDriver);
+                Class.forName(aDriver, true,
                               ClassLoader.getSystemClassLoader());
             } catch (Exception ex) {
                 println("DriverManager.Initialize: load failed: " + ex);
             }
         }

@@ -572,11 +540,10 @@
 
 
     //  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)
          * classloader, so that the JDBC driver class outside rt.jar
          * can be loaded from here.

@@ -592,44 +559,36 @@
             throw new SQLException("The url cannot be null", "08001");
         }
 
         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 " + di);
-                Connection result = di.driver.connect(url, info);
-                if (result != null) {
+                    println("    trying " + aDriver.getClass().getName());
+                    Connection con = aDriver.connect(url, info);
+                    if (con != null) {
                     // Success!
-                    println("getConnection returning " + di);
-                    return (result);
+                        println("getConnection returning " + aDriver.getClass().getName());
+                        return (con);
                 }
             } catch (SQLException ex) {
                 if (reason == null) {
                     reason = ex;
                 }
             }
+
+            } else {
+                println("    skipping: " + aDriver.getClass().getName());
+            }
+
         }
 
         // if we got here nobody could connect.
         if (reason != null)    {
             println("getConnection failed: " + reason);

@@ -638,47 +597,12 @@
 
         println("getConnection: no suitable driver found for "+ url);
         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 + "]");
-    }
-}