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