blob: 5530fda159d7366e7499dc589ea957a36100843b [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
Paul Sandoze56c76e2015-06-09 07:10:02 +01002 * Copyright (c) 1996, 2015, Oracle and/or its affiliates. All rights reserved.
J. Duke319a3b92007-12-01 00:00:00 +00003 * 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
Kelly O'Hairfe008ae2010-05-25 15:58:33 -07007 * published by the Free Software Foundation. Oracle designates this
J. Duke319a3b92007-12-01 00:00:00 +00008 * particular file as subject to the "Classpath" exception as provided
Kelly O'Hairfe008ae2010-05-25 15:58:33 -07009 * by Oracle in the LICENSE file that accompanied this code.
J. Duke319a3b92007-12-01 00:00:00 +000010 *
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 *
Kelly O'Hairfe008ae2010-05-25 15:58:33 -070021 * 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.
J. Duke319a3b92007-12-01 00:00:00 +000024 */
25
26package java.sql;
27
Paul Sandoze56c76e2015-06-09 07:10:02 +010028import java.util.ArrayList;
29import java.util.Collections;
30import java.util.Enumeration;
J. Duke319a3b92007-12-01 00:00:00 +000031import java.util.Iterator;
Paul Sandoze56c76e2015-06-09 07:10:02 +010032import java.util.List;
J. Duke319a3b92007-12-01 00:00:00 +000033import java.util.ServiceLoader;
34import java.security.AccessController;
35import java.security.PrivilegedAction;
Lance Andersen725342d2011-03-17 11:37:06 -040036import java.util.concurrent.CopyOnWriteArrayList;
Paul Sandoze56c76e2015-06-09 07:10:02 +010037import java.util.stream.Stream;
38
Chris Hegarty07cdc332016-04-15 16:19:15 +010039import jdk.internal.reflect.CallerSensitive;
40import jdk.internal.reflect.Reflection;
J. Duke319a3b92007-12-01 00:00:00 +000041
42
43/**
44 * <P>The basic service for managing a set of JDBC drivers.<br>
Alan Bateman451a0032013-06-10 12:58:32 +010045 * <B>NOTE:</B> The {@link javax.sql.DataSource} interface, new in the
J. Duke319a3b92007-12-01 00:00:00 +000046 * 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 *
Sergey Malenkovc500ed62013-10-29 17:01:06 +040068 * <P>Applications no longer need to explicitly load JDBC drivers using <code>Class.forName()</code>. Existing programs
J. Duke319a3b92007-12-01 00:00:00 +000069 * 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 */
87public class DriverManager {
88
89
Lance Andersen725342d2011-03-17 11:37:06 -040090 // List of registered JDBC drivers
Lance Andersen1c74eea2011-12-02 19:33:54 -050091 private final static CopyOnWriteArrayList<DriverInfo> registeredDrivers = new CopyOnWriteArrayList<>();
Lance Andersen725342d2011-03-17 11:37:06 -040092 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
Lance Andersen7e500d52014-12-03 16:50:55 -050096 private final static Object logSync = new Object();
Lance Andersenddcbf612014-12-18 18:51:28 -050097 // Used in ensureDriversInitialized() to synchronize driversInitialized
98 private final static Object lockForInitDrivers = new Object();
Lance Andersen7e500d52014-12-03 16:50:55 -050099 private static volatile boolean driversInitialized;
100 private static final String JDBC_DRIVERS_PROPERTY = "jdbc.drivers";
Lance Andersen725342d2011-03-17 11:37:06 -0400101
102 /* Prevent the DriverManager class from being instantiated. */
103 private DriverManager(){}
104
J. Duke319a3b92007-12-01 00:00:00 +0000105 /**
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
Lance Andersen785f0d22013-04-30 14:44:25 -0400113 /**
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
J. Duke319a3b92007-12-01 00:00:00 +0000121 //--------------------------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.
Lance Andersen69757a12013-01-19 10:53:14 -0500184 *<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.
J. Duke319a3b92007-12-01 00:00:00 +0000190 *
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
Lance Andersen69757a12013-01-19 10:53:14 -0500197 * @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
J. Duke319a3b92007-12-01 00:00:00 +0000203 */
Mandy Chung176ed8d2013-04-16 21:39:52 -0700204 @CallerSensitive
J. Duke319a3b92007-12-01 00:00:00 +0000205 public static Connection getConnection(String url,
206 java.util.Properties info) throws SQLException {
207
Mandy Chung176ed8d2013-04-16 21:39:52 -0700208 return (getConnection(url, info, Reflection.getCallerClass()));
J. Duke319a3b92007-12-01 00:00:00 +0000209 }
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.
Lance Andersen69757a12013-01-19 10:53:14 -0500215 *<p>
Lance Andersenff86cc72013-12-02 16:06:03 -0500216 * <B>Note:</B> If the {@code user} or {@code password} property are
217 * also specified as part of the {@code url}, it is
Lance Andersen69757a12013-01-19 10:53:14 -0500218 * implementation-defined as to which value will take precedence.
219 * For maximum portability, an application should only specify a
220 * property once.
J. Duke319a3b92007-12-01 00:00:00 +0000221 *
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
Lance Andersen69757a12013-01-19 10:53:14 -0500228 * @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
J. Duke319a3b92007-12-01 00:00:00 +0000234 */
Mandy Chung176ed8d2013-04-16 21:39:52 -0700235 @CallerSensitive
J. Duke319a3b92007-12-01 00:00:00 +0000236 public static Connection getConnection(String url,
237 String user, String password) throws SQLException {
238 java.util.Properties info = new java.util.Properties();
239
J. Duke319a3b92007-12-01 00:00:00 +0000240 if (user != null) {
241 info.put("user", user);
242 }
243 if (password != null) {
244 info.put("password", password);
245 }
246
Mandy Chung176ed8d2013-04-16 21:39:52 -0700247 return (getConnection(url, info, Reflection.getCallerClass()));
J. Duke319a3b92007-12-01 00:00:00 +0000248 }
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
Lance Andersen69757a12013-01-19 10:53:14 -0500258 * @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
J. Duke319a3b92007-12-01 00:00:00 +0000264 */
Mandy Chung176ed8d2013-04-16 21:39:52 -0700265 @CallerSensitive
J. Duke319a3b92007-12-01 00:00:00 +0000266 public static Connection getConnection(String url)
267 throws SQLException {
268
269 java.util.Properties info = new java.util.Properties();
Mandy Chung176ed8d2013-04-16 21:39:52 -0700270 return (getConnection(url, info, Reflection.getCallerClass()));
J. Duke319a3b92007-12-01 00:00:00 +0000271 }
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 */
Mandy Chung176ed8d2013-04-16 21:39:52 -0700284 @CallerSensitive
J. Duke319a3b92007-12-01 00:00:00 +0000285 public static Driver getDriver(String url)
286 throws SQLException {
J. Duke319a3b92007-12-01 00:00:00 +0000287
288 println("DriverManager.getDriver(\"" + url + "\")");
289
Lance Andersenddcbf612014-12-18 18:51:28 -0500290 ensureDriversInitialized();
291
Mandy Chung176ed8d2013-04-16 21:39:52 -0700292 Class<?> callerClass = Reflection.getCallerClass();
J. Duke319a3b92007-12-01 00:00:00 +0000293
Lance Andersen725342d2011-03-17 11:37:06 -0400294 // Walk through the loaded registeredDrivers attempting to locate someone
J. Duke319a3b92007-12-01 00:00:00 +0000295 // who understands the given URL.
Lance Andersenddcbf612014-12-18 18:51:28 -0500296 for (DriverInfo aDriver : registeredDrivers) {
J. Duke319a3b92007-12-01 00:00:00 +0000297 // If the caller does not have permission to load the driver then
298 // skip it.
Lance Andersen7e500d52014-12-03 16:50:55 -0500299 if (isDriverAllowed(aDriver.driver, callerClass)) {
Lance Andersen725342d2011-03-17 11:37:06 -0400300 try {
Lance Andersen7e500d52014-12-03 16:50:55 -0500301 if (aDriver.driver.acceptsURL(url)) {
Lance Andersen725342d2011-03-17 11:37:06 -0400302 // Success!
Lance Andersen56352662011-04-06 17:37:36 -0400303 println("getDriver returning " + aDriver.driver.getClass().getName());
304 return (aDriver.driver);
Lance Andersen725342d2011-03-17 11:37:06 -0400305 }
306
307 } catch(SQLException sqe) {
308 // Drop through and try the next driver.
J. Duke319a3b92007-12-01 00:00:00 +0000309 }
Lance Andersen725342d2011-03-17 11:37:06 -0400310 } else {
Lance Andersen56352662011-04-06 17:37:36 -0400311 println(" skipping: " + aDriver.driver.getClass().getName());
J. Duke319a3b92007-12-01 00:00:00 +0000312 }
Lance Andersen725342d2011-03-17 11:37:06 -0400313
J. Duke319a3b92007-12-01 00:00:00 +0000314 }
315
316 println("getDriver: no suitable driver");
317 throw new SQLException("No suitable driver", "08001");
318 }
319
320
321 /**
Lance Andersen785f0d22013-04-30 14:44:25 -0400322 * Registers the given driver with the {@code DriverManager}.
J. Duke319a3b92007-12-01 00:00:00 +0000323 * A newly-loaded driver class should call
Lance Andersen785f0d22013-04-30 14:44:25 -0400324 * the method {@code registerDriver} to make itself
Lance Andersenff86cc72013-12-02 16:06:03 -0500325 * known to the {@code DriverManager}. If the driver is currently
Lance Andersen785f0d22013-04-30 14:44:25 -0400326 * registered, no action is taken.
J. Duke319a3b92007-12-01 00:00:00 +0000327 *
328 * @param driver the new JDBC Driver that is to be registered with the
Lance Andersen785f0d22013-04-30 14:44:25 -0400329 * {@code DriverManager}
J. Duke319a3b92007-12-01 00:00:00 +0000330 * @exception SQLException if a database access error occurs
Lance Andersen320e8d22013-09-13 19:10:31 -0400331 * @exception NullPointerException if {@code driver} is null
J. Duke319a3b92007-12-01 00:00:00 +0000332 */
Lance Andersen7e500d52014-12-03 16:50:55 -0500333 public static void registerDriver(java.sql.Driver driver)
J. Duke319a3b92007-12-01 00:00:00 +0000334 throws SQLException {
Lance Andersen725342d2011-03-17 11:37:06 -0400335
Lance Andersen785f0d22013-04-30 14:44:25 -0400336 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
Lance Andersenff86cc72013-12-02 16:06:03 -0500343 * known to the {@code DriverManager}. If the driver is currently
Lance Andersen785f0d22013-04-30 14:44:25 -0400344 * 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
Lance Andersen320e8d22013-09-13 19:10:31 -0400351 * @exception NullPointerException if {@code driver} is null
Lance Andersenff86cc72013-12-02 16:06:03 -0500352 * @since 1.8
Lance Andersen785f0d22013-04-30 14:44:25 -0400353 */
Lance Andersen7e500d52014-12-03 16:50:55 -0500354 public static void registerDriver(java.sql.Driver driver,
Lance Andersen785f0d22013-04-30 14:44:25 -0400355 DriverAction da)
356 throws SQLException {
357
Lance Andersen725342d2011-03-17 11:37:06 -0400358 /* Register the driver if it has not already been added to our list */
Lance Andersen7e500d52014-12-03 16:50:55 -0500359 if (driver != null) {
Lance Andersen785f0d22013-04-30 14:44:25 -0400360 registeredDrivers.addIfAbsent(new DriverInfo(driver, da));
Lance Andersen725342d2011-03-17 11:37:06 -0400361 } else {
362 // This is for compatibility with the original DriverManager
363 throw new NullPointerException();
J. Duke319a3b92007-12-01 00:00:00 +0000364 }
365
Lance Andersen725342d2011-03-17 11:37:06 -0400366 println("registerDriver: " + driver);
J. Duke319a3b92007-12-01 00:00:00 +0000367
368 }
369
370 /**
Lance Andersen785f0d22013-04-30 14:44:25 -0400371 * 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.
J. Duke319a3b92007-12-01 00:00:00 +0000387 *
Lance Andersen785f0d22013-04-30 14:44:25 -0400388 * @param driver the JDBC Driver to remove
J. Duke319a3b92007-12-01 00:00:00 +0000389 * @exception SQLException if a database access error occurs
Lance Andersen785f0d22013-04-30 14:44:25 -0400390 * @throws SecurityException if a security manager exists and its
391 * {@code checkPermission} method denies permission to deregister a driver.
392 *
393 * @see SecurityManager#checkPermission
J. Duke319a3b92007-12-01 00:00:00 +0000394 */
Mandy Chung176ed8d2013-04-16 21:39:52 -0700395 @CallerSensitive
Lance Andersenddcbf612014-12-18 18:51:28 -0500396 public static void deregisterDriver(Driver driver) throws SQLException {
Lance Andersen725342d2011-03-17 11:37:06 -0400397 if (driver == null) {
398 return;
399 }
400
Lance Andersen785f0d22013-04-30 14:44:25 -0400401 SecurityManager sec = System.getSecurityManager();
402 if (sec != null) {
403 sec.checkPermission(DEREGISTER_DRIVER_PERMISSION);
404 }
405
J. Duke319a3b92007-12-01 00:00:00 +0000406 println("DriverManager.deregisterDriver: " + driver);
407
Lance Andersen785f0d22013-04-30 14:44:25 -0400408 DriverInfo aDriver = new DriverInfo(driver, null);
Lance Andersenddcbf612014-12-18 18:51:28 -0500409 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 }
Lance Andersen725342d2011-03-17 11:37:06 -0400424 } else {
Lance Andersenddcbf612014-12-18 18:51:28 -0500425 println(" couldn't find driver to unload");
J. Duke319a3b92007-12-01 00:00:00 +0000426 }
J. Duke319a3b92007-12-01 00:00:00 +0000427 }
J. Duke319a3b92007-12-01 00:00:00 +0000428 }
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
Paul Sandoze56c76e2015-06-09 07:10:02 +0100438 * @see #drivers()
J. Duke319a3b92007-12-01 00:00:00 +0000439 */
Mandy Chung176ed8d2013-04-16 21:39:52 -0700440 @CallerSensitive
Paul Sandoze56c76e2015-06-09 07:10:02 +0100441 public static Enumeration<Driver> getDrivers() {
Lance Andersenddcbf612014-12-18 18:51:28 -0500442 ensureDriversInitialized();
443
Paul Sandoze56c76e2015-06-09 07:10:02 +0100444 return Collections.enumeration(getDrivers(Reflection.getCallerClass()));
445 }
J. Duke319a3b92007-12-01 00:00:00 +0000446
Paul Sandoze56c76e2015-06-09 07:10:02 +0100447 /**
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
Iris Clark9d07dc02016-01-20 11:02:36 -0800452 * @since 9
Paul Sandoze56c76e2015-06-09 07:10:02 +0100453 */
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<>();
Lance Andersen725342d2011-03-17 11:37:06 -0400463 // Walk through the loaded registeredDrivers.
Lance Andersenddcbf612014-12-18 18:51:28 -0500464 for (DriverInfo aDriver : registeredDrivers) {
J. Duke319a3b92007-12-01 00:00:00 +0000465 // If the caller does not have permission to load the driver then
466 // skip it.
Lance Andersen7e500d52014-12-03 16:50:55 -0500467 if (isDriverAllowed(aDriver.driver, callerClass)) {
Paul Sandoze56c76e2015-06-09 07:10:02 +0100468 result.add(aDriver.driver);
Lance Andersen725342d2011-03-17 11:37:06 -0400469 } else {
470 println(" skipping: " + aDriver.getClass().getName());
J. Duke319a3b92007-12-01 00:00:00 +0000471 }
J. Duke319a3b92007-12-01 00:00:00 +0000472 }
Paul Sandoze56c76e2015-06-09 07:10:02 +0100473 return result;
J. Duke319a3b92007-12-01 00:00:00 +0000474 }
475
J. Duke319a3b92007-12-01 00:00:00 +0000476 /**
477 * Sets the maximum time in seconds that a driver will wait
Lance Andersen69757a12013-01-19 10:53:14 -0500478 * while attempting to connect to a database once the driver has
479 * been identified.
J. Duke319a3b92007-12-01 00:00:00 +0000480 *
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>
Lance Andersen2a6e8cc2012-10-10 11:15:27 -0400511 * @deprecated Use {@code setLogWriter}
J. Duke319a3b92007-12-01 00:00:00 +0000512 * @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 */
Lance Andersen2a3853c2012-10-09 08:58:27 -0400518 @Deprecated
J. Duke319a3b92007-12-01 00:00:00 +0000519 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>
Lance Andersen2a6e8cc2012-10-10 11:15:27 -0400538 * @deprecated Use {@code getLogWriter}
J. Duke319a3b92007-12-01 00:00:00 +0000539 * @see #setLogStream
540 */
Lance Andersen2a3853c2012-10-09 08:58:27 -0400541 @Deprecated
J. Duke319a3b92007-12-01 00:00:00 +0000542 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
Lance Andersen725342d2011-03-17 11:37:06 -0400564 // Indicates whether the class object that would be created if the code calling
565 // DriverManager is accessible.
Mandy Chung176ed8d2013-04-16 21:39:52 -0700566 private static boolean isDriverAllowed(Driver driver, Class<?> caller) {
567 ClassLoader callerCL = caller != null ? caller.getClassLoader() : null;
568 return isDriverAllowed(driver, callerCL);
569 }
570
Lance Andersen725342d2011-03-17 11:37:06 -0400571 private static boolean isDriverAllowed(Driver driver, ClassLoader classLoader) {
572 boolean result = false;
Lance Andersen7e500d52014-12-03 16:50:55 -0500573 if (driver != null) {
Lance Andersen725342d2011-03-17 11:37:06 -0400574 Class<?> aClass = null;
575 try {
576 aClass = Class.forName(driver.getClass().getName(), true, classLoader);
577 } catch (Exception ex) {
578 result = false;
579 }
J. Duke319a3b92007-12-01 00:00:00 +0000580
Lance Andersen725342d2011-03-17 11:37:06 -0400581 result = ( aClass == driver.getClass() ) ? true : false;
J. Duke319a3b92007-12-01 00:00:00 +0000582 }
583
Lance Andersen725342d2011-03-17 11:37:06 -0400584 return result;
J. Duke319a3b92007-12-01 00:00:00 +0000585 }
586
Lance Andersen7e500d52014-12-03 16:50:55 -0500587 /*
Lance Andersen7e500d52014-12-03 16:50:55 -0500588 * Load the initial JDBC drivers by checking the System property
Lance Andersenddcbf612014-12-18 18:51:28 -0500589 * jdbc.drivers and then use the {@code ServiceLoader} mechanism
Lance Andersen7e500d52014-12-03 16:50:55 -0500590 */
Lance Andersenddcbf612014-12-18 18:51:28 -0500591 private static void ensureDriversInitialized() {
Lance Andersen7e500d52014-12-03 16:50:55 -0500592 if (driversInitialized) {
593 return;
594 }
595
Lance Andersenddcbf612014-12-18 18:51:28 -0500596 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;
J. Duke319a3b92007-12-01 00:00:00 +0000641 }
642 });
J. Duke319a3b92007-12-01 00:00:00 +0000643
Lance Andersenddcbf612014-12-18 18:51:28 -0500644 println("DriverManager.initialize: jdbc.drivers = " + drivers);
J. Duke319a3b92007-12-01 00:00:00 +0000645
Lance Andersenddcbf612014-12-18 18:51:28 -0500646 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);
J. Duke319a3b92007-12-01 00:00:00 +0000656 }
J. Duke319a3b92007-12-01 00:00:00 +0000657 }
J. Duke319a3b92007-12-01 00:00:00 +0000658 }
J. Duke319a3b92007-12-01 00:00:00 +0000659
Lance Andersenddcbf612014-12-18 18:51:28 -0500660 driversInitialized = true;
661 println("JDBC DriverManager initialized");
J. Duke319a3b92007-12-01 00:00:00 +0000662 }
J. Duke319a3b92007-12-01 00:00:00 +0000663 }
664
665
666 // Worker method called by the public getConnection() methods.
667 private static Connection getConnection(
Mandy Chung176ed8d2013-04-16 21:39:52 -0700668 String url, java.util.Properties info, Class<?> caller) throws SQLException {
J. Duke319a3b92007-12-01 00:00:00 +0000669 /*
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 */
Mandy Chung176ed8d2013-04-16 21:39:52 -0700675 ClassLoader callerCL = caller != null ? caller.getClassLoader() : null;
Lance Andersen7e500d52014-12-03 16:50:55 -0500676 if (callerCL == null) {
677 callerCL = Thread.currentThread().getContextClassLoader();
J. Duke319a3b92007-12-01 00:00:00 +0000678 }
679
Lance Andersen7e500d52014-12-03 16:50:55 -0500680 if (url == null) {
J. Duke319a3b92007-12-01 00:00:00 +0000681 throw new SQLException("The url cannot be null", "08001");
682 }
683
684 println("DriverManager.getConnection(\"" + url + "\")");
685
Lance Andersenddcbf612014-12-18 18:51:28 -0500686 ensureDriversInitialized();
687
Lance Andersen725342d2011-03-17 11:37:06 -0400688 // Walk through the loaded registeredDrivers attempting to make a connection.
J. Duke319a3b92007-12-01 00:00:00 +0000689 // Remember the first exception that gets raised so we can reraise it.
690 SQLException reason = null;
J. Duke319a3b92007-12-01 00:00:00 +0000691
Lance Andersenddcbf612014-12-18 18:51:28 -0500692 for (DriverInfo aDriver : registeredDrivers) {
J. Duke319a3b92007-12-01 00:00:00 +0000693 // If the caller does not have permission to load the driver then
694 // skip it.
Lance Andersen7e500d52014-12-03 16:50:55 -0500695 if (isDriverAllowed(aDriver.driver, callerCL)) {
Lance Andersen725342d2011-03-17 11:37:06 -0400696 try {
Lance Andersen56352662011-04-06 17:37:36 -0400697 println(" trying " + aDriver.driver.getClass().getName());
698 Connection con = aDriver.driver.connect(url, info);
Lance Andersen725342d2011-03-17 11:37:06 -0400699 if (con != null) {
700 // Success!
Lance Andersen56352662011-04-06 17:37:36 -0400701 println("getConnection returning " + aDriver.driver.getClass().getName());
Lance Andersen725342d2011-03-17 11:37:06 -0400702 return (con);
703 }
704 } catch (SQLException ex) {
705 if (reason == null) {
706 reason = ex;
707 }
J. Duke319a3b92007-12-01 00:00:00 +0000708 }
Lance Andersen725342d2011-03-17 11:37:06 -0400709
710 } else {
711 println(" skipping: " + aDriver.getClass().getName());
J. Duke319a3b92007-12-01 00:00:00 +0000712 }
Lance Andersen725342d2011-03-17 11:37:06 -0400713
J. Duke319a3b92007-12-01 00:00:00 +0000714 }
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
J. Duke319a3b92007-12-01 00:00:00 +0000726
727}
Lance Andersen56352662011-04-06 17:37:36 -0400728
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 */
734class DriverInfo {
735
736 final Driver driver;
Lance Andersen785f0d22013-04-30 14:44:25 -0400737 DriverAction da;
738 DriverInfo(Driver driver, DriverAction action) {
Lance Andersen56352662011-04-06 17:37:36 -0400739 this.driver = driver;
Lance Andersen785f0d22013-04-30 14:44:25 -0400740 da = action;
Lance Andersen56352662011-04-06 17:37:36 -0400741 }
742
Lance Andersen1c74eea2011-12-02 19:33:54 -0500743 @Override
Lance Andersen56352662011-04-06 17:37:36 -0400744 public boolean equals(Object other) {
745 return (other instanceof DriverInfo)
746 && this.driver == ((DriverInfo) other).driver;
747 }
748
Lance Andersen1c74eea2011-12-02 19:33:54 -0500749 @Override
Lance Andersen56352662011-04-06 17:37:36 -0400750 public int hashCode() {
751 return driver.hashCode();
752 }
753
Lance Andersen1c74eea2011-12-02 19:33:54 -0500754 @Override
Lance Andersen56352662011-04-06 17:37:36 -0400755 public String toString() {
756 return ("driver[className=" + driver + "]");
757 }
Lance Andersen785f0d22013-04-30 14:44:25 -0400758
759 DriverAction action() {
760 return da;
761 }
Lance Andersen56352662011-04-06 17:37:36 -0400762}