Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/java/sql/DriverManager.java
38829 views
/*1* Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package java.sql;2627import java.util.Iterator;28import java.util.ServiceLoader;29import java.security.AccessController;30import java.security.PrivilegedAction;31import java.util.concurrent.CopyOnWriteArrayList;32import sun.reflect.CallerSensitive;33import sun.reflect.Reflection;343536/**37* <P>The basic service for managing a set of JDBC drivers.<br>38* <B>NOTE:</B> The {@link javax.sql.DataSource} interface, new in the39* JDBC 2.0 API, provides another way to connect to a data source.40* The use of a <code>DataSource</code> object is the preferred means of41* connecting to a data source.42*43* <P>As part of its initialization, the <code>DriverManager</code> class will44* attempt to load the driver classes referenced in the "jdbc.drivers"45* system property. This allows a user to customize the JDBC Drivers46* used by their applications. For example in your47* ~/.hotjava/properties file you might specify:48* <pre>49* <CODE>jdbc.drivers=foo.bah.Driver:wombat.sql.Driver:bad.taste.ourDriver</CODE>50* </pre>51*<P> The <code>DriverManager</code> methods <code>getConnection</code> and52* <code>getDrivers</code> have been enhanced to support the Java Standard Edition53* <a href="../../../technotes/guides/jar/jar.html#Service%20Provider">Service Provider</a> mechanism. JDBC 4.0 Drivers must54* include the file <code>META-INF/services/java.sql.Driver</code>. This file contains the name of the JDBC drivers55* implementation of <code>java.sql.Driver</code>. For example, to load the <code>my.sql.Driver</code> class,56* the <code>META-INF/services/java.sql.Driver</code> file would contain the entry:57* <pre>58* <code>my.sql.Driver</code>59* </pre>60*61* <P>Applications no longer need to explicitly load JDBC drivers using <code>Class.forName()</code>. Existing programs62* which currently load JDBC drivers using <code>Class.forName()</code> will continue to work without63* modification.64*65* <P>When the method <code>getConnection</code> is called,66* the <code>DriverManager</code> will attempt to67* locate a suitable driver from amongst those loaded at68* initialization and those loaded explicitly using the same classloader69* as the current applet or application.70*71* <P>72* Starting with the Java 2 SDK, Standard Edition, version 1.3, a73* logging stream can be set only if the proper74* permission has been granted. Normally this will be done with75* the tool PolicyTool, which can be used to grant <code>permission76* java.sql.SQLPermission "setLog"</code>.77* @see Driver78* @see Connection79*/80public class DriverManager {818283// List of registered JDBC drivers84private final static CopyOnWriteArrayList<DriverInfo> registeredDrivers = new CopyOnWriteArrayList<>();85private static volatile int loginTimeout = 0;86private static volatile java.io.PrintWriter logWriter = null;87private static volatile java.io.PrintStream logStream = null;88// Used in println() to synchronize logWriter89private final static Object logSync = new Object();9091/* Prevent the DriverManager class from being instantiated. */92private DriverManager(){}939495/**96* Load the initial JDBC drivers by checking the System property97* jdbc.properties and then use the {@code ServiceLoader} mechanism98*/99static {100loadInitialDrivers();101println("JDBC DriverManager initialized");102}103104/**105* The <code>SQLPermission</code> constant that allows the106* setting of the logging stream.107* @since 1.3108*/109final static SQLPermission SET_LOG_PERMISSION =110new SQLPermission("setLog");111112/**113* The {@code SQLPermission} constant that allows the114* un-register a registered JDBC driver.115* @since 1.8116*/117final static SQLPermission DEREGISTER_DRIVER_PERMISSION =118new SQLPermission("deregisterDriver");119120//--------------------------JDBC 2.0-----------------------------121122/**123* Retrieves the log writer.124*125* The <code>getLogWriter</code> and <code>setLogWriter</code>126* methods should be used instead127* of the <code>get/setlogStream</code> methods, which are deprecated.128* @return a <code>java.io.PrintWriter</code> object129* @see #setLogWriter130* @since 1.2131*/132public static java.io.PrintWriter getLogWriter() {133return logWriter;134}135136/**137* Sets the logging/tracing <code>PrintWriter</code> object138* that is used by the <code>DriverManager</code> and all drivers.139* <P>140* There is a minor versioning problem created by the introduction141* of the method <code>setLogWriter</code>. The142* method <code>setLogWriter</code> cannot create a <code>PrintStream</code> object143* that will be returned by <code>getLogStream</code>---the Java platform does144* not provide a backward conversion. As a result, a new application145* that uses <code>setLogWriter</code> and also uses a JDBC 1.0 driver that uses146* <code>getLogStream</code> will likely not see debugging information written147* by that driver.148*<P>149* Starting with the Java 2 SDK, Standard Edition, version 1.3 release, this method checks150* to see that there is an <code>SQLPermission</code> object before setting151* the logging stream. If a <code>SecurityManager</code> exists and its152* <code>checkPermission</code> method denies setting the log writer, this153* method throws a <code>java.lang.SecurityException</code>.154*155* @param out the new logging/tracing <code>PrintStream</code> object;156* <code>null</code> to disable logging and tracing157* @throws SecurityException158* if a security manager exists and its159* <code>checkPermission</code> method denies160* setting the log writer161*162* @see SecurityManager#checkPermission163* @see #getLogWriter164* @since 1.2165*/166public static void setLogWriter(java.io.PrintWriter out) {167168SecurityManager sec = System.getSecurityManager();169if (sec != null) {170sec.checkPermission(SET_LOG_PERMISSION);171}172logStream = null;173logWriter = out;174}175176177//---------------------------------------------------------------178179/**180* Attempts to establish a connection to the given database URL.181* The <code>DriverManager</code> attempts to select an appropriate driver from182* the set of registered JDBC drivers.183*<p>184* <B>Note:</B> If a property is specified as part of the {@code url} and185* is also specified in the {@code Properties} object, it is186* implementation-defined as to which value will take precedence.187* For maximum portability, an application should only specify a188* property once.189*190* @param url a database url of the form191* <code> jdbc:<em>subprotocol</em>:<em>subname</em></code>192* @param info a list of arbitrary string tag/value pairs as193* connection arguments; normally at least a "user" and194* "password" property should be included195* @return a Connection to the URL196* @exception SQLException if a database access error occurs or the url is197* {@code null}198* @throws SQLTimeoutException when the driver has determined that the199* timeout value specified by the {@code setLoginTimeout} method200* has been exceeded and has at least tried to cancel the201* current database connection attempt202*/203@CallerSensitive204public static Connection getConnection(String url,205java.util.Properties info) throws SQLException {206207return (getConnection(url, info, Reflection.getCallerClass()));208}209210/**211* Attempts to establish a connection to the given database URL.212* The <code>DriverManager</code> attempts to select an appropriate driver from213* the set of registered JDBC drivers.214*<p>215* <B>Note:</B> If the {@code user} or {@code password} property are216* also specified as part of the {@code url}, it is217* implementation-defined as to which value will take precedence.218* For maximum portability, an application should only specify a219* property once.220*221* @param url a database url of the form222* <code>jdbc:<em>subprotocol</em>:<em>subname</em></code>223* @param user the database user on whose behalf the connection is being224* made225* @param password the user's password226* @return a connection to the URL227* @exception SQLException if a database access error occurs or the url is228* {@code null}229* @throws SQLTimeoutException when the driver has determined that the230* timeout value specified by the {@code setLoginTimeout} method231* has been exceeded and has at least tried to cancel the232* current database connection attempt233*/234@CallerSensitive235public static Connection getConnection(String url,236String user, String password) throws SQLException {237java.util.Properties info = new java.util.Properties();238239if (user != null) {240info.put("user", user);241}242if (password != null) {243info.put("password", password);244}245246return (getConnection(url, info, Reflection.getCallerClass()));247}248249/**250* Attempts to establish a connection to the given database URL.251* The <code>DriverManager</code> attempts to select an appropriate driver from252* the set of registered JDBC drivers.253*254* @param url a database url of the form255* <code> jdbc:<em>subprotocol</em>:<em>subname</em></code>256* @return a connection to the URL257* @exception SQLException if a database access error occurs or the url is258* {@code null}259* @throws SQLTimeoutException when the driver has determined that the260* timeout value specified by the {@code setLoginTimeout} method261* has been exceeded and has at least tried to cancel the262* current database connection attempt263*/264@CallerSensitive265public static Connection getConnection(String url)266throws SQLException {267268java.util.Properties info = new java.util.Properties();269return (getConnection(url, info, Reflection.getCallerClass()));270}271272/**273* Attempts to locate a driver that understands the given URL.274* The <code>DriverManager</code> attempts to select an appropriate driver from275* the set of registered JDBC drivers.276*277* @param url a database URL of the form278* <code>jdbc:<em>subprotocol</em>:<em>subname</em></code>279* @return a <code>Driver</code> object representing a driver280* that can connect to the given URL281* @exception SQLException if a database access error occurs282*/283@CallerSensitive284public static Driver getDriver(String url)285throws SQLException {286287println("DriverManager.getDriver(\"" + url + "\")");288289Class<?> callerClass = Reflection.getCallerClass();290291// Walk through the loaded registeredDrivers attempting to locate someone292// who understands the given URL.293for (DriverInfo aDriver : registeredDrivers) {294// If the caller does not have permission to load the driver then295// skip it.296if(isDriverAllowed(aDriver.driver, callerClass)) {297try {298if(aDriver.driver.acceptsURL(url)) {299// Success!300println("getDriver returning " + aDriver.driver.getClass().getName());301return (aDriver.driver);302}303304} catch(SQLException sqe) {305// Drop through and try the next driver.306}307} else {308println(" skipping: " + aDriver.driver.getClass().getName());309}310311}312313println("getDriver: no suitable driver");314throw new SQLException("No suitable driver", "08001");315}316317318/**319* Registers the given driver with the {@code DriverManager}.320* A newly-loaded driver class should call321* the method {@code registerDriver} to make itself322* known to the {@code DriverManager}. If the driver is currently323* registered, no action is taken.324*325* @param driver the new JDBC Driver that is to be registered with the326* {@code DriverManager}327* @exception SQLException if a database access error occurs328* @exception NullPointerException if {@code driver} is null329*/330public static synchronized void registerDriver(java.sql.Driver driver)331throws SQLException {332333registerDriver(driver, null);334}335336/**337* Registers the given driver with the {@code DriverManager}.338* A newly-loaded driver class should call339* the method {@code registerDriver} to make itself340* known to the {@code DriverManager}. If the driver is currently341* registered, no action is taken.342*343* @param driver the new JDBC Driver that is to be registered with the344* {@code DriverManager}345* @param da the {@code DriverAction} implementation to be used when346* {@code DriverManager#deregisterDriver} is called347* @exception SQLException if a database access error occurs348* @exception NullPointerException if {@code driver} is null349* @since 1.8350*/351public static synchronized void registerDriver(java.sql.Driver driver,352DriverAction da)353throws SQLException {354355/* Register the driver if it has not already been added to our list */356if(driver != null) {357registeredDrivers.addIfAbsent(new DriverInfo(driver, da));358} else {359// This is for compatibility with the original DriverManager360throw new NullPointerException();361}362363println("registerDriver: " + driver);364365}366367/**368* Removes the specified driver from the {@code DriverManager}'s list of369* registered drivers.370* <p>371* If a {@code null} value is specified for the driver to be removed, then no372* action is taken.373* <p>374* If a security manager exists and its {@code checkPermission} denies375* permission, then a {@code SecurityException} will be thrown.376* <p>377* If the specified driver is not found in the list of registered drivers,378* then no action is taken. If the driver was found, it will be removed379* from the list of registered drivers.380* <p>381* If a {@code DriverAction} instance was specified when the JDBC driver was382* registered, its deregister method will be called383* prior to the driver being removed from the list of registered drivers.384*385* @param driver the JDBC Driver to remove386* @exception SQLException if a database access error occurs387* @throws SecurityException if a security manager exists and its388* {@code checkPermission} method denies permission to deregister a driver.389*390* @see SecurityManager#checkPermission391*/392@CallerSensitive393public static synchronized void deregisterDriver(Driver driver)394throws SQLException {395if (driver == null) {396return;397}398399SecurityManager sec = System.getSecurityManager();400if (sec != null) {401sec.checkPermission(DEREGISTER_DRIVER_PERMISSION);402}403404println("DriverManager.deregisterDriver: " + driver);405406DriverInfo aDriver = new DriverInfo(driver, null);407if(registeredDrivers.contains(aDriver)) {408if (isDriverAllowed(driver, Reflection.getCallerClass())) {409DriverInfo di = registeredDrivers.get(registeredDrivers.indexOf(aDriver));410// If a DriverAction was specified, Call it to notify the411// driver that it has been deregistered412if(di.action() != null) {413di.action().deregister();414}415registeredDrivers.remove(aDriver);416} else {417// If the caller does not have permission to load the driver then418// throw a SecurityException.419throw new SecurityException();420}421} else {422println(" couldn't find driver to unload");423}424}425426/**427* Retrieves an Enumeration with all of the currently loaded JDBC drivers428* to which the current caller has access.429*430* <P><B>Note:</B> The classname of a driver can be found using431* <CODE>d.getClass().getName()</CODE>432*433* @return the list of JDBC Drivers loaded by the caller's class loader434*/435@CallerSensitive436public static java.util.Enumeration<Driver> getDrivers() {437java.util.Vector<Driver> result = new java.util.Vector<>();438439Class<?> callerClass = Reflection.getCallerClass();440441// Walk through the loaded registeredDrivers.442for(DriverInfo aDriver : registeredDrivers) {443// If the caller does not have permission to load the driver then444// skip it.445if(isDriverAllowed(aDriver.driver, callerClass)) {446result.addElement(aDriver.driver);447} else {448println(" skipping: " + aDriver.getClass().getName());449}450}451return (result.elements());452}453454455/**456* Sets the maximum time in seconds that a driver will wait457* while attempting to connect to a database once the driver has458* been identified.459*460* @param seconds the login time limit in seconds; zero means there is no limit461* @see #getLoginTimeout462*/463public static void setLoginTimeout(int seconds) {464loginTimeout = seconds;465}466467/**468* Gets the maximum time in seconds that a driver can wait469* when attempting to log in to a database.470*471* @return the driver login time limit in seconds472* @see #setLoginTimeout473*/474public static int getLoginTimeout() {475return (loginTimeout);476}477478/**479* Sets the logging/tracing PrintStream that is used480* by the <code>DriverManager</code>481* and all drivers.482*<P>483* In the Java 2 SDK, Standard Edition, version 1.3 release, this method checks484* to see that there is an <code>SQLPermission</code> object before setting485* the logging stream. If a <code>SecurityManager</code> exists and its486* <code>checkPermission</code> method denies setting the log writer, this487* method throws a <code>java.lang.SecurityException</code>.488*489* @param out the new logging/tracing PrintStream; to disable, set to <code>null</code>490* @deprecated Use {@code setLogWriter}491* @throws SecurityException if a security manager exists and its492* <code>checkPermission</code> method denies setting the log stream493*494* @see SecurityManager#checkPermission495* @see #getLogStream496*/497@Deprecated498public static void setLogStream(java.io.PrintStream out) {499500SecurityManager sec = System.getSecurityManager();501if (sec != null) {502sec.checkPermission(SET_LOG_PERMISSION);503}504505logStream = out;506if ( out != null )507logWriter = new java.io.PrintWriter(out);508else509logWriter = null;510}511512/**513* Retrieves the logging/tracing PrintStream that is used by the <code>DriverManager</code>514* and all drivers.515*516* @return the logging/tracing PrintStream; if disabled, is <code>null</code>517* @deprecated Use {@code getLogWriter}518* @see #setLogStream519*/520@Deprecated521public static java.io.PrintStream getLogStream() {522return logStream;523}524525/**526* Prints a message to the current JDBC log stream.527*528* @param message a log or tracing message529*/530public static void println(String message) {531synchronized (logSync) {532if (logWriter != null) {533logWriter.println(message);534535// automatic flushing is never enabled, so we must do it ourselves536logWriter.flush();537}538}539}540541//------------------------------------------------------------------------542543// Indicates whether the class object that would be created if the code calling544// DriverManager is accessible.545private static boolean isDriverAllowed(Driver driver, Class<?> caller) {546ClassLoader callerCL = caller != null ? caller.getClassLoader() : null;547return isDriverAllowed(driver, callerCL);548}549550private static boolean isDriverAllowed(Driver driver, ClassLoader classLoader) {551boolean result = false;552if(driver != null) {553Class<?> aClass = null;554try {555aClass = Class.forName(driver.getClass().getName(), true, classLoader);556} catch (Exception ex) {557result = false;558}559560result = ( aClass == driver.getClass() ) ? true : false;561}562563return result;564}565566private static void loadInitialDrivers() {567String drivers;568try {569drivers = AccessController.doPrivileged(new PrivilegedAction<String>() {570public String run() {571return System.getProperty("jdbc.drivers");572}573});574} catch (Exception ex) {575drivers = null;576}577// If the driver is packaged as a Service Provider, load it.578// Get all the drivers through the classloader579// exposed as a java.sql.Driver.class service.580// ServiceLoader.load() replaces the sun.misc.Providers()581582AccessController.doPrivileged(new PrivilegedAction<Void>() {583public Void run() {584585ServiceLoader<Driver> loadedDrivers = ServiceLoader.load(Driver.class);586Iterator<Driver> driversIterator = loadedDrivers.iterator();587588/* Load these drivers, so that they can be instantiated.589* It may be the case that the driver class may not be there590* i.e. there may be a packaged driver with the service class591* as implementation of java.sql.Driver but the actual class592* may be missing. In that case a java.util.ServiceConfigurationError593* will be thrown at runtime by the VM trying to locate594* and load the service.595*596* Adding a try catch block to catch those runtime errors597* if driver not available in classpath but it's598* packaged as service and that service is there in classpath.599*/600try{601while(driversIterator.hasNext()) {602driversIterator.next();603}604} catch(Throwable t) {605// Do nothing606}607return null;608}609});610611println("DriverManager.initialize: jdbc.drivers = " + drivers);612613if (drivers == null || drivers.equals("")) {614return;615}616String[] driversList = drivers.split(":");617println("number of Drivers:" + driversList.length);618for (String aDriver : driversList) {619try {620println("DriverManager.Initialize: loading " + aDriver);621Class.forName(aDriver, true,622ClassLoader.getSystemClassLoader());623} catch (Exception ex) {624println("DriverManager.Initialize: load failed: " + ex);625}626}627}628629630// Worker method called by the public getConnection() methods.631private static Connection getConnection(632String url, java.util.Properties info, Class<?> caller) throws SQLException {633/*634* When callerCl is null, we should check the application's635* (which is invoking this class indirectly)636* classloader, so that the JDBC driver class outside rt.jar637* can be loaded from here.638*/639ClassLoader callerCL = caller != null ? caller.getClassLoader() : null;640synchronized(DriverManager.class) {641// synchronize loading of the correct classloader.642if (callerCL == null) {643callerCL = Thread.currentThread().getContextClassLoader();644}645}646647if(url == null) {648throw new SQLException("The url cannot be null", "08001");649}650651println("DriverManager.getConnection(\"" + url + "\")");652653// Walk through the loaded registeredDrivers attempting to make a connection.654// Remember the first exception that gets raised so we can reraise it.655SQLException reason = null;656657for(DriverInfo aDriver : registeredDrivers) {658// If the caller does not have permission to load the driver then659// skip it.660if(isDriverAllowed(aDriver.driver, callerCL)) {661try {662println(" trying " + aDriver.driver.getClass().getName());663Connection con = aDriver.driver.connect(url, info);664if (con != null) {665// Success!666println("getConnection returning " + aDriver.driver.getClass().getName());667return (con);668}669} catch (SQLException ex) {670if (reason == null) {671reason = ex;672}673}674675} else {676println(" skipping: " + aDriver.getClass().getName());677}678679}680681// if we got here nobody could connect.682if (reason != null) {683println("getConnection failed: " + reason);684throw reason;685}686687println("getConnection: no suitable driver found for "+ url);688throw new SQLException("No suitable driver found for "+ url, "08001");689}690691692}693694/*695* Wrapper class for registered Drivers in order to not expose Driver.equals()696* to avoid the capture of the Driver it being compared to as it might not697* normally have access.698*/699class DriverInfo {700701final Driver driver;702DriverAction da;703DriverInfo(Driver driver, DriverAction action) {704this.driver = driver;705da = action;706}707708@Override709public boolean equals(Object other) {710return (other instanceof DriverInfo)711&& this.driver == ((DriverInfo) other).driver;712}713714@Override715public int hashCode() {716return driver.hashCode();717}718719@Override720public String toString() {721return ("driver[className=" + driver + "]");722}723724DriverAction action() {725return da;726}727}728729730