1. /*
  2. * Copyright 1999-2004 The Apache Software Foundation.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. package org.apache.commons.dbcp;
  17. import java.io.PrintWriter;
  18. import java.util.Properties;
  19. import java.sql.Connection;
  20. import java.sql.Driver;
  21. import java.sql.DriverManager;
  22. import java.sql.SQLException;
  23. import javax.sql.DataSource;
  24. import org.apache.commons.pool.impl.GenericKeyedObjectPool;
  25. import org.apache.commons.pool.impl.GenericKeyedObjectPoolFactory;
  26. import org.apache.commons.pool.impl.GenericObjectPool;
  27. /**
  28. * <p>Basic implementation of <code>javax.sql.DataSource</code> that is
  29. * configured via JavaBeans properties. This is not the only way to
  30. * combine the <em>commons-dbcp</em> and <em>commons-pool</em> packages,
  31. * but provides a "one stop shopping" solution for basic requirements.</p>
  32. *
  33. * @author Glenn L. Nielsen
  34. * @author Craig R. McClanahan
  35. * @author Dirk Verbeeck
  36. * @version $Revision: 1.37 $ $Date: 2004/06/09 18:21:23 $
  37. */
  38. public class BasicDataSource implements DataSource {
  39. // ------------------------------------------------------------- Properties
  40. /**
  41. * The default auto-commit state of connections created by this pool.
  42. */
  43. protected boolean defaultAutoCommit = true;
  44. public synchronized boolean getDefaultAutoCommit() {
  45. return this.defaultAutoCommit;
  46. }
  47. public synchronized void setDefaultAutoCommit(boolean defaultAutoCommit) {
  48. this.defaultAutoCommit = defaultAutoCommit;
  49. this.restartNeeded = true;
  50. }
  51. /**
  52. * The default read-only state of connections created by this pool.
  53. */
  54. protected Boolean defaultReadOnly = null;
  55. public synchronized boolean getDefaultReadOnly() {
  56. if (this.defaultReadOnly != null) {
  57. return this.defaultReadOnly.booleanValue();
  58. }
  59. return false;
  60. }
  61. public synchronized void setDefaultReadOnly(boolean defaultReadOnly) {
  62. this.defaultReadOnly = defaultReadOnly ? Boolean.TRUE : Boolean.FALSE;
  63. this.restartNeeded = true;
  64. }
  65. /**
  66. * The default TransactionIsolation state of connections created by this pool.
  67. */
  68. protected int defaultTransactionIsolation = PoolableConnectionFactory.UNKNOWN_TRANSACTIONISOLATION;
  69. public synchronized int getDefaultTransactionIsolation() {
  70. return this.defaultTransactionIsolation;
  71. }
  72. public synchronized void setDefaultTransactionIsolation(int defaultTransactionIsolation) {
  73. this.defaultTransactionIsolation = defaultTransactionIsolation;
  74. this.restartNeeded = true;
  75. }
  76. /**
  77. * The default "catalog" of connections created by this pool.
  78. */
  79. protected String defaultCatalog = null;
  80. public synchronized String getDefaultCatalog() {
  81. return this.defaultCatalog;
  82. }
  83. public synchronized void setDefaultCatalog(String defaultCatalog) {
  84. if ((defaultCatalog != null) && (defaultCatalog.trim().length() > 0)) {
  85. this.defaultCatalog = defaultCatalog;
  86. }
  87. else {
  88. this.defaultCatalog = null;
  89. }
  90. this.restartNeeded = true;
  91. }
  92. /**
  93. * The fully qualified Java class name of the JDBC driver to be used.
  94. */
  95. protected String driverClassName = null;
  96. public synchronized String getDriverClassName() {
  97. return this.driverClassName;
  98. }
  99. public synchronized void setDriverClassName(String driverClassName) {
  100. if ((driverClassName != null) && (driverClassName.trim().length() > 0)) {
  101. this.driverClassName = driverClassName;
  102. }
  103. else {
  104. this.driverClassName = null;
  105. }
  106. this.restartNeeded = true;
  107. }
  108. /**
  109. * The maximum number of active connections that can be allocated from
  110. * this pool at the same time, or zero for no limit.
  111. */
  112. protected int maxActive = GenericObjectPool.DEFAULT_MAX_ACTIVE;
  113. public synchronized int getMaxActive() {
  114. return this.maxActive;
  115. }
  116. public synchronized void setMaxActive(int maxActive) {
  117. this.maxActive = maxActive;
  118. if (connectionPool != null) {
  119. connectionPool.setMaxActive(maxActive);
  120. }
  121. }
  122. /**
  123. * The maximum number of active connections that can remain idle in the
  124. * pool, without extra ones being released, or zero for no limit.
  125. */
  126. protected int maxIdle = GenericObjectPool.DEFAULT_MAX_IDLE;;
  127. public synchronized int getMaxIdle() {
  128. return this.maxIdle;
  129. }
  130. public synchronized void setMaxIdle(int maxIdle) {
  131. this.maxIdle = maxIdle;
  132. if (connectionPool != null) {
  133. connectionPool.setMaxIdle(maxIdle);
  134. }
  135. }
  136. /**
  137. * The minimum number of active connections that can remain idle in the
  138. * pool, without extra ones being created, or 0 to create none.
  139. */
  140. protected int minIdle = GenericObjectPool.DEFAULT_MIN_IDLE;;
  141. public synchronized int getMinIdle() {
  142. return this.minIdle;
  143. }
  144. public synchronized void setMinIdle(int minIdle) {
  145. this.minIdle = minIdle;
  146. if (connectionPool != null) {
  147. connectionPool.setMinIdle(minIdle);
  148. }
  149. }
  150. /**
  151. * The initial number of connections that are created when the pool
  152. * is started.
  153. * @since 1.2
  154. */
  155. protected int initialSize = 0;
  156. public synchronized int getInitialSize() {
  157. return this.initialSize;
  158. }
  159. public synchronized void setInitialSize(int initialSize) {
  160. this.initialSize = initialSize;
  161. this.restartNeeded = true;
  162. }
  163. /**
  164. * The maximum number of milliseconds that the pool will wait (when there
  165. * are no available connections) for a connection to be returned before
  166. * throwing an exception, or -1 to wait indefinitely.
  167. */
  168. protected long maxWait = GenericObjectPool.DEFAULT_MAX_WAIT;
  169. public synchronized long getMaxWait() {
  170. return this.maxWait;
  171. }
  172. public synchronized void setMaxWait(long maxWait) {
  173. this.maxWait = maxWait;
  174. if (connectionPool != null) {
  175. connectionPool.setMaxWait(maxWait);
  176. }
  177. }
  178. /**
  179. * Prepared statement pooling for this pool.
  180. */
  181. protected boolean poolPreparedStatements = false;
  182. /**
  183. * Returns true if we are pooling statements.
  184. * @return boolean
  185. */
  186. public synchronized boolean isPoolPreparedStatements() {
  187. return this.poolPreparedStatements;
  188. }
  189. /**
  190. * Sets whether to pool statements or not.
  191. * @param poolPreparedStatements pooling on or off
  192. */
  193. public synchronized void setPoolPreparedStatements(boolean poolingStatements) {
  194. this.poolPreparedStatements = poolingStatements;
  195. this.restartNeeded = true;
  196. }
  197. /**
  198. * The maximum number of open statements that can be allocated from
  199. * the statement pool at the same time, or zero for no limit. Since
  200. * a connection usually only uses one or two statements at a time, this is
  201. * mostly used to help detect resource leaks.
  202. */
  203. protected int maxOpenPreparedStatements = GenericKeyedObjectPool.DEFAULT_MAX_TOTAL;
  204. public synchronized int getMaxOpenPreparedStatements() {
  205. return this.maxOpenPreparedStatements;
  206. }
  207. public synchronized void setMaxOpenPreparedStatements(int maxOpenStatements) {
  208. this.maxOpenPreparedStatements = maxOpenStatements;
  209. this.restartNeeded = true;
  210. }
  211. /**
  212. * The indication of whether objects will be validated before being
  213. * borrowed from the pool. If the object fails to validate, it will be
  214. * dropped from the pool, and we will attempt to borrow another.
  215. */
  216. protected boolean testOnBorrow = true;
  217. public synchronized boolean getTestOnBorrow() {
  218. return this.testOnBorrow;
  219. }
  220. public synchronized void setTestOnBorrow(boolean testOnBorrow) {
  221. this.testOnBorrow = testOnBorrow;
  222. if (connectionPool != null) {
  223. connectionPool.setTestOnBorrow(testOnBorrow);
  224. }
  225. }
  226. /**
  227. * The indication of whether objects will be validated before being
  228. * returned to the pool.
  229. */
  230. protected boolean testOnReturn = false;
  231. public synchronized boolean getTestOnReturn() {
  232. return this.testOnReturn;
  233. }
  234. public synchronized void setTestOnReturn(boolean testOnReturn) {
  235. this.testOnReturn = testOnReturn;
  236. if (connectionPool != null) {
  237. connectionPool.setTestOnReturn(testOnReturn);
  238. }
  239. }
  240. /**
  241. * The number of milliseconds to sleep between runs of the idle object
  242. * evictor thread. When non-positive, no idle object evictor thread will
  243. * be run.
  244. */
  245. protected long timeBetweenEvictionRunsMillis =
  246. GenericObjectPool.DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS;
  247. public synchronized long getTimeBetweenEvictionRunsMillis() {
  248. return this.timeBetweenEvictionRunsMillis;
  249. }
  250. public synchronized void setTimeBetweenEvictionRunsMillis(long timeBetweenEvictionRunsMillis) {
  251. this.timeBetweenEvictionRunsMillis = timeBetweenEvictionRunsMillis;
  252. if (connectionPool != null) {
  253. connectionPool.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
  254. }
  255. }
  256. /**
  257. * The number of objects to examine during each run of the idle object
  258. * evictor thread (if any).
  259. */
  260. protected int numTestsPerEvictionRun =
  261. GenericObjectPool.DEFAULT_NUM_TESTS_PER_EVICTION_RUN;
  262. public synchronized int getNumTestsPerEvictionRun() {
  263. return this.numTestsPerEvictionRun;
  264. }
  265. public synchronized void setNumTestsPerEvictionRun(int numTestsPerEvictionRun) {
  266. this.numTestsPerEvictionRun = numTestsPerEvictionRun;
  267. if (connectionPool != null) {
  268. connectionPool.setNumTestsPerEvictionRun(numTestsPerEvictionRun);
  269. }
  270. }
  271. /**
  272. * The minimum amount of time an object may sit idle in the pool before it
  273. * is eligable for eviction by the idle object evictor (if any).
  274. */
  275. protected long minEvictableIdleTimeMillis =
  276. GenericObjectPool.DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS;
  277. public synchronized long getMinEvictableIdleTimeMillis() {
  278. return this.minEvictableIdleTimeMillis;
  279. }
  280. public synchronized void setMinEvictableIdleTimeMillis(long minEvictableIdleTimeMillis) {
  281. this.minEvictableIdleTimeMillis = minEvictableIdleTimeMillis;
  282. if (connectionPool != null) {
  283. connectionPool.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
  284. }
  285. }
  286. /**
  287. * The indication of whether objects will be validated by the idle object
  288. * evictor (if any). If an object fails to validate, it will be dropped
  289. * from the pool.
  290. */
  291. protected boolean testWhileIdle = false;
  292. public synchronized boolean getTestWhileIdle() {
  293. return this.testWhileIdle;
  294. }
  295. public synchronized void setTestWhileIdle(boolean testWhileIdle) {
  296. this.testWhileIdle = testWhileIdle;
  297. if (connectionPool != null) {
  298. connectionPool.setTestWhileIdle(testWhileIdle);
  299. }
  300. }
  301. /**
  302. * [Read Only] The current number of active connections that have been
  303. * allocated from this data source.
  304. */
  305. public synchronized int getNumActive() {
  306. if (connectionPool != null) {
  307. return connectionPool.getNumActive();
  308. } else {
  309. return 0;
  310. }
  311. }
  312. /**
  313. * [Read Only] The current number of idle connections that are waiting
  314. * to be allocated from this data source.
  315. */
  316. public synchronized int getNumIdle() {
  317. if (connectionPool != null) {
  318. return connectionPool.getNumIdle();
  319. } else {
  320. return 0;
  321. }
  322. }
  323. /**
  324. * The connection password to be passed to our JDBC driver to establish
  325. * a connection.
  326. */
  327. protected String password = null;
  328. public synchronized String getPassword() {
  329. return this.password;
  330. }
  331. public synchronized void setPassword(String password) {
  332. this.password = password;
  333. this.restartNeeded = true;
  334. }
  335. /**
  336. * The connection URL to be passed to our JDBC driver to establish
  337. * a connection.
  338. */
  339. protected String url = null;
  340. public synchronized String getUrl() {
  341. return this.url;
  342. }
  343. public synchronized void setUrl(String url) {
  344. this.url = url;
  345. this.restartNeeded = true;
  346. }
  347. /**
  348. * The connection username to be passed to our JDBC driver to
  349. * establish a connection.
  350. */
  351. protected String username = null;
  352. public synchronized String getUsername() {
  353. return this.username;
  354. }
  355. public synchronized void setUsername(String username) {
  356. this.username = username;
  357. this.restartNeeded = true;
  358. }
  359. /**
  360. * The SQL query that will be used to validate connections from this pool
  361. * before returning them to the caller. If specified, this query
  362. * <strong>MUST</strong> be an SQL SELECT statement that returns at least
  363. * one row.
  364. */
  365. protected String validationQuery = null;
  366. public synchronized String getValidationQuery() {
  367. return this.validationQuery;
  368. }
  369. public synchronized void setValidationQuery(String validationQuery) {
  370. if ((validationQuery != null) && (validationQuery.trim().length() > 0)) {
  371. this.validationQuery = validationQuery;
  372. } else {
  373. this.validationQuery = null;
  374. }
  375. this.restartNeeded = true;
  376. }
  377. /**
  378. * Controls access to the underlying connection
  379. */
  380. private boolean accessToUnderlyingConnectionAllowed = false;
  381. /**
  382. * Returns the value of the accessToUnderlyingConnectionAllowed property.
  383. *
  384. * @return true if access to the underlying is allowed, false otherwise.
  385. */
  386. public synchronized boolean isAccessToUnderlyingConnectionAllowed() {
  387. return this.accessToUnderlyingConnectionAllowed;
  388. }
  389. /**
  390. * Sets the value of the accessToUnderlyingConnectionAllowed property.
  391. * It controls if the PoolGuard allows access to the underlying connection.
  392. * (Default: false)
  393. *
  394. * @param allow Access to the underlying connection is granted when true.
  395. */
  396. public synchronized void setAccessToUnderlyingConnectionAllowed(boolean allow) {
  397. this.accessToUnderlyingConnectionAllowed = allow;
  398. this.restartNeeded = true;
  399. }
  400. // ----------------------------------------------------- Instance Variables
  401. // TODO: review & make isRestartNeeded() public, restartNeeded protected
  402. private boolean restartNeeded = false;
  403. /**
  404. * Returns whether or not a restart is needed.
  405. * @return true if a restart is needed
  406. */
  407. private synchronized boolean isRestartNeeded() {
  408. return restartNeeded;
  409. }
  410. /**
  411. * The object pool that internally manages our connections.
  412. */
  413. protected GenericObjectPool connectionPool = null;
  414. /**
  415. * The connection properties that will be sent to our JDBC driver when
  416. * establishing new connections. <strong>NOTE</strong> - The "user" and
  417. * "password" properties will be passed explicitly, so they do not need
  418. * to be included here.
  419. */
  420. protected Properties connectionProperties = new Properties();
  421. /**
  422. * The data source we will use to manage connections. This object should
  423. * be acquired <strong>ONLY</strong> by calls to the
  424. * <code>createDataSource()</code> method.
  425. */
  426. protected DataSource dataSource = null;
  427. /**
  428. * The PrintWriter to which log messages should be directed.
  429. */
  430. protected PrintWriter logWriter = new PrintWriter(System.out);
  431. // ----------------------------------------------------- DataSource Methods
  432. /**
  433. * Create (if necessary) and return a connection to the database.
  434. *
  435. * @exception SQLException if a database access error occurs
  436. */
  437. public Connection getConnection() throws SQLException {
  438. return createDataSource().getConnection();
  439. }
  440. /**
  441. * Create (if necessary) and return a connection to the database.
  442. *
  443. * @param username Database user on whose behalf the Connection
  444. * is being made
  445. * @param password The database user's password
  446. *
  447. * @exception SQLException if a database access error occurs
  448. */
  449. public Connection getConnection(String username, String password) throws SQLException {
  450. return createDataSource().getConnection(username, password);
  451. }
  452. /**
  453. * Return the login timeout (in seconds) for connecting to the database.
  454. *
  455. * @exception SQLException if a database access error occurs
  456. */
  457. public int getLoginTimeout() throws SQLException {
  458. return createDataSource().getLoginTimeout();
  459. }
  460. /**
  461. * Return the log writer being used by this data source.
  462. *
  463. * @exception SQLException if a database access error occurs
  464. */
  465. public PrintWriter getLogWriter() throws SQLException {
  466. return createDataSource().getLogWriter();
  467. }
  468. /**
  469. * Set the login timeout (in seconds) for connecting to the database.
  470. *
  471. * @param loginTimeout The new login timeout, or zero for no timeout
  472. *
  473. * @exception SQLException if a database access error occurs
  474. */
  475. public void setLoginTimeout(int loginTimeout) throws SQLException {
  476. createDataSource().setLoginTimeout(loginTimeout);
  477. }
  478. /**
  479. * Set the log writer being used by this data source.
  480. *
  481. * @param logWriter The new log writer
  482. *
  483. * @exception SQLException if a database access error occurs
  484. */
  485. public void setLogWriter(PrintWriter logWriter) throws SQLException {
  486. createDataSource().setLogWriter(logWriter);
  487. this.logWriter = logWriter;
  488. }
  489. private AbandonedConfig abandonedConfig;
  490. /**
  491. * Flag to remove abandoned connections if they exceed the
  492. * removeAbandonedTimout.
  493. *
  494. * Set to true or false, default false.
  495. * If set to true a connection is considered abandoned and eligible
  496. * for removal if it has been idle longer than the removeAbandonedTimeout.
  497. * Setting this to true can recover db connections from poorly written
  498. * applications which fail to close a connection.
  499. * @deprecated
  500. */
  501. public boolean getRemoveAbandoned() {
  502. if (abandonedConfig != null) {
  503. return abandonedConfig.getRemoveAbandoned();
  504. }
  505. return false;
  506. }
  507. /**
  508. * @deprecated
  509. * @param removeAbandoned
  510. */
  511. public void setRemoveAbandoned(boolean removeAbandoned) {
  512. if (abandonedConfig == null) {
  513. abandonedConfig = new AbandonedConfig();
  514. }
  515. abandonedConfig.setRemoveAbandoned(removeAbandoned);
  516. this.restartNeeded = true;
  517. }
  518. /**
  519. * Timeout in seconds before an abandoned connection can be removed.
  520. *
  521. * Defaults to 300 seconds.
  522. * @deprecated
  523. */
  524. public int getRemoveAbandonedTimeout() {
  525. if (abandonedConfig != null) {
  526. return abandonedConfig.getRemoveAbandonedTimeout();
  527. }
  528. return 300;
  529. }
  530. /**
  531. * @deprecated
  532. * @param removeAbandonedTimeout
  533. */
  534. public void setRemoveAbandonedTimeout(int removeAbandonedTimeout) {
  535. if (abandonedConfig == null) {
  536. abandonedConfig = new AbandonedConfig();
  537. }
  538. abandonedConfig.setRemoveAbandonedTimeout(removeAbandonedTimeout);
  539. this.restartNeeded = true;
  540. }
  541. /**
  542. * Flag to log stack traces for application code which abandoned
  543. * a Statement or Connection.
  544. *
  545. * Defaults to false.
  546. *
  547. * Logging of abandoned Statements and Connections adds overhead
  548. * for every Connection open or new Statement because a stack
  549. * trace has to be generated.
  550. * @deprecated
  551. */
  552. public boolean getLogAbandoned() {
  553. if (abandonedConfig != null) {
  554. return abandonedConfig.getLogAbandoned();
  555. }
  556. return false;
  557. }
  558. /**
  559. * @deprecated
  560. * @param logAbandoned
  561. */
  562. public void setLogAbandoned(boolean logAbandoned) {
  563. if (abandonedConfig == null) {
  564. abandonedConfig = new AbandonedConfig();
  565. }
  566. abandonedConfig.setLogAbandoned(logAbandoned);
  567. this.restartNeeded = true;
  568. }
  569. // --------------------------------------------------------- Public Methods
  570. /**
  571. * Add a custom connection property to the set that will be passed to our
  572. * JDBC driver. This <strong>MUST</strong> be called before the first
  573. * connection is retrieved (along with all the other configuration
  574. * property setters).
  575. *
  576. * @param name Name of the custom connection property
  577. * @param value Value of the custom connection property
  578. */
  579. public void addConnectionProperty(String name, String value) {
  580. connectionProperties.put(name, value);
  581. this.restartNeeded = true;
  582. }
  583. public void removeConnectionProperty(String name) {
  584. connectionProperties.remove(name);
  585. this.restartNeeded = true;
  586. }
  587. /**
  588. * Close and release all connections that are currently stored in the
  589. * connection pool associated with our data source.
  590. *
  591. * @exception SQLException if a database error occurs
  592. */
  593. public synchronized void close() throws SQLException {
  594. GenericObjectPool oldpool = connectionPool;
  595. connectionPool = null;
  596. dataSource = null;
  597. try {
  598. if (oldpool != null) {
  599. oldpool.close();
  600. }
  601. } catch(SQLException e) {
  602. throw e;
  603. } catch(RuntimeException e) {
  604. throw e;
  605. } catch(Exception e) {
  606. throw new SQLNestedException("Cannot close connection pool", e);
  607. }
  608. }
  609. // ------------------------------------------------------ Protected Methods
  610. /**
  611. * <p>Create (if necessary) and return the internal data source we are
  612. * using to manage our connections.</p>
  613. *
  614. * <p><strong>IMPLEMENTATION NOTE</strong> - It is tempting to use the
  615. * "double checked locking" idiom in an attempt to avoid synchronizing
  616. * on every single call to this method. However, this idiom fails to
  617. * work correctly in the face of some optimizations that are legal for
  618. * a JVM to perform.</p>
  619. *
  620. * @exception SQLException if the object pool cannot be created.
  621. */
  622. protected synchronized DataSource createDataSource()
  623. throws SQLException {
  624. // Return the pool if we have already created it
  625. if (dataSource != null) {
  626. return (dataSource);
  627. }
  628. // Load the JDBC driver class
  629. if (driverClassName != null) {
  630. try {
  631. Class.forName(driverClassName);
  632. } catch (Throwable t) {
  633. String message = "Cannot load JDBC driver class '" +
  634. driverClassName + "'";
  635. logWriter.println(message);
  636. t.printStackTrace(logWriter);
  637. throw new SQLNestedException(message, t);
  638. }
  639. }
  640. // Create a JDBC driver instance
  641. Driver driver = null;
  642. try {
  643. driver = DriverManager.getDriver(url);
  644. } catch (Throwable t) {
  645. String message = "Cannot create JDBC driver of class '" +
  646. (driverClassName != null ? driverClassName : "") +
  647. "' for connect URL '" + url + "'";
  648. logWriter.println(message);
  649. t.printStackTrace(logWriter);
  650. throw new SQLNestedException(message, t);
  651. }
  652. // Can't test without a validationQuery
  653. if (validationQuery == null) {
  654. setTestOnBorrow(false);
  655. setTestOnReturn(false);
  656. setTestWhileIdle(false);
  657. }
  658. // Create an object pool to contain our active connections
  659. if ((abandonedConfig != null) && (abandonedConfig.getRemoveAbandoned() == true)) {
  660. connectionPool = new AbandonedObjectPool(null,abandonedConfig);
  661. }
  662. else {
  663. connectionPool = new GenericObjectPool();
  664. }
  665. connectionPool.setMaxActive(maxActive);
  666. connectionPool.setMaxIdle(maxIdle);
  667. connectionPool.setMinIdle(minIdle);
  668. connectionPool.setMaxWait(maxWait);
  669. connectionPool.setTestOnBorrow(testOnBorrow);
  670. connectionPool.setTestOnReturn(testOnReturn);
  671. connectionPool.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
  672. connectionPool.setNumTestsPerEvictionRun(numTestsPerEvictionRun);
  673. connectionPool.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
  674. connectionPool.setTestWhileIdle(testWhileIdle);
  675. // Set up statement pool, if desired
  676. GenericKeyedObjectPoolFactory statementPoolFactory = null;
  677. if (isPoolPreparedStatements()) {
  678. statementPoolFactory = new GenericKeyedObjectPoolFactory(null,
  679. -1, // unlimited maxActive (per key)
  680. GenericKeyedObjectPool.WHEN_EXHAUSTED_FAIL,
  681. 0, // maxWait
  682. 1, // maxIdle (per key)
  683. maxOpenPreparedStatements);
  684. }
  685. // Set up the driver connection factory we will use
  686. if (username != null) {
  687. connectionProperties.put("user", username);
  688. } else {
  689. log("DBCP DataSource configured without a 'username'");
  690. }
  691. if (password != null) {
  692. connectionProperties.put("password", password);
  693. } else {
  694. log("DBCP DataSource configured without a 'password'");
  695. }
  696. DriverConnectionFactory driverConnectionFactory =
  697. new DriverConnectionFactory(driver, url, connectionProperties);
  698. // Set up the poolable connection factory we will use
  699. PoolableConnectionFactory connectionFactory = null;
  700. try {
  701. connectionFactory =
  702. new PoolableConnectionFactory(driverConnectionFactory,
  703. connectionPool,
  704. statementPoolFactory,
  705. validationQuery,
  706. defaultReadOnly,
  707. defaultAutoCommit,
  708. defaultTransactionIsolation,
  709. defaultCatalog,
  710. abandonedConfig);
  711. if (connectionFactory == null) {
  712. throw new SQLException("Cannot create PoolableConnectionFactory");
  713. }
  714. validateConnectionFactory(connectionFactory);
  715. } catch (RuntimeException e) {
  716. throw e;
  717. } catch (Exception e) {
  718. throw new SQLNestedException("Cannot create PoolableConnectionFactory (" + e.getMessage() + ")", e);
  719. }
  720. // Create and return the pooling data source to manage the connections
  721. dataSource = new PoolingDataSource(connectionPool);
  722. ((PoolingDataSource) dataSource).setAccessToUnderlyingConnectionAllowed(isAccessToUnderlyingConnectionAllowed());
  723. dataSource.setLogWriter(logWriter);
  724. try {
  725. for (int i = 0 ; i < initialSize ; i++) {
  726. connectionPool.addObject();
  727. }
  728. } catch (Exception e) {
  729. throw new SQLNestedException("Error preloading the connection pool", e);
  730. }
  731. return dataSource;
  732. }
  733. private static void validateConnectionFactory(PoolableConnectionFactory connectionFactory) throws Exception {
  734. Connection conn = null;
  735. try {
  736. conn = (Connection) connectionFactory.makeObject();
  737. connectionFactory.activateObject(conn);
  738. connectionFactory.validateConnection(conn);
  739. connectionFactory.passivateObject(conn);
  740. }
  741. finally {
  742. connectionFactory.destroyObject(conn);
  743. }
  744. }
  745. private void restart() {
  746. try {
  747. close();
  748. } catch (SQLException e) {
  749. log("Could not restart DataSource, cause: " + e.getMessage());
  750. }
  751. }
  752. private void log(String message) {
  753. if (logWriter != null) {
  754. logWriter.println(message);
  755. }
  756. }
  757. }