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