History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/java/sql/DriverManager.java (1 of 18352 files). Show all

Unified · Split

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