1. /*
  2. * @(#)DriverManager.java 1.32 00/02/02
  3. *
  4. * Copyright 1996-2000 Sun Microsystems, Inc. All Rights Reserved.
  5. *
  6. * This software is the proprietary information of Sun Microsystems, Inc.
  7. * Use is subject to license terms.
  8. *
  9. */
  10. package java.sql;
  11. /**
  12. * <P>The basic service for managing a set of JDBC drivers.<br>
  13. * <B>NOTE:</B> The {@link <code>DataSource</code>} interface, new in the
  14. * JDBC 2.0 API, provides another way to connect to a data source.
  15. * The use of a <code>DataSource</code> object is the preferred means of
  16. * connecting to a data source.
  17. *
  18. * <P>As part of its initialization, the <code>DriverManager</code> class will
  19. * attempt to load the driver classes referenced in the "jdbc.drivers"
  20. * system property. This allows a user to customize the JDBC Drivers
  21. * used by their applications. For example in your
  22. * ~/.hotjava/properties file you might specify:
  23. * <pre>
  24. * <CODE>jdbc.drivers=foo.bah.Driver:wombat.sql.Driver:bad.taste.ourDriver</CODE>
  25. * </pre>
  26. *
  27. * A program can also explicitly load JDBC drivers at any time. For
  28. * example, the my.sql.Driver is loaded with the following statement:
  29. * <pre>
  30. * <CODE>Class.forName("my.sql.Driver");</CODE>
  31. * </pre>
  32. *
  33. * <P>When the method <code>getConnection</code> is called,
  34. * the <code>DriverManager</code> will attempt to
  35. * locate a suitable driver from amongst those loaded at
  36. * initialization and those loaded explicitly using the same classloader
  37. * as the current applet or application.
  38. * <P>
  39. * Starting with the Java 2 SDK, Standard Edition, version 1.3, a
  40. * logging stream can be set only if the proper
  41. * permission has been granted. Normally this will be done with
  42. * the tool PolicyTool, which can be used to grant <code>permission
  43. * java.sql.SQLPermission "setLog"</code>.
  44. * @see Driver
  45. * @see Connection
  46. * <P>
  47. * Some methods in this class are new in the JDBC 2.0 API. They are marked
  48. * with "since 1.2". API marked "since 1.3" is new in the JDBC 2.0 API and
  49. * is included in the Java 2 SDK, Standard Edition, version 1.3.
  50. */
  51. public class DriverManager {
  52. /**
  53. * The <code>SQLPermission</code> constant that allows the
  54. * setting of the logging stream.
  55. * @since 1.3
  56. */
  57. final static SQLPermission SET_LOG_PERMISSION =
  58. new SQLPermission("setLog");
  59. //--------------------------JDBC 2.0-----------------------------
  60. /**
  61. * Gets the log writer.
  62. *
  63. * The <code>getLogWriter</code> and <code>setLogWriter</code>
  64. * methods should be used instead
  65. * of the <code>get/setlogStream</code> methods, which are deprecated.
  66. * @return a <code>java.io.PrintWriter</code> object
  67. * @see <a href="package-summary.html#2.0 API">What Is in the JDBC
  68. * 2.0 API</a>
  69. * @since 1.2
  70. */
  71. public static java.io.PrintWriter getLogWriter() {
  72. return logWriter;
  73. }
  74. /**
  75. * Sets the logging/tracing <code>PrintWriter</code> object
  76. * that is used by the <code>DriverManager</code> and all drivers.
  77. * <P>
  78. * There is a minor versioning problem created by the introduction
  79. * of the method </code>setLogWriter</code>. The
  80. * method <code>setLogWriter</code> cannot create a <code>PrintStream</code> object
  81. * that will be returned by <code>getLogStream</code>---the Java platform does
  82. * not provide a backward conversion. As a result, a new application
  83. * that uses <code>setLogWriter</code> and also uses a JDBC 1.0 driver that uses
  84. * <code>getLogStream</code> will likely not see debugging information written
  85. * by that driver.
  86. *<P>
  87. * In the Java 2 SDK, Standard Edition, version 1.3 release, this method checks
  88. * to see that there is an <code>SQLPermission</code> object before setting
  89. * the logging stream. If a <code>SecurityManager</code> exists and its
  90. * <code>checkPermission</code> method denies setting the log writer, this
  91. * method throws a <code>java.lang.SecurityException</code>.
  92. *
  93. * @param out the new logging/tracing <code>PrintStream</code> object;
  94. * <code>null</code> to disable logging and tracing
  95. * @throws SecurityException
  96. * if a security manager exists and its
  97. * <code>checkPermission</code> method denies
  98. * setting the log writer
  99. *
  100. * @see SecurityManager#checkPermission
  101. * @see <a href="package-summary.html#2.0 API">What Is in the JDBC
  102. * 2.0 API</a>
  103. * @since 1.2
  104. */
  105. public static synchronized void setLogWriter(java.io.PrintWriter out) {
  106. SecurityManager sec = System.getSecurityManager();
  107. if (sec != null) {
  108. sec.checkPermission(SET_LOG_PERMISSION);
  109. }
  110. logStream = null;
  111. logWriter = out;
  112. }
  113. //---------------------------------------------------------------
  114. /**
  115. * Attempts to establish a connection to the given database URL.
  116. * The <code>DriverManager</code> attempts to select an appropriate driver from
  117. * the set of registered JDBC drivers.
  118. *
  119. * @param url a database url of the form
  120. * <code> jdbc:<em>subprotocol</em>:<em>subname</em></code>
  121. * @param info a list of arbitrary string tag/value pairs as
  122. * connection arguments; normally at least a "user" and
  123. * "password" property should be included
  124. * @return a Connection to the URL
  125. * @exception SQLException if a database access error occurs
  126. */
  127. public static synchronized Connection getConnection(String url,
  128. java.util.Properties info) throws SQLException {
  129. // Gets the classloader of the code that called this method, may
  130. // be null.
  131. ClassLoader callerCL = DriverManager.getCallerClassLoader();
  132. return (getConnection(url, info, callerCL));
  133. }
  134. /**
  135. * Attempts to establish a connection to the given database URL.
  136. * The <code>DriverManager</code> attempts to select an appropriate driver from
  137. * the set of registered JDBC drivers.
  138. *
  139. * @param url a database url of the form
  140. * <code>jdbc:<em>subprotocol</em>:<em>subname</em></code>
  141. * @param user the database user on whose behalf the connection is being
  142. * made
  143. * @param password the user's password
  144. * @return a connection to the URL
  145. * @exception SQLException if a database access error occurs
  146. */
  147. public static synchronized Connection getConnection(String url,
  148. String user, String password) throws SQLException {
  149. java.util.Properties info = new java.util.Properties();
  150. // Gets the classloader of the code that called this method, may
  151. // be null.
  152. ClassLoader callerCL = DriverManager.getCallerClassLoader();
  153. if (user != null) {
  154. info.put("user", user);
  155. }
  156. if (password != null) {
  157. info.put("password", password);
  158. }
  159. return (getConnection(url, info, callerCL));
  160. }
  161. /**
  162. * Attempts to establish a connection to the given database URL.
  163. * The <code>DriverManager</code> attempts to select an appropriate driver from
  164. * the set of registered JDBC drivers.
  165. *
  166. * @param url a database url of the form
  167. * <code> jdbc:<em>subprotocol</em>:<em>subname</em></code>
  168. * @return a connection to the URL
  169. * @exception SQLException if a database access error occurs
  170. */
  171. public static synchronized Connection getConnection(String url)
  172. throws SQLException {
  173. java.util.Properties info = new java.util.Properties();
  174. // Gets the classloader of the code that called this method, may
  175. // be null.
  176. ClassLoader callerCL = DriverManager.getCallerClassLoader();
  177. return (getConnection(url, info, callerCL));
  178. }
  179. /**
  180. * Attempts to locate a driver that understands the given URL.
  181. * The <code>DriverManager</code> attempts to select an appropriate driver from
  182. * the set of registered JDBC drivers.
  183. *
  184. * @param url a database URL of the form
  185. * <code>jdbc:<em>subprotocol</em>:<em>subname</em></code>
  186. * @return a <code>Driver</code> object representing a driver
  187. * that can connect to the given URL
  188. * @exception SQLException if a database access error occurs
  189. */
  190. public static synchronized Driver getDriver(String url)
  191. throws SQLException {
  192. println("DriverManager.getDriver(\"" + url + "\")");
  193. if (!initialized) {
  194. initialize();
  195. }
  196. // Gets the classloader of the code that called this method, may
  197. // be null.
  198. ClassLoader callerCL = DriverManager.getCallerClassLoader();
  199. // Walk through the loaded drivers attempting to locate someone
  200. // who understands the given URL.
  201. for (int i = 0; i < drivers.size(); i++) {
  202. DriverInfo di = (DriverInfo)drivers.elementAt(i);
  203. // If the caller does not have permission to load the driver then
  204. // skip it.
  205. if ( getCallerClass(callerCL, di.driverClassName ) !=
  206. di.driverClass ) {
  207. println(" skipping: " + di);
  208. continue;
  209. }
  210. try {
  211. println(" trying " + di);
  212. if (di.driver.acceptsURL(url)) {
  213. // Success!
  214. println("getDriver returning " + di);
  215. return (di.driver);
  216. }
  217. } catch (SQLException ex) {
  218. // Drop through and try the next driver.
  219. }
  220. }
  221. println("getDriver: no suitable driver");
  222. throw new SQLException("No suitable driver", "08001");
  223. }
  224. /**
  225. * Registers the given driver with the <code>DriverManager</code>.
  226. * A newly-loaded driver class should call
  227. * the method <code>registerDriver</code> to make itself
  228. * known to the <code>DriverManager</code>.
  229. *
  230. * @param driver the new JDBC Driver that is to be registered with the
  231. * <code>DriverManager</code>
  232. * @exception SQLException if a database access error occurs
  233. */
  234. public static synchronized void registerDriver(java.sql.Driver driver)
  235. throws SQLException {
  236. if (!initialized) {
  237. initialize();
  238. }
  239. DriverInfo di = new DriverInfo();
  240. di.driver = driver;
  241. di.driverClass = driver.getClass();
  242. di.driverClassName = di.driverClass.getName();
  243. drivers.addElement(di);
  244. println("registerDriver: " + di);
  245. }
  246. /**
  247. * Drops a Driver from the <code>DriverManager</code>'s list. Applets can only
  248. * deregister Drivers from their own classloaders.
  249. *
  250. * @param driver the JDBC Driver to drop
  251. * @exception SQLException if a database access error occurs
  252. */
  253. public static synchronized void deregisterDriver(Driver driver)
  254. throws SQLException {
  255. // Gets the classloader of the code that called this method, may
  256. // be null.
  257. ClassLoader callerCL = DriverManager.getCallerClassLoader();
  258. println("DriverManager.deregisterDriver: " + driver);
  259. // Walk through the loaded drivers.
  260. int i;
  261. DriverInfo di = null;
  262. for (i = 0; i < drivers.size(); i++) {
  263. di = (DriverInfo)drivers.elementAt(i);
  264. if (di.driver == driver) {
  265. break;
  266. }
  267. }
  268. // If we can't find the driver just return.
  269. if (i >= drivers.size()) {
  270. println(" couldn't find driver to unload");
  271. return;
  272. }
  273. // If the caller does not have permission to load the driver then
  274. // throw a security exception.
  275. if ( getCallerClass(callerCL, di.driverClassName ) != di.driverClass ) {
  276. throw new SecurityException();
  277. }
  278. // Remove the driver. Other entries in drivers get shuffled down.
  279. drivers.removeElementAt(i);
  280. }
  281. /**
  282. * Retrieves an Enumeration with all of the currently loaded JDBC drivers
  283. * to which the current caller has access.
  284. *
  285. * <P><B>Note:</B> The classname of a driver can be found using
  286. * <CODE>d.getClass().getName()</CODE>
  287. *
  288. * @return the list of JDBC Drivers loaded by the caller's class loader
  289. */
  290. public static synchronized java.util.Enumeration getDrivers() {
  291. java.util.Vector result = new java.util.Vector();
  292. if (!initialized) {
  293. initialize();
  294. }
  295. // Gets the classloader of the code that called this method, may
  296. // be null.
  297. ClassLoader callerCL = DriverManager.getCallerClassLoader();
  298. // Walk through the loaded drivers.
  299. for (int i = 0; i < drivers.size(); i++) {
  300. DriverInfo di = (DriverInfo)drivers.elementAt(i);
  301. // If the caller does not have permission to load the driver then
  302. // skip it.
  303. if ( getCallerClass(callerCL, di.driverClassName ) != di.driverClass ) {
  304. println(" skipping: " + di);
  305. continue;
  306. }
  307. result.addElement(di.driver);
  308. }
  309. return (result.elements());
  310. }
  311. /**
  312. * <p>Sets the maximum time in seconds that a driver will wait
  313. * while attempting to connect to a database.
  314. *
  315. * @param seconds the login time limit in seconds
  316. */
  317. public static void setLoginTimeout(int seconds) {
  318. loginTimeout = seconds;
  319. }
  320. /**
  321. * Gets the maximum time in seconds that a driver can wait
  322. * when attempting to log in to a database.
  323. *
  324. * @return the driver login time limit in seconds
  325. */
  326. public static int getLoginTimeout() {
  327. return (loginTimeout);
  328. }
  329. /**
  330. * Sets the logging/tracing PrintStream that is used
  331. * by the <code>DriverManager</code>
  332. * and all drivers.
  333. *<P>
  334. * In the Java 2 SDK, Standard Edition, version 1.3 release, this method checks
  335. * to see that there is an <code>SQLPermission</code> object before setting
  336. * the logging stream. If a <code>SecurityManager</code> exists and its
  337. * <code>checkPermission</code> method denies setting the log writer, this
  338. * method throws a <code>java.lang.SecurityException</code>.
  339. *
  340. * @param out the new logging/tracing PrintStream; to disable, set to <code>null</code>
  341. * @deprecated
  342. * @throws SecurityException
  343. * if a security manager exists and its
  344. * <code>checkPermission</code> method denies
  345. * setting the log stream.
  346. *
  347. * @see SecurityManager#checkPermission
  348. */
  349. public static synchronized void setLogStream(java.io.PrintStream out) {
  350. SecurityManager sec = System.getSecurityManager();
  351. if (sec != null) {
  352. sec.checkPermission(SET_LOG_PERMISSION);
  353. }
  354. logStream = out;
  355. if ( out != null )
  356. logWriter = new java.io.PrintWriter(out);
  357. else
  358. logWriter = null;
  359. }
  360. /**
  361. * Gets the logging/tracing PrintStream that is used by the <code>DriverManager</code>
  362. * and all drivers.
  363. *
  364. * @return the logging/tracing PrintStream; if disabled, is <code>null</code>
  365. * @deprecated
  366. */
  367. public static java.io.PrintStream getLogStream() {
  368. return logStream;
  369. }
  370. /**
  371. * Prints a message to the current JDBC log stream.
  372. *
  373. * @param message a log or tracing message
  374. */
  375. public static synchronized void println(String message) {
  376. if (logWriter != null) {
  377. logWriter.println(message);
  378. // automatic flushing is never enabled, so we must do it ourselves
  379. logWriter.flush();
  380. }
  381. }
  382. //------------------------------------------------------------------------
  383. // Returns the class object that would be created if the code calling the
  384. // driver manager had loaded the driver class, or null if the class
  385. // is inaccessible.
  386. private static Class getCallerClass(ClassLoader callerClassLoader,
  387. String driverClassName) {
  388. Class callerC = null;
  389. try {
  390. callerC = Class.forName(driverClassName, true, callerClassLoader);
  391. }
  392. catch (Exception ex) {
  393. callerC = null; // being very careful
  394. }
  395. return callerC;
  396. }
  397. private static void loadInitialDrivers() {
  398. String drivers;
  399. try {
  400. drivers = (String) java.security.AccessController.doPrivileged(
  401. new sun.security.action.GetPropertyAction("jdbc.drivers"));
  402. } catch (Exception ex) {
  403. drivers = null;
  404. }
  405. println("DriverManager.initialize: jdbc.drivers = " + drivers);
  406. if (drivers == null) {
  407. return;
  408. }
  409. while (drivers.length() != 0) {
  410. int x = drivers.indexOf(':');
  411. String driver;
  412. if (x < 0) {
  413. driver = drivers;
  414. drivers = "";
  415. } else {
  416. driver = drivers.substring(0, x);
  417. drivers = drivers.substring(x+1);
  418. }
  419. if (driver.length() == 0) {
  420. continue;
  421. }
  422. try {
  423. println("DriverManager.Initialize: loading " + driver);
  424. Class.forName(driver, true,
  425. ClassLoader.getSystemClassLoader());
  426. } catch (Exception ex) {
  427. println("DriverManager.Initialize: load failed: " + ex);
  428. }
  429. }
  430. }
  431. // Worker method called by the public getConnection() methods.
  432. private static synchronized Connection getConnection(
  433. String url,
  434. java.util.Properties info,
  435. ClassLoader callerCL) throws SQLException
  436. {
  437. if(url == null) {
  438. throw new SQLException("The url cannot be null", "08001");
  439. }
  440. println("DriverManager.getConnection(\"" + url + "\")");
  441. if (!initialized) {
  442. initialize();
  443. }
  444. // Walk through the loaded drivers attempting to make a connection.
  445. // Remember the first exception that gets raised so we can reraise it.
  446. SQLException reason = null;
  447. for (int i = 0; i < drivers.size(); i++) {
  448. DriverInfo di = (DriverInfo)drivers.elementAt(i);
  449. // If the caller does not have permission to load the driver then
  450. // skip it.
  451. if ( getCallerClass(callerCL, di.driverClassName ) != di.driverClass ) {
  452. println(" skipping: " + di);
  453. continue;
  454. }
  455. try {
  456. println(" trying " + di);
  457. Connection result = di.driver.connect(url, info);
  458. if (result != null) {
  459. // Success!
  460. println("getConnection returning " + di);
  461. return (result);
  462. }
  463. } catch (SQLException ex) {
  464. if (reason == null) {
  465. reason = ex;
  466. }
  467. }
  468. }
  469. // if we got here nobody could connect.
  470. if (reason != null) {
  471. println("getConnection failed: " + reason);
  472. throw reason;
  473. }
  474. println("getConnection: no suitable driver");
  475. throw new SQLException("No suitable driver", "08001");
  476. }
  477. // Class initialization.
  478. static void initialize() {
  479. if (initialized) {
  480. return;
  481. }
  482. initialized = true;
  483. loadInitialDrivers();
  484. println("JDBC DriverManager initialized");
  485. }
  486. // Prevent the DriverManager class from being instantiated.
  487. private DriverManager(){}
  488. private static java.util.Vector drivers = new java.util.Vector();
  489. private static int loginTimeout = 0;
  490. private static java.io.PrintWriter logWriter = null;
  491. private static java.io.PrintStream logStream = null;
  492. private static boolean initialized = false;
  493. // Returns the caller's class loader, or null if none
  494. private static native ClassLoader getCallerClassLoader();
  495. }
  496. // DriverInfo is a package-private support class.
  497. class DriverInfo {
  498. Driver driver;
  499. Class driverClass;
  500. String driverClassName;
  501. public String toString() {
  502. return ("driver[className=" + driverClassName + "," + driver + "]");
  503. }
  504. }