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 org.apache.commons.dbcp;
019
020 import java.io.PrintWriter;
021 import java.util.Properties;
022 import java.util.Collection;
023 import java.util.List;
024 import java.util.ArrayList;
025 import java.util.Iterator;
026 import java.util.Collections;
027 import java.sql.Connection;
028 import java.sql.Driver;
029 import java.sql.DriverManager;
030 import java.sql.SQLException;
031 import javax.sql.DataSource;
032
033 import org.apache.commons.pool.KeyedObjectPoolFactory;
034 import org.apache.commons.pool.impl.GenericKeyedObjectPool;
035 import org.apache.commons.pool.impl.GenericKeyedObjectPoolFactory;
036 import org.apache.commons.pool.impl.GenericObjectPool;
037
038
039 /**
040 * <p>Basic implementation of <code>javax.sql.DataSource</code> that is
041 * configured via JavaBeans properties. This is not the only way to
042 * combine the <em>commons-dbcp</em> and <em>commons-pool</em> packages,
043 * but provides a "one stop shopping" solution for basic requirements.</p>
044 *
045 * <p>Users extending this class should take care to use appropriate accessors
046 * rather than accessing protected fields directly to ensure thread-safety.</p>
047 *
048 * @author Glenn L. Nielsen
049 * @author Craig R. McClanahan
050 * @author Dirk Verbeeck
051 * @version $Revision: 892307 $ $Date: 2013-12-31 23:27:28 +0000 (Tue, 31 Dec 2013) $
052 */
053 public class BasicDataSource implements DataSource {
054
055 static {
056 // Attempt to prevent deadlocks - see DBCP - 272
057 DriverManager.getDrivers();
058 }
059
060 // ------------------------------------------------------------- Properties
061
062 /**
063 * The default auto-commit state of connections created by this pool.
064 */
065 protected volatile boolean defaultAutoCommit = true;
066
067 /**
068 * Returns the default auto-commit property.
069 *
070 * @return true if default auto-commit is enabled
071 */
072 public boolean getDefaultAutoCommit() {
073 return this.defaultAutoCommit;
074 }
075
076 /**
077 * <p>Sets default auto-commit state of connections returned by this
078 * datasource.</p>
079 * <p>
080 * Note: this method currently has no effect once the pool has been
081 * initialized. The pool is initialized the first time one of the
082 * following methods is invoked: <code>getConnection, setLogwriter,
083 * setLoginTimeout, getLoginTimeout, getLogWriter.</code></p>
084 *
085 * @param defaultAutoCommit default auto-commit value
086 */
087 public void setDefaultAutoCommit(boolean defaultAutoCommit) {
088 this.defaultAutoCommit = defaultAutoCommit;
089 this.restartNeeded = true;
090 }
091
092
093 /**
094 * The default read-only state of connections created by this pool.
095 */
096 protected transient Boolean defaultReadOnly = null;
097
098 /**
099 * Returns the default readOnly property.
100 *
101 * @return true if connections are readOnly by default
102 */
103 public boolean getDefaultReadOnly() {
104 Boolean val = defaultReadOnly;
105 if (val != null) {
106 return val.booleanValue();
107 }
108 return false;
109 }
110
111 /**
112 * <p>Sets defaultReadonly property.</p>
113 * <p>
114 * Note: this method currently has no effect once the pool has been
115 * initialized. The pool is initialized the first time one of the
116 * following methods is invoked: <code>getConnection, setLogwriter,
117 * setLoginTimeout, getLoginTimeout, getLogWriter.</code></p>
118 *
119 * @param defaultReadOnly default read-only value
120 */
121 public void setDefaultReadOnly(boolean defaultReadOnly) {
122 this.defaultReadOnly = defaultReadOnly ? Boolean.TRUE : Boolean.FALSE;
123 this.restartNeeded = true;
124 }
125
126 /**
127 * The default TransactionIsolation state of connections created by this pool.
128 */
129 protected volatile int defaultTransactionIsolation =
130 PoolableConnectionFactory.UNKNOWN_TRANSACTIONISOLATION;
131
132 /**
133 * Returns the default transaction isolation state of returned connections.
134 *
135 * @return the default value for transaction isolation state
136 * @see Connection#getTransactionIsolation
137 */
138 public int getDefaultTransactionIsolation() {
139 return this.defaultTransactionIsolation;
140 }
141
142 /**
143 * <p>Sets the default transaction isolation state for returned
144 * connections.</p>
145 * <p>
146 * Note: this method currently has no effect once the pool has been
147 * initialized. The pool is initialized the first time one of the
148 * following methods is invoked: <code>getConnection, setLogwriter,
149 * setLoginTimeout, getLoginTimeout, getLogWriter.</code></p>
150 *
151 * @param defaultTransactionIsolation the default transaction isolation
152 * state
153 * @see Connection#getTransactionIsolation
154 */
155 public void setDefaultTransactionIsolation(int defaultTransactionIsolation) {
156 this.defaultTransactionIsolation = defaultTransactionIsolation;
157 this.restartNeeded = true;
158 }
159
160
161 /**
162 * The default "catalog" of connections created by this pool.
163 */
164 protected volatile String defaultCatalog = null;
165
166 /**
167 * Returns the default catalog.
168 *
169 * @return the default catalog
170 */
171 public String getDefaultCatalog() {
172 return this.defaultCatalog;
173 }
174
175 /**
176 * <p>Sets the default catalog.</p>
177 * <p>
178 * Note: this method currently has no effect once the pool has been
179 * initialized. The pool is initialized the first time one of the
180 * following methods is invoked: <code>getConnection, setLogwriter,
181 * setLoginTimeout, getLoginTimeout, getLogWriter.</code></p>
182 *
183 * @param defaultCatalog the default catalog
184 */
185 public void setDefaultCatalog(String defaultCatalog) {
186 if ((defaultCatalog != null) && (defaultCatalog.trim().length() > 0)) {
187 this.defaultCatalog = defaultCatalog;
188 }
189 else {
190 this.defaultCatalog = null;
191 }
192 this.restartNeeded = true;
193 }
194
195
196 /**
197 * The fully qualified Java class name of the JDBC driver to be used.
198 */
199 protected String driverClassName = null;
200
201 /**
202 * Returns the jdbc driver class name.
203 *
204 * @return the jdbc driver class name
205 */
206 public synchronized String getDriverClassName() {
207 return this.driverClassName;
208 }
209
210 /**
211 * <p>Sets the jdbc driver class name.</p>
212 * <p>
213 * Note: this method currently has no effect once the pool has been
214 * initialized. The pool is initialized the first time one of the
215 * following methods is invoked: <code>getConnection, setLogwriter,
216 * setLoginTimeout, getLoginTimeout, getLogWriter.</code></p>
217 *
218 * @param driverClassName the class name of the jdbc driver
219 */
220 public synchronized void setDriverClassName(String driverClassName) {
221 if ((driverClassName != null) && (driverClassName.trim().length() > 0)) {
222 this.driverClassName = driverClassName;
223 }
224 else {
225 this.driverClassName = null;
226 }
227 this.restartNeeded = true;
228 }
229
230 /**
231 * The class loader instance to use to load the JDBC driver. If not
232 * specified, {@link Class#forName(String)} is used to load the JDBC driver.
233 * If specified, {@link Class#forName(String, boolean, ClassLoader)} is
234 * used.
235 */
236 protected ClassLoader driverClassLoader = null;
237
238 /**
239 * Returns the class loader specified for loading the JDBC driver. Returns
240 * <code>null</code> if no class loader has been explicitly specified.
241 */
242 public synchronized ClassLoader getDriverClassLoader() {
243 return this.driverClassLoader;
244 }
245
246 /**
247 * <p>Sets the class loader to be used to load the JDBC driver.</p>
248 * <p>
249 * Note: this method currently has no effect once the pool has been
250 * initialized. The pool is initialized the first time one of the
251 * following methods is invoked: <code>getConnection, setLogwriter,
252 * setLoginTimeout, getLoginTimeout, getLogWriter.</code></p>
253 *
254 * @param driverClassLoader the class loader with which to load the JDBC
255 * driver
256 */
257 public synchronized void setDriverClassLoader(
258 ClassLoader driverClassLoader) {
259 this.driverClassLoader = driverClassLoader;
260 this.restartNeeded = true;
261 }
262
263 /**
264 * The maximum number of active connections that can be allocated from
265 * this pool at the same time, or negative for no limit.
266 */
267 protected int maxActive = GenericObjectPool.DEFAULT_MAX_ACTIVE;
268
269 /**
270 * <p>Returns the maximum number of active connections that can be
271 * allocated at the same time.
272 * </p>
273 * <p>A negative number means that there is no limit.</p>
274 *
275 * @return the maximum number of active connections
276 */
277 public synchronized int getMaxActive() {
278 return this.maxActive;
279 }
280
281 /**
282 * Sets the maximum number of active connections that can be
283 * allocated at the same time. Use a negative value for no limit.
284 *
285 * @param maxActive the new value for maxActive
286 * @see #getMaxActive()
287 */
288 public synchronized void setMaxActive(int maxActive) {
289 this.maxActive = maxActive;
290 if (connectionPool != null) {
291 connectionPool.setMaxActive(maxActive);
292 }
293 }
294
295 /**
296 * The maximum number of connections that can remain idle in the
297 * pool, without extra ones being released, or negative for no limit.
298 * If maxIdle is set too low on heavily loaded systems it is possible you
299 * will see connections being closed and almost immediately new connections
300 * being opened. This is a result of the active threads momentarily closing
301 * connections faster than they are opening them, causing the number of idle
302 * connections to rise above maxIdle. The best value for maxIdle for heavily
303 * loaded system will vary but the default is a good starting point.
304 */
305 protected int maxIdle = GenericObjectPool.DEFAULT_MAX_IDLE;
306
307 /**
308 * <p>Returns the maximum number of connections that can remain idle in the
309 * pool.
310 * </p>
311 * <p>A negative value indicates that there is no limit</p>
312 *
313 * @return the maximum number of idle connections
314 */
315 public synchronized int getMaxIdle() {
316 return this.maxIdle;
317 }
318
319 /**
320 * Sets the maximum number of connections that can remain idle in the
321 * pool.
322 *
323 * @see #getMaxIdle()
324 * @param maxIdle the new value for maxIdle
325 */
326 public synchronized void setMaxIdle(int maxIdle) {
327 this.maxIdle = maxIdle;
328 if (connectionPool != null) {
329 connectionPool.setMaxIdle(maxIdle);
330 }
331 }
332
333 /**
334 * The minimum number of active connections that can remain idle in the
335 * pool, without extra ones being created, or 0 to create none.
336 */
337 protected int minIdle = GenericObjectPool.DEFAULT_MIN_IDLE;
338
339 /**
340 * Returns the minimum number of idle connections in the pool
341 *
342 * @return the minimum number of idle connections
343 * @see GenericObjectPool#getMinIdle()
344 */
345 public synchronized int getMinIdle() {
346 return this.minIdle;
347 }
348
349 /**
350 * Sets the minimum number of idle connections in the pool.
351 *
352 * @param minIdle the new value for minIdle
353 * @see GenericObjectPool#setMinIdle(int)
354 */
355 public synchronized void setMinIdle(int minIdle) {
356 this.minIdle = minIdle;
357 if (connectionPool != null) {
358 connectionPool.setMinIdle(minIdle);
359 }
360 }
361
362 /**
363 * The initial number of connections that are created when the pool
364 * is started.
365 *
366 * @since 1.2
367 */
368 protected int initialSize = 0;
369
370 /**
371 * Returns the initial size of the connection pool.
372 *
373 * @return the number of connections created when the pool is initialized
374 */
375 public synchronized int getInitialSize() {
376 return this.initialSize;
377 }
378
379 /**
380 * <p>Sets the initial size of the connection pool.</p>
381 * <p>
382 * Note: this method currently has no effect once the pool has been
383 * initialized. The pool is initialized the first time one of the
384 * following methods is invoked: <code>getConnection, setLogwriter,
385 * setLoginTimeout, getLoginTimeout, getLogWriter.</code></p>
386 *
387 * @param initialSize the number of connections created when the pool
388 * is initialized
389 */
390 public synchronized void setInitialSize(int initialSize) {
391 this.initialSize = initialSize;
392 this.restartNeeded = true;
393 }
394
395 /**
396 * The maximum number of milliseconds that the pool will wait (when there
397 * are no available connections) for a connection to be returned before
398 * throwing an exception, or <= 0 to wait indefinitely.
399 */
400 protected long maxWait = GenericObjectPool.DEFAULT_MAX_WAIT;
401
402 /**
403 * <p>Returns the maximum number of milliseconds that the pool will wait
404 * for a connection to be returned before throwing an exception.
405 * </p>
406 * <p>A value less than or equal to zero means the pool is set to wait
407 * indefinitely.</p>
408 *
409 * @return the maxWait property value
410 */
411 public synchronized long getMaxWait() {
412 return this.maxWait;
413 }
414
415 /**
416 * <p>Sets the maxWait property.
417 * </p>
418 * <p>Use -1 to make the pool wait indefinitely.
419 * </p>
420 *
421 * @param maxWait the new value for maxWait
422 * @see #getMaxWait()
423 */
424 public synchronized void setMaxWait(long maxWait) {
425 this.maxWait = maxWait;
426 if (connectionPool != null) {
427 connectionPool.setMaxWait(maxWait);
428 }
429 }
430
431 /**
432 * Prepared statement pooling for this pool. When this property is set to <code>true</code>
433 * both PreparedStatements and CallableStatements are pooled.
434 */
435 protected boolean poolPreparedStatements = false;
436
437 /**
438 * Returns true if we are pooling statements.
439 *
440 * @return true if prepared and callable statements are pooled
441 */
442 public synchronized boolean isPoolPreparedStatements() {
443 return this.poolPreparedStatements;
444 }
445
446 /**
447 * <p>Sets whether to pool statements or not.</p>
448 * <p>
449 * Note: this method currently has no effect once the pool has been
450 * initialized. The pool is initialized the first time one of the
451 * following methods is invoked: <code>getConnection, setLogwriter,
452 * setLoginTimeout, getLoginTimeout, getLogWriter.</code></p>
453 *
454 * @param poolingStatements pooling on or off
455 */
456 public synchronized void setPoolPreparedStatements(boolean poolingStatements) {
457 this.poolPreparedStatements = poolingStatements;
458 this.restartNeeded = true;
459 }
460
461 /**
462 * <p>The maximum number of open statements that can be allocated from
463 * the statement pool at the same time, or non-positive for no limit. Since
464 * a connection usually only uses one or two statements at a time, this is
465 * mostly used to help detect resource leaks.</p>
466 *
467 * <p>Note: As of version 1.3, CallableStatements (those produced by {@link Connection#prepareCall})
468 * are pooled along with PreparedStatements (produced by {@link Connection#prepareStatement})
469 * and <code>maxOpenPreparedStatements</code> limits the total number of prepared or callable statements
470 * that may be in use at a given time.</p>
471 */
472 protected int maxOpenPreparedStatements = GenericKeyedObjectPool.DEFAULT_MAX_TOTAL;
473
474 /**
475 * Gets the value of the {@link #maxOpenPreparedStatements} property.
476 *
477 * @return the maximum number of open statements
478 * @see #maxOpenPreparedStatements
479 */
480 public synchronized int getMaxOpenPreparedStatements() {
481 return this.maxOpenPreparedStatements;
482 }
483
484 /**
485 * <p>Sets the value of the {@link #maxOpenPreparedStatements}
486 * property.</p>
487 * <p>
488 * Note: this method currently has no effect once the pool has been
489 * initialized. The pool is initialized the first time one of the
490 * following methods is invoked: <code>getConnection, setLogwriter,
491 * setLoginTimeout, getLoginTimeout, getLogWriter.</code></p>
492 *
493 * @param maxOpenStatements the new maximum number of prepared statements
494 * @see #maxOpenPreparedStatements
495 */
496 public synchronized void setMaxOpenPreparedStatements(int maxOpenStatements) {
497 this.maxOpenPreparedStatements = maxOpenStatements;
498 this.restartNeeded = true;
499 }
500
501 /**
502 * The indication of whether objects will be validated before being
503 * borrowed from the pool. If the object fails to validate, it will be
504 * dropped from the pool, and we will attempt to borrow another.
505 */
506 protected boolean testOnBorrow = true;
507
508 /**
509 * Returns the {@link #testOnBorrow} property.
510 *
511 * @return true if objects are validated before being borrowed from the
512 * pool
513 *
514 * @see #testOnBorrow
515 */
516 public synchronized boolean getTestOnBorrow() {
517 return this.testOnBorrow;
518 }
519
520 /**
521 * Sets the {@link #testOnBorrow} property. This property determines
522 * whether or not the pool will validate objects before they are borrowed
523 * from the pool. For a <code>true</code> value to have any effect, the
524 * <code>validationQuery</code> property must be set to a non-null string.
525 *
526 * @param testOnBorrow new value for testOnBorrow property
527 */
528 public synchronized void setTestOnBorrow(boolean testOnBorrow) {
529 this.testOnBorrow = testOnBorrow;
530 if (connectionPool != null) {
531 connectionPool.setTestOnBorrow(testOnBorrow);
532 }
533 }
534
535 /**
536 * The indication of whether objects will be validated before being
537 * returned to the pool.
538 */
539 protected boolean testOnReturn = false;
540
541 /**
542 * Returns the value of the {@link #testOnReturn} property.
543 *
544 * @return true if objects are validated before being returned to the
545 * pool
546 * @see #testOnReturn
547 */
548 public synchronized boolean getTestOnReturn() {
549 return this.testOnReturn;
550 }
551
552 /**
553 * Sets the <code>testOnReturn</code> property. This property determines
554 * whether or not the pool will validate objects before they are returned
555 * to the pool. For a <code>true</code> value to have any effect, the
556 * <code>validationQuery</code> property must be set to a non-null string.
557 *
558 * @param testOnReturn new value for testOnReturn property
559 */
560 public synchronized void setTestOnReturn(boolean testOnReturn) {
561 this.testOnReturn = testOnReturn;
562 if (connectionPool != null) {
563 connectionPool.setTestOnReturn(testOnReturn);
564 }
565 }
566
567 /**
568 * The number of milliseconds to sleep between runs of the idle object
569 * evictor thread. When non-positive, no idle object evictor thread will
570 * be run.
571 */
572 protected long timeBetweenEvictionRunsMillis =
573 GenericObjectPool.DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS;
574
575 /**
576 * Returns the value of the {@link #timeBetweenEvictionRunsMillis}
577 * property.
578 *
579 * @return the time (in miliseconds) between evictor runs
580 * @see #timeBetweenEvictionRunsMillis
581 */
582 public synchronized long getTimeBetweenEvictionRunsMillis() {
583 return this.timeBetweenEvictionRunsMillis;
584 }
585
586 /**
587 * Sets the {@link #timeBetweenEvictionRunsMillis} property.
588 *
589 * @param timeBetweenEvictionRunsMillis the new time between evictor runs
590 * @see #timeBetweenEvictionRunsMillis
591 */
592 public synchronized void setTimeBetweenEvictionRunsMillis(long timeBetweenEvictionRunsMillis) {
593 this.timeBetweenEvictionRunsMillis = timeBetweenEvictionRunsMillis;
594 if (connectionPool != null) {
595 connectionPool.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
596 }
597 }
598
599 /**
600 * The number of objects to examine during each run of the idle object
601 * evictor thread (if any).
602 */
603 protected int numTestsPerEvictionRun =
604 GenericObjectPool.DEFAULT_NUM_TESTS_PER_EVICTION_RUN;
605
606 /**
607 * Returns the value of the {@link #numTestsPerEvictionRun} property.
608 *
609 * @return the number of objects to examine during idle object evictor
610 * runs
611 * @see #numTestsPerEvictionRun
612 */
613 public synchronized int getNumTestsPerEvictionRun() {
614 return this.numTestsPerEvictionRun;
615 }
616
617 /**
618 * Sets the value of the {@link #numTestsPerEvictionRun} property.
619 *
620 * @param numTestsPerEvictionRun the new {@link #numTestsPerEvictionRun}
621 * value
622 * @see #numTestsPerEvictionRun
623 */
624 public synchronized void setNumTestsPerEvictionRun(int numTestsPerEvictionRun) {
625 this.numTestsPerEvictionRun = numTestsPerEvictionRun;
626 if (connectionPool != null) {
627 connectionPool.setNumTestsPerEvictionRun(numTestsPerEvictionRun);
628 }
629 }
630
631 /**
632 * The minimum amount of time an object may sit idle in the pool before it
633 * is eligable for eviction by the idle object evictor (if any).
634 */
635 protected long minEvictableIdleTimeMillis =
636 GenericObjectPool.DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS;
637
638 /**
639 * Returns the {@link #minEvictableIdleTimeMillis} property.
640 *
641 * @return the value of the {@link #minEvictableIdleTimeMillis} property
642 * @see #minEvictableIdleTimeMillis
643 */
644 public synchronized long getMinEvictableIdleTimeMillis() {
645 return this.minEvictableIdleTimeMillis;
646 }
647
648 /**
649 * Sets the {@link #minEvictableIdleTimeMillis} property.
650 *
651 * @param minEvictableIdleTimeMillis the minimum amount of time an object
652 * may sit idle in the pool
653 * @see #minEvictableIdleTimeMillis
654 */
655 public synchronized void setMinEvictableIdleTimeMillis(long minEvictableIdleTimeMillis) {
656 this.minEvictableIdleTimeMillis = minEvictableIdleTimeMillis;
657 if (connectionPool != null) {
658 connectionPool.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
659 }
660 }
661
662 /**
663 * The indication of whether objects will be validated by the idle object
664 * evictor (if any). If an object fails to validate, it will be dropped
665 * from the pool.
666 */
667 protected boolean testWhileIdle = false;
668
669 /**
670 * Returns the value of the {@link #testWhileIdle} property.
671 *
672 * @return true if objects examined by the idle object evictor are
673 * validated
674 * @see #testWhileIdle
675 */
676 public synchronized boolean getTestWhileIdle() {
677 return this.testWhileIdle;
678 }
679
680 /**
681 * Sets the <code>testWhileIdle</code> property. This property determines
682 * whether or not the idle object evictor will validate connections. For a
683 * <code>true</code> value to have any effect, the
684 * <code>validationQuery</code> property must be set to a non-null string.
685 *
686 * @param testWhileIdle new value for testWhileIdle property
687 */
688 public synchronized void setTestWhileIdle(boolean testWhileIdle) {
689 this.testWhileIdle = testWhileIdle;
690 if (connectionPool != null) {
691 connectionPool.setTestWhileIdle(testWhileIdle);
692 }
693 }
694
695 /**
696 * [Read Only] The current number of active connections that have been
697 * allocated from this data source.
698 *
699 * @return the current number of active connections
700 */
701 public synchronized int getNumActive() {
702 if (connectionPool != null) {
703 return connectionPool.getNumActive();
704 } else {
705 return 0;
706 }
707 }
708
709
710 /**
711 * [Read Only] The current number of idle connections that are waiting
712 * to be allocated from this data source.
713 *
714 * @return the current number of idle connections
715 */
716 public synchronized int getNumIdle() {
717 if (connectionPool != null) {
718 return connectionPool.getNumIdle();
719 } else {
720 return 0;
721 }
722 }
723
724 /**
725 * The connection password to be passed to our JDBC driver to establish
726 * a connection.
727 */
728 protected volatile String password = null;
729
730 /**
731 * Returns the password passed to the JDBC driver to establish connections.
732 *
733 * @return the connection password
734 */
735 public String getPassword() {
736 return this.password;
737 }
738
739 /**
740 * <p>Sets the {@link #password}.</p>
741 * <p>
742 * Note: this method currently has no effect once the pool has been
743 * initialized. The pool is initialized the first time one of the
744 * following methods is invoked: <code>getConnection, setLogwriter,
745 * setLoginTimeout, getLoginTimeout, getLogWriter.</code></p>
746 *
747 * @param password new value for the password
748 */
749 public void setPassword(String password) {
750 this.password = password;
751 this.restartNeeded = true;
752 }
753
754 /**
755 * The connection URL to be passed to our JDBC driver to establish
756 * a connection.
757 */
758 protected String url = null;
759
760 /**
761 * Returns the JDBC connection {@link #url} property.
762 *
763 * @return the {@link #url} passed to the JDBC driver to establish
764 * connections
765 */
766 public synchronized String getUrl() {
767 return this.url;
768 }
769
770 /**
771 * <p>Sets the {@link #url}.</p>
772 * <p>
773 * Note: this method currently has no effect once the pool has been
774 * initialized. The pool is initialized the first time one of the
775 * following methods is invoked: <code>getConnection, setLogwriter,
776 * setLoginTimeout, getLoginTimeout, getLogWriter.</code></p>
777 *
778 * @param url the new value for the JDBC connection url
779 */
780 public synchronized void setUrl(String url) {
781 this.url = url;
782 this.restartNeeded = true;
783 }
784
785 /**
786 * The connection username to be passed to our JDBC driver to
787 * establish a connection.
788 */
789 protected String username = null;
790
791 /**
792 * Returns the JDBC connection {@link #username} property.
793 *
794 * @return the {@link #username} passed to the JDBC driver to establish
795 * connections
796 */
797 public String getUsername() {
798 return this.username;
799 }
800
801 /**
802 * <p>Sets the {@link #username}.</p>
803 * <p>
804 * Note: this method currently has no effect once the pool has been
805 * initialized. The pool is initialized the first time one of the
806 * following methods is invoked: <code>getConnection, setLogwriter,
807 * setLoginTimeout, getLoginTimeout, getLogWriter.</code></p>
808 *
809 * @param username the new value for the JDBC connection username
810 */
811 public void setUsername(String username) {
812 this.username = username;
813 this.restartNeeded = true;
814 }
815
816 /**
817 * The SQL query that will be used to validate connections from this pool
818 * before returning them to the caller. If specified, this query
819 * <strong>MUST</strong> be an SQL SELECT statement that returns at least
820 * one row.
821 */
822 protected volatile String validationQuery = null;
823
824 /**
825 * Returns the validation query used to validate connections before
826 * returning them.
827 *
828 * @return the SQL validation query
829 * @see #validationQuery
830 */
831 public String getValidationQuery() {
832 return this.validationQuery;
833 }
834
835 /**
836 * <p>Sets the {@link #validationQuery}.</p>
837 * <p>
838 * Note: this method currently has no effect once the pool has been
839 * initialized. The pool is initialized the first time one of the
840 * following methods is invoked: <code>getConnection, setLogwriter,
841 * setLoginTimeout, getLoginTimeout, getLogWriter.</code></p>
842 *
843 * @param validationQuery the new value for the validation query
844 */
845 public void setValidationQuery(String validationQuery) {
846 if ((validationQuery != null) && (validationQuery.trim().length() > 0)) {
847 this.validationQuery = validationQuery;
848 } else {
849 this.validationQuery = null;
850 }
851 this.restartNeeded = true;
852 }
853
854 /**
855 * Timeout in seconds before connection validation queries fail.
856 *
857 * @since 1.3
858 */
859 protected volatile int validationQueryTimeout = -1;
860
861 /**
862 * Returns the validation query timeout.
863 *
864 * @return the timeout in seconds before connection validation queries fail.
865 * @since 1.3
866 */
867 public int getValidationQueryTimeout() {
868 return validationQueryTimeout;
869 }
870
871 /**
872 * Sets the validation query timeout, the amount of time, in seconds, that
873 * connection validation will wait for a response from the database when
874 * executing a validation query. Use a value less than or equal to 0 for
875 * no timeout.
876 * <p>
877 * Note: this method currently has no effect once the pool has been
878 * initialized. The pool is initialized the first time one of the
879 * following methods is invoked: <code>getConnection, setLogwriter,
880 * setLoginTimeout, getLoginTimeout, getLogWriter.</code></p>
881 *
882 * @param timeout new validation query timeout value in seconds
883 * @since 1.3
884 */
885 public void setValidationQueryTimeout(int timeout) {
886 this.validationQueryTimeout = timeout;
887 restartNeeded = true;
888 }
889
890 /**
891 * These SQL statements run once after a Connection is created.
892 * <p>
893 * This property can be used for example to run ALTER SESSION SET
894 * NLS_SORT=XCYECH in an Oracle Database only once after connection
895 * creation.
896 * </p>
897 *
898 * @since 1.3
899 */
900 protected volatile List connectionInitSqls;
901
902 /**
903 * Returns the list of SQL statements executed when a physical connection
904 * is first created. Returns an empty list if there are no initialization
905 * statements configured.
906 *
907 * @return initialization SQL statements
908 * @since 1.3
909 */
910 public Collection getConnectionInitSqls() {
911 Collection result = connectionInitSqls;
912 if (result == null) {
913 return Collections.EMPTY_LIST;
914 }
915 return result;
916 }
917
918 /**
919 * Sets the list of SQL statements to be executed when a physical
920 * connection is first created.
921 * <p>
922 * Note: this method currently has no effect once the pool has been
923 * initialized. The pool is initialized the first time one of the
924 * following methods is invoked: <code>getConnection, setLogwriter,
925 * setLoginTimeout, getLoginTimeout, getLogWriter.</code></p>
926 *
927 * @param connectionInitSqls Collection of SQL statements to execute
928 * on connection creation
929 */
930 public void setConnectionInitSqls(Collection connectionInitSqls) {
931 if ((connectionInitSqls != null) && (connectionInitSqls.size() > 0)) {
932 ArrayList newVal = null;
933 for (Iterator iterator = connectionInitSqls.iterator();
934 iterator.hasNext();) {
935 Object o = iterator.next();
936 if (o != null) {
937 String s = o.toString();
938 if (s.trim().length() > 0) {
939 if (newVal == null) {
940 newVal = new ArrayList();
941 }
942 newVal.add(s);
943 }
944 }
945 }
946 this.connectionInitSqls = newVal;
947 } else {
948 this.connectionInitSqls = null;
949 }
950 this.restartNeeded = true;
951 }
952
953
954 /**
955 * Controls access to the underlying connection.
956 */
957 private boolean accessToUnderlyingConnectionAllowed = false;
958
959 /**
960 * Returns the value of the accessToUnderlyingConnectionAllowed property.
961 *
962 * @return true if access to the underlying connection is allowed, false
963 * otherwise.
964 */
965 public synchronized boolean isAccessToUnderlyingConnectionAllowed() {
966 return this.accessToUnderlyingConnectionAllowed;
967 }
968
969 /**
970 * <p>Sets the value of the accessToUnderlyingConnectionAllowed property.
971 * It controls if the PoolGuard allows access to the underlying connection.
972 * (Default: false)</p>
973 * <p>
974 * Note: this method currently has no effect once the pool has been
975 * initialized. The pool is initialized the first time one of the
976 * following methods is invoked: <code>getConnection, setLogwriter,
977 * setLoginTimeout, getLoginTimeout, getLogWriter.</code></p>
978 *
979 * @param allow Access to the underlying connection is granted when true.
980 */
981 public synchronized void setAccessToUnderlyingConnectionAllowed(boolean allow) {
982 this.accessToUnderlyingConnectionAllowed = allow;
983 this.restartNeeded = true;
984 }
985
986 // ----------------------------------------------------- Instance Variables
987
988 // TODO: review & make isRestartNeeded() public, restartNeeded protected
989
990 /**
991 * A property setter has been invoked that will require the connection
992 * pool to be re-initialized. Currently, restart is not triggered, so
993 * this property has no effect.
994 */
995 private volatile boolean restartNeeded = false;
996
997 /**
998 * Returns whether or not a restart is needed.
999 *
1000 * Note: restart is not currently triggered by property changes.
1001 *
1002 * @return true if a restart is needed
1003 */
1004 private boolean isRestartNeeded() {
1005 return restartNeeded;
1006 }
1007
1008 /**
1009 * The object pool that internally manages our connections.
1010 */
1011 protected volatile GenericObjectPool connectionPool = null;
1012
1013 /**
1014 * The connection properties that will be sent to our JDBC driver when
1015 * establishing new connections. <strong>NOTE</strong> - The "user" and
1016 * "password" properties will be passed explicitly, so they do not need
1017 * to be included here.
1018 */
1019 protected Properties connectionProperties = new Properties();
1020
1021 /**
1022 * The data source we will use to manage connections. This object should
1023 * be acquired <strong>ONLY</strong> by calls to the
1024 * <code>createDataSource()</code> method.
1025 */
1026 protected volatile DataSource dataSource = null;
1027
1028 /**
1029 * The PrintWriter to which log messages should be directed.
1030 */
1031 protected PrintWriter logWriter = new PrintWriter(System.out);
1032
1033
1034 // ----------------------------------------------------- DataSource Methods
1035
1036
1037 /**
1038 * Create (if necessary) and return a connection to the database.
1039 *
1040 * @throws SQLException if a database access error occurs
1041 * @return a database connection
1042 */
1043 public Connection getConnection() throws SQLException {
1044 return createDataSource().getConnection();
1045 }
1046
1047
1048 /**
1049 * <strong>BasicDataSource does NOT support this method. </strong>
1050 *
1051 * @param user Database user on whose behalf the Connection
1052 * is being made
1053 * @param pass The database user's password
1054 *
1055 * @throws UnsupportedOperationException
1056 * @throws SQLException if a database access error occurs
1057 * @return nothing - always throws UnsupportedOperationException
1058 */
1059 public Connection getConnection(String user, String pass) throws SQLException {
1060 // This method isn't supported by the PoolingDataSource returned by
1061 // the createDataSource
1062 throw new UnsupportedOperationException("Not supported by BasicDataSource");
1063 // return createDataSource().getConnection(username, password);
1064 }
1065
1066
1067 /**
1068 * <strong>BasicDataSource does NOT support this method. </strong>
1069 *
1070 * <p>Returns the login timeout (in seconds) for connecting to the database.
1071 * </p>
1072 * <p>Calls {@link #createDataSource()}, so has the side effect
1073 * of initializing the connection pool.</p>
1074 *
1075 * @throws SQLException if a database access error occurs
1076 * @throws UnsupportedOperationException If the DataSource implementation
1077 * does not support the login timeout feature.
1078 * @return login timeout in seconds
1079 */
1080 public int getLoginTimeout() throws SQLException {
1081 // This method isn't supported by the PoolingDataSource returned by
1082 // the createDataSource
1083 throw new UnsupportedOperationException("Not supported by BasicDataSource");
1084 //return createDataSource().getLoginTimeout();
1085 }
1086
1087
1088 /**
1089 * <p>Returns the log writer being used by this data source.</p>
1090 * <p>
1091 * Calls {@link #createDataSource()}, so has the side effect
1092 * of initializing the connection pool.</p>
1093 *
1094 * @throws SQLException if a database access error occurs
1095 * @return log writer in use
1096 */
1097 public PrintWriter getLogWriter() throws SQLException {
1098 return createDataSource().getLogWriter();
1099 }
1100
1101
1102 /**
1103 * <strong>BasicDataSource does NOT support this method. </strong>
1104 *
1105 * <p>Set the login timeout (in seconds) for connecting to the
1106 * database.</p>
1107 * <p>
1108 * Calls {@link #createDataSource()}, so has the side effect
1109 * of initializing the connection pool.</p>
1110 *
1111 * @param loginTimeout The new login timeout, or zero for no timeout
1112 * @throws UnsupportedOperationException If the DataSource implementation
1113 * does not support the login timeout feature.
1114 * @throws SQLException if a database access error occurs
1115 */
1116 public void setLoginTimeout(int loginTimeout) throws SQLException {
1117 // This method isn't supported by the PoolingDataSource returned by
1118 // the createDataSource
1119 throw new UnsupportedOperationException("Not supported by BasicDataSource");
1120 //createDataSource().setLoginTimeout(loginTimeout);
1121 }
1122
1123
1124 /**
1125 * <p>Sets the log writer being used by this data source.</p>
1126 * <p>
1127 * Calls {@link #createDataSource()}, so has the side effect
1128 * of initializing the connection pool.</p>
1129 *
1130 * @param logWriter The new log writer
1131 * @throws SQLException if a database access error occurs
1132 */
1133 public void setLogWriter(PrintWriter logWriter) throws SQLException {
1134 createDataSource().setLogWriter(logWriter);
1135 this.logWriter = logWriter;
1136 }
1137
1138 private AbandonedConfig abandonedConfig;
1139
1140 /**
1141 * Flag to remove abandoned connections if they exceed the
1142 * removeAbandonedTimout.
1143 *
1144 * Set to true or false, default false.
1145 * If set to true a connection is considered abandoned and eligible
1146 * for removal if it has been idle longer than the removeAbandonedTimeout.
1147 * Setting this to true can recover db connections from poorly written
1148 * applications which fail to close a connection.
1149 * <p>
1150 * Abandonded connections are identified and removed when
1151 * {@link #getConnection()} is invoked and the following conditions hold
1152 * <ul><li>{@link #getRemoveAbandoned()} = true </li>
1153 * <li>{@link #getNumActive()} > {@link #getMaxActive()} - 3 </li>
1154 * <li>{@link #getNumIdle()} < 2 </li></ul></p>
1155 */
1156 public boolean getRemoveAbandoned() {
1157 if (abandonedConfig != null) {
1158 return abandonedConfig.getRemoveAbandoned();
1159 }
1160 return false;
1161 }
1162
1163 /**
1164 * @param removeAbandoned new removeAbandoned property value
1165 * @see #getRemoveAbandoned()
1166 */
1167 public void setRemoveAbandoned(boolean removeAbandoned) {
1168 if (abandonedConfig == null) {
1169 abandonedConfig = new AbandonedConfig();
1170 }
1171 abandonedConfig.setRemoveAbandoned(removeAbandoned);
1172 this.restartNeeded = true;
1173 }
1174
1175 /**
1176 * Timeout in seconds before an abandoned connection can be removed.
1177 *
1178 * Defaults to 300 seconds.
1179 * @return abandoned connection timeout
1180 */
1181 public int getRemoveAbandonedTimeout() {
1182 if (abandonedConfig != null) {
1183 return abandonedConfig.getRemoveAbandonedTimeout();
1184 }
1185 return 300;
1186 }
1187
1188 /**
1189 * @param removeAbandonedTimeout new removeAbandonedTimeout value
1190 */
1191 public void setRemoveAbandonedTimeout(int removeAbandonedTimeout) {
1192 if (abandonedConfig == null) {
1193 abandonedConfig = new AbandonedConfig();
1194 }
1195 abandonedConfig.setRemoveAbandonedTimeout(removeAbandonedTimeout);
1196 this.restartNeeded = true;
1197 }
1198
1199 /**
1200 * <p>Flag to log stack traces for application code which abandoned
1201 * a Statement or Connection.
1202 * </p>
1203 * <p>Defaults to false.
1204 * </p>
1205 * <p>Logging of abandoned Statements and Connections adds overhead
1206 * for every Connection open or new Statement because a stack
1207 * trace has to be generated. </p>
1208 */
1209 public boolean getLogAbandoned() {
1210 if (abandonedConfig != null) {
1211 return abandonedConfig.getLogAbandoned();
1212 }
1213 return false;
1214 }
1215
1216 /**
1217 * @param logAbandoned new logAbandoned property value
1218 */
1219 public void setLogAbandoned(boolean logAbandoned) {
1220 if (abandonedConfig == null) {
1221 abandonedConfig = new AbandonedConfig();
1222 }
1223 abandonedConfig.setLogAbandoned(logAbandoned);
1224 this.restartNeeded = true;
1225 }
1226
1227 // --------------------------------------------------------- Public Methods
1228
1229 /**
1230 * Add a custom connection property to the set that will be passed to our
1231 * JDBC driver. This <strong>MUST</strong> be called before the first
1232 * connection is retrieved (along with all the other configuration
1233 * property setters). Calls to this method after the connection pool
1234 * has been initialized have no effect.
1235 *
1236 * @param name Name of the custom connection property
1237 * @param value Value of the custom connection property
1238 */
1239 public void addConnectionProperty(String name, String value) {
1240 connectionProperties.put(name, value);
1241 this.restartNeeded = true;
1242 }
1243
1244 /**
1245 * Remove a custom connection property.
1246 *
1247 * @param name Name of the custom connection property to remove
1248 * @see #addConnectionProperty(String, String)
1249 */
1250 public void removeConnectionProperty(String name) {
1251 connectionProperties.remove(name);
1252 this.restartNeeded = true;
1253 }
1254
1255 /**
1256 * Sets the connection properties passed to driver.connect(...).
1257 *
1258 * Format of the string must be [propertyName=property;]*
1259 *
1260 * NOTE - The "user" and "password" properties will be added
1261 * explicitly, so they do not need to be included here.
1262 *
1263 * @param connectionProperties the connection properties used to
1264 * create new connections
1265 */
1266 public void setConnectionProperties(String connectionProperties) {
1267 if (connectionProperties == null) throw new NullPointerException("connectionProperties is null");
1268
1269 String[] entries = connectionProperties.split(";");
1270 Properties properties = new Properties();
1271 for (int i = 0; i < entries.length; i++) {
1272 String entry = entries[i];
1273 if (entry.length() > 0) {
1274 int index = entry.indexOf('=');
1275 if (index > 0) {
1276 String name = entry.substring(0, index);
1277 String value = entry.substring(index + 1);
1278 properties.setProperty(name, value);
1279 } else {
1280 // no value is empty string which is how java.util.Properties works
1281 properties.setProperty(entry, "");
1282 }
1283 }
1284 }
1285 this.connectionProperties = properties;
1286 this.restartNeeded = true;
1287 }
1288
1289 protected boolean closed;
1290
1291 /**
1292 * <p>Closes and releases all idle connections that are currently stored in the connection pool
1293 * associated with this data source.</p>
1294 *
1295 * <p>Connections that are checked out to clients when this method is invoked are not affected.
1296 * When client applications subsequently invoke {@link Connection#close()} to return
1297 * these connections to the pool, the underlying JDBC connections are closed.</p>
1298 *
1299 * <p>Attempts to acquire connections using {@link #getConnection()} after this method has been
1300 * invoked result in SQLExceptions.<p>
1301 *
1302 * <p>This method is idempotent - i.e., closing an already closed BasicDataSource has no effect
1303 * and does not generate exceptions.</p>
1304 *
1305 * @throws SQLException if an error occurs closing idle connections
1306 */
1307 public synchronized void close() throws SQLException {
1308 closed = true;
1309 GenericObjectPool oldpool = connectionPool;
1310 connectionPool = null;
1311 dataSource = null;
1312 try {
1313 if (oldpool != null) {
1314 oldpool.close();
1315 }
1316 } catch(SQLException e) {
1317 throw e;
1318 } catch(RuntimeException e) {
1319 throw e;
1320 } catch(Exception e) {
1321 throw new SQLNestedException("Cannot close connection pool", e);
1322 }
1323 }
1324
1325 /**
1326 * If true, this data source is closed and no more connections can be retrieved from this datasource.
1327 * @return true, if the data source is closed; false otherwise
1328 */
1329 public synchronized boolean isClosed() {
1330 return closed;
1331 }
1332
1333 /*
1334 public boolean isWrapperFor(Class<?> iface) throws SQLException {
1335 return false;
1336 }
1337
1338 public <T> T unwrap(Class<T> iface) throws SQLException {
1339 throw new SQLException("BasicDataSource is not a wrapper.");
1340 }
1341 */
1342
1343
1344 // ------------------------------------------------------ Protected Methods
1345
1346
1347 /**
1348 * <p>Create (if necessary) and return the internal data source we are
1349 * using to manage our connections.</p>
1350 *
1351 * <p><strong>IMPLEMENTATION NOTE</strong> - It is tempting to use the
1352 * "double checked locking" idiom in an attempt to avoid synchronizing
1353 * on every single call to this method. However, this idiom fails to
1354 * work correctly in the face of some optimizations that are legal for
1355 * a JVM to perform.</p>
1356 *
1357 * @throws SQLException if the object pool cannot be created.
1358 */
1359 protected synchronized DataSource createDataSource()
1360 throws SQLException {
1361 if (closed) {
1362 throw new SQLException("Data source is closed");
1363 }
1364
1365 // Return the pool if we have already created it
1366 if (dataSource != null) {
1367 return (dataSource);
1368 }
1369
1370 // create factory which returns raw physical connections
1371 ConnectionFactory driverConnectionFactory = createConnectionFactory();
1372
1373 // create a pool for our connections
1374 createConnectionPool();
1375
1376 // Set up statement pool, if desired
1377 GenericKeyedObjectPoolFactory statementPoolFactory = null;
1378 if (isPoolPreparedStatements()) {
1379 statementPoolFactory = new GenericKeyedObjectPoolFactory(null,
1380 -1, // unlimited maxActive (per key)
1381 GenericKeyedObjectPool.WHEN_EXHAUSTED_FAIL,
1382 0, // maxWait
1383 1, // maxIdle (per key)
1384 maxOpenPreparedStatements);
1385 }
1386
1387 // Set up the poolable connection factory
1388 createPoolableConnectionFactory(driverConnectionFactory, statementPoolFactory, abandonedConfig);
1389
1390 // Create and return the pooling data source to manage the connections
1391 createDataSourceInstance();
1392
1393 try {
1394 for (int i = 0 ; i < initialSize ; i++) {
1395 connectionPool.addObject();
1396 }
1397 } catch (Exception e) {
1398 throw new SQLNestedException("Error preloading the connection pool", e);
1399 }
1400
1401 return dataSource;
1402 }
1403
1404 /**
1405 * Creates a JDBC connection factory for this datasource. This method only
1406 * exists so subclasses can replace the implementation class.
1407 */
1408 protected ConnectionFactory createConnectionFactory() throws SQLException {
1409 // Load the JDBC driver class
1410 Class driverFromCCL = null;
1411 if (driverClassName != null) {
1412 try {
1413 try {
1414 if (driverClassLoader == null) {
1415 Class.forName(driverClassName);
1416 } else {
1417 Class.forName(driverClassName, true, driverClassLoader);
1418 }
1419 } catch (ClassNotFoundException cnfe) {
1420 driverFromCCL = Thread.currentThread(
1421 ).getContextClassLoader().loadClass(
1422 driverClassName);
1423 }
1424 } catch (Throwable t) {
1425 String message = "Cannot load JDBC driver class '" +
1426 driverClassName + "'";
1427 logWriter.println(message);
1428 t.printStackTrace(logWriter);
1429 throw new SQLNestedException(message, t);
1430 }
1431 }
1432
1433 // Create a JDBC driver instance
1434 Driver driver = null;
1435 try {
1436 if (driverFromCCL == null) {
1437 driver = DriverManager.getDriver(url);
1438 } else {
1439 // Usage of DriverManager is not possible, as it does not
1440 // respect the ContextClassLoader
1441 driver = (Driver) driverFromCCL.newInstance();
1442 if (!driver.acceptsURL(url)) {
1443 throw new SQLException("No suitable driver", "08001");
1444 }
1445 }
1446 } catch (Throwable t) {
1447 String message = "Cannot create JDBC driver of class '" +
1448 (driverClassName != null ? driverClassName : "") +
1449 "' for connect URL '" + url + "'";
1450 logWriter.println(message);
1451 t.printStackTrace(logWriter);
1452 throw new SQLNestedException(message, t);
1453 }
1454
1455 // Can't test without a validationQuery
1456 if (validationQuery == null) {
1457 setTestOnBorrow(false);
1458 setTestOnReturn(false);
1459 setTestWhileIdle(false);
1460 }
1461
1462 // Set up the driver connection factory we will use
1463 String user = username;
1464 if (user != null) {
1465 connectionProperties.put("user", user);
1466 } else {
1467 log("DBCP DataSource configured without a 'username'");
1468 }
1469
1470 String pwd = password;
1471 if (pwd != null) {
1472 connectionProperties.put("password", pwd);
1473 } else {
1474 log("DBCP DataSource configured without a 'password'");
1475 }
1476
1477 ConnectionFactory driverConnectionFactory = new DriverConnectionFactory(driver, url, connectionProperties);
1478 return driverConnectionFactory;
1479 }
1480
1481 /**
1482 * Creates a connection pool for this datasource. This method only exists
1483 * so subclasses can replace the implementation class.
1484 */
1485 protected void createConnectionPool() {
1486 // Create an object pool to contain our active connections
1487 GenericObjectPool gop;
1488 if ((abandonedConfig != null) && (abandonedConfig.getRemoveAbandoned())) {
1489 gop = new AbandonedObjectPool(null,abandonedConfig);
1490 }
1491 else {
1492 gop = new GenericObjectPool();
1493 }
1494 gop.setMaxActive(maxActive);
1495 gop.setMaxIdle(maxIdle);
1496 gop.setMinIdle(minIdle);
1497 gop.setMaxWait(maxWait);
1498 gop.setTestOnBorrow(testOnBorrow);
1499 gop.setTestOnReturn(testOnReturn);
1500 gop.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
1501 gop.setNumTestsPerEvictionRun(numTestsPerEvictionRun);
1502 gop.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
1503 gop.setTestWhileIdle(testWhileIdle);
1504 connectionPool = gop;
1505 }
1506
1507 /**
1508 * Creates the actual data source instance. This method only exists so
1509 * subclasses can replace the implementation class.
1510 *
1511 * @throws SQLException if unable to create a datasource instance
1512 */
1513 protected void createDataSourceInstance() throws SQLException {
1514 PoolingDataSource pds = new PoolingDataSource(connectionPool);
1515 pds.setAccessToUnderlyingConnectionAllowed(isAccessToUnderlyingConnectionAllowed());
1516 pds.setLogWriter(logWriter);
1517 dataSource = pds;
1518 }
1519
1520 /**
1521 * Creates the PoolableConnectionFactory and attaches it to the connection pool. This method only exists
1522 * so subclasses can replace the default implementation.
1523 *
1524 * @param driverConnectionFactory JDBC connection factory
1525 * @param statementPoolFactory statement pool factory (null if statement pooling is turned off)
1526 * @param configuration abandoned connection tracking configuration (null if no tracking)
1527 * @throws SQLException if an error occurs creating the PoolableConnectionFactory
1528 */
1529 protected void createPoolableConnectionFactory(ConnectionFactory driverConnectionFactory,
1530 KeyedObjectPoolFactory statementPoolFactory, AbandonedConfig configuration) throws SQLException {
1531 PoolableConnectionFactory connectionFactory = null;
1532 try {
1533 connectionFactory =
1534 new PoolableConnectionFactory(driverConnectionFactory,
1535 connectionPool,
1536 statementPoolFactory,
1537 validationQuery,
1538 validationQueryTimeout,
1539 connectionInitSqls,
1540 defaultReadOnly,
1541 defaultAutoCommit,
1542 defaultTransactionIsolation,
1543 defaultCatalog,
1544 configuration);
1545 validateConnectionFactory(connectionFactory);
1546 } catch (RuntimeException e) {
1547 throw e;
1548 } catch (Exception e) {
1549 throw new SQLNestedException("Cannot create PoolableConnectionFactory (" + e.getMessage() + ")", e);
1550 }
1551 }
1552
1553 protected static void validateConnectionFactory(PoolableConnectionFactory connectionFactory) throws Exception {
1554 Connection conn = null;
1555 try {
1556 conn = (Connection) connectionFactory.makeObject();
1557 connectionFactory.activateObject(conn);
1558 connectionFactory.validateConnection(conn);
1559 connectionFactory.passivateObject(conn);
1560 }
1561 finally {
1562 connectionFactory.destroyObject(conn);
1563 }
1564 }
1565
1566 /**
1567 * Not used currently
1568 */
1569 private void restart() {
1570 try {
1571 close();
1572 } catch (SQLException e) {
1573 log("Could not restart DataSource, cause: " + e.getMessage());
1574 }
1575 }
1576
1577 protected void log(String message) {
1578 if (logWriter != null) {
1579 logWriter.println(message);
1580 }
1581 }
1582 }