| /* |
| * 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 java.util.ArrayList; |
| import java.util.List; |
| import java.util.Properties; |
| import java.util.Enumeration; |
| import java.util.Iterator; |
| import java.io.PrintStream; |
| import java.io.PrintWriter; |
| import java.util.Vector; |
| import java.security.AccessController; |
| import org.apache.harmony.luni.util.PriviAction; |
| import org.apache.harmony.sql.internal.nls.Messages; |
| import org.apache.harmony.kernel.vm.VM; |
| |
| /** |
| * 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"); //$NON-NLS-1$ |
| |
| /* |
| * 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)); //$NON-NLS-1$ |
| |
| 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(":"); //$NON-NLS-1$ |
| |
| 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 = VM.callerClassLoader(); |
| |
| if (!DriverManager.isClassFromClassLoader(driver, callerClassLoader)) { |
| // sql.1=DriverManager: calling class not authorized to deregister |
| // JDBC driver |
| throw new SecurityException(Messages.getString("sql.1")); //$NON-NLS-1$ |
| } // end if |
| 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"; //$NON-NLS-1$ |
| if (url == null) { |
| // sql.5=The url cannot be null |
| throw new SQLException(Messages.getString("sql.5"), sqlState); //$NON-NLS-1$ |
| } |
| 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 |
| // sql.6=No suitable driver |
| throw new SQLException(Messages.getString("sql.6"), sqlState); //$NON-NLS-1$ |
| } |
| |
| /** |
| * 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); //$NON-NLS-1$ |
| } |
| if (null != password) { |
| theProperties.setProperty("password", password); //$NON-NLS-1$ |
| } |
| 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 { |
| ClassLoader callerClassLoader = VM.callerClassLoader(); |
| |
| 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 |
| // sql.6=No suitable driver |
| // SQLState: 08 - connection exception |
| // 001 - SQL-client unable to establish SQL-connection |
| throw new SQLException(Messages.getString("sql.6"), "08001"); //$NON-NLS-1$ //$NON-NLS-2$ |
| } |
| |
| /** |
| * 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() { |
| ClassLoader callerClassLoader = VM.callerClassLoader(); |
| /* |
| * 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; |
| } |
| } |