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.
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.
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).
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.
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
28
import ikvm.internal.CallerID;
29
import java.util.Iterator;
30
import java.sql.Driver;
31
import java.util.ServiceLoader;
32
import java.security.AccessController;
33
import java.security.PrivilegedAction;
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.
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:
49
* <CODE>jdbc.drivers=foo.bah.Driver:wombat.sql.Driver:bad.taste.ourDriver</CODE>
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:
58
* <code>my.sql.Driver</code>
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
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.
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>.
80
public class DriverManager {
84
* The <code>SQLPermission</code> constant that allows the
85
* setting of the logging stream.
88
final static SQLPermission SET_LOG_PERMISSION =
89
new SQLPermission("setLog");
91
//--------------------------JDBC 2.0-----------------------------
94
* Retrieves the log writer.
96
* The <code>getLogWriter</code> and <code>setLogWriter</code>
97
* methods should be used instead
98
* of the <code>get/setlogStream</code> methods, which are deprecated.
99
* @return a <code>java.io.PrintWriter</code> object
103
public static java.io.PrintWriter getLogWriter() {
108
* Sets the logging/tracing <code>PrintWriter</code> object
109
* that is used by the <code>DriverManager</code> and all drivers.
111
* There is a minor versioning problem created by the introduction
112
* of the method <code>setLogWriter</code>. The
113
* method <code>setLogWriter</code> cannot create a <code>PrintStream</code> object
114
* that will be returned by <code>getLogStream</code>---the Java platform does
115
* not provide a backward conversion. As a result, a new application
116
* that uses <code>setLogWriter</code> and also uses a JDBC 1.0 driver that uses
117
* <code>getLogStream</code> will likely not see debugging information written
120
* Starting with the Java 2 SDK, Standard Edition, version 1.3 release, this method checks
121
* to see that there is an <code>SQLPermission</code> object before setting
122
* the logging stream. If a <code>SecurityManager</code> exists and its
123
* <code>checkPermission</code> method denies setting the log writer, this
124
* method throws a <code>java.lang.SecurityException</code>.
126
* @param out the new logging/tracing <code>PrintStream</code> object;
127
* <code>null</code> to disable logging and tracing
128
* @throws SecurityException
129
* if a security manager exists and its
130
* <code>checkPermission</code> method denies
131
* setting the log writer
133
* @see SecurityManager#checkPermission
137
public static void setLogWriter(java.io.PrintWriter out) {
139
SecurityManager sec = System.getSecurityManager();
141
sec.checkPermission(SET_LOG_PERMISSION);
148
//---------------------------------------------------------------
151
* Attempts to establish a connection to the given database URL.
152
* The <code>DriverManager</code> attempts to select an appropriate driver from
153
* the set of registered JDBC drivers.
155
* @param url a database url of the form
156
* <code> jdbc:<em>subprotocol</em>:<em>subname</em></code>
157
* @param info a list of arbitrary string tag/value pairs as
158
* connection arguments; normally at least a "user" and
159
* "password" property should be included
160
* @return a Connection to the URL
161
* @exception SQLException if a database access error occurs
163
@ikvm.internal.HasCallerID
164
public static Connection getConnection(String url,
165
java.util.Properties info) throws SQLException {
167
// Gets the classloader of the code that called this method, may
169
ClassLoader callerCL = CallerID.getCallerID().getCallerClassLoader();
171
return (getConnection(url, info, callerCL));
175
* Attempts to establish a connection to the given database URL.
176
* The <code>DriverManager</code> attempts to select an appropriate driver from
177
* the set of registered JDBC drivers.
179
* @param url a database url of the form
180
* <code>jdbc:<em>subprotocol</em>:<em>subname</em></code>
181
* @param user the database user on whose behalf the connection is being
183
* @param password the user's password
184
* @return a connection to the URL
185
* @exception SQLException if a database access error occurs
187
@ikvm.internal.HasCallerID
188
public static Connection getConnection(String url,
189
String user, String password) throws SQLException {
190
java.util.Properties info = new java.util.Properties();
192
// Gets the classloader of the code that called this method, may
194
ClassLoader callerCL = CallerID.getCallerID().getCallerClassLoader();
197
info.put("user", user);
199
if (password != null) {
200
info.put("password", password);
203
return (getConnection(url, info, callerCL));
207
* Attempts to establish a connection to the given database URL.
208
* The <code>DriverManager</code> attempts to select an appropriate driver from
209
* the set of registered JDBC drivers.
211
* @param url a database url of the form
212
* <code> jdbc:<em>subprotocol</em>:<em>subname</em></code>
213
* @return a connection to the URL
214
* @exception SQLException if a database access error occurs
216
@ikvm.internal.HasCallerID
217
public static Connection getConnection(String url)
218
throws SQLException {
220
java.util.Properties info = new java.util.Properties();
222
// Gets the classloader of the code that called this method, may
224
ClassLoader callerCL = CallerID.getCallerID().getCallerClassLoader();
226
return (getConnection(url, info, callerCL));
230
* Attempts to locate a driver that understands the given URL.
231
* The <code>DriverManager</code> attempts to select an appropriate driver from
232
* the set of registered JDBC drivers.
234
* @param url a database URL of the form
235
* <code>jdbc:<em>subprotocol</em>:<em>subname</em></code>
236
* @return a <code>Driver</code> object representing a driver
237
* that can connect to the given URL
238
* @exception SQLException if a database access error occurs
240
@ikvm.internal.HasCallerID
241
public static Driver getDriver(String url)
242
throws SQLException {
243
java.util.Vector drivers = null;
245
println("DriverManager.getDriver(\"" + url + "\")");
251
synchronized (DriverManager.class){
252
// use the read copy of the drivers vector
253
drivers = readDrivers;
256
// Gets the classloader of the code that called this method, may
258
ClassLoader callerCL = CallerID.getCallerID().getCallerClassLoader();
260
// Walk through the loaded drivers attempting to locate someone
261
// who understands the given URL.
262
for (int i = 0; i < drivers.size(); i++) {
263
DriverInfo di = (DriverInfo)drivers.elementAt(i);
264
// If the caller does not have permission to load the driver then
266
if ( getCallerClass(callerCL, di.driverClassName ) !=
268
println(" skipping: " + di);
272
println(" trying " + di);
273
if (di.driver.acceptsURL(url)) {
275
println("getDriver returning " + di);
278
} catch (SQLException ex) {
279
// Drop through and try the next driver.
283
println("getDriver: no suitable driver");
284
throw new SQLException("No suitable driver", "08001");
289
* Registers the given driver with the <code>DriverManager</code>.
290
* A newly-loaded driver class should call
291
* the method <code>registerDriver</code> to make itself
292
* known to the <code>DriverManager</code>.
294
* @param driver the new JDBC Driver that is to be registered with the
295
* <code>DriverManager</code>
296
* @exception SQLException if a database access error occurs
298
public static synchronized void registerDriver(java.sql.Driver driver)
299
throws SQLException {
304
DriverInfo di = new DriverInfo();
307
di.driverClass = driver.getClass();
308
di.driverClassName = di.driverClass.getName();
310
// Not Required -- drivers.addElement(di);
312
writeDrivers.addElement(di);
313
println("registerDriver: " + di);
315
/* update the read copy of drivers vector */
316
readDrivers = (java.util.Vector) writeDrivers.clone();
321
* Drops a driver from the <code>DriverManager</code>'s list.
322
* Applets can only deregister drivers from their own classloaders.
324
* @param driver the JDBC Driver to drop
325
* @exception SQLException if a database access error occurs
327
@ikvm.internal.HasCallerID
328
public static synchronized void deregisterDriver(Driver driver)
329
throws SQLException {
330
// Gets the classloader of the code that called this method,
332
ClassLoader callerCL = CallerID.getCallerID().getCallerClassLoader();
333
println("DriverManager.deregisterDriver: " + driver);
335
// Walk through the loaded drivers.
337
DriverInfo di = null;
338
for (i = 0; i < writeDrivers.size(); i++) {
339
di = (DriverInfo)writeDrivers.elementAt(i);
340
if (di.driver == driver) {
344
// If we can't find the driver just return.
345
if (i >= writeDrivers.size()) {
346
println(" couldn't find driver to unload");
350
// If the caller does not have permission to load the driver then
351
// throw a security exception.
352
if (getCallerClass(callerCL, di.driverClassName ) != di.driverClass ) {
353
throw new SecurityException();
356
// Remove the driver. Other entries in drivers get shuffled down.
357
writeDrivers.removeElementAt(i);
359
/* update the read copy of drivers vector */
360
readDrivers = (java.util.Vector) writeDrivers.clone();
364
* Retrieves an Enumeration with all of the currently loaded JDBC drivers
365
* to which the current caller has access.
367
* <P><B>Note:</B> The classname of a driver can be found using
368
* <CODE>d.getClass().getName()</CODE>
370
* @return the list of JDBC Drivers loaded by the caller's class loader
372
@ikvm.internal.HasCallerID
373
public static java.util.Enumeration<Driver> getDrivers() {
374
java.util.Vector<Driver> result = new java.util.Vector<Driver>();
375
java.util.Vector drivers = null;
381
synchronized (DriverManager.class){
382
// use the readcopy of drivers
383
drivers = readDrivers;
386
// Gets the classloader of the code that called this method, may
388
ClassLoader callerCL = CallerID.getCallerID().getCallerClassLoader();
390
// Walk through the loaded drivers.
391
for (int i = 0; i < drivers.size(); i++) {
392
DriverInfo di = (DriverInfo)drivers.elementAt(i);
393
// If the caller does not have permission to load the driver then
395
if ( getCallerClass(callerCL, di.driverClassName ) != di.driverClass ) {
396
println(" skipping: " + di);
399
result.addElement(di.driver);
402
return (result.elements());
407
* Sets the maximum time in seconds that a driver will wait
408
* while attempting to connect to a database.
410
* @param seconds the login time limit in seconds; zero means there is no limit
411
* @see #getLoginTimeout
413
public static void setLoginTimeout(int seconds) {
414
loginTimeout = seconds;
418
* Gets the maximum time in seconds that a driver can wait
419
* when attempting to log in to a database.
421
* @return the driver login time limit in seconds
422
* @see #setLoginTimeout
424
public static int getLoginTimeout() {
425
return (loginTimeout);
429
* Sets the logging/tracing PrintStream that is used
430
* by the <code>DriverManager</code>
433
* In the Java 2 SDK, Standard Edition, version 1.3 release, this method checks
434
* to see that there is an <code>SQLPermission</code> object before setting
435
* the logging stream. If a <code>SecurityManager</code> exists and its
436
* <code>checkPermission</code> method denies setting the log writer, this
437
* method throws a <code>java.lang.SecurityException</code>.
439
* @param out the new logging/tracing PrintStream; to disable, set to <code>null</code>
441
* @throws SecurityException if a security manager exists and its
442
* <code>checkPermission</code> method denies setting the log stream
444
* @see SecurityManager#checkPermission
447
public static void setLogStream(java.io.PrintStream out) {
449
SecurityManager sec = System.getSecurityManager();
451
sec.checkPermission(SET_LOG_PERMISSION);
456
logWriter = new java.io.PrintWriter(out);
462
* Retrieves the logging/tracing PrintStream that is used by the <code>DriverManager</code>
465
* @return the logging/tracing PrintStream; if disabled, is <code>null</code>
469
public static java.io.PrintStream getLogStream() {
474
* Prints a message to the current JDBC log stream.
476
* @param message a log or tracing message
478
public static void println(String message) {
479
synchronized (logSync) {
480
if (logWriter != null) {
481
logWriter.println(message);
483
// automatic flushing is never enabled, so we must do it ourselves
489
//------------------------------------------------------------------------
491
// Returns the class object that would be created if the code calling the
492
// driver manager had loaded the driver class, or null if the class
494
private static Class getCallerClass(ClassLoader callerClassLoader,
495
String driverClassName) {
496
Class callerC = null;
499
callerC = Class.forName(driverClassName, true, callerClassLoader);
501
catch (Exception ex) {
502
callerC = null; // being very careful
508
private static void loadInitialDrivers() {
511
drivers = (String) AccessController.doPrivileged(new PrivilegedAction() {
512
public Object run() {
513
return System.getProperty("jdbc.drivers");
516
} catch (Exception ex) {
519
// If the driver is packaged as a Service Provider, load it.
520
// Get all the drivers through the classloader
521
// exposed as a java.sql.Driver.class service.
522
// ServiceLoader.load() replaces the sun.misc.Providers()
524
AccessController.doPrivileged(new PrivilegedAction() {
525
public Object run() {
527
ServiceLoader<Driver> loadedDrivers = ServiceLoader.load(Driver.class);
528
Iterator driversIterator = loadedDrivers.iterator();
530
/* Load these drivers, so that they can be instantiated.
531
* It may be the case that the driver class may not be there
532
* i.e. there may be a packaged driver with the service class
533
* as implementation of java.sql.Driver but the actual class
534
* may be missing. In that case a java.util.ServiceConfigurationError
535
* will be thrown at runtime by the VM trying to locate
536
* and load the service.
538
* Adding a try catch block to catch those runtime errors
539
* if driver not available in classpath but it's
540
* packaged as service and that service is there in classpath.
543
while(driversIterator.hasNext()) {
544
println(" Loading done by the java.util.ServiceLoader : "+driversIterator.next());
546
} catch(Throwable t) {
553
println("DriverManager.initialize: jdbc.drivers = " + drivers);
554
if (drivers == null) {
557
while (drivers.length() != 0) {
558
int x = drivers.indexOf(':');
564
driver = drivers.substring(0, x);
565
drivers = drivers.substring(x+1);
567
if (driver.length() == 0) {
571
println("DriverManager.Initialize: loading " + driver);
572
Class.forName(driver, true,
573
ClassLoader.getSystemClassLoader());
574
} catch (Exception ex) {
575
println("DriverManager.Initialize: load failed: " + ex);
581
// Worker method called by the public getConnection() methods.
582
private static Connection getConnection(
583
String url, java.util.Properties info, ClassLoader callerCL) throws SQLException {
584
java.util.Vector drivers = null;
586
* When callerCl is null, we should check the application's
587
* (which is invoking this class indirectly)
588
* classloader, so that the JDBC driver class outside rt.jar
589
* can be loaded from here.
591
synchronized(DriverManager.class) {
592
// synchronize loading of the correct classloader.
593
if(callerCL == null) {
594
callerCL = Thread.currentThread().getContextClassLoader();
599
throw new SQLException("The url cannot be null", "08001");
602
println("DriverManager.getConnection(\"" + url + "\")");
608
synchronized (DriverManager.class){
609
// use the readcopy of drivers
610
drivers = readDrivers;
613
// Walk through the loaded drivers attempting to make a connection.
614
// Remember the first exception that gets raised so we can reraise it.
615
SQLException reason = null;
616
for (int i = 0; i < drivers.size(); i++) {
617
DriverInfo di = (DriverInfo)drivers.elementAt(i);
619
// If the caller does not have permission to load the driver then
621
if ( getCallerClass(callerCL, di.driverClassName ) != di.driverClass ) {
622
println(" skipping: " + di);
626
println(" trying " + di);
627
Connection result = di.driver.connect(url, info);
628
if (result != null) {
630
println("getConnection returning " + di);
633
} catch (SQLException ex) {
634
if (reason == null) {
640
// if we got here nobody could connect.
641
if (reason != null) {
642
println("getConnection failed: " + reason);
646
println("getConnection: no suitable driver found for "+ url);
647
throw new SQLException("No suitable driver found for "+ url, "08001");
651
// Class initialization.
652
static void initialize() {
657
loadInitialDrivers();
658
println("JDBC DriverManager initialized");
661
/* Prevent the DriverManager class from being instantiated. */
662
private DriverManager(){}
664
/* write copy of the drivers vector */
665
private static java.util.Vector writeDrivers = new java.util.Vector();
667
/* write copy of the drivers vector */
668
private static java.util.Vector readDrivers = new java.util.Vector();
670
private static int loginTimeout = 0;
671
private static java.io.PrintWriter logWriter = null;
672
private static java.io.PrintStream logStream = null;
673
private static boolean initialized = false;
675
private static Object logSync = new Object();
679
// DriverInfo is a package-private support class.
683
String driverClassName;
685
public String toString() {
686
return ("driver[className=" + driverClassName + "," + driver + "]");