|
1 /* |
|
2 * Copyright (c) 1996, 2017, Oracle and/or its affiliates. All rights reserved. |
|
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
|
4 * |
|
5 * This code is free software; you can redistribute it and/or modify it |
|
6 * under the terms of the GNU General Public License version 2 only, as |
|
7 * published by the Free Software Foundation. Oracle designates this |
|
8 * particular file as subject to the "Classpath" exception as provided |
|
9 * by Oracle in the LICENSE file that accompanied this code. |
|
10 * |
|
11 * This code is distributed in the hope that it will be useful, but WITHOUT |
|
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
|
14 * version 2 for more details (a copy is included in the LICENSE file that |
|
15 * accompanied this code). |
|
16 * |
|
17 * You should have received a copy of the GNU General Public License version |
|
18 * 2 along with this work; if not, write to the Free Software Foundation, |
|
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
|
20 * |
|
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
|
22 * or visit www.oracle.com if you need additional information or have any |
|
23 * questions. |
|
24 */ |
|
25 |
|
26 package java.sql; |
|
27 |
|
28 import java.util.ArrayList; |
|
29 import java.util.Collections; |
|
30 import java.util.Enumeration; |
|
31 import java.util.Iterator; |
|
32 import java.util.List; |
|
33 import java.util.ServiceLoader; |
|
34 import java.security.AccessController; |
|
35 import java.security.PrivilegedAction; |
|
36 import java.util.concurrent.CopyOnWriteArrayList; |
|
37 import java.util.stream.Stream; |
|
38 |
|
39 import jdk.internal.reflect.CallerSensitive; |
|
40 import jdk.internal.reflect.Reflection; |
|
41 |
|
42 |
|
43 /** |
|
44 * The basic service for managing a set of JDBC drivers. |
|
45 * <p> |
|
46 * <strong>NOTE:</strong> The {@link javax.sql.DataSource} interface, provides |
|
47 * another way to connect to a data source. |
|
48 * The use of a {@code DataSource} object is the preferred means of |
|
49 * connecting to a data source. |
|
50 * <P> |
|
51 * As part of its initialization, the {@code DriverManager} class will |
|
52 * attempt to load available JDBC drivers by using: |
|
53 * <ul> |
|
54 * <li>The {@code jdbc.drivers} system property which contains a |
|
55 * colon separated list of fully qualified class names of JDBC drivers. Each |
|
56 * driver is loaded using the {@linkplain ClassLoader#getSystemClassLoader |
|
57 * system class loader}: |
|
58 * <ul> |
|
59 * <li>{@code jdbc.drivers=foo.bah.Driver:wombat.sql.Driver:bad.taste.ourDriver} |
|
60 * </ul> |
|
61 * |
|
62 * <li>Service providers of the {@code java.sql.Driver} class, that are loaded |
|
63 * via the {@linkplain ServiceLoader#load service-provider loading} mechanism. |
|
64 *</ul> |
|
65 * |
|
66 * @implNote |
|
67 * {@code DriverManager} initialization is done lazily and looks up service |
|
68 * providers using the thread context class loader. The drivers loaded and |
|
69 * available to an application will depend on the thread context class loader of |
|
70 * the thread that triggers driver initialization by {@code DriverManager}. |
|
71 * |
|
72 * <P>When the method {@code getConnection} is called, |
|
73 * the {@code DriverManager} will attempt to |
|
74 * locate a suitable driver from amongst those loaded at |
|
75 * initialization and those loaded explicitly using the same class loader |
|
76 * as the current application. |
|
77 * |
|
78 * @see Driver |
|
79 * @see Connection |
|
80 * @since 1.1 |
|
81 */ |
|
82 public class DriverManager { |
|
83 |
|
84 |
|
85 // List of registered JDBC drivers |
|
86 private final static CopyOnWriteArrayList<DriverInfo> registeredDrivers = new CopyOnWriteArrayList<>(); |
|
87 private static volatile int loginTimeout = 0; |
|
88 private static volatile java.io.PrintWriter logWriter = null; |
|
89 private static volatile java.io.PrintStream logStream = null; |
|
90 // Used in println() to synchronize logWriter |
|
91 private final static Object logSync = new Object(); |
|
92 // Used in ensureDriversInitialized() to synchronize driversInitialized |
|
93 private final static Object lockForInitDrivers = new Object(); |
|
94 private static volatile boolean driversInitialized; |
|
95 private static final String JDBC_DRIVERS_PROPERTY = "jdbc.drivers"; |
|
96 |
|
97 /* Prevent the DriverManager class from being instantiated. */ |
|
98 private DriverManager(){} |
|
99 |
|
100 /** |
|
101 * The <code>SQLPermission</code> constant that allows the |
|
102 * setting of the logging stream. |
|
103 * @since 1.3 |
|
104 */ |
|
105 final static SQLPermission SET_LOG_PERMISSION = |
|
106 new SQLPermission("setLog"); |
|
107 |
|
108 /** |
|
109 * The {@code SQLPermission} constant that allows the |
|
110 * un-register a registered JDBC driver. |
|
111 * @since 1.8 |
|
112 */ |
|
113 final static SQLPermission DEREGISTER_DRIVER_PERMISSION = |
|
114 new SQLPermission("deregisterDriver"); |
|
115 |
|
116 //--------------------------JDBC 2.0----------------------------- |
|
117 |
|
118 /** |
|
119 * Retrieves the log writer. |
|
120 * |
|
121 * The <code>getLogWriter</code> and <code>setLogWriter</code> |
|
122 * methods should be used instead |
|
123 * of the <code>get/setlogStream</code> methods, which are deprecated. |
|
124 * @return a <code>java.io.PrintWriter</code> object |
|
125 * @see #setLogWriter |
|
126 * @since 1.2 |
|
127 */ |
|
128 public static java.io.PrintWriter getLogWriter() { |
|
129 return logWriter; |
|
130 } |
|
131 |
|
132 /** |
|
133 * Sets the logging/tracing <code>PrintWriter</code> object |
|
134 * that is used by the <code>DriverManager</code> and all drivers. |
|
135 *<P> |
|
136 * If a security manager exists, its {@code checkPermission} |
|
137 * method is first called with a {@code SQLPermission("setLog")} |
|
138 * permission to check that the caller is allowed to call {@code setLogWriter}. |
|
139 * |
|
140 * @param out the new logging/tracing <code>PrintStream</code> object; |
|
141 * <code>null</code> to disable logging and tracing |
|
142 * @throws SecurityException if a security manager exists and its |
|
143 * {@code checkPermission} method denies permission to set the log writer. |
|
144 * @see SecurityManager#checkPermission |
|
145 * @see #getLogWriter |
|
146 * @since 1.2 |
|
147 */ |
|
148 public static void setLogWriter(java.io.PrintWriter out) { |
|
149 |
|
150 SecurityManager sec = System.getSecurityManager(); |
|
151 if (sec != null) { |
|
152 sec.checkPermission(SET_LOG_PERMISSION); |
|
153 } |
|
154 logStream = null; |
|
155 logWriter = out; |
|
156 } |
|
157 |
|
158 |
|
159 //--------------------------------------------------------------- |
|
160 |
|
161 /** |
|
162 * Attempts to establish a connection to the given database URL. |
|
163 * The <code>DriverManager</code> attempts to select an appropriate driver from |
|
164 * the set of registered JDBC drivers. |
|
165 *<p> |
|
166 * <B>Note:</B> If a property is specified as part of the {@code url} and |
|
167 * is also specified in the {@code Properties} object, it is |
|
168 * implementation-defined as to which value will take precedence. |
|
169 * For maximum portability, an application should only specify a |
|
170 * property once. |
|
171 * |
|
172 * @param url a database url of the form |
|
173 * <code> jdbc:<em>subprotocol</em>:<em>subname</em></code> |
|
174 * @param info a list of arbitrary string tag/value pairs as |
|
175 * connection arguments; normally at least a "user" and |
|
176 * "password" property should be included |
|
177 * @return a Connection to the URL |
|
178 * @exception SQLException if a database access error occurs or the url is |
|
179 * {@code null} |
|
180 * @throws SQLTimeoutException when the driver has determined that the |
|
181 * timeout value specified by the {@code setLoginTimeout} method |
|
182 * has been exceeded and has at least tried to cancel the |
|
183 * current database connection attempt |
|
184 */ |
|
185 @CallerSensitive |
|
186 public static Connection getConnection(String url, |
|
187 java.util.Properties info) throws SQLException { |
|
188 |
|
189 return (getConnection(url, info, Reflection.getCallerClass())); |
|
190 } |
|
191 |
|
192 /** |
|
193 * Attempts to establish a connection to the given database URL. |
|
194 * The <code>DriverManager</code> attempts to select an appropriate driver from |
|
195 * the set of registered JDBC drivers. |
|
196 *<p> |
|
197 * <B>Note:</B> If the {@code user} or {@code password} property are |
|
198 * also specified as part of the {@code url}, it is |
|
199 * implementation-defined as to which value will take precedence. |
|
200 * For maximum portability, an application should only specify a |
|
201 * property once. |
|
202 * |
|
203 * @param url a database url of the form |
|
204 * <code>jdbc:<em>subprotocol</em>:<em>subname</em></code> |
|
205 * @param user the database user on whose behalf the connection is being |
|
206 * made |
|
207 * @param password the user's password |
|
208 * @return a connection to the URL |
|
209 * @exception SQLException if a database access error occurs or the url is |
|
210 * {@code null} |
|
211 * @throws SQLTimeoutException when the driver has determined that the |
|
212 * timeout value specified by the {@code setLoginTimeout} method |
|
213 * has been exceeded and has at least tried to cancel the |
|
214 * current database connection attempt |
|
215 */ |
|
216 @CallerSensitive |
|
217 public static Connection getConnection(String url, |
|
218 String user, String password) throws SQLException { |
|
219 java.util.Properties info = new java.util.Properties(); |
|
220 |
|
221 if (user != null) { |
|
222 info.put("user", user); |
|
223 } |
|
224 if (password != null) { |
|
225 info.put("password", password); |
|
226 } |
|
227 |
|
228 return (getConnection(url, info, Reflection.getCallerClass())); |
|
229 } |
|
230 |
|
231 /** |
|
232 * Attempts to establish a connection to the given database URL. |
|
233 * The <code>DriverManager</code> attempts to select an appropriate driver from |
|
234 * the set of registered JDBC drivers. |
|
235 * |
|
236 * @param url a database url of the form |
|
237 * <code> jdbc:<em>subprotocol</em>:<em>subname</em></code> |
|
238 * @return a connection to the URL |
|
239 * @exception SQLException if a database access error occurs or the url is |
|
240 * {@code null} |
|
241 * @throws SQLTimeoutException when the driver has determined that the |
|
242 * timeout value specified by the {@code setLoginTimeout} method |
|
243 * has been exceeded and has at least tried to cancel the |
|
244 * current database connection attempt |
|
245 */ |
|
246 @CallerSensitive |
|
247 public static Connection getConnection(String url) |
|
248 throws SQLException { |
|
249 |
|
250 java.util.Properties info = new java.util.Properties(); |
|
251 return (getConnection(url, info, Reflection.getCallerClass())); |
|
252 } |
|
253 |
|
254 /** |
|
255 * Attempts to locate a driver that understands the given URL. |
|
256 * The <code>DriverManager</code> attempts to select an appropriate driver from |
|
257 * the set of registered JDBC drivers. |
|
258 * |
|
259 * @param url a database URL of the form |
|
260 * <code>jdbc:<em>subprotocol</em>:<em>subname</em></code> |
|
261 * @return a <code>Driver</code> object representing a driver |
|
262 * that can connect to the given URL |
|
263 * @exception SQLException if a database access error occurs |
|
264 */ |
|
265 @CallerSensitive |
|
266 public static Driver getDriver(String url) |
|
267 throws SQLException { |
|
268 |
|
269 println("DriverManager.getDriver(\"" + url + "\")"); |
|
270 |
|
271 ensureDriversInitialized(); |
|
272 |
|
273 Class<?> callerClass = Reflection.getCallerClass(); |
|
274 |
|
275 // Walk through the loaded registeredDrivers attempting to locate someone |
|
276 // who understands the given URL. |
|
277 for (DriverInfo aDriver : registeredDrivers) { |
|
278 // If the caller does not have permission to load the driver then |
|
279 // skip it. |
|
280 if (isDriverAllowed(aDriver.driver, callerClass)) { |
|
281 try { |
|
282 if (aDriver.driver.acceptsURL(url)) { |
|
283 // Success! |
|
284 println("getDriver returning " + aDriver.driver.getClass().getName()); |
|
285 return (aDriver.driver); |
|
286 } |
|
287 |
|
288 } catch(SQLException sqe) { |
|
289 // Drop through and try the next driver. |
|
290 } |
|
291 } else { |
|
292 println(" skipping: " + aDriver.driver.getClass().getName()); |
|
293 } |
|
294 |
|
295 } |
|
296 |
|
297 println("getDriver: no suitable driver"); |
|
298 throw new SQLException("No suitable driver", "08001"); |
|
299 } |
|
300 |
|
301 |
|
302 /** |
|
303 * Registers the given driver with the {@code DriverManager}. |
|
304 * A newly-loaded driver class should call |
|
305 * the method {@code registerDriver} to make itself |
|
306 * known to the {@code DriverManager}. If the driver is currently |
|
307 * registered, no action is taken. |
|
308 * |
|
309 * @param driver the new JDBC Driver that is to be registered with the |
|
310 * {@code DriverManager} |
|
311 * @exception SQLException if a database access error occurs |
|
312 * @exception NullPointerException if {@code driver} is null |
|
313 */ |
|
314 public static void registerDriver(java.sql.Driver driver) |
|
315 throws SQLException { |
|
316 |
|
317 registerDriver(driver, null); |
|
318 } |
|
319 |
|
320 /** |
|
321 * Registers the given driver with the {@code DriverManager}. |
|
322 * A newly-loaded driver class should call |
|
323 * the method {@code registerDriver} to make itself |
|
324 * known to the {@code DriverManager}. If the driver is currently |
|
325 * registered, no action is taken. |
|
326 * |
|
327 * @param driver the new JDBC Driver that is to be registered with the |
|
328 * {@code DriverManager} |
|
329 * @param da the {@code DriverAction} implementation to be used when |
|
330 * {@code DriverManager#deregisterDriver} is called |
|
331 * @exception SQLException if a database access error occurs |
|
332 * @exception NullPointerException if {@code driver} is null |
|
333 * @since 1.8 |
|
334 */ |
|
335 public static void registerDriver(java.sql.Driver driver, |
|
336 DriverAction da) |
|
337 throws SQLException { |
|
338 |
|
339 /* Register the driver if it has not already been added to our list */ |
|
340 if (driver != null) { |
|
341 registeredDrivers.addIfAbsent(new DriverInfo(driver, da)); |
|
342 } else { |
|
343 // This is for compatibility with the original DriverManager |
|
344 throw new NullPointerException(); |
|
345 } |
|
346 |
|
347 println("registerDriver: " + driver); |
|
348 |
|
349 } |
|
350 |
|
351 /** |
|
352 * Removes the specified driver from the {@code DriverManager}'s list of |
|
353 * registered drivers. |
|
354 * <p> |
|
355 * If a {@code null} value is specified for the driver to be removed, then no |
|
356 * action is taken. |
|
357 * <p> |
|
358 * If a security manager exists, its {@code checkPermission} |
|
359 * method is first called with a {@code SQLPermission("deregisterDriver")} |
|
360 * permission to check that the caller is allowed to deregister a JDBC Driver. |
|
361 * <p> |
|
362 * If the specified driver is not found in the list of registered drivers, |
|
363 * then no action is taken. If the driver was found, it will be removed |
|
364 * from the list of registered drivers. |
|
365 * <p> |
|
366 * If a {@code DriverAction} instance was specified when the JDBC driver was |
|
367 * registered, its deregister method will be called |
|
368 * prior to the driver being removed from the list of registered drivers. |
|
369 * |
|
370 * @param driver the JDBC Driver to remove |
|
371 * @exception SQLException if a database access error occurs |
|
372 * @throws SecurityException if a security manager exists and its |
|
373 * {@code checkPermission} method denies permission to deregister a driver. |
|
374 * |
|
375 * @see SecurityManager#checkPermission |
|
376 */ |
|
377 @CallerSensitive |
|
378 public static void deregisterDriver(Driver driver) throws SQLException { |
|
379 if (driver == null) { |
|
380 return; |
|
381 } |
|
382 |
|
383 SecurityManager sec = System.getSecurityManager(); |
|
384 if (sec != null) { |
|
385 sec.checkPermission(DEREGISTER_DRIVER_PERMISSION); |
|
386 } |
|
387 |
|
388 println("DriverManager.deregisterDriver: " + driver); |
|
389 |
|
390 DriverInfo aDriver = new DriverInfo(driver, null); |
|
391 synchronized (lockForInitDrivers) { |
|
392 if (registeredDrivers.contains(aDriver)) { |
|
393 if (isDriverAllowed(driver, Reflection.getCallerClass())) { |
|
394 DriverInfo di = registeredDrivers.get(registeredDrivers.indexOf(aDriver)); |
|
395 // If a DriverAction was specified, Call it to notify the |
|
396 // driver that it has been deregistered |
|
397 if (di.action() != null) { |
|
398 di.action().deregister(); |
|
399 } |
|
400 registeredDrivers.remove(aDriver); |
|
401 } else { |
|
402 // If the caller does not have permission to load the driver then |
|
403 // throw a SecurityException. |
|
404 throw new SecurityException(); |
|
405 } |
|
406 } else { |
|
407 println(" couldn't find driver to unload"); |
|
408 } |
|
409 } |
|
410 } |
|
411 |
|
412 /** |
|
413 * Retrieves an Enumeration with all of the currently loaded JDBC drivers |
|
414 * to which the current caller has access. |
|
415 * |
|
416 * <P><B>Note:</B> The classname of a driver can be found using |
|
417 * <CODE>d.getClass().getName()</CODE> |
|
418 * |
|
419 * @return the list of JDBC Drivers loaded by the caller's class loader |
|
420 * @see #drivers() |
|
421 */ |
|
422 @CallerSensitive |
|
423 public static Enumeration<Driver> getDrivers() { |
|
424 ensureDriversInitialized(); |
|
425 |
|
426 return Collections.enumeration(getDrivers(Reflection.getCallerClass())); |
|
427 } |
|
428 |
|
429 /** |
|
430 * Retrieves a Stream with all of the currently loaded JDBC drivers |
|
431 * to which the current caller has access. |
|
432 * |
|
433 * @return the stream of JDBC Drivers loaded by the caller's class loader |
|
434 * @since 9 |
|
435 */ |
|
436 @CallerSensitive |
|
437 public static Stream<Driver> drivers() { |
|
438 ensureDriversInitialized(); |
|
439 |
|
440 return getDrivers(Reflection.getCallerClass()).stream(); |
|
441 } |
|
442 |
|
443 private static List<Driver> getDrivers(Class<?> callerClass) { |
|
444 List<Driver> result = new ArrayList<>(); |
|
445 // Walk through the loaded registeredDrivers. |
|
446 for (DriverInfo aDriver : registeredDrivers) { |
|
447 // If the caller does not have permission to load the driver then |
|
448 // skip it. |
|
449 if (isDriverAllowed(aDriver.driver, callerClass)) { |
|
450 result.add(aDriver.driver); |
|
451 } else { |
|
452 println(" skipping: " + aDriver.getClass().getName()); |
|
453 } |
|
454 } |
|
455 return result; |
|
456 } |
|
457 |
|
458 /** |
|
459 * Sets the maximum time in seconds that a driver will wait |
|
460 * while attempting to connect to a database once the driver has |
|
461 * been identified. |
|
462 * |
|
463 * @param seconds the login time limit in seconds; zero means there is no limit |
|
464 * @see #getLoginTimeout |
|
465 */ |
|
466 public static void setLoginTimeout(int seconds) { |
|
467 loginTimeout = seconds; |
|
468 } |
|
469 |
|
470 /** |
|
471 * Gets the maximum time in seconds that a driver can wait |
|
472 * when attempting to log in to a database. |
|
473 * |
|
474 * @return the driver login time limit in seconds |
|
475 * @see #setLoginTimeout |
|
476 */ |
|
477 public static int getLoginTimeout() { |
|
478 return (loginTimeout); |
|
479 } |
|
480 |
|
481 /** |
|
482 * Sets the logging/tracing PrintStream that is used |
|
483 * by the <code>DriverManager</code> |
|
484 * and all drivers. |
|
485 *<P> |
|
486 * If a security manager exists, its {@code checkPermission} |
|
487 * method is first called with a {@code SQLPermission("setLog")} |
|
488 * permission to check that the caller is allowed to call {@code setLogStream}. |
|
489 * |
|
490 * @param out the new logging/tracing PrintStream; to disable, set to <code>null</code> |
|
491 * @deprecated Use {@code setLogWriter} |
|
492 * @throws SecurityException if a security manager exists and its |
|
493 * {@code checkPermission} method denies permission to set the log stream. |
|
494 * @see SecurityManager#checkPermission |
|
495 * @see #getLogStream |
|
496 */ |
|
497 @Deprecated(since="1.2") |
|
498 public static void setLogStream(java.io.PrintStream out) { |
|
499 |
|
500 SecurityManager sec = System.getSecurityManager(); |
|
501 if (sec != null) { |
|
502 sec.checkPermission(SET_LOG_PERMISSION); |
|
503 } |
|
504 |
|
505 logStream = out; |
|
506 if ( out != null ) |
|
507 logWriter = new java.io.PrintWriter(out); |
|
508 else |
|
509 logWriter = null; |
|
510 } |
|
511 |
|
512 /** |
|
513 * Retrieves the logging/tracing PrintStream that is used by the <code>DriverManager</code> |
|
514 * and all drivers. |
|
515 * |
|
516 * @return the logging/tracing PrintStream; if disabled, is <code>null</code> |
|
517 * @deprecated Use {@code getLogWriter} |
|
518 * @see #setLogStream |
|
519 */ |
|
520 @Deprecated(since="1.2") |
|
521 public static java.io.PrintStream getLogStream() { |
|
522 return logStream; |
|
523 } |
|
524 |
|
525 /** |
|
526 * Prints a message to the current JDBC log stream. |
|
527 * |
|
528 * @param message a log or tracing message |
|
529 */ |
|
530 public static void println(String message) { |
|
531 synchronized (logSync) { |
|
532 if (logWriter != null) { |
|
533 logWriter.println(message); |
|
534 |
|
535 // automatic flushing is never enabled, so we must do it ourselves |
|
536 logWriter.flush(); |
|
537 } |
|
538 } |
|
539 } |
|
540 |
|
541 //------------------------------------------------------------------------ |
|
542 |
|
543 // Indicates whether the class object that would be created if the code calling |
|
544 // DriverManager is accessible. |
|
545 private static boolean isDriverAllowed(Driver driver, Class<?> caller) { |
|
546 ClassLoader callerCL = caller != null ? caller.getClassLoader() : null; |
|
547 return isDriverAllowed(driver, callerCL); |
|
548 } |
|
549 |
|
550 private static boolean isDriverAllowed(Driver driver, ClassLoader classLoader) { |
|
551 boolean result = false; |
|
552 if (driver != null) { |
|
553 Class<?> aClass = null; |
|
554 try { |
|
555 aClass = Class.forName(driver.getClass().getName(), true, classLoader); |
|
556 } catch (Exception ex) { |
|
557 result = false; |
|
558 } |
|
559 |
|
560 result = ( aClass == driver.getClass() ) ? true : false; |
|
561 } |
|
562 |
|
563 return result; |
|
564 } |
|
565 |
|
566 /* |
|
567 * Load the initial JDBC drivers by checking the System property |
|
568 * jdbc.drivers and then use the {@code ServiceLoader} mechanism |
|
569 */ |
|
570 private static void ensureDriversInitialized() { |
|
571 if (driversInitialized) { |
|
572 return; |
|
573 } |
|
574 |
|
575 synchronized (lockForInitDrivers) { |
|
576 if (driversInitialized) { |
|
577 return; |
|
578 } |
|
579 String drivers; |
|
580 try { |
|
581 drivers = AccessController.doPrivileged(new PrivilegedAction<String>() { |
|
582 public String run() { |
|
583 return System.getProperty(JDBC_DRIVERS_PROPERTY); |
|
584 } |
|
585 }); |
|
586 } catch (Exception ex) { |
|
587 drivers = null; |
|
588 } |
|
589 // If the driver is packaged as a Service Provider, load it. |
|
590 // Get all the drivers through the classloader |
|
591 // exposed as a java.sql.Driver.class service. |
|
592 // ServiceLoader.load() replaces the sun.misc.Providers() |
|
593 |
|
594 AccessController.doPrivileged(new PrivilegedAction<Void>() { |
|
595 public Void run() { |
|
596 |
|
597 ServiceLoader<Driver> loadedDrivers = ServiceLoader.load(Driver.class); |
|
598 Iterator<Driver> driversIterator = loadedDrivers.iterator(); |
|
599 |
|
600 /* Load these drivers, so that they can be instantiated. |
|
601 * It may be the case that the driver class may not be there |
|
602 * i.e. there may be a packaged driver with the service class |
|
603 * as implementation of java.sql.Driver but the actual class |
|
604 * may be missing. In that case a java.util.ServiceConfigurationError |
|
605 * will be thrown at runtime by the VM trying to locate |
|
606 * and load the service. |
|
607 * |
|
608 * Adding a try catch block to catch those runtime errors |
|
609 * if driver not available in classpath but it's |
|
610 * packaged as service and that service is there in classpath. |
|
611 */ |
|
612 try { |
|
613 while (driversIterator.hasNext()) { |
|
614 driversIterator.next(); |
|
615 } |
|
616 } catch (Throwable t) { |
|
617 // Do nothing |
|
618 } |
|
619 return null; |
|
620 } |
|
621 }); |
|
622 |
|
623 println("DriverManager.initialize: jdbc.drivers = " + drivers); |
|
624 |
|
625 if (drivers != null && !drivers.equals("")) { |
|
626 String[] driversList = drivers.split(":"); |
|
627 println("number of Drivers:" + driversList.length); |
|
628 for (String aDriver : driversList) { |
|
629 try { |
|
630 println("DriverManager.Initialize: loading " + aDriver); |
|
631 Class.forName(aDriver, true, |
|
632 ClassLoader.getSystemClassLoader()); |
|
633 } catch (Exception ex) { |
|
634 println("DriverManager.Initialize: load failed: " + ex); |
|
635 } |
|
636 } |
|
637 } |
|
638 |
|
639 driversInitialized = true; |
|
640 println("JDBC DriverManager initialized"); |
|
641 } |
|
642 } |
|
643 |
|
644 |
|
645 // Worker method called by the public getConnection() methods. |
|
646 private static Connection getConnection( |
|
647 String url, java.util.Properties info, Class<?> caller) throws SQLException { |
|
648 /* |
|
649 * When callerCl is null, we should check the application's |
|
650 * (which is invoking this class indirectly) |
|
651 * classloader, so that the JDBC driver class outside rt.jar |
|
652 * can be loaded from here. |
|
653 */ |
|
654 ClassLoader callerCL = caller != null ? caller.getClassLoader() : null; |
|
655 if (callerCL == null) { |
|
656 callerCL = Thread.currentThread().getContextClassLoader(); |
|
657 } |
|
658 |
|
659 if (url == null) { |
|
660 throw new SQLException("The url cannot be null", "08001"); |
|
661 } |
|
662 |
|
663 println("DriverManager.getConnection(\"" + url + "\")"); |
|
664 |
|
665 ensureDriversInitialized(); |
|
666 |
|
667 // Walk through the loaded registeredDrivers attempting to make a connection. |
|
668 // Remember the first exception that gets raised so we can reraise it. |
|
669 SQLException reason = null; |
|
670 |
|
671 for (DriverInfo aDriver : registeredDrivers) { |
|
672 // If the caller does not have permission to load the driver then |
|
673 // skip it. |
|
674 if (isDriverAllowed(aDriver.driver, callerCL)) { |
|
675 try { |
|
676 println(" trying " + aDriver.driver.getClass().getName()); |
|
677 Connection con = aDriver.driver.connect(url, info); |
|
678 if (con != null) { |
|
679 // Success! |
|
680 println("getConnection returning " + aDriver.driver.getClass().getName()); |
|
681 return (con); |
|
682 } |
|
683 } catch (SQLException ex) { |
|
684 if (reason == null) { |
|
685 reason = ex; |
|
686 } |
|
687 } |
|
688 |
|
689 } else { |
|
690 println(" skipping: " + aDriver.getClass().getName()); |
|
691 } |
|
692 |
|
693 } |
|
694 |
|
695 // if we got here nobody could connect. |
|
696 if (reason != null) { |
|
697 println("getConnection failed: " + reason); |
|
698 throw reason; |
|
699 } |
|
700 |
|
701 println("getConnection: no suitable driver found for "+ url); |
|
702 throw new SQLException("No suitable driver found for "+ url, "08001"); |
|
703 } |
|
704 |
|
705 |
|
706 } |
|
707 |
|
708 /* |
|
709 * Wrapper class for registered Drivers in order to not expose Driver.equals() |
|
710 * to avoid the capture of the Driver it being compared to as it might not |
|
711 * normally have access. |
|
712 */ |
|
713 class DriverInfo { |
|
714 |
|
715 final Driver driver; |
|
716 DriverAction da; |
|
717 DriverInfo(Driver driver, DriverAction action) { |
|
718 this.driver = driver; |
|
719 da = action; |
|
720 } |
|
721 |
|
722 @Override |
|
723 public boolean equals(Object other) { |
|
724 return (other instanceof DriverInfo) |
|
725 && this.driver == ((DriverInfo) other).driver; |
|
726 } |
|
727 |
|
728 @Override |
|
729 public int hashCode() { |
|
730 return driver.hashCode(); |
|
731 } |
|
732 |
|
733 @Override |
|
734 public String toString() { |
|
735 return ("driver[className=" + driver + "]"); |
|
736 } |
|
737 |
|
738 DriverAction action() { |
|
739 return da; |
|
740 } |
|
741 } |