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