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