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 }