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