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 }