• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements.  See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License.  You may obtain a copy of the License at
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 
18 package java.sql;
19 
20 import java.util.ArrayList;
21 import java.util.List;
22 import java.util.Properties;
23 import java.util.Enumeration;
24 import java.util.Iterator;
25 import java.io.PrintStream;
26 import java.io.PrintWriter;
27 import java.util.Vector;
28 import java.security.AccessController;
29 import org.apache.harmony.luni.util.PriviAction;
30 import org.apache.harmony.sql.internal.nls.Messages;
31 // BEGIN android-changed
32 import dalvik.system.VMStack;
33 // END android-changed
34 
35 /**
36  * Provides facilities for managing JDBC drivers.
37  * <p>
38  * The {@code DriverManager} class loads JDBC drivers during its initialization,
39  * from the list of drivers referenced by the system property {@code
40  * "jdbc.drivers"}.
41  */
42 public class DriverManager {
43 
44     /*
45      * Facilities for logging. The Print Stream is deprecated but is maintained
46      * here for compatibility.
47      */
48     private static PrintStream thePrintStream;
49 
50     private static PrintWriter thePrintWriter;
51 
52     // Login timeout value - by default set to 0 -> "wait forever"
53     private static int loginTimeout = 0;
54 
55     /*
56      * Set to hold Registered Drivers - initial capacity 10 drivers (will expand
57      * automatically if necessary.
58      */
59     private static final List<Driver> theDrivers = new ArrayList<Driver>(10);
60 
61     // Permission for setting log
62     private static final SQLPermission logPermission = new SQLPermission(
63             "setLog"); //$NON-NLS-1$
64 
65     /*
66      * Load drivers on initialization
67      */
68     static {
loadInitialDrivers()69         loadInitialDrivers();
70     }
71 
72     /*
73      * Loads the set of JDBC drivers defined by the Property "jdbc.drivers" if
74      * it is defined.
75      */
loadInitialDrivers()76     private static void loadInitialDrivers() {
77         String theDriverList = AccessController
78                 .doPrivileged(new PriviAction<String>("jdbc.drivers", null)); //$NON-NLS-1$
79 
80         if (theDriverList == null) {
81             return;
82         }
83 
84         /*
85          * Get the names of the drivers as an array of Strings from the system
86          * property by splitting the property at the separator character ':'
87          */
88         String[] theDriverNames = theDriverList.split(":"); //$NON-NLS-1$
89 
90         for (String element : theDriverNames) {
91             try {
92                 // Load the driver class
93                 Class
94                         .forName(element, true, ClassLoader
95                                 .getSystemClassLoader());
96             } catch (Throwable t) {
97                 // Ignored
98             }
99         }
100     }
101 
102     /*
103      * A private constructor to prevent allocation
104      */
DriverManager()105     private DriverManager() {
106         super();
107     }
108 
109     /**
110      * Removes a driver from the {@code DriverManager}'s registered driver list.
111      * This will only succeed when the caller's class loader loaded the driver
112      * that is to be removed. If the driver was loaded by a different class
113      * loader, the removal of the driver fails silently.
114      * <p>
115      * If the removal succeeds, the {@code DriverManager} will not use this
116      * driver in the future when asked to get a {@code Connection}.
117      *
118      * @param driver
119      *            the JDBC driver to remove.
120      * @throws SQLException
121      *             if there is a problem interfering with accessing the
122      *             database.
123      */
deregisterDriver(Driver driver)124     public static void deregisterDriver(Driver driver) throws SQLException {
125         if (driver == null) {
126             return;
127         }
128         // BEGIN android-changed
129         ClassLoader callerClassLoader = VMStack.getCallingClassLoader();
130         // END android-changed
131 
132         if (!DriverManager.isClassFromClassLoader(driver, callerClassLoader)) {
133             // sql.1=DriverManager: calling class not authorized to deregister
134             // JDBC driver
135             throw new SecurityException(Messages.getString("sql.1")); //$NON-NLS-1$
136         } // end if
137         synchronized (theDrivers) {
138             theDrivers.remove(driver);
139         }
140     }
141 
142     /**
143      * Attempts to establish a connection to the given database URL.
144      *
145      * @param url
146      *            a URL string representing the database target to connect with.
147      * @return a {@code Connection} to the database identified by the URL.
148      *         {@code null} if no connection can be established.
149      * @throws SQLException
150      *             if there is an error while attempting to connect to the
151      *             database identified by the URL.
152      */
getConnection(String url)153     public static Connection getConnection(String url) throws SQLException {
154         return getConnection(url, new Properties());
155     }
156 
157     /**
158      * Attempts to establish a connection to the given database URL.
159      *
160      * @param url
161      *            a URL string representing the database target to connect with
162      * @param info
163      *            a set of properties to use as arguments to set up the
164      *            connection. Properties are arbitrary string/value pairs.
165      *            Normally, at least the properties {@code "user"} and {@code
166      *            "password"} should be passed, with appropriate settings for
167      *            the user ID and its corresponding password to get access to
168      *            the corresponding database.
169      * @return a {@code Connection} to the database identified by the URL.
170      *         {@code null} if no connection can be established.
171      * @throws SQLException
172      *             if there is an error while attempting to connect to the
173      *             database identified by the URL.
174      */
getConnection(String url, Properties info)175     public static Connection getConnection(String url, Properties info)
176             throws SQLException {
177         // 08 - connection exception
178         // 001 - SQL-client unable to establish SQL-connection
179         String sqlState = "08001"; //$NON-NLS-1$
180         if (url == null) {
181             // sql.5=The url cannot be null
182             throw new SQLException(Messages.getString("sql.5"), sqlState); //$NON-NLS-1$
183         }
184         synchronized (theDrivers) {
185             /*
186              * Loop over the drivers in the DriverSet checking to see if one can
187              * open a connection to the supplied URL - return the first
188              * connection which is returned
189              */
190             for (Driver theDriver : theDrivers) {
191                 Connection theConnection = theDriver.connect(url, info);
192                 if (theConnection != null) {
193                     return theConnection;
194                 }
195             }
196         }
197         // If we get here, none of the drivers are able to resolve the URL
198         // sql.6=No suitable driver
199         throw new SQLException(Messages.getString("sql.6"), sqlState); //$NON-NLS-1$
200     }
201 
202     /**
203      * Attempts to establish a connection to the given database URL.
204      *
205      * @param url
206      *            a URL string representing the database target to connect with.
207      * @param user
208      *            a user ID used to login to the database.
209      * @param password
210      *            a password for the user ID to login to the database.
211      * @return a {@code Connection} to the database identified by the URL.
212      *         {@code null} if no connection can be established.
213      * @throws SQLException
214      *             if there is an error while attempting to connect to the
215      *             database identified by the URL.
216      */
getConnection(String url, String user, String password)217     public static Connection getConnection(String url, String user,
218             String password) throws SQLException {
219         Properties theProperties = new Properties();
220         if (null != user) {
221             theProperties.setProperty("user", user); //$NON-NLS-1$
222         }
223         if (null != password) {
224             theProperties.setProperty("password", password); //$NON-NLS-1$
225         }
226         return getConnection(url, theProperties);
227     }
228 
229     /**
230      * Tries to find a driver that can interpret the supplied URL.
231      *
232      * @param url
233      *            the URL of a database.
234      * @return a {@code Driver} that matches the provided URL. {@code null} if
235      *         no {@code Driver} understands the URL
236      * @throws SQLException
237      *             if there is any kind of problem accessing the database.
238      */
getDriver(String url)239     public static Driver getDriver(String url) throws SQLException {
240         // BEGIN android-changed
241         ClassLoader callerClassLoader = VMStack.getCallingClassLoader();
242         // END android-changed
243 
244         synchronized (theDrivers) {
245             /*
246              * Loop over the drivers in the DriverSet checking to see if one
247              * does understand the supplied URL - return the first driver which
248              * does understand the URL
249              */
250             Iterator<Driver> theIterator = theDrivers.iterator();
251             while (theIterator.hasNext()) {
252                 Driver theDriver = theIterator.next();
253                 if (theDriver.acceptsURL(url)
254                         && DriverManager.isClassFromClassLoader(theDriver,
255                                 callerClassLoader)) {
256                     return theDriver;
257                 }
258             }
259         }
260         // If no drivers understand the URL, throw an SQLException
261         // sql.6=No suitable driver
262         // SQLState: 08 - connection exception
263         // 001 - SQL-client unable to establish SQL-connection
264         throw new SQLException(Messages.getString("sql.6"), "08001"); //$NON-NLS-1$ //$NON-NLS-2$
265     }
266 
267     /**
268      * Returns an {@code Enumeration} that contains all of the loaded JDBC
269      * drivers that the current caller can access.
270      *
271      * @return An {@code Enumeration} containing all the currently loaded JDBC
272      *         {@code Drivers}.
273      */
getDrivers()274     public static Enumeration<Driver> getDrivers() {
275         // BEGIN android-changed
276         ClassLoader callerClassLoader = VMStack.getCallingClassLoader();
277         // END android-changed
278         /*
279          * Synchronize to avoid clashes with additions and removals of drivers
280          * in the DriverSet
281          */
282         synchronized (theDrivers) {
283             /*
284              * Create the Enumeration by building a Vector from the elements of
285              * the DriverSet
286              */
287             Vector<Driver> theVector = new Vector<Driver>();
288             Iterator<Driver> theIterator = theDrivers.iterator();
289             while (theIterator.hasNext()) {
290                 Driver theDriver = theIterator.next();
291                 if (DriverManager.isClassFromClassLoader(theDriver,
292                         callerClassLoader)) {
293                     theVector.add(theDriver);
294                 }
295             }
296             return theVector.elements();
297         }
298     }
299 
300     /**
301      * Returns the login timeout when connecting to a database in seconds.
302      *
303      * @return the login timeout in seconds.
304      */
getLoginTimeout()305     public static int getLoginTimeout() {
306         return loginTimeout;
307     }
308 
309     /**
310      * Gets the log {@code PrintStream} used by the {@code DriverManager} and
311      * all the JDBC Drivers.
312      *
313      * @deprecated use {@link #getLogWriter()} instead.
314      * @return the {@code PrintStream} used for logging activities.
315      */
316     @Deprecated
getLogStream()317     public static PrintStream getLogStream() {
318         return thePrintStream;
319     }
320 
321     /**
322      * Retrieves the log writer.
323      *
324      * @return A {@code PrintWriter} object used as the log writer. {@code null}
325      *         if no log writer is set.
326      */
getLogWriter()327     public static PrintWriter getLogWriter() {
328         return thePrintWriter;
329     }
330 
331     /**
332      * Prints a message to the current JDBC log stream. This is either the
333      * {@code PrintWriter} or (deprecated) the {@code PrintStream}, if set.
334      *
335      * @param message
336      *            the message to print to the JDBC log stream.
337      */
println(String message)338     public static void println(String message) {
339         if (thePrintWriter != null) {
340             thePrintWriter.println(message);
341             thePrintWriter.flush();
342         } else if (thePrintStream != null) {
343             thePrintStream.println(message);
344             thePrintStream.flush();
345         }
346         /*
347          * If neither the PrintWriter not the PrintStream are set, then silently
348          * do nothing the message is not recorded and no exception is generated.
349          */
350         return;
351     }
352 
353     /**
354      * Registers a given JDBC driver with the {@code DriverManager}.
355      * <p>
356      * A newly loaded JDBC driver class should register itself with the
357      * {@code DriverManager} by calling this method.
358      *
359      * @param driver
360      *            the {@code Driver} to register with the {@code DriverManager}.
361      * @throws SQLException
362      *             if a database access error occurs.
363      */
registerDriver(Driver driver)364     public static void registerDriver(Driver driver) throws SQLException {
365         if (driver == null) {
366             throw new NullPointerException();
367         }
368         synchronized (theDrivers) {
369             theDrivers.add(driver);
370         }
371     }
372 
373     /**
374      * Sets the login timeout when connecting to a database in seconds.
375      *
376      * @param seconds
377      *            seconds until timeout. 0 indicates wait forever.
378      */
setLoginTimeout(int seconds)379     public static void setLoginTimeout(int seconds) {
380         loginTimeout = seconds;
381         return;
382     }
383 
384     /**
385      * Sets the print stream to use for logging data from the {@code
386      * DriverManager} and the JDBC drivers.
387      *
388      * @deprecated Use {@link #setLogWriter} instead.
389      * @param out
390      *            the {@code PrintStream} to use for logging.
391      */
392     @Deprecated
setLogStream(PrintStream out)393     public static void setLogStream(PrintStream out) {
394         checkLogSecurity();
395         thePrintStream = out;
396     }
397 
398     /**
399      * Sets the {@code PrintWriter} that is used by all loaded drivers, and also
400      * the {@code DriverManager}.
401      *
402      * @param out
403      *            the {@code PrintWriter} to be used.
404      */
setLogWriter(PrintWriter out)405     public static void setLogWriter(PrintWriter out) {
406         checkLogSecurity();
407         thePrintWriter = out;
408     }
409 
410     /*
411      * Method which checks to see if setting a logging stream is allowed by the
412      * Security manager
413      */
checkLogSecurity()414     private static void checkLogSecurity() {
415         SecurityManager securityManager = System.getSecurityManager();
416         if (securityManager != null) {
417             // Throws a SecurityException if setting the log is not permitted
418             securityManager.checkPermission(logPermission);
419         }
420     }
421 
422     /**
423      * Determines whether the supplied object was loaded by the given {@code ClassLoader}.
424      *
425      * @param theObject
426      *            the object to check.
427      * @param theClassLoader
428      *            the {@code ClassLoader}.
429      * @return {@code true} if the Object does belong to the {@code ClassLoader}
430      *         , {@code false} otherwise
431      */
isClassFromClassLoader(Object theObject, ClassLoader theClassLoader)432     private static boolean isClassFromClassLoader(Object theObject,
433             ClassLoader theClassLoader) {
434 
435         if ((theObject == null) || (theClassLoader == null)) {
436             return false;
437         }
438 
439         Class<?> objectClass = theObject.getClass();
440 
441         try {
442             Class<?> checkClass = Class.forName(objectClass.getName(), true,
443                     theClassLoader);
444             if (checkClass == objectClass) {
445                 return true;
446             }
447         } catch (Throwable t) {
448             // Empty
449         }
450         return false;
451     }
452 }
453