From f5e53fe271fdfbd42a89d85e4efb04d4e3543b52 Mon Sep 17 00:00:00 2001 From: lancea Date: Thu, 17 Mar 2011 11:37:06 -0400 Subject: [PATCH] 7026898: DriverManager to now use CopyOnWriteArrayList Reviewed-by: alanb, briangoetz --- src/share/classes/java/sql/DriverManager.java | 285 +++++++----------- 1 file changed, 105 insertions(+), 180 deletions(-) diff --git a/src/share/classes/java/sql/DriverManager.java b/src/share/classes/java/sql/DriverManager.java index 15273877d..ce6c6bf48 100644 --- a/src/share/classes/java/sql/DriverManager.java +++ b/src/share/classes/java/sql/DriverManager.java @@ -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 @@ import java.security.PrivilegedAction; public class DriverManager { + // List of registered JDBC drivers + private final static CopyOnWriteArrayList registeredDrivers = new CopyOnWriteArrayList(); + 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 SQLPermission constant that allows the * setting of the logging stream. @@ -235,44 +256,33 @@ public class DriverManager { */ 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; - } - try { - println(" trying " + di); - if (di.driver.acceptsURL(url)) { - // Success! - println("getDriver returning " + di); - return (di.driver); + 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. } - } catch (SQLException ex) { - // Drop through and try the next driver. + } else { + println(" skipping: " + aDriver.getClass().getName()); } + } println("getDriver: no suitable driver"); @@ -292,23 +302,16 @@ public class DriverManager { */ 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); } @@ -321,37 +324,26 @@ public class DriverManager { */ 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 @@ public class DriverManager { * @return the list of JDBC Drivers loaded by the caller's class loader */ public static java.util.Enumeration getDrivers() { - java.util.Vector 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 result = new java.util.Vector(); // 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 @@ public class DriverManager { //------------------------------------------------------------------------ - // 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 @@ public class DriverManager { }); 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 @@ public class DriverManager { // 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 @@ public class DriverManager { 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; - } - 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(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()); } + } // if we got here nobody could connect. @@ -640,45 +603,7 @@ public class DriverManager { 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 + "]"); - } -} -- GitLab