1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18 package org.apache.commons.dbcp;
19
20 import java.io.PrintWriter;
21 import java.util.Properties;
22 import java.util.Collection;
23 import java.util.List;
24 import java.util.ArrayList;
25 import java.util.Iterator;
26 import java.util.Collections;
27 import java.sql.Connection;
28 import java.sql.Driver;
29 import java.sql.DriverManager;
30 import java.sql.SQLException;
31 import javax.sql.DataSource;
32
33 import org.apache.commons.pool.KeyedObjectPoolFactory;
34 import org.apache.commons.pool.impl.GenericKeyedObjectPool;
35 import org.apache.commons.pool.impl.GenericKeyedObjectPoolFactory;
36 import org.apache.commons.pool.impl.GenericObjectPool;
37
38
39 /**
40 * <p>Basic implementation of <code>javax.sql.DataSource</code> that is
41 * configured via JavaBeans properties. This is not the only way to
42 * combine the <em>commons-dbcp</em> and <em>commons-pool</em> packages,
43 * but provides a "one stop shopping" solution for basic requirements.</p>
44 *
45 * <p>Users extending this class should take care to use appropriate accessors
46 * rather than accessing protected fields directly to ensure thread-safety.</p>
47 *
48 * @author Glenn L. Nielsen
49 * @author Craig R. McClanahan
50 * @author Dirk Verbeeck
51 * @version $Revision: 1023401 $ $Date: 2010-10-16 21:54:24 -0400 (Sat, 16 Oct 2010) $
52 */
53 public class BasicDataSource implements DataSource {
54
55 static {
56 // Attempt to prevent deadlocks - see DBCP - 272
57 DriverManager.getDrivers();
58 }
59
60 // ------------------------------------------------------------- Properties
61
62 /**
63 * The default auto-commit state of connections created by this pool.
64 */
65 protected volatile boolean defaultAutoCommit = true;
66
67 /**
68 * Returns the default auto-commit property.
69 *
70 * @return true if default auto-commit is enabled
71 */
72 public boolean getDefaultAutoCommit() {
73 return this.defaultAutoCommit;
74 }
75
76 /**
77 * <p>Sets default auto-commit state of connections returned by this
78 * datasource.</p>
79 * <p>
80 * Note: this method currently has no effect once the pool has been
81 * initialized. The pool is initialized the first time one of the
82 * following methods is invoked: <code>getConnection, setLogwriter,
83 * setLoginTimeout, getLoginTimeout, getLogWriter.</code></p>
84 *
85 * @param defaultAutoCommit default auto-commit value
86 */
87 public void setDefaultAutoCommit(boolean defaultAutoCommit) {
88 this.defaultAutoCommit = defaultAutoCommit;
89 this.restartNeeded = true;
90 }
91
92
93 /**
94 * The default read-only state of connections created by this pool.
95 */
96 protected transient Boolean defaultReadOnly = null;
97
98 /**
99 * 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 destroyed, 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. Excess idle connections are destroyed on return to the 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. Excess idle connections are destroyed on return to the 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 when the evictor runs, or 0 to create none.
336 * The pool attempts to ensure that minIdle connections are available when the idle object evictor
337 * runs. The value of this property has no effect unless {@link #timeBetweenEvictionRunsMillis}
338 * has a positive value.
339 */
340 protected int minIdle = GenericObjectPool.DEFAULT_MIN_IDLE;
341
342 /**
343 * Returns the minimum number of idle connections in the pool. The pool attempts
344 * to ensure that minIdle connections are available when the idle object evictor
345 * runs. The value of this property has no effect unless {@link #timeBetweenEvictionRunsMillis}
346 * has a positive value.
347 *
348 * @return the minimum number of idle connections
349 * @see GenericObjectPool#getMinIdle()
350 */
351 public synchronized int getMinIdle() {
352 return this.minIdle;
353 }
354
355 /**
356 * Sets the minimum number of idle connections in the pool. The pool attempts
357 * to ensure that minIdle connections are available when the idle object evictor
358 * runs. The value of this property has no effect unless {@link #timeBetweenEvictionRunsMillis}
359 * has a positive value.
360 *
361 * @param minIdle the new value for minIdle
362 * @see GenericObjectPool#setMinIdle(int)
363 */
364 public synchronized void setMinIdle(int minIdle) {
365 this.minIdle = minIdle;
366 if (connectionPool != null) {
367 connectionPool.setMinIdle(minIdle);
368 }
369 }
370
371 /**
372 * The initial number of connections that are created when the pool
373 * is started.
374 *
375 * @since 1.2
376 */
377 protected int initialSize = 0;
378
379 /**
380 * Returns the initial size of the connection pool.
381 *
382 * @return the number of connections created when the pool is initialized
383 */
384 public synchronized int getInitialSize() {
385 return this.initialSize;
386 }
387
388 /**
389 * <p>Sets the initial size of the connection pool.</p>
390 * <p>
391 * Note: this method currently has no effect once the pool has been
392 * initialized. The pool is initialized the first time one of the
393 * following methods is invoked: <code>getConnection, setLogwriter,
394 * setLoginTimeout, getLoginTimeout, getLogWriter.</code></p>
395 *
396 * @param initialSize the number of connections created when the pool
397 * is initialized
398 */
399 public synchronized void setInitialSize(int initialSize) {
400 this.initialSize = initialSize;
401 this.restartNeeded = true;
402 }
403
404 /**
405 * The maximum number of milliseconds that the pool will wait (when there
406 * are no available connections) for a connection to be returned before
407 * throwing an exception, or <= 0 to wait indefinitely.
408 */
409 protected long maxWait = GenericObjectPool.DEFAULT_MAX_WAIT;
410
411 /**
412 * <p>Returns the maximum number of milliseconds that the pool will wait
413 * for a connection to be returned before throwing an exception.
414 * </p>
415 * <p>A value less than or equal to zero means the pool is set to wait
416 * indefinitely.</p>
417 *
418 * @return the maxWait property value
419 */
420 public synchronized long getMaxWait() {
421 return this.maxWait;
422 }
423
424 /**
425 * <p>Sets the maxWait property.
426 * </p>
427 * <p>Use -1 to make the pool wait indefinitely.
428 * </p>
429 *
430 * @param maxWait the new value for maxWait
431 * @see #getMaxWait()
432 */
433 public synchronized void setMaxWait(long maxWait) {
434 this.maxWait = maxWait;
435 if (connectionPool != null) {
436 connectionPool.setMaxWait(maxWait);
437 }
438 }
439
440 /**
441 * Prepared statement pooling for this pool. When this property is set to <code>true</code>
442 * both PreparedStatements and CallableStatements are pooled.
443 */
444 protected boolean poolPreparedStatements = false;
445
446 /**
447 * Returns true if we are pooling statements.
448 *
449 * @return true if prepared and callable statements are pooled
450 */
451 public synchronized boolean isPoolPreparedStatements() {
452 return this.poolPreparedStatements;
453 }
454
455 /**
456 * <p>Sets whether to pool statements or not.</p>
457 * <p>
458 * Note: this method currently has no effect once the pool has been
459 * initialized. The pool is initialized the first time one of the
460 * following methods is invoked: <code>getConnection, setLogwriter,
461 * setLoginTimeout, getLoginTimeout, getLogWriter.</code></p>
462 *
463 * @param poolingStatements pooling on or off
464 */
465 public synchronized void setPoolPreparedStatements(boolean poolingStatements) {
466 this.poolPreparedStatements = poolingStatements;
467 this.restartNeeded = true;
468 }
469
470 /**
471 * <p>The maximum number of open statements that can be allocated from
472 * the statement pool at the same time, or non-positive for no limit. Since
473 * a connection usually only uses one or two statements at a time, this is
474 * mostly used to help detect resource leaks.</p>
475 *
476 * <p>Note: As of version 1.3, CallableStatements (those produced by {@link Connection#prepareCall})
477 * are pooled along with PreparedStatements (produced by {@link Connection#prepareStatement})
478 * and <code>maxOpenPreparedStatements</code> limits the total number of prepared or callable statements
479 * that may be in use at a given time.</p>
480 */
481 protected int maxOpenPreparedStatements = GenericKeyedObjectPool.DEFAULT_MAX_TOTAL;
482
483 /**
484 * Gets the value of the {@link #maxOpenPreparedStatements} property.
485 *
486 * @return the maximum number of open statements
487 * @see #maxOpenPreparedStatements
488 */
489 public synchronized int getMaxOpenPreparedStatements() {
490 return this.maxOpenPreparedStatements;
491 }
492
493 /**
494 * <p>Sets the value of the {@link #maxOpenPreparedStatements}
495 * property.</p>
496 * <p>
497 * Note: this method currently has no effect once the pool has been
498 * initialized. The pool is initialized the first time one of the
499 * following methods is invoked: <code>getConnection, setLogwriter,
500 * setLoginTimeout, getLoginTimeout, getLogWriter.</code></p>
501 *
502 * @param maxOpenStatements the new maximum number of prepared statements
503 * @see #maxOpenPreparedStatements
504 */
505 public synchronized void setMaxOpenPreparedStatements(int maxOpenStatements) {
506 this.maxOpenPreparedStatements = maxOpenStatements;
507 this.restartNeeded = true;
508 }
509
510 /**
511 * The indication of whether objects will be validated before being
512 * borrowed from the pool. If the object fails to validate, it will be
513 * dropped from the pool, and we will attempt to borrow another.
514 */
515 protected boolean testOnBorrow = true;
516
517 /**
518 * Returns the {@link #testOnBorrow} property.
519 *
520 * @return true if objects are validated before being borrowed from the
521 * pool
522 *
523 * @see #testOnBorrow
524 */
525 public synchronized boolean getTestOnBorrow() {
526 return this.testOnBorrow;
527 }
528
529 /**
530 * Sets the {@link #testOnBorrow} property. This property determines
531 * whether or not the pool will validate objects before they are borrowed
532 * from the pool. For a <code>true</code> value to have any effect, the
533 * <code>validationQuery</code> property must be set to a non-null string.
534 *
535 * @param testOnBorrow new value for testOnBorrow property
536 */
537 public synchronized void setTestOnBorrow(boolean testOnBorrow) {
538 this.testOnBorrow = testOnBorrow;
539 if (connectionPool != null) {
540 connectionPool.setTestOnBorrow(testOnBorrow);
541 }
542 }
543
544 /**
545 * The indication of whether objects will be validated before being
546 * returned to the pool.
547 */
548 protected boolean testOnReturn = false;
549
550 /**
551 * Returns the value of the {@link #testOnReturn} property.
552 *
553 * @return true if objects are validated before being returned to the
554 * pool
555 * @see #testOnReturn
556 */
557 public synchronized boolean getTestOnReturn() {
558 return this.testOnReturn;
559 }
560
561 /**
562 * Sets the <code>testOnReturn</code> property. This property determines
563 * whether or not the pool will validate objects before they are returned
564 * to the pool. For a <code>true</code> value to have any effect, the
565 * <code>validationQuery</code> property must be set to a non-null string.
566 *
567 * @param testOnReturn new value for testOnReturn property
568 */
569 public synchronized void setTestOnReturn(boolean testOnReturn) {
570 this.testOnReturn = testOnReturn;
571 if (connectionPool != null) {
572 connectionPool.setTestOnReturn(testOnReturn);
573 }
574 }
575
576 /**
577 * The number of milliseconds to sleep between runs of the idle object
578 * evictor thread. When non-positive, no idle object evictor thread will
579 * be run.
580 */
581 protected long timeBetweenEvictionRunsMillis =
582 GenericObjectPool.DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS;
583
584 /**
585 * Returns the value of the {@link #timeBetweenEvictionRunsMillis}
586 * property.
587 *
588 * @return the time (in miliseconds) between evictor runs
589 * @see #timeBetweenEvictionRunsMillis
590 */
591 public synchronized long getTimeBetweenEvictionRunsMillis() {
592 return this.timeBetweenEvictionRunsMillis;
593 }
594
595 /**
596 * Sets the {@link #timeBetweenEvictionRunsMillis} property.
597 *
598 * @param timeBetweenEvictionRunsMillis the new time between evictor runs
599 * @see #timeBetweenEvictionRunsMillis
600 */
601 public synchronized void setTimeBetweenEvictionRunsMillis(long timeBetweenEvictionRunsMillis) {
602 this.timeBetweenEvictionRunsMillis = timeBetweenEvictionRunsMillis;
603 if (connectionPool != null) {
604 connectionPool.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
605 }
606 }
607
608 /**
609 * The number of objects to examine during each run of the idle object
610 * evictor thread (if any).
611 */
612 protected int numTestsPerEvictionRun =
613 GenericObjectPool.DEFAULT_NUM_TESTS_PER_EVICTION_RUN;
614
615 /**
616 * Returns the value of the {@link #numTestsPerEvictionRun} property.
617 *
618 * @return the number of objects to examine during idle object evictor
619 * runs
620 * @see #numTestsPerEvictionRun
621 */
622 public synchronized int getNumTestsPerEvictionRun() {
623 return this.numTestsPerEvictionRun;
624 }
625
626 /**
627 * Sets the value of the {@link #numTestsPerEvictionRun} property.
628 *
629 * @param numTestsPerEvictionRun the new {@link #numTestsPerEvictionRun}
630 * value
631 * @see #numTestsPerEvictionRun
632 */
633 public synchronized void setNumTestsPerEvictionRun(int numTestsPerEvictionRun) {
634 this.numTestsPerEvictionRun = numTestsPerEvictionRun;
635 if (connectionPool != null) {
636 connectionPool.setNumTestsPerEvictionRun(numTestsPerEvictionRun);
637 }
638 }
639
640 /**
641 * The minimum amount of time an object may sit idle in the pool before it
642 * is eligible for eviction by the idle object evictor (if any).
643 */
644 protected long minEvictableIdleTimeMillis =
645 GenericObjectPool.DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS;
646
647 /**
648 * Returns the {@link #minEvictableIdleTimeMillis} property.
649 *
650 * @return the value of the {@link #minEvictableIdleTimeMillis} property
651 * @see #minEvictableIdleTimeMillis
652 */
653 public synchronized long getMinEvictableIdleTimeMillis() {
654 return this.minEvictableIdleTimeMillis;
655 }
656
657 /**
658 * Sets the {@link #minEvictableIdleTimeMillis} property.
659 *
660 * @param minEvictableIdleTimeMillis the minimum amount of time an object
661 * may sit idle in the pool
662 * @see #minEvictableIdleTimeMillis
663 */
664 public synchronized void setMinEvictableIdleTimeMillis(long minEvictableIdleTimeMillis) {
665 this.minEvictableIdleTimeMillis = minEvictableIdleTimeMillis;
666 if (connectionPool != null) {
667 connectionPool.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
668 }
669 }
670
671 /**
672 * The indication of whether objects will be validated by the idle object
673 * evictor (if any). If an object fails to validate, it will be dropped
674 * from the pool.
675 */
676 protected boolean testWhileIdle = false;
677
678 /**
679 * Returns the value of the {@link #testWhileIdle} property.
680 *
681 * @return true if objects examined by the idle object evictor are
682 * validated
683 * @see #testWhileIdle
684 */
685 public synchronized boolean getTestWhileIdle() {
686 return this.testWhileIdle;
687 }
688
689 /**
690 * Sets the <code>testWhileIdle</code> property. This property determines
691 * whether or not the idle object evictor will validate connections. For a
692 * <code>true</code> value to have any effect, the
693 * <code>validationQuery</code> property must be set to a non-null string.
694 *
695 * @param testWhileIdle new value for testWhileIdle property
696 */
697 public synchronized void setTestWhileIdle(boolean testWhileIdle) {
698 this.testWhileIdle = testWhileIdle;
699 if (connectionPool != null) {
700 connectionPool.setTestWhileIdle(testWhileIdle);
701 }
702 }
703
704 /**
705 * [Read Only] The current number of active connections that have been
706 * allocated from this data source.
707 *
708 * @return the current number of active connections
709 */
710 public synchronized int getNumActive() {
711 if (connectionPool != null) {
712 return connectionPool.getNumActive();
713 } else {
714 return 0;
715 }
716 }
717
718
719 /**
720 * [Read Only] The current number of idle connections that are waiting
721 * to be allocated from this data source.
722 *
723 * @return the current number of idle connections
724 */
725 public synchronized int getNumIdle() {
726 if (connectionPool != null) {
727 return connectionPool.getNumIdle();
728 } else {
729 return 0;
730 }
731 }
732
733 /**
734 * The connection password to be passed to our JDBC driver to establish
735 * a connection.
736 */
737 protected volatile String password = null;
738
739 /**
740 * Returns the password passed to the JDBC driver to establish connections.
741 *
742 * @return the connection password
743 */
744 public String getPassword() {
745 return this.password;
746 }
747
748 /**
749 * <p>Sets the {@link #password}.</p>
750 * <p>
751 * Note: this method currently has no effect once the pool has been
752 * initialized. The pool is initialized the first time one of the
753 * following methods is invoked: <code>getConnection, setLogwriter,
754 * setLoginTimeout, getLoginTimeout, getLogWriter.</code></p>
755 *
756 * @param password new value for the password
757 */
758 public void setPassword(String password) {
759 this.password = password;
760 this.restartNeeded = true;
761 }
762
763 /**
764 * The connection URL to be passed to our JDBC driver to establish
765 * a connection.
766 */
767 protected String url = null;
768
769 /**
770 * Returns the JDBC connection {@link #url} property.
771 *
772 * @return the {@link #url} passed to the JDBC driver to establish
773 * connections
774 */
775 public synchronized String getUrl() {
776 return this.url;
777 }
778
779 /**
780 * <p>Sets the {@link #url}.</p>
781 * <p>
782 * Note: this method currently has no effect once the pool has been
783 * initialized. The pool is initialized the first time one of the
784 * following methods is invoked: <code>getConnection, setLogwriter,
785 * setLoginTimeout, getLoginTimeout, getLogWriter.</code></p>
786 *
787 * @param url the new value for the JDBC connection url
788 */
789 public synchronized void setUrl(String url) {
790 this.url = url;
791 this.restartNeeded = true;
792 }
793
794 /**
795 * The connection username to be passed to our JDBC driver to
796 * establish a connection.
797 */
798 protected String username = null;
799
800 /**
801 * Returns the JDBC connection {@link #username} property.
802 *
803 * @return the {@link #username} passed to the JDBC driver to establish
804 * connections
805 */
806 public String getUsername() {
807 return this.username;
808 }
809
810 /**
811 * <p>Sets the {@link #username}.</p>
812 * <p>
813 * Note: this method currently has no effect once the pool has been
814 * initialized. The pool is initialized the first time one of the
815 * following methods is invoked: <code>getConnection, setLogwriter,
816 * setLoginTimeout, getLoginTimeout, getLogWriter.</code></p>
817 *
818 * @param username the new value for the JDBC connection username
819 */
820 public void setUsername(String username) {
821 this.username = username;
822 this.restartNeeded = true;
823 }
824
825 /**
826 * The SQL query that will be used to validate connections from this pool
827 * before returning them to the caller. If specified, this query
828 * <strong>MUST</strong> be an SQL SELECT statement that returns at least
829 * one row.
830 */
831 protected volatile String validationQuery = null;
832
833 /**
834 * Returns the validation query used to validate connections before
835 * returning them.
836 *
837 * @return the SQL validation query
838 * @see #validationQuery
839 */
840 public String getValidationQuery() {
841 return this.validationQuery;
842 }
843
844 /**
845 * <p>Sets the {@link #validationQuery}.</p>
846 * <p>
847 * Note: this method currently has no effect once the pool has been
848 * initialized. The pool is initialized the first time one of the
849 * following methods is invoked: <code>getConnection, setLogwriter,
850 * setLoginTimeout, getLoginTimeout, getLogWriter.</code></p>
851 *
852 * @param validationQuery the new value for the validation query
853 */
854 public void setValidationQuery(String validationQuery) {
855 if ((validationQuery != null) && (validationQuery.trim().length() > 0)) {
856 this.validationQuery = validationQuery;
857 } else {
858 this.validationQuery = null;
859 }
860 this.restartNeeded = true;
861 }
862
863 /**
864 * Timeout in seconds before connection validation queries fail.
865 *
866 * @since 1.3
867 */
868 protected volatile int validationQueryTimeout = -1;
869
870 /**
871 * Returns the validation query timeout.
872 *
873 * @return the timeout in seconds before connection validation queries fail.
874 * @since 1.3
875 */
876 public int getValidationQueryTimeout() {
877 return validationQueryTimeout;
878 }
879
880 /**
881 * Sets the validation query timeout, the amount of time, in seconds, that
882 * connection validation will wait for a response from the database when
883 * executing a validation query. Use a value less than or equal to 0 for
884 * no timeout.
885 * <p>
886 * Note: this method currently has no effect once the pool has been
887 * initialized. The pool is initialized the first time one of the
888 * following methods is invoked: <code>getConnection, setLogwriter,
889 * setLoginTimeout, getLoginTimeout, getLogWriter.</code></p>
890 *
891 * @param timeout new validation query timeout value in seconds
892 * @since 1.3
893 */
894 public void setValidationQueryTimeout(int timeout) {
895 this.validationQueryTimeout = timeout;
896 restartNeeded = true;
897 }
898
899 /**
900 * These SQL statements run once after a Connection is created.
901 * <p>
902 * This property can be used for example to run ALTER SESSION SET
903 * NLS_SORT=XCYECH in an Oracle Database only once after connection
904 * creation.
905 * </p>
906 *
907 * @since 1.3
908 */
909 protected volatile List connectionInitSqls;
910
911 /**
912 * Returns the list of SQL statements executed when a physical connection
913 * is first created. Returns an empty list if there are no initialization
914 * statements configured.
915 *
916 * @return initialization SQL statements
917 * @since 1.3
918 */
919 public Collection getConnectionInitSqls() {
920 Collection result = connectionInitSqls;
921 if (result == null) {
922 return Collections.EMPTY_LIST;
923 }
924 return result;
925 }
926
927 /**
928 * Sets the list of SQL statements to be executed when a physical
929 * connection is first created.
930 * <p>
931 * Note: this method currently has no effect once the pool has been
932 * initialized. The pool is initialized the first time one of the
933 * following methods is invoked: <code>getConnection, setLogwriter,
934 * setLoginTimeout, getLoginTimeout, getLogWriter.</code></p>
935 *
936 * @param connectionInitSqls Collection of SQL statements to execute
937 * on connection creation
938 */
939 public void setConnectionInitSqls(Collection connectionInitSqls) {
940 if ((connectionInitSqls != null) && (connectionInitSqls.size() > 0)) {
941 ArrayList newVal = null;
942 for (Iterator iterator = connectionInitSqls.iterator();
943 iterator.hasNext();) {
944 Object o = iterator.next();
945 if (o != null) {
946 String s = o.toString();
947 if (s.trim().length() > 0) {
948 if (newVal == null) {
949 newVal = new ArrayList();
950 }
951 newVal.add(s);
952 }
953 }
954 }
955 this.connectionInitSqls = newVal;
956 } else {
957 this.connectionInitSqls = null;
958 }
959 this.restartNeeded = true;
960 }
961
962
963 /**
964 * Controls access to the underlying connection.
965 */
966 private boolean accessToUnderlyingConnectionAllowed = false;
967
968 /**
969 * Returns the value of the accessToUnderlyingConnectionAllowed property.
970 *
971 * @return true if access to the underlying connection is allowed, false
972 * otherwise.
973 */
974 public synchronized boolean isAccessToUnderlyingConnectionAllowed() {
975 return this.accessToUnderlyingConnectionAllowed;
976 }
977
978 /**
979 * <p>Sets the value of the accessToUnderlyingConnectionAllowed property.
980 * It controls if the PoolGuard allows access to the underlying connection.
981 * (Default: false)</p>
982 * <p>
983 * Note: this method currently has no effect once the pool has been
984 * initialized. The pool is initialized the first time one of the
985 * following methods is invoked: <code>getConnection, setLogwriter,
986 * setLoginTimeout, getLoginTimeout, getLogWriter.</code></p>
987 *
988 * @param allow Access to the underlying connection is granted when true.
989 */
990 public synchronized void setAccessToUnderlyingConnectionAllowed(boolean allow) {
991 this.accessToUnderlyingConnectionAllowed = allow;
992 this.restartNeeded = true;
993 }
994
995 // ----------------------------------------------------- Instance Variables
996
997 // TODO: review & make isRestartNeeded() public, restartNeeded protected
998
999 /**
1000 * A property setter has been invoked that will require the connection
1001 * pool to be re-initialized. Currently, restart is not triggered, so
1002 * this property has no effect.
1003 */
1004 private volatile boolean restartNeeded = false;
1005
1006 /**
1007 * Returns whether or not a restart is needed.
1008 *
1009 * Note: restart is not currently triggered by property changes.
1010 *
1011 * @return true if a restart is needed
1012 */
1013 private boolean isRestartNeeded() {
1014 return restartNeeded;
1015 }
1016
1017 /**
1018 * The object pool that internally manages our connections.
1019 */
1020 protected volatile GenericObjectPool connectionPool = null;
1021
1022 /**
1023 * The connection properties that will be sent to our JDBC driver when
1024 * establishing new connections. <strong>NOTE</strong> - The "user" and
1025 * "password" properties will be passed explicitly, so they do not need
1026 * to be included here.
1027 */
1028 protected Properties connectionProperties = new Properties();
1029
1030 /**
1031 * The data source we will use to manage connections. This object should
1032 * be acquired <strong>ONLY</strong> by calls to the
1033 * <code>createDataSource()</code> method.
1034 */
1035 protected volatile DataSource dataSource = null;
1036
1037 /**
1038 * The PrintWriter to which log messages should be directed.
1039 */
1040 protected PrintWriter logWriter = new PrintWriter(System.out);
1041
1042
1043 // ----------------------------------------------------- DataSource Methods
1044
1045
1046 /**
1047 * Create (if necessary) and return a connection to the database.
1048 *
1049 * @throws SQLException if a database access error occurs
1050 * @return a database connection
1051 */
1052 public Connection getConnection() throws SQLException {
1053 return createDataSource().getConnection();
1054 }
1055
1056
1057 /**
1058 * <strong>BasicDataSource does NOT support this method. </strong>
1059 *
1060 * @param user Database user on whose behalf the Connection
1061 * is being made
1062 * @param pass The database user's password
1063 *
1064 * @throws UnsupportedOperationException
1065 * @throws SQLException if a database access error occurs
1066 * @return nothing - always throws UnsupportedOperationException
1067 */
1068 public Connection getConnection(String user, String pass) throws SQLException {
1069 // This method isn't supported by the PoolingDataSource returned by
1070 // the createDataSource
1071 throw new UnsupportedOperationException("Not supported by BasicDataSource");
1072 // return createDataSource().getConnection(username, password);
1073 }
1074
1075
1076 /**
1077 * <strong>BasicDataSource does NOT support this method. </strong>
1078 *
1079 * <p>Returns the login timeout (in seconds) for connecting to the database.
1080 * </p>
1081 * <p>Calls {@link #createDataSource()}, so has the side effect
1082 * of initializing the connection pool.</p>
1083 *
1084 * @throws SQLException if a database access error occurs
1085 * @throws UnsupportedOperationException If the DataSource implementation
1086 * does not support the login timeout feature.
1087 * @return login timeout in seconds
1088 */
1089 public int getLoginTimeout() throws SQLException {
1090 // This method isn't supported by the PoolingDataSource returned by
1091 // the createDataSource
1092 throw new UnsupportedOperationException("Not supported by BasicDataSource");
1093 //return createDataSource().getLoginTimeout();
1094 }
1095
1096
1097 /**
1098 * <p>Returns the log writer being used by this data source.</p>
1099 * <p>
1100 * Calls {@link #createDataSource()}, so has the side effect
1101 * of initializing the connection pool.</p>
1102 *
1103 * @throws SQLException if a database access error occurs
1104 * @return log writer in use
1105 */
1106 public PrintWriter getLogWriter() throws SQLException {
1107 return createDataSource().getLogWriter();
1108 }
1109
1110
1111 /**
1112 * <strong>BasicDataSource does NOT support this method. </strong>
1113 *
1114 * <p>Set the login timeout (in seconds) for connecting to the
1115 * database.</p>
1116 * <p>
1117 * Calls {@link #createDataSource()}, so has the side effect
1118 * of initializing the connection pool.</p>
1119 *
1120 * @param loginTimeout The new login timeout, or zero for no timeout
1121 * @throws UnsupportedOperationException If the DataSource implementation
1122 * does not support the login timeout feature.
1123 * @throws SQLException if a database access error occurs
1124 */
1125 public void setLoginTimeout(int loginTimeout) throws SQLException {
1126 // This method isn't supported by the PoolingDataSource returned by
1127 // the createDataSource
1128 throw new UnsupportedOperationException("Not supported by BasicDataSource");
1129 //createDataSource().setLoginTimeout(loginTimeout);
1130 }
1131
1132
1133 /**
1134 * <p>Sets the log writer being used by this data source.</p>
1135 * <p>
1136 * Calls {@link #createDataSource()}, so has the side effect
1137 * of initializing the connection pool.</p>
1138 *
1139 * @param logWriter The new log writer
1140 * @throws SQLException if a database access error occurs
1141 */
1142 public void setLogWriter(PrintWriter logWriter) throws SQLException {
1143 createDataSource().setLogWriter(logWriter);
1144 this.logWriter = logWriter;
1145 }
1146
1147 private AbandonedConfig abandonedConfig;
1148
1149 /**
1150 * Flag to remove abandoned connections if they exceed the
1151 * removeAbandonedTimout.
1152 *
1153 * Set to true or false, default false.
1154 * If set to true a connection is considered abandoned and eligible
1155 * for removal if it has been idle longer than the removeAbandonedTimeout.
1156 * Setting this to true can recover db connections from poorly written
1157 * applications which fail to close a connection.
1158 * <p>
1159 * Abandonded connections are identified and removed when
1160 * {@link #getConnection()} is invoked and the following conditions hold
1161 * <ul><li>{@link #getRemoveAbandoned()} = true </li>
1162 * <li>{@link #getNumActive()} > {@link #getMaxActive()} - 3 </li>
1163 * <li>{@link #getNumIdle()} < 2 </li></ul></p>
1164 */
1165 public boolean getRemoveAbandoned() {
1166 if (abandonedConfig != null) {
1167 return abandonedConfig.getRemoveAbandoned();
1168 }
1169 return false;
1170 }
1171
1172 /**
1173 * @param removeAbandoned new removeAbandoned property value
1174 * @see #getRemoveAbandoned()
1175 */
1176 public void setRemoveAbandoned(boolean removeAbandoned) {
1177 if (abandonedConfig == null) {
1178 abandonedConfig = new AbandonedConfig();
1179 }
1180 abandonedConfig.setRemoveAbandoned(removeAbandoned);
1181 this.restartNeeded = true;
1182 }
1183
1184 /**
1185 * Timeout in seconds before an abandoned connection can be removed.
1186 *
1187 * Defaults to 300 seconds.
1188 * @return abandoned connection timeout
1189 */
1190 public int getRemoveAbandonedTimeout() {
1191 if (abandonedConfig != null) {
1192 return abandonedConfig.getRemoveAbandonedTimeout();
1193 }
1194 return 300;
1195 }
1196
1197 /**
1198 * @param removeAbandonedTimeout new removeAbandonedTimeout value
1199 */
1200 public void setRemoveAbandonedTimeout(int removeAbandonedTimeout) {
1201 if (abandonedConfig == null) {
1202 abandonedConfig = new AbandonedConfig();
1203 }
1204 abandonedConfig.setRemoveAbandonedTimeout(removeAbandonedTimeout);
1205 this.restartNeeded = true;
1206 }
1207
1208 /**
1209 * <p>Flag to log stack traces for application code which abandoned
1210 * a Statement or Connection.
1211 * </p>
1212 * <p>Defaults to false.
1213 * </p>
1214 * <p>Logging of abandoned Statements and Connections adds overhead
1215 * for every Connection open or new Statement because a stack
1216 * trace has to be generated. </p>
1217 */
1218 public boolean getLogAbandoned() {
1219 if (abandonedConfig != null) {
1220 return abandonedConfig.getLogAbandoned();
1221 }
1222 return false;
1223 }
1224
1225 /**
1226 * @param logAbandoned new logAbandoned property value
1227 */
1228 public void setLogAbandoned(boolean logAbandoned) {
1229 if (abandonedConfig == null) {
1230 abandonedConfig = new AbandonedConfig();
1231 }
1232 abandonedConfig.setLogAbandoned(logAbandoned);
1233 this.restartNeeded = true;
1234 }
1235
1236 // --------------------------------------------------------- Public Methods
1237
1238 /**
1239 * Add a custom connection property to the set that will be passed to our
1240 * JDBC driver. This <strong>MUST</strong> be called before the first
1241 * connection is retrieved (along with all the other configuration
1242 * property setters). Calls to this method after the connection pool
1243 * has been initialized have no effect.
1244 *
1245 * @param name Name of the custom connection property
1246 * @param value Value of the custom connection property
1247 */
1248 public void addConnectionProperty(String name, String value) {
1249 connectionProperties.put(name, value);
1250 this.restartNeeded = true;
1251 }
1252
1253 /**
1254 * Remove a custom connection property.
1255 *
1256 * @param name Name of the custom connection property to remove
1257 * @see #addConnectionProperty(String, String)
1258 */
1259 public void removeConnectionProperty(String name) {
1260 connectionProperties.remove(name);
1261 this.restartNeeded = true;
1262 }
1263
1264 /**
1265 * Sets the connection properties passed to driver.connect(...).
1266 *
1267 * Format of the string must be [propertyName=property;]*
1268 *
1269 * NOTE - The "user" and "password" properties will be added
1270 * explicitly, so they do not need to be included here.
1271 *
1272 * @param connectionProperties the connection properties used to
1273 * create new connections
1274 */
1275 public void setConnectionProperties(String connectionProperties) {
1276 if (connectionProperties == null) throw new NullPointerException("connectionProperties is null");
1277
1278 String[] entries = connectionProperties.split(";");
1279 Properties properties = new Properties();
1280 for (int i = 0; i < entries.length; i++) {
1281 String entry = entries[i];
1282 if (entry.length() > 0) {
1283 int index = entry.indexOf('=');
1284 if (index > 0) {
1285 String name = entry.substring(0, index);
1286 String value = entry.substring(index + 1);
1287 properties.setProperty(name, value);
1288 } else {
1289 // no value is empty string which is how java.util.Properties works
1290 properties.setProperty(entry, "");
1291 }
1292 }
1293 }
1294 this.connectionProperties = properties;
1295 this.restartNeeded = true;
1296 }
1297
1298 protected boolean closed;
1299
1300 /**
1301 * <p>Closes and releases all idle connections that are currently stored in the connection pool
1302 * associated with this data source.</p>
1303 *
1304 * <p>Connections that are checked out to clients when this method is invoked are not affected.
1305 * When client applications subsequently invoke {@link Connection#close()} to return
1306 * these connections to the pool, the underlying JDBC connections are closed.</p>
1307 *
1308 * <p>Attempts to acquire connections using {@link #getConnection()} after this method has been
1309 * invoked result in SQLExceptions.<p>
1310 *
1311 * <p>This method is idempotent - i.e., closing an already closed BasicDataSource has no effect
1312 * and does not generate exceptions.</p>
1313 *
1314 * @throws SQLException if an error occurs closing idle connections
1315 */
1316 public synchronized void close() throws SQLException {
1317 closed = true;
1318 GenericObjectPool oldpool = connectionPool;
1319 connectionPool = null;
1320 dataSource = null;
1321 try {
1322 if (oldpool != null) {
1323 oldpool.close();
1324 }
1325 } catch(SQLException e) {
1326 throw e;
1327 } catch(RuntimeException e) {
1328 throw e;
1329 } catch(Exception e) {
1330 throw new SQLNestedException("Cannot close connection pool", e);
1331 }
1332 }
1333
1334 /**
1335 * If true, this data source is closed and no more connections can be retrieved from this datasource.
1336 * @return true, if the data source is closed; false otherwise
1337 */
1338 public synchronized boolean isClosed() {
1339 return closed;
1340 }
1341
1342 /* JDBC_4_ANT_KEY_BEGIN */
1343 public boolean isWrapperFor(Class<?> iface) throws SQLException {
1344 return false;
1345 }
1346
1347 public <T> T unwrap(Class<T> iface) throws SQLException {
1348 throw new SQLException("BasicDataSource is not a wrapper.");
1349 }
1350 /* JDBC_4_ANT_KEY_END */
1351
1352
1353 // ------------------------------------------------------ Protected Methods
1354
1355
1356 /**
1357 * <p>Create (if necessary) and return the internal data source we are
1358 * using to manage our connections.</p>
1359 *
1360 * <p><strong>IMPLEMENTATION NOTE</strong> - It is tempting to use the
1361 * "double checked locking" idiom in an attempt to avoid synchronizing
1362 * on every single call to this method. However, this idiom fails to
1363 * work correctly in the face of some optimizations that are legal for
1364 * a JVM to perform.</p>
1365 *
1366 * @throws SQLException if the object pool cannot be created.
1367 */
1368 protected synchronized DataSource createDataSource()
1369 throws SQLException {
1370 if (closed) {
1371 throw new SQLException("Data source is closed");
1372 }
1373
1374 // Return the pool if we have already created it
1375 if (dataSource != null) {
1376 return (dataSource);
1377 }
1378
1379 // create factory which returns raw physical connections
1380 ConnectionFactory driverConnectionFactory = createConnectionFactory();
1381
1382 // create a pool for our connections
1383 createConnectionPool();
1384
1385 // Set up statement pool, if desired
1386 GenericKeyedObjectPoolFactory statementPoolFactory = null;
1387 if (isPoolPreparedStatements()) {
1388 statementPoolFactory = new GenericKeyedObjectPoolFactory(null,
1389 -1, // unlimited maxActive (per key)
1390 GenericKeyedObjectPool.WHEN_EXHAUSTED_FAIL,
1391 0, // maxWait
1392 1, // maxIdle (per key)
1393 maxOpenPreparedStatements);
1394 }
1395
1396 // Set up the poolable connection factory
1397 createPoolableConnectionFactory(driverConnectionFactory, statementPoolFactory, abandonedConfig);
1398
1399 // Create and return the pooling data source to manage the connections
1400 createDataSourceInstance();
1401
1402 try {
1403 for (int i = 0 ; i < initialSize ; i++) {
1404 connectionPool.addObject();
1405 }
1406 } catch (Exception e) {
1407 throw new SQLNestedException("Error preloading the connection pool", e);
1408 }
1409
1410 return dataSource;
1411 }
1412
1413 /**
1414 * Creates a JDBC connection factory for this datasource. This method only
1415 * exists so subclasses can replace the implementation class.
1416 */
1417 protected ConnectionFactory createConnectionFactory() throws SQLException {
1418 // Load the JDBC driver class
1419 Class driverFromCCL = null;
1420 if (driverClassName != null) {
1421 try {
1422 try {
1423 if (driverClassLoader == null) {
1424 Class.forName(driverClassName);
1425 } else {
1426 Class.forName(driverClassName, true, driverClassLoader);
1427 }
1428 } catch (ClassNotFoundException cnfe) {
1429 driverFromCCL = Thread.currentThread(
1430 ).getContextClassLoader().loadClass(
1431 driverClassName);
1432 }
1433 } catch (Throwable t) {
1434 String message = "Cannot load JDBC driver class '" +
1435 driverClassName + "'";
1436 logWriter.println(message);
1437 t.printStackTrace(logWriter);
1438 throw new SQLNestedException(message, t);
1439 }
1440 }
1441
1442 // Create a JDBC driver instance
1443 Driver driver = null;
1444 try {
1445 if (driverFromCCL == null) {
1446 driver = DriverManager.getDriver(url);
1447 } else {
1448 // Usage of DriverManager is not possible, as it does not
1449 // respect the ContextClassLoader
1450 driver = (Driver) driverFromCCL.newInstance();
1451 if (!driver.acceptsURL(url)) {
1452 throw new SQLException("No suitable driver", "08001");
1453 }
1454 }
1455 } catch (Throwable t) {
1456 String message = "Cannot create JDBC driver of class '" +
1457 (driverClassName != null ? driverClassName : "") +
1458 "' for connect URL '" + url + "'";
1459 logWriter.println(message);
1460 t.printStackTrace(logWriter);
1461 throw new SQLNestedException(message, t);
1462 }
1463
1464 // Can't test without a validationQuery
1465 if (validationQuery == null) {
1466 setTestOnBorrow(false);
1467 setTestOnReturn(false);
1468 setTestWhileIdle(false);
1469 }
1470
1471 // Set up the driver connection factory we will use
1472 String user = username;
1473 if (user != null) {
1474 connectionProperties.put("user", user);
1475 } else {
1476 log("DBCP DataSource configured without a 'username'");
1477 }
1478
1479 String pwd = password;
1480 if (pwd != null) {
1481 connectionProperties.put("password", pwd);
1482 } else {
1483 log("DBCP DataSource configured without a 'password'");
1484 }
1485
1486 ConnectionFactory driverConnectionFactory = new DriverConnectionFactory(driver, url, connectionProperties);
1487 return driverConnectionFactory;
1488 }
1489
1490 /**
1491 * Creates a connection pool for this datasource. This method only exists
1492 * so subclasses can replace the implementation class.
1493 */
1494 protected void createConnectionPool() {
1495 // Create an object pool to contain our active connections
1496 GenericObjectPool gop;
1497 if ((abandonedConfig != null) && (abandonedConfig.getRemoveAbandoned())) {
1498 gop = new AbandonedObjectPool(null,abandonedConfig);
1499 }
1500 else {
1501 gop = new GenericObjectPool();
1502 }
1503 gop.setMaxActive(maxActive);
1504 gop.setMaxIdle(maxIdle);
1505 gop.setMinIdle(minIdle);
1506 gop.setMaxWait(maxWait);
1507 gop.setTestOnBorrow(testOnBorrow);
1508 gop.setTestOnReturn(testOnReturn);
1509 gop.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
1510 gop.setNumTestsPerEvictionRun(numTestsPerEvictionRun);
1511 gop.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
1512 gop.setTestWhileIdle(testWhileIdle);
1513 connectionPool = gop;
1514 }
1515
1516 /**
1517 * Creates the actual data source instance. This method only exists so
1518 * subclasses can replace the implementation class.
1519 *
1520 * @throws SQLException if unable to create a datasource instance
1521 */
1522 protected void createDataSourceInstance() throws SQLException {
1523 PoolingDataSource pds = new PoolingDataSource(connectionPool);
1524 pds.setAccessToUnderlyingConnectionAllowed(isAccessToUnderlyingConnectionAllowed());
1525 pds.setLogWriter(logWriter);
1526 dataSource = pds;
1527 }
1528
1529 /**
1530 * Creates the PoolableConnectionFactory and attaches it to the connection pool. This method only exists
1531 * so subclasses can replace the default implementation.
1532 *
1533 * @param driverConnectionFactory JDBC connection factory
1534 * @param statementPoolFactory statement pool factory (null if statement pooling is turned off)
1535 * @param configuration abandoned connection tracking configuration (null if no tracking)
1536 * @throws SQLException if an error occurs creating the PoolableConnectionFactory
1537 */
1538 protected void createPoolableConnectionFactory(ConnectionFactory driverConnectionFactory,
1539 KeyedObjectPoolFactory statementPoolFactory, AbandonedConfig configuration) throws SQLException {
1540 PoolableConnectionFactory connectionFactory = null;
1541 try {
1542 connectionFactory =
1543 new PoolableConnectionFactory(driverConnectionFactory,
1544 connectionPool,
1545 statementPoolFactory,
1546 validationQuery,
1547 validationQueryTimeout,
1548 connectionInitSqls,
1549 defaultReadOnly,
1550 defaultAutoCommit,
1551 defaultTransactionIsolation,
1552 defaultCatalog,
1553 configuration);
1554 validateConnectionFactory(connectionFactory);
1555 } catch (RuntimeException e) {
1556 throw e;
1557 } catch (Exception e) {
1558 throw new SQLNestedException("Cannot create PoolableConnectionFactory (" + e.getMessage() + ")", e);
1559 }
1560 }
1561
1562 protected static void validateConnectionFactory(PoolableConnectionFactory connectionFactory) throws Exception {
1563 Connection conn = null;
1564 try {
1565 conn = (Connection) connectionFactory.makeObject();
1566 connectionFactory.activateObject(conn);
1567 connectionFactory.validateConnection(conn);
1568 connectionFactory.passivateObject(conn);
1569 }
1570 finally {
1571 connectionFactory.destroyObject(conn);
1572 }
1573 }
1574
1575 /**
1576 * Not used currently
1577 */
1578 private void restart() {
1579 try {
1580 close();
1581 } catch (SQLException e) {
1582 log("Could not restart DataSource, cause: " + e.getMessage());
1583 }
1584 }
1585
1586 protected void log(String message) {
1587 if (logWriter != null) {
1588 logWriter.println(message);
1589 }
1590 }
1591 }