src/java.sql/share/classes/java/sql/DriverManager.java
changeset 47216 71c04702a3d5
parent 45885 562fed91cd84
child 51972 67619141f027
equal deleted inserted replaced
47215:4ebc2e2fb97c 47216:71c04702a3d5
       
     1 /*
       
     2  * Copyright (c) 1996, 2017, Oracle and/or its affiliates. All rights reserved.
       
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     4  *
       
     5  * This code is free software; you can redistribute it and/or modify it
       
     6  * under the terms of the GNU General Public License version 2 only, as
       
     7  * published by the Free Software Foundation.  Oracle designates this
       
     8  * particular file as subject to the "Classpath" exception as provided
       
     9  * by Oracle in the LICENSE file that accompanied this code.
       
    10  *
       
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    14  * version 2 for more details (a copy is included in the LICENSE file that
       
    15  * accompanied this code).
       
    16  *
       
    17  * You should have received a copy of the GNU General Public License version
       
    18  * 2 along with this work; if not, write to the Free Software Foundation,
       
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    20  *
       
    21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
       
    22  * or visit www.oracle.com if you need additional information or have any
       
    23  * questions.
       
    24  */
       
    25 
       
    26 package java.sql;
       
    27 
       
    28 import java.util.ArrayList;
       
    29 import java.util.Collections;
       
    30 import java.util.Enumeration;
       
    31 import java.util.Iterator;
       
    32 import java.util.List;
       
    33 import java.util.ServiceLoader;
       
    34 import java.security.AccessController;
       
    35 import java.security.PrivilegedAction;
       
    36 import java.util.concurrent.CopyOnWriteArrayList;
       
    37 import java.util.stream.Stream;
       
    38 
       
    39 import jdk.internal.reflect.CallerSensitive;
       
    40 import jdk.internal.reflect.Reflection;
       
    41 
       
    42 
       
    43 /**
       
    44  * The basic service for managing a set of JDBC drivers.
       
    45  * <p>
       
    46  * <strong>NOTE:</strong> The {@link javax.sql.DataSource} interface, provides
       
    47  * another way to connect to a data source.
       
    48  * The use of a {@code DataSource} object is the preferred means of
       
    49  * connecting to a data source.
       
    50  * <P>
       
    51  * As part of its initialization, the {@code DriverManager} class will
       
    52  * attempt to load available JDBC drivers by using:
       
    53  * <ul>
       
    54  * <li>The {@code jdbc.drivers} system property which contains a
       
    55  * colon separated list of fully qualified class names of JDBC drivers. Each
       
    56  * driver is loaded using the {@linkplain ClassLoader#getSystemClassLoader
       
    57  * system class loader}:
       
    58  * <ul>
       
    59  * <li>{@code jdbc.drivers=foo.bah.Driver:wombat.sql.Driver:bad.taste.ourDriver}
       
    60  * </ul>
       
    61  *
       
    62  * <li>Service providers of the {@code java.sql.Driver} class, that are loaded
       
    63  * via the {@linkplain ServiceLoader#load service-provider loading} mechanism.
       
    64  *</ul>
       
    65  *
       
    66  * @implNote
       
    67  * {@code DriverManager} initialization is done lazily and looks up service
       
    68  * providers using the thread context class loader.  The drivers loaded and
       
    69  * available to an application will depend on the thread context class loader of
       
    70  * the thread that triggers driver initialization by {@code DriverManager}.
       
    71  *
       
    72  * <P>When the method {@code getConnection} is called,
       
    73  * the {@code DriverManager} will attempt to
       
    74  * locate a suitable driver from amongst those loaded at
       
    75  * initialization and those loaded explicitly using the same class loader
       
    76  * as the current application.
       
    77  *
       
    78  * @see Driver
       
    79  * @see Connection
       
    80  * @since 1.1
       
    81  */
       
    82 public class DriverManager {
       
    83 
       
    84 
       
    85     // List of registered JDBC drivers
       
    86     private final static CopyOnWriteArrayList<DriverInfo> registeredDrivers = new CopyOnWriteArrayList<>();
       
    87     private static volatile int loginTimeout = 0;
       
    88     private static volatile java.io.PrintWriter logWriter = null;
       
    89     private static volatile java.io.PrintStream logStream = null;
       
    90     // Used in println() to synchronize logWriter
       
    91     private final static Object logSync = new Object();
       
    92     // Used in ensureDriversInitialized() to synchronize driversInitialized
       
    93     private final static Object lockForInitDrivers = new Object();
       
    94     private static volatile boolean driversInitialized;
       
    95     private static final String JDBC_DRIVERS_PROPERTY = "jdbc.drivers";
       
    96 
       
    97     /* Prevent the DriverManager class from being instantiated. */
       
    98     private DriverManager(){}
       
    99 
       
   100     /**
       
   101      * The <code>SQLPermission</code> constant that allows the
       
   102      * setting of the logging stream.
       
   103      * @since 1.3
       
   104      */
       
   105     final static SQLPermission SET_LOG_PERMISSION =
       
   106         new SQLPermission("setLog");
       
   107 
       
   108     /**
       
   109      * The {@code SQLPermission} constant that allows the
       
   110      * un-register a registered JDBC driver.
       
   111      * @since 1.8
       
   112      */
       
   113     final static SQLPermission DEREGISTER_DRIVER_PERMISSION =
       
   114         new SQLPermission("deregisterDriver");
       
   115 
       
   116     //--------------------------JDBC 2.0-----------------------------
       
   117 
       
   118     /**
       
   119      * Retrieves the log writer.
       
   120      *
       
   121      * The <code>getLogWriter</code> and <code>setLogWriter</code>
       
   122      * methods should be used instead
       
   123      * of the <code>get/setlogStream</code> methods, which are deprecated.
       
   124      * @return a <code>java.io.PrintWriter</code> object
       
   125      * @see #setLogWriter
       
   126      * @since 1.2
       
   127      */
       
   128     public static java.io.PrintWriter getLogWriter() {
       
   129             return logWriter;
       
   130     }
       
   131 
       
   132     /**
       
   133      * Sets the logging/tracing <code>PrintWriter</code> object
       
   134      * that is used by the <code>DriverManager</code> and all drivers.
       
   135      *<P>
       
   136      * If a security manager exists, its {@code checkPermission}
       
   137      * method is first called with a {@code SQLPermission("setLog")}
       
   138      * permission to check that the caller is allowed to call {@code setLogWriter}.
       
   139      *
       
   140      * @param out the new logging/tracing <code>PrintStream</code> object;
       
   141      *      <code>null</code> to disable logging and tracing
       
   142      * @throws SecurityException if a security manager exists and its
       
   143      * {@code checkPermission} method denies permission to set the log writer.
       
   144      * @see SecurityManager#checkPermission
       
   145      * @see #getLogWriter
       
   146      * @since 1.2
       
   147      */
       
   148     public static void setLogWriter(java.io.PrintWriter out) {
       
   149 
       
   150         SecurityManager sec = System.getSecurityManager();
       
   151         if (sec != null) {
       
   152             sec.checkPermission(SET_LOG_PERMISSION);
       
   153         }
       
   154             logStream = null;
       
   155             logWriter = out;
       
   156     }
       
   157 
       
   158 
       
   159     //---------------------------------------------------------------
       
   160 
       
   161     /**
       
   162      * Attempts to establish a connection to the given database URL.
       
   163      * The <code>DriverManager</code> attempts to select an appropriate driver from
       
   164      * the set of registered JDBC drivers.
       
   165      *<p>
       
   166      * <B>Note:</B> If a property is specified as part of the {@code url} and
       
   167      * is also specified in the {@code Properties} object, it is
       
   168      * implementation-defined as to which value will take precedence.
       
   169      * For maximum portability, an application should only specify a
       
   170      * property once.
       
   171      *
       
   172      * @param url a database url of the form
       
   173      * <code> jdbc:<em>subprotocol</em>:<em>subname</em></code>
       
   174      * @param info a list of arbitrary string tag/value pairs as
       
   175      * connection arguments; normally at least a "user" and
       
   176      * "password" property should be included
       
   177      * @return a Connection to the URL
       
   178      * @exception SQLException if a database access error occurs or the url is
       
   179      * {@code null}
       
   180      * @throws SQLTimeoutException  when the driver has determined that the
       
   181      * timeout value specified by the {@code setLoginTimeout} method
       
   182      * has been exceeded and has at least tried to cancel the
       
   183      * current database connection attempt
       
   184      */
       
   185     @CallerSensitive
       
   186     public static Connection getConnection(String url,
       
   187         java.util.Properties info) throws SQLException {
       
   188 
       
   189         return (getConnection(url, info, Reflection.getCallerClass()));
       
   190     }
       
   191 
       
   192     /**
       
   193      * Attempts to establish a connection to the given database URL.
       
   194      * The <code>DriverManager</code> attempts to select an appropriate driver from
       
   195      * the set of registered JDBC drivers.
       
   196      *<p>
       
   197      * <B>Note:</B> If the {@code user} or {@code password} property are
       
   198      * also specified as part of the {@code url}, it is
       
   199      * implementation-defined as to which value will take precedence.
       
   200      * For maximum portability, an application should only specify a
       
   201      * property once.
       
   202      *
       
   203      * @param url a database url of the form
       
   204      * <code>jdbc:<em>subprotocol</em>:<em>subname</em></code>
       
   205      * @param user the database user on whose behalf the connection is being
       
   206      *   made
       
   207      * @param password the user's password
       
   208      * @return a connection to the URL
       
   209      * @exception SQLException if a database access error occurs or the url is
       
   210      * {@code null}
       
   211      * @throws SQLTimeoutException  when the driver has determined that the
       
   212      * timeout value specified by the {@code setLoginTimeout} method
       
   213      * has been exceeded and has at least tried to cancel the
       
   214      * current database connection attempt
       
   215      */
       
   216     @CallerSensitive
       
   217     public static Connection getConnection(String url,
       
   218         String user, String password) throws SQLException {
       
   219         java.util.Properties info = new java.util.Properties();
       
   220 
       
   221         if (user != null) {
       
   222             info.put("user", user);
       
   223         }
       
   224         if (password != null) {
       
   225             info.put("password", password);
       
   226         }
       
   227 
       
   228         return (getConnection(url, info, Reflection.getCallerClass()));
       
   229     }
       
   230 
       
   231     /**
       
   232      * Attempts to establish a connection to the given database URL.
       
   233      * The <code>DriverManager</code> attempts to select an appropriate driver from
       
   234      * the set of registered JDBC drivers.
       
   235      *
       
   236      * @param url a database url of the form
       
   237      *  <code> jdbc:<em>subprotocol</em>:<em>subname</em></code>
       
   238      * @return a connection to the URL
       
   239      * @exception SQLException if a database access error occurs or the url is
       
   240      * {@code null}
       
   241      * @throws SQLTimeoutException  when the driver has determined that the
       
   242      * timeout value specified by the {@code setLoginTimeout} method
       
   243      * has been exceeded and has at least tried to cancel the
       
   244      * current database connection attempt
       
   245      */
       
   246     @CallerSensitive
       
   247     public static Connection getConnection(String url)
       
   248         throws SQLException {
       
   249 
       
   250         java.util.Properties info = new java.util.Properties();
       
   251         return (getConnection(url, info, Reflection.getCallerClass()));
       
   252     }
       
   253 
       
   254     /**
       
   255      * Attempts to locate a driver that understands the given URL.
       
   256      * The <code>DriverManager</code> attempts to select an appropriate driver from
       
   257      * the set of registered JDBC drivers.
       
   258      *
       
   259      * @param url a database URL of the form
       
   260      *     <code>jdbc:<em>subprotocol</em>:<em>subname</em></code>
       
   261      * @return a <code>Driver</code> object representing a driver
       
   262      * that can connect to the given URL
       
   263      * @exception SQLException if a database access error occurs
       
   264      */
       
   265     @CallerSensitive
       
   266     public static Driver getDriver(String url)
       
   267         throws SQLException {
       
   268 
       
   269         println("DriverManager.getDriver(\"" + url + "\")");
       
   270 
       
   271         ensureDriversInitialized();
       
   272 
       
   273         Class<?> callerClass = Reflection.getCallerClass();
       
   274 
       
   275         // Walk through the loaded registeredDrivers attempting to locate someone
       
   276         // who understands the given URL.
       
   277         for (DriverInfo aDriver : registeredDrivers) {
       
   278             // If the caller does not have permission to load the driver then
       
   279             // skip it.
       
   280             if (isDriverAllowed(aDriver.driver, callerClass)) {
       
   281                 try {
       
   282                     if (aDriver.driver.acceptsURL(url)) {
       
   283                         // Success!
       
   284                         println("getDriver returning " + aDriver.driver.getClass().getName());
       
   285                     return (aDriver.driver);
       
   286                     }
       
   287 
       
   288                 } catch(SQLException sqe) {
       
   289                     // Drop through and try the next driver.
       
   290                 }
       
   291             } else {
       
   292                 println("    skipping: " + aDriver.driver.getClass().getName());
       
   293             }
       
   294 
       
   295         }
       
   296 
       
   297         println("getDriver: no suitable driver");
       
   298         throw new SQLException("No suitable driver", "08001");
       
   299     }
       
   300 
       
   301 
       
   302     /**
       
   303      * Registers the given driver with the {@code DriverManager}.
       
   304      * A newly-loaded driver class should call
       
   305      * the method {@code registerDriver} to make itself
       
   306      * known to the {@code DriverManager}. If the driver is currently
       
   307      * registered, no action is taken.
       
   308      *
       
   309      * @param driver the new JDBC Driver that is to be registered with the
       
   310      *               {@code DriverManager}
       
   311      * @exception SQLException if a database access error occurs
       
   312      * @exception NullPointerException if {@code driver} is null
       
   313      */
       
   314     public static void registerDriver(java.sql.Driver driver)
       
   315         throws SQLException {
       
   316 
       
   317         registerDriver(driver, null);
       
   318     }
       
   319 
       
   320     /**
       
   321      * Registers the given driver with the {@code DriverManager}.
       
   322      * A newly-loaded driver class should call
       
   323      * the method {@code registerDriver} to make itself
       
   324      * known to the {@code DriverManager}. If the driver is currently
       
   325      * registered, no action is taken.
       
   326      *
       
   327      * @param driver the new JDBC Driver that is to be registered with the
       
   328      *               {@code DriverManager}
       
   329      * @param da     the {@code DriverAction} implementation to be used when
       
   330      *               {@code DriverManager#deregisterDriver} is called
       
   331      * @exception SQLException if a database access error occurs
       
   332      * @exception NullPointerException if {@code driver} is null
       
   333      * @since 1.8
       
   334      */
       
   335     public static void registerDriver(java.sql.Driver driver,
       
   336             DriverAction da)
       
   337         throws SQLException {
       
   338 
       
   339         /* Register the driver if it has not already been added to our list */
       
   340         if (driver != null) {
       
   341             registeredDrivers.addIfAbsent(new DriverInfo(driver, da));
       
   342         } else {
       
   343             // This is for compatibility with the original DriverManager
       
   344             throw new NullPointerException();
       
   345         }
       
   346 
       
   347         println("registerDriver: " + driver);
       
   348 
       
   349     }
       
   350 
       
   351     /**
       
   352      * Removes the specified driver from the {@code DriverManager}'s list of
       
   353      * registered drivers.
       
   354      * <p>
       
   355      * If a {@code null} value is specified for the driver to be removed, then no
       
   356      * action is taken.
       
   357      * <p>
       
   358      * If a security manager exists, its {@code checkPermission}
       
   359      * method is first called with a {@code SQLPermission("deregisterDriver")}
       
   360      * permission to check that the caller is allowed to deregister a JDBC Driver.
       
   361      * <p>
       
   362      * If the specified driver is not found in the list of registered drivers,
       
   363      * then no action is taken.  If the driver was found, it will be removed
       
   364      * from the list of registered drivers.
       
   365      * <p>
       
   366      * If a {@code DriverAction} instance was specified when the JDBC driver was
       
   367      * registered, its deregister method will be called
       
   368      * prior to the driver being removed from the list of registered drivers.
       
   369      *
       
   370      * @param driver the JDBC Driver to remove
       
   371      * @exception SQLException if a database access error occurs
       
   372      * @throws SecurityException if a security manager exists and its
       
   373      * {@code checkPermission} method denies permission to deregister a driver.
       
   374      *
       
   375      * @see SecurityManager#checkPermission
       
   376      */
       
   377     @CallerSensitive
       
   378     public static void deregisterDriver(Driver driver) throws SQLException {
       
   379         if (driver == null) {
       
   380             return;
       
   381         }
       
   382 
       
   383         SecurityManager sec = System.getSecurityManager();
       
   384         if (sec != null) {
       
   385             sec.checkPermission(DEREGISTER_DRIVER_PERMISSION);
       
   386         }
       
   387 
       
   388         println("DriverManager.deregisterDriver: " + driver);
       
   389 
       
   390         DriverInfo aDriver = new DriverInfo(driver, null);
       
   391         synchronized (lockForInitDrivers) {
       
   392             if (registeredDrivers.contains(aDriver)) {
       
   393                 if (isDriverAllowed(driver, Reflection.getCallerClass())) {
       
   394                     DriverInfo di = registeredDrivers.get(registeredDrivers.indexOf(aDriver));
       
   395                      // If a DriverAction was specified, Call it to notify the
       
   396                      // driver that it has been deregistered
       
   397                      if (di.action() != null) {
       
   398                          di.action().deregister();
       
   399                      }
       
   400                      registeredDrivers.remove(aDriver);
       
   401                 } else {
       
   402                     // If the caller does not have permission to load the driver then
       
   403                     // throw a SecurityException.
       
   404                     throw new SecurityException();
       
   405                 }
       
   406             } else {
       
   407                 println("    couldn't find driver to unload");
       
   408             }
       
   409         }
       
   410     }
       
   411 
       
   412     /**
       
   413      * Retrieves an Enumeration with all of the currently loaded JDBC drivers
       
   414      * to which the current caller has access.
       
   415      *
       
   416      * <P><B>Note:</B> The classname of a driver can be found using
       
   417      * <CODE>d.getClass().getName()</CODE>
       
   418      *
       
   419      * @return the list of JDBC Drivers loaded by the caller's class loader
       
   420      * @see #drivers()
       
   421      */
       
   422     @CallerSensitive
       
   423     public static Enumeration<Driver> getDrivers() {
       
   424         ensureDriversInitialized();
       
   425 
       
   426         return Collections.enumeration(getDrivers(Reflection.getCallerClass()));
       
   427     }
       
   428 
       
   429     /**
       
   430      * Retrieves a Stream with all of the currently loaded JDBC drivers
       
   431      * to which the current caller has access.
       
   432      *
       
   433      * @return the stream of JDBC Drivers loaded by the caller's class loader
       
   434      * @since 9
       
   435      */
       
   436     @CallerSensitive
       
   437     public static Stream<Driver> drivers() {
       
   438         ensureDriversInitialized();
       
   439 
       
   440         return getDrivers(Reflection.getCallerClass()).stream();
       
   441     }
       
   442 
       
   443     private static List<Driver> getDrivers(Class<?> callerClass) {
       
   444         List<Driver> result = new ArrayList<>();
       
   445         // Walk through the loaded registeredDrivers.
       
   446         for (DriverInfo aDriver : registeredDrivers) {
       
   447             // If the caller does not have permission to load the driver then
       
   448             // skip it.
       
   449             if (isDriverAllowed(aDriver.driver, callerClass)) {
       
   450                 result.add(aDriver.driver);
       
   451             } else {
       
   452                 println("    skipping: " + aDriver.getClass().getName());
       
   453             }
       
   454         }
       
   455         return result;
       
   456     }
       
   457 
       
   458     /**
       
   459      * Sets the maximum time in seconds that a driver will wait
       
   460      * while attempting to connect to a database once the driver has
       
   461      * been identified.
       
   462      *
       
   463      * @param seconds the login time limit in seconds; zero means there is no limit
       
   464      * @see #getLoginTimeout
       
   465      */
       
   466     public static void setLoginTimeout(int seconds) {
       
   467         loginTimeout = seconds;
       
   468     }
       
   469 
       
   470     /**
       
   471      * Gets the maximum time in seconds that a driver can wait
       
   472      * when attempting to log in to a database.
       
   473      *
       
   474      * @return the driver login time limit in seconds
       
   475      * @see #setLoginTimeout
       
   476      */
       
   477     public static int getLoginTimeout() {
       
   478         return (loginTimeout);
       
   479     }
       
   480 
       
   481     /**
       
   482      * Sets the logging/tracing PrintStream that is used
       
   483      * by the <code>DriverManager</code>
       
   484      * and all drivers.
       
   485      *<P>
       
   486      * If a security manager exists, its {@code checkPermission}
       
   487      * method is first called with a {@code SQLPermission("setLog")}
       
   488      * permission to check that the caller is allowed to call {@code setLogStream}.
       
   489      *
       
   490      * @param out the new logging/tracing PrintStream; to disable, set to <code>null</code>
       
   491      * @deprecated Use {@code setLogWriter}
       
   492      * @throws SecurityException if a security manager exists and its
       
   493      * {@code checkPermission} method denies permission to set the log stream.
       
   494      * @see SecurityManager#checkPermission
       
   495      * @see #getLogStream
       
   496      */
       
   497     @Deprecated(since="1.2")
       
   498     public static void setLogStream(java.io.PrintStream out) {
       
   499 
       
   500         SecurityManager sec = System.getSecurityManager();
       
   501         if (sec != null) {
       
   502             sec.checkPermission(SET_LOG_PERMISSION);
       
   503         }
       
   504 
       
   505         logStream = out;
       
   506         if ( out != null )
       
   507             logWriter = new java.io.PrintWriter(out);
       
   508         else
       
   509             logWriter = null;
       
   510     }
       
   511 
       
   512     /**
       
   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 #setLogStream
       
   519      */
       
   520     @Deprecated(since="1.2")
       
   521     public static java.io.PrintStream getLogStream() {
       
   522         return logStream;
       
   523     }
       
   524 
       
   525     /**
       
   526      * Prints a message to the current JDBC log stream.
       
   527      *
       
   528      * @param message a log or tracing message
       
   529      */
       
   530     public static void println(String message) {
       
   531         synchronized (logSync) {
       
   532             if (logWriter != null) {
       
   533                 logWriter.println(message);
       
   534 
       
   535                 // automatic flushing is never enabled, so we must do it ourselves
       
   536                 logWriter.flush();
       
   537             }
       
   538         }
       
   539     }
       
   540 
       
   541     //------------------------------------------------------------------------
       
   542 
       
   543     // Indicates whether the class object that would be created if the code calling
       
   544     // DriverManager is accessible.
       
   545     private static boolean isDriverAllowed(Driver driver, Class<?> caller) {
       
   546         ClassLoader callerCL = caller != null ? caller.getClassLoader() : null;
       
   547         return isDriverAllowed(driver, callerCL);
       
   548     }
       
   549 
       
   550     private static boolean isDriverAllowed(Driver driver, ClassLoader classLoader) {
       
   551         boolean result = false;
       
   552         if (driver != null) {
       
   553             Class<?> aClass = null;
       
   554             try {
       
   555                 aClass =  Class.forName(driver.getClass().getName(), true, classLoader);
       
   556             } catch (Exception ex) {
       
   557                 result = false;
       
   558             }
       
   559 
       
   560              result = ( aClass == driver.getClass() ) ? true : false;
       
   561         }
       
   562 
       
   563         return result;
       
   564     }
       
   565 
       
   566     /*
       
   567      * Load the initial JDBC drivers by checking the System property
       
   568      * jdbc.drivers and then use the {@code ServiceLoader} mechanism
       
   569      */
       
   570     private static void ensureDriversInitialized() {
       
   571         if (driversInitialized) {
       
   572             return;
       
   573         }
       
   574 
       
   575         synchronized (lockForInitDrivers) {
       
   576             if (driversInitialized) {
       
   577                 return;
       
   578             }
       
   579             String drivers;
       
   580             try {
       
   581                 drivers = AccessController.doPrivileged(new PrivilegedAction<String>() {
       
   582                     public String run() {
       
   583                         return System.getProperty(JDBC_DRIVERS_PROPERTY);
       
   584                     }
       
   585                 });
       
   586             } catch (Exception ex) {
       
   587                 drivers = null;
       
   588             }
       
   589             // If the driver is packaged as a Service Provider, load it.
       
   590             // Get all the drivers through the classloader
       
   591             // exposed as a java.sql.Driver.class service.
       
   592             // ServiceLoader.load() replaces the sun.misc.Providers()
       
   593 
       
   594             AccessController.doPrivileged(new PrivilegedAction<Void>() {
       
   595                 public Void run() {
       
   596 
       
   597                     ServiceLoader<Driver> loadedDrivers = ServiceLoader.load(Driver.class);
       
   598                     Iterator<Driver> driversIterator = loadedDrivers.iterator();
       
   599 
       
   600                     /* Load these drivers, so that they can be instantiated.
       
   601                      * It may be the case that the driver class may not be there
       
   602                      * i.e. there may be a packaged driver with the service class
       
   603                      * as implementation of java.sql.Driver but the actual class
       
   604                      * may be missing. In that case a java.util.ServiceConfigurationError
       
   605                      * will be thrown at runtime by the VM trying to locate
       
   606                      * and load the service.
       
   607                      *
       
   608                      * Adding a try catch block to catch those runtime errors
       
   609                      * if driver not available in classpath but it's
       
   610                      * packaged as service and that service is there in classpath.
       
   611                      */
       
   612                     try {
       
   613                         while (driversIterator.hasNext()) {
       
   614                             driversIterator.next();
       
   615                         }
       
   616                     } catch (Throwable t) {
       
   617                         // Do nothing
       
   618                     }
       
   619                     return null;
       
   620                 }
       
   621             });
       
   622 
       
   623             println("DriverManager.initialize: jdbc.drivers = " + drivers);
       
   624 
       
   625             if (drivers != null && !drivers.equals("")) {
       
   626                 String[] driversList = drivers.split(":");
       
   627                 println("number of Drivers:" + driversList.length);
       
   628                 for (String aDriver : driversList) {
       
   629                     try {
       
   630                         println("DriverManager.Initialize: loading " + aDriver);
       
   631                         Class.forName(aDriver, true,
       
   632                                 ClassLoader.getSystemClassLoader());
       
   633                     } catch (Exception ex) {
       
   634                         println("DriverManager.Initialize: load failed: " + ex);
       
   635                     }
       
   636                 }
       
   637             }
       
   638 
       
   639             driversInitialized = true;
       
   640             println("JDBC DriverManager initialized");
       
   641         }
       
   642     }
       
   643 
       
   644 
       
   645     //  Worker method called by the public getConnection() methods.
       
   646     private static Connection getConnection(
       
   647         String url, java.util.Properties info, Class<?> caller) throws SQLException {
       
   648         /*
       
   649          * When callerCl is null, we should check the application's
       
   650          * (which is invoking this class indirectly)
       
   651          * classloader, so that the JDBC driver class outside rt.jar
       
   652          * can be loaded from here.
       
   653          */
       
   654         ClassLoader callerCL = caller != null ? caller.getClassLoader() : null;
       
   655         if (callerCL == null) {
       
   656             callerCL = Thread.currentThread().getContextClassLoader();
       
   657         }
       
   658 
       
   659         if (url == null) {
       
   660             throw new SQLException("The url cannot be null", "08001");
       
   661         }
       
   662 
       
   663         println("DriverManager.getConnection(\"" + url + "\")");
       
   664 
       
   665         ensureDriversInitialized();
       
   666 
       
   667         // Walk through the loaded registeredDrivers attempting to make a connection.
       
   668         // Remember the first exception that gets raised so we can reraise it.
       
   669         SQLException reason = null;
       
   670 
       
   671         for (DriverInfo aDriver : registeredDrivers) {
       
   672             // If the caller does not have permission to load the driver then
       
   673             // skip it.
       
   674             if (isDriverAllowed(aDriver.driver, callerCL)) {
       
   675                 try {
       
   676                     println("    trying " + aDriver.driver.getClass().getName());
       
   677                     Connection con = aDriver.driver.connect(url, info);
       
   678                     if (con != null) {
       
   679                         // Success!
       
   680                         println("getConnection returning " + aDriver.driver.getClass().getName());
       
   681                         return (con);
       
   682                     }
       
   683                 } catch (SQLException ex) {
       
   684                     if (reason == null) {
       
   685                         reason = ex;
       
   686                     }
       
   687                 }
       
   688 
       
   689             } else {
       
   690                 println("    skipping: " + aDriver.getClass().getName());
       
   691             }
       
   692 
       
   693         }
       
   694 
       
   695         // if we got here nobody could connect.
       
   696         if (reason != null)    {
       
   697             println("getConnection failed: " + reason);
       
   698             throw reason;
       
   699         }
       
   700 
       
   701         println("getConnection: no suitable driver found for "+ url);
       
   702         throw new SQLException("No suitable driver found for "+ url, "08001");
       
   703     }
       
   704 
       
   705 
       
   706 }
       
   707 
       
   708 /*
       
   709  * Wrapper class for registered Drivers in order to not expose Driver.equals()
       
   710  * to avoid the capture of the Driver it being compared to as it might not
       
   711  * normally have access.
       
   712  */
       
   713 class DriverInfo {
       
   714 
       
   715     final Driver driver;
       
   716     DriverAction da;
       
   717     DriverInfo(Driver driver, DriverAction action) {
       
   718         this.driver = driver;
       
   719         da = action;
       
   720     }
       
   721 
       
   722     @Override
       
   723     public boolean equals(Object other) {
       
   724         return (other instanceof DriverInfo)
       
   725                 && this.driver == ((DriverInfo) other).driver;
       
   726     }
       
   727 
       
   728     @Override
       
   729     public int hashCode() {
       
   730         return driver.hashCode();
       
   731     }
       
   732 
       
   733     @Override
       
   734     public String toString() {
       
   735         return ("driver[className="  + driver + "]");
       
   736     }
       
   737 
       
   738     DriverAction action() {
       
   739         return da;
       
   740     }
       
   741 }