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