diff options
Diffstat (limited to 'luni/src/main/java/java/sql/DriverManager.java')
-rw-r--r-- | luni/src/main/java/java/sql/DriverManager.java | 439 |
1 files changed, 439 insertions, 0 deletions
diff --git a/luni/src/main/java/java/sql/DriverManager.java b/luni/src/main/java/java/sql/DriverManager.java new file mode 100644 index 0000000..8d3adde --- /dev/null +++ b/luni/src/main/java/java/sql/DriverManager.java @@ -0,0 +1,439 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package java.sql; + +import dalvik.system.VMStack; +import java.io.PrintStream; +import java.io.PrintWriter; +import java.security.AccessController; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.Iterator; +import java.util.List; +import java.util.Properties; +import java.util.Vector; +import org.apache.harmony.luni.util.PriviAction; + +/** + * Provides facilities for managing JDBC drivers. + * <p> + * The {@code DriverManager} class loads JDBC drivers during its initialization, + * from the list of drivers referenced by the system property {@code + * "jdbc.drivers"}. + */ +public class DriverManager { + + /* + * Facilities for logging. The Print Stream is deprecated but is maintained + * here for compatibility. + */ + private static PrintStream thePrintStream; + + private static PrintWriter thePrintWriter; + + // Login timeout value - by default set to 0 -> "wait forever" + private static int loginTimeout = 0; + + /* + * Set to hold Registered Drivers - initial capacity 10 drivers (will expand + * automatically if necessary. + */ + private static final List<Driver> theDrivers = new ArrayList<Driver>(10); + + // Permission for setting log + private static final SQLPermission logPermission = new SQLPermission("setLog"); + + /* + * Load drivers on initialization + */ + static { + loadInitialDrivers(); + } + + /* + * Loads the set of JDBC drivers defined by the Property "jdbc.drivers" if + * it is defined. + */ + private static void loadInitialDrivers() { + String theDriverList = AccessController + .doPrivileged(new PriviAction<String>("jdbc.drivers", null)); + + if (theDriverList == null) { + return; + } + + /* + * Get the names of the drivers as an array of Strings from the system + * property by splitting the property at the separator character ':' + */ + String[] theDriverNames = theDriverList.split(":"); + + for (String element : theDriverNames) { + try { + // Load the driver class + Class + .forName(element, true, ClassLoader + .getSystemClassLoader()); + } catch (Throwable t) { + // Ignored + } + } + } + + /* + * A private constructor to prevent allocation + */ + private DriverManager() { + super(); + } + + /** + * Removes a driver from the {@code DriverManager}'s registered driver list. + * This will only succeed when the caller's class loader loaded the driver + * that is to be removed. If the driver was loaded by a different class + * loader, the removal of the driver fails silently. + * <p> + * If the removal succeeds, the {@code DriverManager} will not use this + * driver in the future when asked to get a {@code Connection}. + * + * @param driver + * the JDBC driver to remove. + * @throws SQLException + * if there is a problem interfering with accessing the + * database. + */ + public static void deregisterDriver(Driver driver) throws SQLException { + if (driver == null) { + return; + } + ClassLoader callerClassLoader = VMStack.getCallingClassLoader(); + if (!DriverManager.isClassFromClassLoader(driver, callerClassLoader)) { + throw new SecurityException("calling class not authorized to deregister JDBC driver"); + } + synchronized (theDrivers) { + theDrivers.remove(driver); + } + } + + /** + * Attempts to establish a connection to the given database URL. + * + * @param url + * a URL string representing the database target to connect with. + * @return a {@code Connection} to the database identified by the URL. + * {@code null} if no connection can be established. + * @throws SQLException + * if there is an error while attempting to connect to the + * database identified by the URL. + */ + public static Connection getConnection(String url) throws SQLException { + return getConnection(url, new Properties()); + } + + /** + * Attempts to establish a connection to the given database URL. + * + * @param url + * a URL string representing the database target to connect with + * @param info + * a set of properties to use as arguments to set up the + * connection. Properties are arbitrary string/value pairs. + * Normally, at least the properties {@code "user"} and {@code + * "password"} should be passed, with appropriate settings for + * the user ID and its corresponding password to get access to + * the corresponding database. + * @return a {@code Connection} to the database identified by the URL. + * {@code null} if no connection can be established. + * @throws SQLException + * if there is an error while attempting to connect to the + * database identified by the URL. + */ + public static Connection getConnection(String url, Properties info) throws SQLException { + // 08 - connection exception + // 001 - SQL-client unable to establish SQL-connection + String sqlState = "08001"; + if (url == null) { + throw new SQLException("The url cannot be null", sqlState); + } + synchronized (theDrivers) { + /* + * Loop over the drivers in the DriverSet checking to see if one can + * open a connection to the supplied URL - return the first + * connection which is returned + */ + for (Driver theDriver : theDrivers) { + Connection theConnection = theDriver.connect(url, info); + if (theConnection != null) { + return theConnection; + } + } + } + // If we get here, none of the drivers are able to resolve the URL + throw new SQLException("No suitable driver", sqlState); + } + + /** + * Attempts to establish a connection to the given database URL. + * + * @param url + * a URL string representing the database target to connect with. + * @param user + * a user ID used to login to the database. + * @param password + * a password for the user ID to login to the database. + * @return a {@code Connection} to the database identified by the URL. + * {@code null} if no connection can be established. + * @throws SQLException + * if there is an error while attempting to connect to the + * database identified by the URL. + */ + public static Connection getConnection(String url, String user, + String password) throws SQLException { + Properties theProperties = new Properties(); + if (null != user) { + theProperties.setProperty("user", user); + } + if (null != password) { + theProperties.setProperty("password", password); + } + return getConnection(url, theProperties); + } + + /** + * Tries to find a driver that can interpret the supplied URL. + * + * @param url + * the URL of a database. + * @return a {@code Driver} that matches the provided URL. {@code null} if + * no {@code Driver} understands the URL + * @throws SQLException + * if there is any kind of problem accessing the database. + */ + public static Driver getDriver(String url) throws SQLException { + // BEGIN android-changed + ClassLoader callerClassLoader = VMStack.getCallingClassLoader(); + // END android-changed + + synchronized (theDrivers) { + /* + * Loop over the drivers in the DriverSet checking to see if one + * does understand the supplied URL - return the first driver which + * does understand the URL + */ + Iterator<Driver> theIterator = theDrivers.iterator(); + while (theIterator.hasNext()) { + Driver theDriver = theIterator.next(); + if (theDriver.acceptsURL(url) + && DriverManager.isClassFromClassLoader(theDriver, + callerClassLoader)) { + return theDriver; + } + } + } + // If no drivers understand the URL, throw an SQLException + // SQLState: 08 - connection exception + // 001 - SQL-client unable to establish SQL-connection + throw new SQLException("No suitable driver", "08001"); + } + + /** + * Returns an {@code Enumeration} that contains all of the loaded JDBC + * drivers that the current caller can access. + * + * @return An {@code Enumeration} containing all the currently loaded JDBC + * {@code Drivers}. + */ + public static Enumeration<Driver> getDrivers() { + // BEGIN android-changed + ClassLoader callerClassLoader = VMStack.getCallingClassLoader(); + // END android-changed + /* + * Synchronize to avoid clashes with additions and removals of drivers + * in the DriverSet + */ + synchronized (theDrivers) { + /* + * Create the Enumeration by building a Vector from the elements of + * the DriverSet + */ + Vector<Driver> theVector = new Vector<Driver>(); + Iterator<Driver> theIterator = theDrivers.iterator(); + while (theIterator.hasNext()) { + Driver theDriver = theIterator.next(); + if (DriverManager.isClassFromClassLoader(theDriver, + callerClassLoader)) { + theVector.add(theDriver); + } + } + return theVector.elements(); + } + } + + /** + * Returns the login timeout when connecting to a database in seconds. + * + * @return the login timeout in seconds. + */ + public static int getLoginTimeout() { + return loginTimeout; + } + + /** + * Gets the log {@code PrintStream} used by the {@code DriverManager} and + * all the JDBC Drivers. + * + * @deprecated use {@link #getLogWriter()} instead. + * @return the {@code PrintStream} used for logging activities. + */ + @Deprecated + public static PrintStream getLogStream() { + return thePrintStream; + } + + /** + * Retrieves the log writer. + * + * @return A {@code PrintWriter} object used as the log writer. {@code null} + * if no log writer is set. + */ + public static PrintWriter getLogWriter() { + return thePrintWriter; + } + + /** + * Prints a message to the current JDBC log stream. This is either the + * {@code PrintWriter} or (deprecated) the {@code PrintStream}, if set. + * + * @param message + * the message to print to the JDBC log stream. + */ + public static void println(String message) { + if (thePrintWriter != null) { + thePrintWriter.println(message); + thePrintWriter.flush(); + } else if (thePrintStream != null) { + thePrintStream.println(message); + thePrintStream.flush(); + } + /* + * If neither the PrintWriter not the PrintStream are set, then silently + * do nothing the message is not recorded and no exception is generated. + */ + return; + } + + /** + * Registers a given JDBC driver with the {@code DriverManager}. + * <p> + * A newly loaded JDBC driver class should register itself with the + * {@code DriverManager} by calling this method. + * + * @param driver + * the {@code Driver} to register with the {@code DriverManager}. + * @throws SQLException + * if a database access error occurs. + */ + public static void registerDriver(Driver driver) throws SQLException { + if (driver == null) { + throw new NullPointerException(); + } + synchronized (theDrivers) { + theDrivers.add(driver); + } + } + + /** + * Sets the login timeout when connecting to a database in seconds. + * + * @param seconds + * seconds until timeout. 0 indicates wait forever. + */ + public static void setLoginTimeout(int seconds) { + loginTimeout = seconds; + return; + } + + /** + * Sets the print stream to use for logging data from the {@code + * DriverManager} and the JDBC drivers. + * + * @deprecated Use {@link #setLogWriter} instead. + * @param out + * the {@code PrintStream} to use for logging. + */ + @Deprecated + public static void setLogStream(PrintStream out) { + checkLogSecurity(); + thePrintStream = out; + } + + /** + * Sets the {@code PrintWriter} that is used by all loaded drivers, and also + * the {@code DriverManager}. + * + * @param out + * the {@code PrintWriter} to be used. + */ + public static void setLogWriter(PrintWriter out) { + checkLogSecurity(); + thePrintWriter = out; + } + + /* + * Method which checks to see if setting a logging stream is allowed by the + * Security manager + */ + private static void checkLogSecurity() { + SecurityManager securityManager = System.getSecurityManager(); + if (securityManager != null) { + // Throws a SecurityException if setting the log is not permitted + securityManager.checkPermission(logPermission); + } + } + + /** + * Determines whether the supplied object was loaded by the given {@code ClassLoader}. + * + * @param theObject + * the object to check. + * @param theClassLoader + * the {@code ClassLoader}. + * @return {@code true} if the Object does belong to the {@code ClassLoader} + * , {@code false} otherwise + */ + private static boolean isClassFromClassLoader(Object theObject, + ClassLoader theClassLoader) { + + if ((theObject == null) || (theClassLoader == null)) { + return false; + } + + Class<?> objectClass = theObject.getClass(); + + try { + Class<?> checkClass = Class.forName(objectClass.getName(), true, + theClassLoader); + if (checkClass == objectClass) { + return true; + } + } catch (Throwable t) { + // Empty + } + return false; + } +} |