/*
 * Copyright (c) 1996, 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 java.sql;

import java.util.Iterator;
import java.util.ServiceLoader;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.concurrent.CopyOnWriteArrayList;
import sun.reflect.CallerSensitive;
import sun.reflect.Reflection;

The basic service for managing a set of JDBC drivers.
NOTE: The DataSource interface, new in the JDBC 2.0 API, provides another way to connect to a data source. The use of a DataSource object is the preferred means of connecting to a data source.

As part of its initialization, the DriverManager class will attempt to load the driver classes referenced in the "jdbc.drivers" system property. This allows a user to customize the JDBC Drivers used by their applications. For example in your ~/.hotjava/properties file you might specify:

jdbc.drivers=foo.bah.Driver:wombat.sql.Driver:bad.taste.ourDriver

The DriverManager methods getConnection and getDrivers have been enhanced to support the Java Standard Edition Service Provider mechanism. JDBC 4.0 Drivers must include the file META-INF/services/java.sql.Driver. This file contains the name of the JDBC drivers implementation of java.sql.Driver. For example, to load the my.sql.Driver class, the META-INF/services/java.sql.Driver file would contain the entry:

my.sql.Driver

Applications no longer need to explicitly load JDBC drivers using Class.forName(). Existing programs which currently load JDBC drivers using Class.forName() will continue to work without modification.

When the method getConnection is called, the DriverManager will attempt to locate a suitable driver from amongst those loaded at initialization and those loaded explicitly using the same classloader as the current applet or application.

Starting with the Java 2 SDK, Standard Edition, version 1.3, a logging stream can be set only if the proper permission has been granted. Normally this will be done with the tool PolicyTool, which can be used to grant permission java.sql.SQLPermission "setLog".

See Also:
/** * <P>The basic service for managing a set of JDBC drivers.<br> * <B>NOTE:</B> The {@link javax.sql.DataSource} interface, new in the * JDBC 2.0 API, provides another way to connect to a data source. * The use of a <code>DataSource</code> object is the preferred means of * connecting to a data source. * * <P>As part of its initialization, the <code>DriverManager</code> class will * attempt to load the driver classes referenced in the "jdbc.drivers" * system property. This allows a user to customize the JDBC Drivers * used by their applications. For example in your * ~/.hotjava/properties file you might specify: * <pre> * <CODE>jdbc.drivers=foo.bah.Driver:wombat.sql.Driver:bad.taste.ourDriver</CODE> * </pre> *<P> The <code>DriverManager</code> methods <code>getConnection</code> and * <code>getDrivers</code> have been enhanced to support the Java Standard Edition * <a href="../../../technotes/guides/jar/jar.html#Service%20Provider">Service Provider</a> mechanism. JDBC 4.0 Drivers must * include the file <code>META-INF/services/java.sql.Driver</code>. This file contains the name of the JDBC drivers * implementation of <code>java.sql.Driver</code>. For example, to load the <code>my.sql.Driver</code> class, * the <code>META-INF/services/java.sql.Driver</code> file would contain the entry: * <pre> * <code>my.sql.Driver</code> * </pre> * * <P>Applications no longer need to explicitly load JDBC drivers using <code>Class.forName()</code>. Existing programs * which currently load JDBC drivers using <code>Class.forName()</code> will continue to work without * modification. * * <P>When the method <code>getConnection</code> is called, * the <code>DriverManager</code> will attempt to * locate a suitable driver from amongst those loaded at * initialization and those loaded explicitly using the same classloader * as the current applet or application. * * <P> * Starting with the Java 2 SDK, Standard Edition, version 1.3, a * logging stream can be set only if the proper * permission has been granted. Normally this will be done with * the tool PolicyTool, which can be used to grant <code>permission * java.sql.SQLPermission "setLog"</code>. * @see Driver * @see Connection */
public class DriverManager { // List of registered JDBC drivers private final static CopyOnWriteArrayList<DriverInfo> registeredDrivers = new CopyOnWriteArrayList<DriverInfo>(); 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 ServiceLoader mechanism
/** * 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.
Since:1.3
/** * The <code>SQLPermission</code> constant that allows the * setting of the logging stream. * @since 1.3 */
final static SQLPermission SET_LOG_PERMISSION = new SQLPermission("setLog"); //--------------------------JDBC 2.0-----------------------------
Retrieves the log writer. The getLogWriter and setLogWriter methods should be used instead of the get/setlogStream methods, which are deprecated.
See Also:
Returns:a java.io.PrintWriter object
Since:1.2
/** * Retrieves the log writer. * * The <code>getLogWriter</code> and <code>setLogWriter</code> * methods should be used instead * of the <code>get/setlogStream</code> methods, which are deprecated. * @return a <code>java.io.PrintWriter</code> object * @see #setLogWriter * @since 1.2 */
public static java.io.PrintWriter getLogWriter() { return logWriter; }
Sets the logging/tracing PrintWriter object that is used by the DriverManager and all drivers.

There is a minor versioning problem created by the introduction of the method setLogWriter. The method setLogWriter cannot create a PrintStream object that will be returned by getLogStream---the Java platform does not provide a backward conversion. As a result, a new application that uses setLogWriter and also uses a JDBC 1.0 driver that uses getLogStream will likely not see debugging information written by that driver.

Starting with the Java 2 SDK, Standard Edition, version 1.3 release, this method checks to see that there is an SQLPermission object before setting the logging stream. If a SecurityManager exists and its checkPermission method denies setting the log writer, this method throws a java.lang.SecurityException.

Params:
  • out – the new logging/tracing PrintStream object; null to disable logging and tracing
Throws:
  • SecurityException – if a security manager exists and its checkPermission method denies setting the log writer
See Also:
Since:1.2
/** * Sets the logging/tracing <code>PrintWriter</code> object * that is used by the <code>DriverManager</code> and all drivers. * <P> * There is a minor versioning problem created by the introduction * of the method <code>setLogWriter</code>. The * method <code>setLogWriter</code> cannot create a <code>PrintStream</code> object * that will be returned by <code>getLogStream</code>---the Java platform does * not provide a backward conversion. As a result, a new application * that uses <code>setLogWriter</code> and also uses a JDBC 1.0 driver that uses * <code>getLogStream</code> will likely not see debugging information written * by that driver. *<P> * Starting with the Java 2 SDK, Standard Edition, version 1.3 release, this method checks * to see that there is an <code>SQLPermission</code> object before setting * the logging stream. If a <code>SecurityManager</code> exists and its * <code>checkPermission</code> method denies setting the log writer, this * method throws a <code>java.lang.SecurityException</code>. * * @param out the new logging/tracing <code>PrintStream</code> object; * <code>null</code> to disable logging and tracing * @throws SecurityException * if a security manager exists and its * <code>checkPermission</code> method denies * setting the log writer * * @see SecurityManager#checkPermission * @see #getLogWriter * @since 1.2 */
public static void setLogWriter(java.io.PrintWriter out) { SecurityManager sec = System.getSecurityManager(); if (sec != null) { sec.checkPermission(SET_LOG_PERMISSION); } logStream = null; logWriter = out; } //---------------------------------------------------------------
Attempts to establish a connection to the given database URL. The DriverManager attempts to select an appropriate driver from the set of registered JDBC drivers.
Params:
  • url – a database url of the form jdbc:subprotocol:subname
  • info – a list of arbitrary string tag/value pairs as connection arguments; normally at least a "user" and "password" property should be included
Throws:
Returns:a Connection to the URL
/** * Attempts to establish a connection to the given database URL. * The <code>DriverManager</code> attempts to select an appropriate driver from * the set of registered JDBC drivers. * * @param url a database url of the form * <code> jdbc:<em>subprotocol</em>:<em>subname</em></code> * @param info a list of arbitrary string tag/value pairs as * connection arguments; normally at least a "user" and * "password" property should be included * @return a Connection to the URL * @exception SQLException if a database access error occurs */
@CallerSensitive public static Connection getConnection(String url, java.util.Properties info) throws SQLException { return (getConnection(url, info, Reflection.getCallerClass())); }
Attempts to establish a connection to the given database URL. The DriverManager attempts to select an appropriate driver from the set of registered JDBC drivers.
Params:
  • url – a database url of the form jdbc:subprotocol:subname
  • user – the database user on whose behalf the connection is being made
  • password – the user's password
Throws:
Returns:a connection to the URL
/** * Attempts to establish a connection to the given database URL. * The <code>DriverManager</code> attempts to select an appropriate driver from * the set of registered JDBC drivers. * * @param url a database url of the form * <code>jdbc:<em>subprotocol</em>:<em>subname</em></code> * @param user the database user on whose behalf the connection is being * made * @param password the user's password * @return a connection to the URL * @exception SQLException if a database access error occurs */
@CallerSensitive public static Connection getConnection(String url, String user, String password) throws SQLException { java.util.Properties info = new java.util.Properties(); if (user != null) { info.put("user", user); } if (password != null) { info.put("password", password); } return (getConnection(url, info, Reflection.getCallerClass())); }
Attempts to establish a connection to the given database URL. The DriverManager attempts to select an appropriate driver from the set of registered JDBC drivers.
Params:
  • url – a database url of the form jdbc:subprotocol:subname
Throws:
Returns:a connection to the URL
/** * Attempts to establish a connection to the given database URL. * The <code>DriverManager</code> attempts to select an appropriate driver from * the set of registered JDBC drivers. * * @param url a database url of the form * <code> jdbc:<em>subprotocol</em>:<em>subname</em></code> * @return a connection to the URL * @exception SQLException if a database access error occurs */
@CallerSensitive public static Connection getConnection(String url) throws SQLException { java.util.Properties info = new java.util.Properties(); return (getConnection(url, info, Reflection.getCallerClass())); }
Attempts to locate a driver that understands the given URL. The DriverManager attempts to select an appropriate driver from the set of registered JDBC drivers.
Params:
  • url – a database URL of the form jdbc:subprotocol:subname
Throws:
Returns:a Driver object representing a driver that can connect to the given URL
/** * Attempts to locate a driver that understands the given URL. * The <code>DriverManager</code> attempts to select an appropriate driver from * the set of registered JDBC drivers. * * @param url a database URL of the form * <code>jdbc:<em>subprotocol</em>:<em>subname</em></code> * @return a <code>Driver</code> object representing a driver * that can connect to the given URL * @exception SQLException if a database access error occurs */
@CallerSensitive public static Driver getDriver(String url) throws SQLException { println("DriverManager.getDriver(\"" + url + "\")"); Class<?> callerClass = Reflection.getCallerClass(); // Walk through the loaded registeredDrivers attempting to locate someone // who understands the given URL. for (DriverInfo aDriver : registeredDrivers) { // If the caller does not have permission to load the driver then // skip it. if(isDriverAllowed(aDriver.driver, callerClass)) { try { if(aDriver.driver.acceptsURL(url)) { // Success! println("getDriver returning " + aDriver.driver.getClass().getName()); return (aDriver.driver); } } catch(SQLException sqe) { // Drop through and try the next driver. } } else { println(" skipping: " + aDriver.driver.getClass().getName()); } } println("getDriver: no suitable driver"); throw new SQLException("No suitable driver", "08001"); }
Registers the given driver with the DriverManager. A newly-loaded driver class should call the method registerDriver to make itself known to the DriverManager.
Params:
  • driver – the new JDBC Driver that is to be registered with the DriverManager
Throws:
/** * Registers the given driver with the <code>DriverManager</code>. * A newly-loaded driver class should call * the method <code>registerDriver</code> to make itself * known to the <code>DriverManager</code>. * * @param driver the new JDBC Driver that is to be registered with the * <code>DriverManager</code> * @exception SQLException if a database access error occurs */
public static synchronized void registerDriver(java.sql.Driver driver) throws SQLException { /* Register the driver if it has not already been added to our list */ if(driver != null) { registeredDrivers.addIfAbsent(new DriverInfo(driver)); } else { // This is for compatibility with the original DriverManager throw new NullPointerException(); } println("registerDriver: " + driver); }
Drops a driver from the DriverManager's list. Applets can only deregister drivers from their own classloaders.
Params:
  • driver – the JDBC Driver to drop
Throws:
/** * Drops a driver from the <code>DriverManager</code>'s list. * Applets can only deregister drivers from their own classloaders. * * @param driver the JDBC Driver to drop * @exception SQLException if a database access error occurs */
@CallerSensitive public static synchronized void deregisterDriver(Driver driver) throws SQLException { if (driver == null) { return; } println("DriverManager.deregisterDriver: " + driver); DriverInfo aDriver = new DriverInfo(driver); if(registeredDrivers.contains(aDriver)) { if (isDriverAllowed(driver, Reflection.getCallerClass())) { registeredDrivers.remove(aDriver); } else { // If the caller does not have permission to load the driver then // throw a SecurityException. throw new SecurityException(); } } 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.

Note: The classname of a driver can be found using d.getClass().getName()

Returns:the list of JDBC Drivers loaded by the caller's class loader
/** * Retrieves an Enumeration with all of the currently loaded JDBC drivers * to which the current caller has access. * * <P><B>Note:</B> The classname of a driver can be found using * <CODE>d.getClass().getName()</CODE> * * @return the list of JDBC Drivers loaded by the caller's class loader */
@CallerSensitive public static java.util.Enumeration<Driver> getDrivers() { java.util.Vector<Driver> result = new java.util.Vector<Driver>(); Class<?> callerClass = Reflection.getCallerClass(); // Walk through the loaded registeredDrivers. for(DriverInfo aDriver : registeredDrivers) { // If the caller does not have permission to load the driver then // skip it. if(isDriverAllowed(aDriver.driver, callerClass)) { result.addElement(aDriver.driver); } else { println(" skipping: " + aDriver.getClass().getName()); } } return (result.elements()); }
Sets the maximum time in seconds that a driver will wait while attempting to connect to a database.
Params:
  • seconds – the login time limit in seconds; zero means there is no limit
See Also:
/** * Sets the maximum time in seconds that a driver will wait * while attempting to connect to a database. * * @param seconds the login time limit in seconds; zero means there is no limit * @see #getLoginTimeout */
public static void setLoginTimeout(int seconds) { loginTimeout = seconds; }
Gets the maximum time in seconds that a driver can wait when attempting to log in to a database.
See Also:
Returns:the driver login time limit in seconds
/** * Gets the maximum time in seconds that a driver can wait * when attempting to log in to a database. * * @return the driver login time limit in seconds * @see #setLoginTimeout */
public static int getLoginTimeout() { return (loginTimeout); }
Sets the logging/tracing PrintStream that is used by the DriverManager and all drivers.

In the Java 2 SDK, Standard Edition, version 1.3 release, this method checks to see that there is an SQLPermission object before setting the logging stream. If a SecurityManager exists and its checkPermission method denies setting the log writer, this method throws a java.lang.SecurityException.

Params:
  • out – the new logging/tracing PrintStream; to disable, set to null
Throws:
  • SecurityException – if a security manager exists and its checkPermission method denies setting the log stream
See Also:
Deprecated:
/** * Sets the logging/tracing PrintStream that is used * by the <code>DriverManager</code> * and all drivers. *<P> * In the Java 2 SDK, Standard Edition, version 1.3 release, this method checks * to see that there is an <code>SQLPermission</code> object before setting * the logging stream. If a <code>SecurityManager</code> exists and its * <code>checkPermission</code> method denies setting the log writer, this * method throws a <code>java.lang.SecurityException</code>. * * @param out the new logging/tracing PrintStream; to disable, set to <code>null</code> * @deprecated * @throws SecurityException if a security manager exists and its * <code>checkPermission</code> method denies setting the log stream * * @see SecurityManager#checkPermission * @see #getLogStream */
public static void setLogStream(java.io.PrintStream out) { SecurityManager sec = System.getSecurityManager(); if (sec != null) { sec.checkPermission(SET_LOG_PERMISSION); } logStream = out; if ( out != null ) logWriter = new java.io.PrintWriter(out); else logWriter = null; }
Retrieves the logging/tracing PrintStream that is used by the DriverManager and all drivers.
See Also:
Returns:the logging/tracing PrintStream; if disabled, is null
Deprecated:
/** * Retrieves the logging/tracing PrintStream that is used by the <code>DriverManager</code> * and all drivers. * * @return the logging/tracing PrintStream; if disabled, is <code>null</code> * @deprecated * @see #setLogStream */
public static java.io.PrintStream getLogStream() { return logStream; }
Prints a message to the current JDBC log stream.
Params:
  • message – a log or tracing message
/** * Prints a message to the current JDBC log stream. * * @param message a log or tracing message */
public static void println(String message) { synchronized (logSync) { if (logWriter != null) { logWriter.println(message); // automatic flushing is never enabled, so we must do it ourselves logWriter.flush(); } } } //------------------------------------------------------------------------ // Indicates whether the class object that would be created if the code calling // DriverManager is accessible. private static boolean isDriverAllowed(Driver driver, Class<?> caller) { ClassLoader callerCL = caller != null ? caller.getClassLoader() : null; return isDriverAllowed(driver, callerCL); } 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; } result = ( aClass == driver.getClass() ) ? true : false; } return result; } private static void loadInitialDrivers() { String drivers; try { drivers = AccessController.doPrivileged(new PrivilegedAction<String>() { public String run() { return System.getProperty("jdbc.drivers"); } }); } catch (Exception ex) { drivers = null; } // If the driver is packaged as a Service Provider, load it. // Get all the drivers through the classloader // exposed as a java.sql.Driver.class service. // ServiceLoader.load() replaces the sun.misc.Providers() AccessController.doPrivileged(new PrivilegedAction<Void>() { public Void run() { ServiceLoader<Driver> loadedDrivers = ServiceLoader.load(Driver.class); Iterator driversIterator = loadedDrivers.iterator(); /* Load these drivers, so that they can be instantiated. * It may be the case that the driver class may not be there * i.e. there may be a packaged driver with the service class * as implementation of java.sql.Driver but the actual class * may be missing. In that case a java.util.ServiceConfigurationError * will be thrown at runtime by the VM trying to locate * and load the service. * * Adding a try catch block to catch those runtime errors * if driver not available in classpath but it's * packaged as service and that service is there in classpath. */ try{ while(driversIterator.hasNext()) { driversIterator.next(); } } catch(Throwable t) { // Do nothing } return null; } }); println("DriverManager.initialize: jdbc.drivers = " + drivers); if (drivers == null || drivers.equals("")) { return; } String[] driversList = drivers.split(":"); println("number of Drivers:" + driversList.length); for (String aDriver : driversList) { try { println("DriverManager.Initialize: loading " + aDriver); Class.forName(aDriver, true, ClassLoader.getSystemClassLoader()); } catch (Exception ex) { println("DriverManager.Initialize: load failed: " + ex); } } } // Worker method called by the public getConnection() methods. private static Connection getConnection( String url, java.util.Properties info, Class<?> caller) throws SQLException { /* * 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. */ ClassLoader callerCL = caller != null ? caller.getClassLoader() : null; synchronized (DriverManager.class) { // synchronize loading of the correct classloader. if (callerCL == null) { callerCL = Thread.currentThread().getContextClassLoader(); } } if(url == null) { throw new SQLException("The url cannot be null", "08001"); } println("DriverManager.getConnection(\"" + url + "\")"); // 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(DriverInfo aDriver : registeredDrivers) { // If the caller does not have permission to load the driver then // skip it. if(isDriverAllowed(aDriver.driver, callerCL)) { try { println(" trying " + aDriver.driver.getClass().getName()); Connection con = aDriver.driver.connect(url, info); if (con != null) { // Success! println("getConnection returning " + aDriver.driver.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); throw reason; } println("getConnection: no suitable driver found for "+ url); throw new SQLException("No suitable driver found for "+ url, "08001"); } } /* * Wrapper class for registered Drivers in order to not expose Driver.equals() * to avoid the capture of the Driver it being compared to as it might not * normally have access. */ class DriverInfo { final Driver driver; DriverInfo(Driver driver) { this.driver = driver; } public boolean equals(Object other) { return (other instanceof DriverInfo) && this.driver == ((DriverInfo) other).driver; } public int hashCode() { return driver.hashCode(); } public String toString() { return ("driver[className=" + driver + "]"); } }