• 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 dalvik.system.VMStack;
21 import java.io.PrintStream;
22 import java.io.PrintWriter;
23 import java.util.ArrayList;
24 import java.util.Collections;
25 import java.util.Enumeration;
26 import java.util.Iterator;
27 import java.util.List;
28 import java.util.Properties;
29 
30 /**
31  * Provides facilities for managing JDBC drivers. The <code>android.database</code> and
32  * <code>android.database.sqlite</code> packages offer a higher-performance alternative for new
33  * code.
34  *
35  * <p>Note that Android does not include any JDBC drivers by default; you must provide your own.
36  *
37  * <p>The {@code DriverManager} class loads JDBC drivers during its initialization,
38  * from the list of drivers referenced by the system property {@code
39  * "jdbc.drivers"}.
40  */
41 public class DriverManager {
42 
43     /*
44      * Facilities for logging. The Print Stream is deprecated but is maintained
45      * here for compatibility.
46      */
47     private static PrintStream thePrintStream;
48 
49     private static PrintWriter thePrintWriter;
50 
51     // Login timeout value - by default set to 0 -> "wait forever"
52     private static int loginTimeout = 0;
53 
54     /*
55      * Set to hold Registered Drivers - initial capacity 10 drivers (will expand
56      * automatically if necessary.
57      */
58     private static final List<Driver> theDrivers = new ArrayList<Driver>(10);
59 
60     // Permission for setting log
61     private static final SQLPermission logPermission = new SQLPermission("setLog");
62 
63     /*
64      * Load drivers on initialization
65      */
66     static {
loadInitialDrivers()67         loadInitialDrivers();
68     }
69 
70     /*
71      * Loads the set of JDBC drivers defined by the Property "jdbc.drivers" if
72      * it is defined.
73      */
loadInitialDrivers()74     private static void loadInitialDrivers() {
75         String theDriverList = System.getProperty("jdbc.drivers", null);
76         if (theDriverList == null) {
77             return;
78         }
79 
80         /*
81          * Get the names of the drivers as an array of Strings from the system
82          * property by splitting the property at the separator character ':'
83          */
84         String[] theDriverNames = theDriverList.split(":");
85 
86         for (String element : theDriverNames) {
87             try {
88                 // Load the driver class
89                 Class
90                         .forName(element, true, ClassLoader
91                                 .getSystemClassLoader());
92             } catch (Throwable t) {
93                 // Ignored
94             }
95         }
96     }
97 
98     /*
99      * A private constructor to prevent allocation
100      */
DriverManager()101     private DriverManager() {
102     }
103 
104     /**
105      * Removes a driver from the {@code DriverManager}'s registered driver list.
106      * This will only succeed when the caller's class loader loaded the driver
107      * that is to be removed. If the driver was loaded by a different class
108      * loader, the removal of the driver fails silently.
109      * <p>
110      * If the removal succeeds, the {@code DriverManager} will not use this
111      * driver in the future when asked to get a {@code Connection}.
112      *
113      * @param driver
114      *            the JDBC driver to remove.
115      * @throws SQLException
116      *             if there is a problem interfering with accessing the
117      *             database.
118      */
deregisterDriver(Driver driver)119     public static void deregisterDriver(Driver driver) throws SQLException {
120         if (driver == null) {
121             return;
122         }
123         ClassLoader callerClassLoader = VMStack.getCallingClassLoader();
124         if (!DriverManager.isClassFromClassLoader(driver, callerClassLoader)) {
125             throw new SecurityException("calling class not authorized to deregister JDBC driver");
126         }
127         synchronized (theDrivers) {
128             theDrivers.remove(driver);
129         }
130     }
131 
132     /**
133      * Attempts to establish a connection to the given database URL.
134      *
135      * @param url
136      *            a URL string representing the database target to connect with.
137      * @return a {@code Connection} to the database identified by the URL.
138      *         {@code null} if no connection can be established.
139      * @throws SQLException
140      *             if there is an error while attempting to connect to the
141      *             database identified by the URL.
142      */
getConnection(String url)143     public static Connection getConnection(String url) throws SQLException {
144         return getConnection(url, new Properties());
145     }
146 
147     /**
148      * Attempts to establish a connection to the given database URL.
149      *
150      * @param url
151      *            a URL string representing the database target to connect with
152      * @param info
153      *            a set of properties to use as arguments to set up the
154      *            connection. Properties are arbitrary string/value pairs.
155      *            Normally, at least the properties {@code "user"} and {@code
156      *            "password"} should be passed, with appropriate settings for
157      *            the user ID and its corresponding password to get access to
158      *            the corresponding database.
159      * @return a {@code Connection} to the database identified by the URL.
160      *         {@code null} if no connection can be established.
161      * @throws SQLException
162      *             if there is an error while attempting to connect to the
163      *             database identified by the URL.
164      */
getConnection(String url, Properties info)165     public static Connection getConnection(String url, Properties info) throws SQLException {
166         // 08 - connection exception
167         // 001 - SQL-client unable to establish SQL-connection
168         String sqlState = "08001";
169         if (url == null) {
170             throw new SQLException("The url cannot be null", sqlState);
171         }
172         synchronized (theDrivers) {
173             /*
174              * Loop over the drivers in the DriverSet checking to see if one can
175              * open a connection to the supplied URL - return the first
176              * connection which is returned
177              */
178             for (Driver theDriver : theDrivers) {
179                 Connection theConnection = theDriver.connect(url, info);
180                 if (theConnection != null) {
181                     return theConnection;
182                 }
183             }
184         }
185         // If we get here, none of the drivers are able to resolve the URL
186         throw new SQLException("No suitable driver", sqlState);
187     }
188 
189     /**
190      * Attempts to establish a connection to the given database URL.
191      *
192      * @param url
193      *            a URL string representing the database target to connect with.
194      * @param user
195      *            a user ID used to login to the database.
196      * @param password
197      *            a password for the user ID to login to the database.
198      * @return a {@code Connection} to the database identified by the URL.
199      *         {@code null} if no connection can be established.
200      * @throws SQLException
201      *             if there is an error while attempting to connect to the
202      *             database identified by the URL.
203      */
getConnection(String url, String user, String password)204     public static Connection getConnection(String url, String user, String password)
205             throws SQLException {
206         Properties theProperties = new Properties();
207         if (user != null) {
208             theProperties.setProperty("user", user);
209         }
210         if (password != null) {
211             theProperties.setProperty("password", password);
212         }
213         return getConnection(url, theProperties);
214     }
215 
216     /**
217      * Tries to find a driver that can interpret the supplied URL.
218      *
219      * @param url
220      *            the URL of a database.
221      * @return a {@code Driver} that matches the provided URL. {@code null} if
222      *         no {@code Driver} understands the URL
223      * @throws SQLException
224      *             if there is any kind of problem accessing the database.
225      */
getDriver(String url)226     public static Driver getDriver(String url) throws SQLException {
227         ClassLoader callerClassLoader = VMStack.getCallingClassLoader();
228         synchronized (theDrivers) {
229             /*
230              * Loop over the drivers in the DriverSet checking to see if one
231              * does understand the supplied URL - return the first driver which
232              * does understand the URL
233              */
234             for (Driver driver : theDrivers) {
235                 if (driver.acceptsURL(url) &&
236                         DriverManager.isClassFromClassLoader(driver, callerClassLoader)) {
237                     return driver;
238                 }
239             }
240         }
241         // If no drivers understand the URL, throw an SQLException
242         // SQLState: 08 - connection exception
243         // 001 - SQL-client unable to establish SQL-connection
244         throw new SQLException("No suitable driver", "08001");
245     }
246 
247     /**
248      * Returns an {@code Enumeration} that contains all of the loaded JDBC
249      * drivers that the current caller can access.
250      *
251      * @return An {@code Enumeration} containing all the currently loaded JDBC
252      *         {@code Drivers}.
253      */
getDrivers()254     public static Enumeration<Driver> getDrivers() {
255         /*
256          * Synchronize to avoid clashes with additions and removals of drivers
257          * in the DriverSet
258          */
259         ClassLoader callerClassLoader = VMStack.getCallingClassLoader();
260         synchronized (theDrivers) {
261             ArrayList<Driver> result = new ArrayList<Driver>();
262             for (Driver driver : theDrivers) {
263                 if (DriverManager.isClassFromClassLoader(driver, callerClassLoader)) {
264                     result.add(driver);
265                 }
266             }
267             return Collections.enumeration(result);
268         }
269     }
270 
271     /**
272      * Returns the login timeout when connecting to a database in seconds.
273      *
274      * @return the login timeout in seconds.
275      */
getLoginTimeout()276     public static int getLoginTimeout() {
277         return loginTimeout;
278     }
279 
280     /**
281      * Gets the log {@code PrintStream} used by the {@code DriverManager} and
282      * all the JDBC Drivers.
283      *
284      * @deprecated Use {@link #getLogWriter()} instead.
285      * @return the {@code PrintStream} used for logging activities.
286      */
287     @Deprecated
getLogStream()288     public static PrintStream getLogStream() {
289         return thePrintStream;
290     }
291 
292     /**
293      * Retrieves the log writer.
294      *
295      * @return A {@code PrintWriter} object used as the log writer. {@code null}
296      *         if no log writer is set.
297      */
getLogWriter()298     public static PrintWriter getLogWriter() {
299         return thePrintWriter;
300     }
301 
302     /**
303      * Prints a message to the current JDBC log stream. This is either the
304      * {@code PrintWriter} or (deprecated) the {@code PrintStream}, if set.
305      *
306      * @param message
307      *            the message to print to the JDBC log stream.
308      */
println(String message)309     public static void println(String message) {
310         if (thePrintWriter != null) {
311             thePrintWriter.println(message);
312             thePrintWriter.flush();
313         } else if (thePrintStream != null) {
314             thePrintStream.println(message);
315             thePrintStream.flush();
316         }
317         /*
318          * If neither the PrintWriter not the PrintStream are set, then silently
319          * do nothing the message is not recorded and no exception is generated.
320          */
321     }
322 
323     /**
324      * Registers a given JDBC driver with the {@code DriverManager}.
325      * <p>
326      * A newly loaded JDBC driver class should register itself with the
327      * {@code DriverManager} by calling this method.
328      *
329      * @param driver
330      *            the {@code Driver} to register with the {@code DriverManager}.
331      * @throws SQLException
332      *             if a database access error occurs.
333      */
registerDriver(Driver driver)334     public static void registerDriver(Driver driver) throws SQLException {
335         if (driver == null) {
336             throw new NullPointerException("driver == null");
337         }
338         synchronized (theDrivers) {
339             theDrivers.add(driver);
340         }
341     }
342 
343     /**
344      * Sets the login timeout when connecting to a database in seconds.
345      *
346      * @param seconds
347      *            seconds until timeout. 0 indicates wait forever.
348      */
setLoginTimeout(int seconds)349     public static void setLoginTimeout(int seconds) {
350         loginTimeout = seconds;
351     }
352 
353     /**
354      * Sets the print stream to use for logging data from the {@code
355      * DriverManager} and the JDBC drivers.
356      *
357      * @deprecated Use {@link #setLogWriter} instead.
358      * @param out
359      *            the {@code PrintStream} to use for logging.
360      */
361     @Deprecated
setLogStream(PrintStream out)362     public static void setLogStream(PrintStream out) {
363         thePrintStream = out;
364     }
365 
366     /**
367      * Sets the {@code PrintWriter} that is used by all loaded drivers, and also
368      * the {@code DriverManager}.
369      *
370      * @param out
371      *            the {@code PrintWriter} to be used.
372      */
setLogWriter(PrintWriter out)373     public static void setLogWriter(PrintWriter out) {
374         thePrintWriter = out;
375     }
376 
377     /**
378      * Determines whether the supplied object was loaded by the given {@code ClassLoader}.
379      *
380      * @param theObject
381      *            the object to check.
382      * @param theClassLoader
383      *            the {@code ClassLoader}.
384      * @return {@code true} if the Object does belong to the {@code ClassLoader}
385      *         , {@code false} otherwise
386      */
isClassFromClassLoader(Object theObject, ClassLoader theClassLoader)387     private static boolean isClassFromClassLoader(Object theObject,
388             ClassLoader theClassLoader) {
389 
390         if ((theObject == null) || (theClassLoader == null)) {
391             return false;
392         }
393 
394         Class<?> objectClass = theObject.getClass();
395 
396         try {
397             Class<?> checkClass = Class.forName(objectClass.getName(), true,
398                     theClassLoader);
399             if (checkClass == objectClass) {
400                 return true;
401             }
402         } catch (Throwable t) {
403             // Empty
404         }
405         return false;
406     }
407 }
408