001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: package java.sql;
019:
020: import java.util.ArrayList;
021: import java.util.List;
022: import java.util.Properties;
023: import java.util.Enumeration;
024: import java.util.Iterator;
025: import java.io.PrintStream;
026: import java.io.PrintWriter;
027: import java.util.Vector;
028: import java.security.AccessController;
029: import org.apache.harmony.luni.util.PriviAction;
030: import org.apache.harmony.sql.internal.nls.Messages;
031: import org.apache.harmony.kernel.vm.VM;
032:
033: /**
034: * Provides facilities for managing JDBC Drivers.
035: * <p>
036: * The DriverManager class will load JDBC drivers during its initialization,
037: * from the list of drivers referenced by the System Property "jdbc.drivers".
038: */
039: public class DriverManager {
040:
041: /*
042: * Facilities for logging. The Print Stream is deprecated but is maintained
043: * here for compatibility.
044: */
045: private static PrintStream thePrintStream;
046:
047: private static PrintWriter thePrintWriter;
048:
049: // Login timeout value - by default set to 0 -> "wait forever"
050: private static int loginTimeout = 0;
051:
052: /*
053: * Set to hold Registered Drivers - initial capacity 10 drivers (will expand
054: * automatically if necessary.
055: */
056: private static final List<Driver> theDrivers = new ArrayList<Driver>(
057: 10);
058:
059: // Permission for setting log
060: private static final SQLPermission logPermission = new SQLPermission(
061: "setLog"); //$NON-NLS-1$
062:
063: /*
064: * Load drivers on initialization
065: */
066: static {
067: loadInitialDrivers();
068: }
069:
070: /*
071: * Loads the set of JDBC drivers defined by the Property "jdbc.drivers" if
072: * it is defined.
073: */
074: private static void loadInitialDrivers() {
075: String theDriverList = AccessController
076: .doPrivileged(new PriviAction<String>(
077: "jdbc.drivers", null)); //$NON-NLS-1$
078:
079: if (theDriverList == null) {
080: return;
081: }
082:
083: /*
084: * Get the names of the drivers as an array of Strings from the system
085: * property by splitting the property at the separator character ':'
086: */
087: String[] theDriverNames = theDriverList.split(":"); //$NON-NLS-1$
088:
089: for (String element : theDriverNames) {
090: try {
091: // Load the driver class
092: Class.forName(element, true, ClassLoader
093: .getSystemClassLoader());
094: } catch (Throwable t) {
095: // Ignored
096: }
097: }
098: }
099:
100: /*
101: * A private constructor to prevent allocation
102: */
103: private DriverManager() {
104: super ();
105: }
106:
107: /**
108: * Removes a driver from the DriverManager's registered driver list. This
109: * will only succeed where the caller's classloader loaded the driver that
110: * is to be removed. If the driver was loaded by a different classloader,
111: * the removal of the driver will fail silently.
112: * <p>
113: * If the removal succeeds, the DriverManager will not in future use this
114: * driver when asked to get a Connection.
115: *
116: * @param driver
117: * @throws SQLException
118: * if there is an exception accessing the database.
119: */
120: public static void deregisterDriver(Driver driver)
121: throws SQLException {
122: if (driver == null) {
123: return;
124: }
125: ClassLoader callerClassLoader = VM.callerClassLoader();
126:
127: if (!DriverManager.isClassFromClassLoader(driver,
128: callerClassLoader)) {
129: // sql.1=DriverManager: calling class not authorized to deregister
130: // JDBC driver
131: throw new SecurityException(Messages.getString("sql.1")); //$NON-NLS-1$
132: } // end if
133: synchronized (theDrivers) {
134: theDrivers.remove(driver);
135: }
136: }
137:
138: /**
139: * Attempts to establish a connection to the given database URL.
140: *
141: * @param url
142: * a URL string representing the database target to connect with
143: * @return a Connection to the database identified by the URL. null if no
144: * connection can be made.
145: * @throws SQLException
146: * if there is an error while attempting to connect to the
147: * database identified by the URL
148: */
149: public static Connection getConnection(String url)
150: throws SQLException {
151: return getConnection(url, new Properties());
152: }
153:
154: /**
155: * Attempts to establish a connection to the given database URL.
156: *
157: * @param url
158: * a URL string representing the database target to connect with
159: * @param info
160: * a set of Properties to use as arguments to set up the
161: * connection. Properties are arbitrary string/value pairs.
162: * Normally, at least the properties "user" and "password" should
163: * be passed, with appropriate settings for the userid and its
164: * corresponding password to get access to the database
165: * concerned.
166: * @return a Connection to the database identified by the URL. null if no
167: * connection can be made.
168: * @throws SQLException
169: * if there is an error while attempting to connect to the
170: * database identified by the URL
171: */
172: public static Connection getConnection(String url, Properties info)
173: throws SQLException {
174: // 08 - connection exception
175: // 001 - SQL-client unable to establish SQL-connection
176: String sqlState = "08001"; //$NON-NLS-1$
177: if (url == null) {
178: // sql.5=The url cannot be null
179: throw new SQLException(
180: Messages.getString("sql.5"), sqlState); //$NON-NLS-1$
181: }
182: synchronized (theDrivers) {
183: /*
184: * Loop over the drivers in the DriverSet checking to see if one can
185: * open a connection to the supplied URL - return the first
186: * connection which is returned
187: */
188: for (Driver theDriver : theDrivers) {
189: Connection theConnection = theDriver.connect(url, info);
190: if (theConnection != null) {
191: return theConnection;
192: }
193: }
194: }
195: // If we get here, none of the drivers are able to resolve the URL
196: // sql.6=No suitable driver
197: throw new SQLException(Messages.getString("sql.6"), sqlState); //$NON-NLS-1$
198: }
199:
200: /**
201: * Attempts to establish a connection to the given database URL.
202: *
203: * @param url
204: * a URL string representing the database target to connect with
205: * @param user
206: * a userid used to login to the database
207: * @param password
208: * a password for the userid to login to the database
209: * @return a Connection to the database identified by the URL. null if no
210: * connection can be made.
211: * @throws SQLException
212: * if there is an error while attempting to connect to the
213: * database identified by the URL
214: */
215: public static Connection getConnection(String url, String user,
216: String password) throws SQLException {
217: Properties theProperties = new Properties();
218: if (null != user) {
219: theProperties.setProperty("user", user); //$NON-NLS-1$
220: }
221: if (null != password) {
222: theProperties.setProperty("password", password); //$NON-NLS-1$
223: }
224: return getConnection(url, theProperties);
225: }
226:
227: /**
228: * Tries to find a driver that can interpret the supplied URL.
229: *
230: * @param url
231: * the URL of a database
232: * @return a Driver that can understand the given URL. null if no Driver
233: * understands the URL
234: * @throws SQLException
235: * if there is any kind of Database Access problem
236: */
237: public static Driver getDriver(String url) throws SQLException {
238: ClassLoader callerClassLoader = VM.callerClassLoader();
239:
240: synchronized (theDrivers) {
241: /*
242: * Loop over the drivers in the DriverSet checking to see if one
243: * does understand the supplied URL - return the first driver which
244: * does understand the URL
245: */
246: Iterator<Driver> theIterator = theDrivers.iterator();
247: while (theIterator.hasNext()) {
248: Driver theDriver = theIterator.next();
249: if (theDriver.acceptsURL(url)
250: && DriverManager.isClassFromClassLoader(
251: theDriver, callerClassLoader)) {
252: return theDriver;
253: }
254: }
255: }
256: // If no drivers understand the URL, throw an SQLException
257: // sql.6=No suitable driver
258: // SQLState: 08 - connection exception
259: // 001 - SQL-client unable to establish SQL-connection
260: throw new SQLException(Messages.getString("sql.6"), "08001"); //$NON-NLS-1$ //$NON-NLS-2$
261: }
262:
263: /**
264: * Returns an Enumeration that contains all of the loaded JDBC drivers that
265: * the current caller can access.
266: *
267: * @return An Enumeration containing all the currently loaded JDBC Drivers
268: */
269: public static Enumeration<Driver> getDrivers() {
270: ClassLoader callerClassLoader = VM.callerClassLoader();
271: /*
272: * Synchronize to avoid clashes with additions and removals of drivers
273: * in the DriverSet
274: */
275: synchronized (theDrivers) {
276: /*
277: * Create the Enumeration by building a Vector from the elements of
278: * the DriverSet
279: */
280: Vector<Driver> theVector = new Vector<Driver>();
281: Iterator<Driver> theIterator = theDrivers.iterator();
282: while (theIterator.hasNext()) {
283: Driver theDriver = theIterator.next();
284: if (DriverManager.isClassFromClassLoader(theDriver,
285: callerClassLoader)) {
286: theVector.add(theDriver);
287: }
288: }
289: return theVector.elements();
290: }
291: }
292:
293: /**
294: * Returns the login timeout when connecting to a database, in seconds.
295: *
296: * @return the login timeout in seconds
297: */
298: public static int getLoginTimeout() {
299: return loginTimeout;
300: }
301:
302: /**
303: * @deprecated Gets the log PrintStream used by the DriverManager and all
304: * the JDBC Drivers.
305: * @return the PrintStream used for logging activity
306: */
307: @Deprecated
308: public static PrintStream getLogStream() {
309: return thePrintStream;
310: }
311:
312: /**
313: * Retrieves the log writer.
314: *
315: * @return A PrintWriter object used as the log writer. null if no log
316: * writer is set.
317: */
318: public static PrintWriter getLogWriter() {
319: return thePrintWriter;
320: }
321:
322: /**
323: * Prints a message to the current JDBC log stream. This is either the
324: * PrintWriter or (deprecated) the PrintStream, if set.
325: *
326: * @param message
327: * the message to print to the JDBC log stream
328: */
329: public static void println(String message) {
330: if (thePrintWriter != null) {
331: thePrintWriter.println(message);
332: thePrintWriter.flush();
333: } else if (thePrintStream != null) {
334: thePrintStream.println(message);
335: thePrintStream.flush();
336: }
337: /*
338: * If neither the PrintWriter not the PrintStream are set, then silently
339: * do nothing the message is not recorded and no exception is generated.
340: */
341: return;
342: }
343:
344: /**
345: * Registers a given JDBC driver with the DriverManager.
346: * <p>
347: * A newly loaded JDBC driver class should register itself with the
348: * DriverManager by calling this method.
349: *
350: * @param driver
351: * the Driver to register with the DriverManager
352: * @throws SQLException
353: * if a database access error occurs.
354: */
355: public static void registerDriver(Driver driver)
356: throws SQLException {
357: if (driver == null) {
358: throw new NullPointerException();
359: }
360: synchronized (theDrivers) {
361: theDrivers.add(driver);
362: }
363: }
364:
365: /**
366: * Set the login timeout when connecting to a database, in seconds.
367: *
368: * @param seconds
369: * seconds until timeout. 0 indicates wait forever.
370: */
371: public static void setLoginTimeout(int seconds) {
372: loginTimeout = seconds;
373: return;
374: }
375:
376: /**
377: * @deprecated Sets the Print Stream to use for logging data from the
378: * DriverManager and the JDBC drivers.
379: * <p>
380: * Use setLogWriter instead.
381: * @param out
382: * the PrintStream to use for logging.
383: */
384: @Deprecated
385: public static void setLogStream(PrintStream out) {
386: checkLogSecurity();
387: thePrintStream = out;
388: }
389:
390: /**
391: * Sets the PrintWriter that will be used by all loaded drivers, and also
392: * the DriverManager.
393: *
394: * @param out
395: * the PrintWriter to be used
396: */
397: public static void setLogWriter(PrintWriter out) {
398: checkLogSecurity();
399: thePrintWriter = out;
400: }
401:
402: /*
403: * Method which checks to see if setting a logging stream is allowed by the
404: * Security manager
405: */
406: private static void checkLogSecurity() {
407: SecurityManager securityManager = System.getSecurityManager();
408: if (securityManager != null) {
409: // Throws a SecurityException if setting the log is not permitted
410: securityManager.checkPermission(logPermission);
411: }
412: }
413:
414: /**
415: * Finds if a supplied Object belongs to the given ClassLoader.
416: *
417: * @param theObject
418: * the object to check
419: * @param theClassLoader
420: * the ClassLoader
421: * @return true if the Object does belong to the ClassLoader, false
422: * otherwise
423: */
424: private static boolean isClassFromClassLoader(Object theObject,
425: ClassLoader theClassLoader) {
426:
427: if ((theObject == null) || (theClassLoader == null)) {
428: return false;
429: }
430:
431: Class<?> objectClass = theObject.getClass();
432:
433: try {
434: Class<?> checkClass = Class.forName(objectClass.getName(),
435: true, theClassLoader);
436: if (checkClass == objectClass) {
437: return true;
438: }
439: } catch (Throwable t) {
440: // Empty
441: }
442: return false;
443: }
444: }
|