1 /*
   2  * Copyright (c) 1996, 2015, 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 sun.reflect.CallerSensitive;
  40 import sun.reflect.Reflection;
  41 
  42 
  43 /**
  44  * <P>The basic service for managing a set of JDBC drivers.<br>
  45  * <B>NOTE:</B> The {@link javax.sql.DataSource} interface, new in the
  46  * JDBC 2.0 API, provides another way to connect to a data source.
  47  * The use of a <code>DataSource</code> object is the preferred means of
  48  * connecting to a data source.
  49  *
  50  * <P>As part of its initialization, the <code>DriverManager</code> class will
  51  * attempt to load the driver classes referenced in the "jdbc.drivers"
  52  * system property. This allows a user to customize the JDBC Drivers
  53  * used by their applications. For example in your
  54  * ~/.hotjava/properties file you might specify:
  55  * <pre>
  56  * <CODE>jdbc.drivers=foo.bah.Driver:wombat.sql.Driver:bad.taste.ourDriver</CODE>
  57  * </pre>
  58  *<P> The <code>DriverManager</code> methods <code>getConnection</code> and
  59  * <code>getDrivers</code> have been enhanced to support the Java Standard Edition
  60  * <a href="../../../technotes/guides/jar/jar.html#Service%20Provider">Service Provider</a> mechanism. JDBC 4.0 Drivers must
  61  * include the file <code>META-INF/services/java.sql.Driver</code>. This file contains the name of the JDBC drivers
  62  * implementation of <code>java.sql.Driver</code>.  For example, to load the <code>my.sql.Driver</code> class,
  63  * the <code>META-INF/services/java.sql.Driver</code> file would contain the entry:
  64  * <pre>
  65  * <code>my.sql.Driver</code>
  66  * </pre>
  67  *
  68  * <P>Applications no longer need to explicitly load JDBC drivers using <code>Class.forName()</code>. Existing programs
  69  * which currently load JDBC drivers using <code>Class.forName()</code> will continue to work without
  70  * modification.
  71  *
  72  * <P>When the method <code>getConnection</code> is called,
  73  * the <code>DriverManager</code> will attempt to
  74  * locate a suitable driver from amongst those loaded at
  75  * initialization and those loaded explicitly using the same classloader
  76  * as the current applet or application.
  77  *
  78  * <P>
  79  * Starting with the Java 2 SDK, Standard Edition, version 1.3, a
  80  * logging stream can be set only if the proper
  81  * permission has been granted.  Normally this will be done with
  82  * the tool PolicyTool, which can be used to grant <code>permission
  83  * java.sql.SQLPermission "setLog"</code>.
  84  * @see Driver
  85  * @see Connection
  86  */
  87 public class DriverManager {
  88 
  89 
  90     // List of registered JDBC drivers
  91     private final static CopyOnWriteArrayList<DriverInfo> registeredDrivers = new CopyOnWriteArrayList<>();
  92     private static volatile int loginTimeout = 0;
  93     private static volatile java.io.PrintWriter logWriter = null;
  94     private static volatile java.io.PrintStream logStream = null;
  95     // Used in println() to synchronize logWriter
  96     private final static Object logSync = new Object();
  97     // Used in ensureDriversInitialized() to synchronize driversInitialized
  98     private final static Object lockForInitDrivers = new Object();
  99     private static volatile boolean driversInitialized;
 100     private static final String JDBC_DRIVERS_PROPERTY = "jdbc.drivers";
 101 
 102     /* Prevent the DriverManager class from being instantiated. */
 103     private DriverManager(){}
 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         ensureDriversInitialized();
 291 
 292         Class<?> callerClass = Reflection.getCallerClass();
 293 
 294         // Walk through the loaded registeredDrivers attempting to locate someone
 295         // who understands the given URL.
 296         for (DriverInfo aDriver : registeredDrivers) {
 297             // If the caller does not have permission to load the driver then
 298             // skip it.
 299             if (isDriverAllowed(aDriver.driver, callerClass)) {
 300                 try {
 301                     if (aDriver.driver.acceptsURL(url)) {
 302                         // Success!
 303                         println("getDriver returning " + aDriver.driver.getClass().getName());
 304                     return (aDriver.driver);
 305                     }
 306 
 307                 } catch(SQLException sqe) {
 308                     // Drop through and try the next driver.
 309                 }
 310             } else {
 311                 println("    skipping: " + aDriver.driver.getClass().getName());
 312             }
 313 
 314         }
 315 
 316         println("getDriver: no suitable driver");
 317         throw new SQLException("No suitable driver", "08001");
 318     }
 319 
 320 
 321     /**
 322      * Registers the given driver with the {@code DriverManager}.
 323      * A newly-loaded driver class should call
 324      * the method {@code registerDriver} to make itself
 325      * known to the {@code DriverManager}. If the driver is currently
 326      * registered, no action is taken.
 327      *
 328      * @param driver the new JDBC Driver that is to be registered with the
 329      *               {@code DriverManager}
 330      * @exception SQLException if a database access error occurs
 331      * @exception NullPointerException if {@code driver} is null
 332      */
 333     public static void registerDriver(java.sql.Driver driver)
 334         throws SQLException {
 335 
 336         registerDriver(driver, null);
 337     }
 338 
 339     /**
 340      * Registers the given driver with the {@code DriverManager}.
 341      * A newly-loaded driver class should call
 342      * the method {@code registerDriver} to make itself
 343      * known to the {@code DriverManager}. If the driver is currently
 344      * registered, no action is taken.
 345      *
 346      * @param driver the new JDBC Driver that is to be registered with the
 347      *               {@code DriverManager}
 348      * @param da     the {@code DriverAction} implementation to be used when
 349      *               {@code DriverManager#deregisterDriver} is called
 350      * @exception SQLException if a database access error occurs
 351      * @exception NullPointerException if {@code driver} is null
 352      * @since 1.8
 353      */
 354     public static void registerDriver(java.sql.Driver driver,
 355             DriverAction da)
 356         throws SQLException {
 357 
 358         /* Register the driver if it has not already been added to our list */
 359         if (driver != null) {
 360             registeredDrivers.addIfAbsent(new DriverInfo(driver, da));
 361         } else {
 362             // This is for compatibility with the original DriverManager
 363             throw new NullPointerException();
 364         }
 365 
 366         println("registerDriver: " + driver);
 367 
 368     }
 369 
 370     /**
 371      * Removes the specified driver from the {@code DriverManager}'s list of
 372      * registered drivers.
 373      * <p>
 374      * If a {@code null} value is specified for the driver to be removed, then no
 375      * action is taken.
 376      * <p>
 377      * If a security manager exists and its {@code checkPermission} denies
 378      * permission, then a {@code SecurityException} will be thrown.
 379      * <p>
 380      * If the specified driver is not found in the list of registered drivers,
 381      * then no action is taken.  If the driver was found, it will be removed
 382      * from the list of registered drivers.
 383      * <p>
 384      * If a {@code DriverAction} instance was specified when the JDBC driver was
 385      * registered, its deregister method will be called
 386      * prior to the driver being removed from the list of registered drivers.
 387      *
 388      * @param driver the JDBC Driver to remove
 389      * @exception SQLException if a database access error occurs
 390      * @throws SecurityException if a security manager exists and its
 391      * {@code checkPermission} method denies permission to deregister a driver.
 392      *
 393      * @see SecurityManager#checkPermission
 394      */
 395     @CallerSensitive
 396     public static void deregisterDriver(Driver driver) throws SQLException {
 397         if (driver == null) {
 398             return;
 399         }
 400 
 401         SecurityManager sec = System.getSecurityManager();
 402         if (sec != null) {
 403             sec.checkPermission(DEREGISTER_DRIVER_PERMISSION);
 404         }
 405 
 406         println("DriverManager.deregisterDriver: " + driver);
 407 
 408         DriverInfo aDriver = new DriverInfo(driver, null);
 409         synchronized (lockForInitDrivers) {
 410             if (registeredDrivers.contains(aDriver)) {
 411                 if (isDriverAllowed(driver, Reflection.getCallerClass())) {
 412                     DriverInfo di = registeredDrivers.get(registeredDrivers.indexOf(aDriver));
 413                      // If a DriverAction was specified, Call it to notify the
 414                      // driver that it has been deregistered
 415                      if (di.action() != null) {
 416                          di.action().deregister();
 417                      }
 418                      registeredDrivers.remove(aDriver);
 419                 } else {
 420                     // If the caller does not have permission to load the driver then
 421                     // throw a SecurityException.
 422                     throw new SecurityException();
 423                 }
 424             } else {
 425                 println("    couldn't find driver to unload");
 426             }
 427         }
 428     }
 429 
 430     /**
 431      * Retrieves an Enumeration with all of the currently loaded JDBC drivers
 432      * to which the current caller has access.
 433      *
 434      * <P><B>Note:</B> The classname of a driver can be found using
 435      * <CODE>d.getClass().getName()</CODE>
 436      *
 437      * @return the list of JDBC Drivers loaded by the caller's class loader
 438      * @see #drivers()
 439      */
 440     @CallerSensitive
 441     public static Enumeration<Driver> getDrivers() {
 442         ensureDriversInitialized();
 443 
 444         return Collections.enumeration(getDrivers(Reflection.getCallerClass()));
 445     }
 446 
 447     /**
 448      * Retrieves a Stream with all of the currently loaded JDBC drivers
 449      * to which the current caller has access.
 450      *
 451      * @return the stream of JDBC Drivers loaded by the caller's class loader
 452      * @since 9
 453      */
 454     @CallerSensitive
 455     public static Stream<Driver> drivers() {
 456         ensureDriversInitialized();
 457 
 458         return getDrivers(Reflection.getCallerClass()).stream();
 459     }
 460 
 461     private static List<Driver> getDrivers(Class<?> callerClass) {
 462         List<Driver> result = new ArrayList<>();
 463         // Walk through the loaded registeredDrivers.
 464         for (DriverInfo aDriver : registeredDrivers) {
 465             // If the caller does not have permission to load the driver then
 466             // skip it.
 467             if (isDriverAllowed(aDriver.driver, callerClass)) {
 468                 result.add(aDriver.driver);
 469             } else {
 470                 println("    skipping: " + aDriver.getClass().getName());
 471             }
 472         }
 473         return result;
 474     }
 475 
 476     /**
 477      * Sets the maximum time in seconds that a driver will wait
 478      * while attempting to connect to a database once the driver has
 479      * been identified.
 480      *
 481      * @param seconds the login time limit in seconds; zero means there is no limit
 482      * @see #getLoginTimeout
 483      */
 484     public static void setLoginTimeout(int seconds) {
 485         loginTimeout = seconds;
 486     }
 487 
 488     /**
 489      * Gets the maximum time in seconds that a driver can wait
 490      * when attempting to log in to a database.
 491      *
 492      * @return the driver login time limit in seconds
 493      * @see #setLoginTimeout
 494      */
 495     public static int getLoginTimeout() {
 496         return (loginTimeout);
 497     }
 498 
 499     /**
 500      * Sets the logging/tracing PrintStream that is used
 501      * by the <code>DriverManager</code>
 502      * and all drivers.
 503      *<P>
 504      * In the Java 2 SDK, Standard Edition, version 1.3 release, this method checks
 505      * to see that there is an <code>SQLPermission</code> object before setting
 506      * the logging stream.  If a <code>SecurityManager</code> exists and its
 507      * <code>checkPermission</code> method denies setting the log writer, this
 508      * method throws a <code>java.lang.SecurityException</code>.
 509      *
 510      * @param out the new logging/tracing PrintStream; to disable, set to <code>null</code>
 511      * @deprecated Use {@code setLogWriter}
 512      * @throws SecurityException if a security manager exists and its
 513      *    <code>checkPermission</code> method denies setting the log stream
 514      *
 515      * @see SecurityManager#checkPermission
 516      * @see #getLogStream
 517      */
 518     @Deprecated
 519     public static void setLogStream(java.io.PrintStream out) {
 520 
 521         SecurityManager sec = System.getSecurityManager();
 522         if (sec != null) {
 523             sec.checkPermission(SET_LOG_PERMISSION);
 524         }
 525 
 526         logStream = out;
 527         if ( out != null )
 528             logWriter = new java.io.PrintWriter(out);
 529         else
 530             logWriter = null;
 531     }
 532 
 533     /**
 534      * Retrieves the logging/tracing PrintStream that is used by the <code>DriverManager</code>
 535      * and all drivers.
 536      *
 537      * @return the logging/tracing PrintStream; if disabled, is <code>null</code>
 538      * @deprecated  Use {@code getLogWriter}
 539      * @see #setLogStream
 540      */
 541     @Deprecated
 542     public static java.io.PrintStream getLogStream() {
 543         return logStream;
 544     }
 545 
 546     /**
 547      * Prints a message to the current JDBC log stream.
 548      *
 549      * @param message a log or tracing message
 550      */
 551     public static void println(String message) {
 552         synchronized (logSync) {
 553             if (logWriter != null) {
 554                 logWriter.println(message);
 555 
 556                 // automatic flushing is never enabled, so we must do it ourselves
 557                 logWriter.flush();
 558             }
 559         }
 560     }
 561 
 562     //------------------------------------------------------------------------
 563 
 564     // Indicates whether the class object that would be created if the code calling
 565     // DriverManager is accessible.
 566     private static boolean isDriverAllowed(Driver driver, Class<?> caller) {
 567         ClassLoader callerCL = caller != null ? caller.getClassLoader() : null;
 568         return isDriverAllowed(driver, callerCL);
 569     }
 570 
 571     private static boolean isDriverAllowed(Driver driver, ClassLoader classLoader) {
 572         boolean result = false;
 573         if (driver != null) {
 574             Class<?> aClass = null;
 575             try {
 576                 aClass =  Class.forName(driver.getClass().getName(), true, classLoader);
 577             } catch (Exception ex) {
 578                 result = false;
 579             }
 580 
 581              result = ( aClass == driver.getClass() ) ? true : false;
 582         }
 583 
 584         return result;
 585     }
 586 
 587     /*
 588      * Load the initial JDBC drivers by checking the System property
 589      * jdbc.drivers and then use the {@code ServiceLoader} mechanism
 590      */
 591     private static void ensureDriversInitialized() {
 592         if (driversInitialized) {
 593             return;
 594         }
 595 
 596         synchronized (lockForInitDrivers) {
 597             if (driversInitialized) {
 598                 return;
 599             }
 600             String drivers;
 601             try {
 602                 drivers = AccessController.doPrivileged(new PrivilegedAction<String>() {
 603                     public String run() {
 604                         return System.getProperty(JDBC_DRIVERS_PROPERTY);
 605                     }
 606                 });
 607             } catch (Exception ex) {
 608                 drivers = null;
 609             }
 610             // If the driver is packaged as a Service Provider, load it.
 611             // Get all the drivers through the classloader
 612             // exposed as a java.sql.Driver.class service.
 613             // ServiceLoader.load() replaces the sun.misc.Providers()
 614 
 615             AccessController.doPrivileged(new PrivilegedAction<Void>() {
 616                 public Void run() {
 617 
 618                     ServiceLoader<Driver> loadedDrivers = ServiceLoader.load(Driver.class);
 619                     Iterator<Driver> driversIterator = loadedDrivers.iterator();
 620 
 621                     /* Load these drivers, so that they can be instantiated.
 622                      * It may be the case that the driver class may not be there
 623                      * i.e. there may be a packaged driver with the service class
 624                      * as implementation of java.sql.Driver but the actual class
 625                      * may be missing. In that case a java.util.ServiceConfigurationError
 626                      * will be thrown at runtime by the VM trying to locate
 627                      * and load the service.
 628                      *
 629                      * Adding a try catch block to catch those runtime errors
 630                      * if driver not available in classpath but it's
 631                      * packaged as service and that service is there in classpath.
 632                      */
 633                     try {
 634                         while (driversIterator.hasNext()) {
 635                             driversIterator.next();
 636                         }
 637                     } catch (Throwable t) {
 638                         // Do nothing
 639                     }
 640                     return null;
 641                 }
 642             });
 643 
 644             println("DriverManager.initialize: jdbc.drivers = " + drivers);
 645 
 646             if (drivers != null && !drivers.equals("")) {
 647                 String[] driversList = drivers.split(":");
 648                 println("number of Drivers:" + driversList.length);
 649                 for (String aDriver : driversList) {
 650                     try {
 651                         println("DriverManager.Initialize: loading " + aDriver);
 652                         Class.forName(aDriver, true,
 653                                 ClassLoader.getSystemClassLoader());
 654                     } catch (Exception ex) {
 655                         println("DriverManager.Initialize: load failed: " + ex);
 656                     }
 657                 }
 658             }
 659 
 660             driversInitialized = true;
 661             println("JDBC DriverManager initialized");
 662         }
 663     }
 664 
 665 
 666     //  Worker method called by the public getConnection() methods.
 667     private static Connection getConnection(
 668         String url, java.util.Properties info, Class<?> caller) throws SQLException {
 669         /*
 670          * When callerCl is null, we should check the application's
 671          * (which is invoking this class indirectly)
 672          * classloader, so that the JDBC driver class outside rt.jar
 673          * can be loaded from here.
 674          */
 675         ClassLoader callerCL = caller != null ? caller.getClassLoader() : null;
 676         if (callerCL == null) {
 677             callerCL = Thread.currentThread().getContextClassLoader();
 678         }
 679 
 680         if (url == null) {
 681             throw new SQLException("The url cannot be null", "08001");
 682         }
 683 
 684         println("DriverManager.getConnection(\"" + url + "\")");
 685 
 686         ensureDriversInitialized();
 687 
 688         // Walk through the loaded registeredDrivers attempting to make a connection.
 689         // Remember the first exception that gets raised so we can reraise it.
 690         SQLException reason = null;
 691 
 692         for (DriverInfo aDriver : registeredDrivers) {
 693             // If the caller does not have permission to load the driver then
 694             // skip it.
 695             if (isDriverAllowed(aDriver.driver, callerCL)) {
 696                 try {
 697                     println("    trying " + aDriver.driver.getClass().getName());
 698                     Connection con = aDriver.driver.connect(url, info);
 699                     if (con != null) {
 700                         // Success!
 701                         println("getConnection returning " + aDriver.driver.getClass().getName());
 702                         return (con);
 703                     }
 704                 } catch (SQLException ex) {
 705                     if (reason == null) {
 706                         reason = ex;
 707                     }
 708                 }
 709 
 710             } else {
 711                 println("    skipping: " + aDriver.getClass().getName());
 712             }
 713 
 714         }
 715 
 716         // if we got here nobody could connect.
 717         if (reason != null)    {
 718             println("getConnection failed: " + reason);
 719             throw reason;
 720         }
 721 
 722         println("getConnection: no suitable driver found for "+ url);
 723         throw new SQLException("No suitable driver found for "+ url, "08001");
 724     }
 725 
 726 
 727 }
 728 
 729 /*
 730  * Wrapper class for registered Drivers in order to not expose Driver.equals()
 731  * to avoid the capture of the Driver it being compared to as it might not
 732  * normally have access.
 733  */
 734 class DriverInfo {
 735 
 736     final Driver driver;
 737     DriverAction da;
 738     DriverInfo(Driver driver, DriverAction action) {
 739         this.driver = driver;
 740         da = action;
 741     }
 742 
 743     @Override
 744     public boolean equals(Object other) {
 745         return (other instanceof DriverInfo)
 746                 && this.driver == ((DriverInfo) other).driver;
 747     }
 748 
 749     @Override
 750     public int hashCode() {
 751         return driver.hashCode();
 752     }
 753 
 754     @Override
 755     public String toString() {
 756         return ("driver[className="  + driver + "]");
 757     }
 758 
 759     DriverAction action() {
 760         return da;
 761     }
 762 }