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 */ 017package org.apache.commons.dbcp2; 018 019import java.io.OutputStreamWriter; 020import java.io.PrintWriter; 021import java.nio.charset.StandardCharsets; 022import java.security.AccessController; 023import java.security.PrivilegedActionException; 024import java.security.PrivilegedExceptionAction; 025import java.sql.Connection; 026import java.sql.Driver; 027import java.sql.DriverManager; 028import java.sql.SQLException; 029import java.sql.SQLFeatureNotSupportedException; 030import java.util.ArrayList; 031import java.util.Collection; 032import java.util.Collections; 033import java.util.HashSet; 034import java.util.List; 035import java.util.Properties; 036import java.util.Set; 037import java.util.logging.Logger; 038 039import javax.management.MBeanRegistration; 040import javax.management.MBeanServer; 041import javax.management.MalformedObjectNameException; 042import javax.management.ObjectName; 043import javax.sql.DataSource; 044 045import org.apache.commons.logging.Log; 046import org.apache.commons.logging.LogFactory; 047import org.apache.commons.pool2.PooledObject; 048import org.apache.commons.pool2.impl.AbandonedConfig; 049import org.apache.commons.pool2.impl.BaseObjectPoolConfig; 050import org.apache.commons.pool2.impl.GenericKeyedObjectPoolConfig; 051import org.apache.commons.pool2.impl.GenericObjectPool; 052import org.apache.commons.pool2.impl.GenericObjectPoolConfig; 053 054/** 055 * <p>Basic implementation of <code>javax.sql.DataSource</code> that is 056 * configured via JavaBeans properties. This is not the only way to 057 * combine the <em>commons-dbcp2</em> and <em>commons-pool2</em> packages, 058 * but provides a "one stop shopping" solution for basic requirements.</p> 059 * 060 * @author Glenn L. Nielsen 061 * @author Craig R. McClanahan 062 * @author Dirk Verbeeck 063 * @version $Id$ 064 * @since 2.0 065 */ 066public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBeanRegistration, AutoCloseable { 067 068 private static final Log log = LogFactory.getLog(BasicDataSource.class); 069 070 static { 071 // Attempt to prevent deadlocks - see DBCP - 272 072 DriverManager.getDrivers(); 073 try { 074 // Load classes now to prevent AccessControlExceptions later 075 // A number of classes are loaded when getConnection() is called 076 // but the following classes are not loaded and therefore require 077 // explicit loading. 078 if (Utils.IS_SECURITY_ENABLED) { 079 final ClassLoader loader = BasicDataSource.class.getClassLoader(); 080 final String dbcpPackageName = BasicDataSource.class.getPackage().getName(); 081 loader.loadClass(dbcpPackageName + ".BasicDataSource$PaGetConnection"); 082 loader.loadClass(dbcpPackageName + ".DelegatingCallableStatement"); 083 loader.loadClass(dbcpPackageName + ".DelegatingDatabaseMetaData"); 084 loader.loadClass(dbcpPackageName + ".DelegatingPreparedStatement"); 085 loader.loadClass(dbcpPackageName + ".DelegatingResultSet"); 086 loader.loadClass(dbcpPackageName + ".PoolableCallableStatement"); 087 loader.loadClass(dbcpPackageName + ".PoolablePreparedStatement"); 088 loader.loadClass(dbcpPackageName + ".PoolingConnection$StatementType"); 089 loader.loadClass(dbcpPackageName + ".PStmtKey"); 090 091 final String poolPackageName = PooledObject.class.getPackage().getName(); 092 loader.loadClass(poolPackageName + ".impl.LinkedBlockingDeque$Node"); 093 loader.loadClass(poolPackageName + ".impl.GenericKeyedObjectPool$ObjectDeque"); 094 } 095 } catch (final ClassNotFoundException cnfe) { 096 throw new IllegalStateException("Unable to pre-load classes", cnfe); 097 } 098 } 099 100 // ------------------------------------------------------------- Properties 101 102 /** 103 * The default auto-commit state of connections created by this pool. 104 */ 105 private volatile Boolean defaultAutoCommit; 106 107 /** 108 * Returns the default auto-commit property. 109 * 110 * @return true if default auto-commit is enabled 111 */ 112 @Override 113 public Boolean getDefaultAutoCommit() { 114 return defaultAutoCommit; 115 } 116 117 /** 118 * <p>Sets default auto-commit state of connections returned by this 119 * datasource.</p> 120 * <p> 121 * Note: this method currently has no effect once the pool has been 122 * initialized. The pool is initialized the first time one of the 123 * following methods is invoked: <code>getConnection, setLogwriter, 124 * setLoginTimeout, getLoginTimeout, getLogWriter.</code></p> 125 * 126 * @param defaultAutoCommit default auto-commit value 127 */ 128 public void setDefaultAutoCommit(final Boolean defaultAutoCommit) { 129 this.defaultAutoCommit = defaultAutoCommit; 130 } 131 132 133 /** 134 * The default read-only state of connections created by this pool. 135 */ 136 private transient Boolean defaultReadOnly; 137 138 /** 139 * Returns the default readOnly property. 140 * 141 * @return true if connections are readOnly by default 142 */ 143 @Override 144 public Boolean getDefaultReadOnly() { 145 return defaultReadOnly; 146 } 147 148 /** 149 * <p>Sets defaultReadonly property.</p> 150 * <p> 151 * Note: this method currently has no effect once the pool has been 152 * initialized. The pool is initialized the first time one of the 153 * following methods is invoked: <code>getConnection, setLogwriter, 154 * setLoginTimeout, getLoginTimeout, getLogWriter.</code></p> 155 * 156 * @param defaultReadOnly default read-only value 157 */ 158 public void setDefaultReadOnly(final Boolean defaultReadOnly) { 159 this.defaultReadOnly = defaultReadOnly; 160 } 161 162 /** 163 * The default TransactionIsolation state of connections created by this pool. 164 */ 165 private volatile int defaultTransactionIsolation = 166 PoolableConnectionFactory.UNKNOWN_TRANSACTIONISOLATION; 167 168 /** 169 * Returns the default transaction isolation state of returned connections. 170 * 171 * @return the default value for transaction isolation state 172 * @see Connection#getTransactionIsolation 173 */ 174 @Override 175 public int getDefaultTransactionIsolation() { 176 return this.defaultTransactionIsolation; 177 } 178 179 /** 180 * <p>Sets the default transaction isolation state for returned 181 * connections.</p> 182 * <p> 183 * Note: this method currently has no effect once the pool has been 184 * initialized. The pool is initialized the first time one of the 185 * following methods is invoked: <code>getConnection, setLogwriter, 186 * setLoginTimeout, getLoginTimeout, getLogWriter.</code></p> 187 * 188 * @param defaultTransactionIsolation the default transaction isolation 189 * state 190 * @see Connection#getTransactionIsolation 191 */ 192 public void setDefaultTransactionIsolation(final int defaultTransactionIsolation) { 193 this.defaultTransactionIsolation = defaultTransactionIsolation; 194 } 195 196 197 private Integer defaultQueryTimeout; 198 199 /** 200 * Obtain the default query timeout that will be used for {@link java.sql.Statement Statement}s 201 * created from this connection. <code>null</code> means that the driver 202 * default will be used. 203 */ 204 public Integer getDefaultQueryTimeout() { 205 return defaultQueryTimeout; 206 } 207 208 209 /** 210 * Set the default query timeout that will be used for {@link java.sql.Statement Statement}s 211 * created from this connection. <code>null</code> means that the driver 212 * default will be used. 213 */ 214 public void setDefaultQueryTimeout(final Integer defaultQueryTimeout) { 215 this.defaultQueryTimeout = defaultQueryTimeout; 216 } 217 218 219 /** 220 * The default "catalog" of connections created by this pool. 221 */ 222 private volatile String defaultCatalog; 223 224 /** 225 * Returns the default catalog. 226 * 227 * @return the default catalog 228 */ 229 @Override 230 public String getDefaultCatalog() { 231 return this.defaultCatalog; 232 } 233 234 /** 235 * <p>Sets the default catalog.</p> 236 * <p> 237 * Note: this method currently has no effect once the pool has been 238 * initialized. The pool is initialized the first time one of the 239 * following methods is invoked: <code>getConnection, setLogwriter, 240 * setLoginTimeout, getLoginTimeout, getLogWriter.</code></p> 241 * 242 * @param defaultCatalog the default catalog 243 */ 244 public void setDefaultCatalog(final String defaultCatalog) { 245 if (defaultCatalog != null && defaultCatalog.trim().length() > 0) { 246 this.defaultCatalog = defaultCatalog; 247 } 248 else { 249 this.defaultCatalog = null; 250 } 251 } 252 253 /** 254 * The property that controls if the pooled connections cache some state 255 * rather than query the database for current state to improve performance. 256 */ 257 private boolean cacheState = true; 258 259 /** 260 * Returns the state caching flag. 261 * 262 * @return the state caching flag 263 */ 264 @Override 265 public boolean getCacheState() { 266 return cacheState; 267 } 268 269 /** 270 * Sets the state caching flag. 271 * 272 * @param cacheState The new value for the state caching flag 273 */ 274 public void setCacheState(final boolean cacheState) { 275 this.cacheState = cacheState; 276 } 277 278 /** 279 * The instance of the JDBC Driver to use. 280 */ 281 private Driver driver; 282 283 /** 284 * Returns the JDBC Driver that has been configured for use by this pool. 285 * <p> 286 * Note: This getter only returns the last value set by a call to 287 * {@link #setDriver(Driver)}. It does not return any driver instance that 288 * may have been created from the value set via 289 * {@link #setDriverClassName(String)}. 290 * 291 * @return the JDBC Driver that has been configured for use by this pool 292 */ 293 public synchronized Driver getDriver() { 294 return driver; 295 } 296 297 /** 298 * Sets the JDBC Driver instance to use for this pool. 299 * <p> 300 * Note: this method currently has no effect once the pool has been 301 * initialized. The pool is initialized the first time one of the 302 * following methods is invoked: <code>getConnection, setLogwriter, 303 * setLoginTimeout, getLoginTimeout, getLogWriter.</code></p> 304 * 305 * @param driver 306 */ 307 public synchronized void setDriver(final Driver driver) { 308 this.driver = driver; 309 } 310 311 /** 312 * The fully qualified Java class name of the JDBC driver to be used. 313 */ 314 private String driverClassName; 315 316 /** 317 * Returns the JDBC driver class name. 318 * <p> 319 * Note: This getter only returns the last value set by a call to 320 * {@link #setDriverClassName(String)}. It does not return the class name of 321 * any driver that may have been set via {@link #setDriver(Driver)}. 322 * 323 * @return the JDBC driver class name 324 */ 325 @Override 326 public synchronized String getDriverClassName() { 327 return this.driverClassName; 328 } 329 330 /** 331 * <p>Sets the JDBC driver class name.</p> 332 * <p> 333 * Note: this method currently has no effect once the pool has been 334 * initialized. The pool is initialized the first time one of the 335 * following methods is invoked: <code>getConnection, setLogwriter, 336 * setLoginTimeout, getLoginTimeout, getLogWriter.</code></p> 337 * 338 * @param driverClassName the class name of the JDBC driver 339 */ 340 public synchronized void setDriverClassName(final String driverClassName) { 341 if (driverClassName != null && driverClassName.trim().length() > 0) { 342 this.driverClassName = driverClassName; 343 } 344 else { 345 this.driverClassName = null; 346 } 347 } 348 349 /** 350 * The class loader instance to use to load the JDBC driver. If not 351 * specified, {@link Class#forName(String)} is used to load the JDBC driver. 352 * If specified, {@link Class#forName(String, boolean, ClassLoader)} is 353 * used. 354 */ 355 private ClassLoader driverClassLoader; 356 357 /** 358 * Returns the class loader specified for loading the JDBC driver. Returns 359 * <code>null</code> if no class loader has been explicitly specified. 360 * <p> 361 * Note: This getter only returns the last value set by a call to 362 * {@link #setDriverClassLoader(ClassLoader)}. It does not return the class 363 * loader of any driver that may have been set via 364 * {@link #setDriver(Driver)}. 365 */ 366 public synchronized ClassLoader getDriverClassLoader() { 367 return this.driverClassLoader; 368 } 369 370 /** 371 * <p>Sets the class loader to be used to load the JDBC driver.</p> 372 * <p> 373 * Note: this method currently has no effect once the pool has been 374 * initialized. The pool is initialized the first time one of the 375 * following methods is invoked: <code>getConnection, setLogwriter, 376 * setLoginTimeout, getLoginTimeout, getLogWriter.</code></p> 377 * 378 * @param driverClassLoader the class loader with which to load the JDBC 379 * driver 380 */ 381 public synchronized void setDriverClassLoader( 382 final ClassLoader driverClassLoader) { 383 this.driverClassLoader = driverClassLoader; 384 } 385 386 /** 387 * True means that borrowObject returns the most recently used ("last in") 388 * connection in the pool (if there are idle connections available). False 389 * means that the pool behaves as a FIFO queue - connections are taken from 390 * the idle instance pool in the order that they are returned to the pool. 391 */ 392 private boolean lifo = BaseObjectPoolConfig.DEFAULT_LIFO; 393 394 /** 395 * Returns the LIFO property. 396 * 397 * @return true if connection pool behaves as a LIFO queue. 398 */ 399 @Override 400 public synchronized boolean getLifo() { 401 return this.lifo; 402 } 403 404 /** 405 * Sets the LIFO property. True means the pool behaves as a LIFO queue; 406 * false means FIFO. 407 * 408 * @param lifo the new value for the LIFO property 409 * 410 */ 411 public synchronized void setLifo(final boolean lifo) { 412 this.lifo = lifo; 413 if (connectionPool != null) { 414 connectionPool.setLifo(lifo); 415 } 416 } 417 418 /** 419 * The maximum number of active connections that can be allocated from 420 * this pool at the same time, or negative for no limit. 421 */ 422 private int maxTotal = GenericObjectPoolConfig.DEFAULT_MAX_TOTAL; 423 424 /** 425 * <p>Returns the maximum number of active connections that can be 426 * allocated at the same time. 427 * </p> 428 * <p>A negative number means that there is no limit.</p> 429 * 430 * @return the maximum number of active connections 431 */ 432 @Override 433 public synchronized int getMaxTotal() { 434 return this.maxTotal; 435 } 436 437 /** 438 * Sets the maximum total number of idle and borrows connections that can be 439 * active at the same time. Use a negative value for no limit. 440 * 441 * @param maxTotal the new value for maxTotal 442 * @see #getMaxTotal() 443 */ 444 public synchronized void setMaxTotal(final int maxTotal) { 445 this.maxTotal = maxTotal; 446 if (connectionPool != null) { 447 connectionPool.setMaxTotal(maxTotal); 448 } 449 } 450 451 /** 452 * The maximum number of connections that can remain idle in the 453 * pool, without extra ones being destroyed, or negative for no limit. 454 * If maxIdle is set too low on heavily loaded systems it is possible you 455 * will see connections being closed and almost immediately new connections 456 * being opened. This is a result of the active threads momentarily closing 457 * connections faster than they are opening them, causing the number of idle 458 * connections to rise above maxIdle. The best value for maxIdle for heavily 459 * loaded system will vary but the default is a good starting point. 460 */ 461 private int maxIdle = GenericObjectPoolConfig.DEFAULT_MAX_IDLE; 462 463 /** 464 * <p>Returns the maximum number of connections that can remain idle in the 465 * pool. Excess idle connections are destroyed on return to the pool. 466 * </p> 467 * <p>A negative value indicates that there is no limit</p> 468 * 469 * @return the maximum number of idle connections 470 */ 471 @Override 472 public synchronized int getMaxIdle() { 473 return this.maxIdle; 474 } 475 476 /** 477 * Sets the maximum number of connections that can remain idle in the 478 * pool. Excess idle connections are destroyed on return to the pool. 479 * 480 * @see #getMaxIdle() 481 * @param maxIdle the new value for maxIdle 482 */ 483 public synchronized void setMaxIdle(final int maxIdle) { 484 this.maxIdle = maxIdle; 485 if (connectionPool != null) { 486 connectionPool.setMaxIdle(maxIdle); 487 } 488 } 489 490 /** 491 * The minimum number of active connections that can remain idle in the 492 * pool, without extra ones being created when the evictor runs, or 0 to create none. 493 * The pool attempts to ensure that minIdle connections are available when the idle object evictor 494 * runs. The value of this property has no effect unless {@link #timeBetweenEvictionRunsMillis} 495 * has a positive value. 496 */ 497 private int minIdle = GenericObjectPoolConfig.DEFAULT_MIN_IDLE; 498 499 /** 500 * Returns the minimum number of idle connections in the pool. The pool attempts 501 * to ensure that minIdle connections are available when the idle object evictor 502 * runs. The value of this property has no effect unless {@link #timeBetweenEvictionRunsMillis} 503 * has a positive value. 504 * 505 * @return the minimum number of idle connections 506 * @see GenericObjectPool#getMinIdle() 507 */ 508 @Override 509 public synchronized int getMinIdle() { 510 return this.minIdle; 511 } 512 513 /** 514 * Sets the minimum number of idle connections in the pool. The pool attempts 515 * to ensure that minIdle connections are available when the idle object evictor 516 * runs. The value of this property has no effect unless {@link #timeBetweenEvictionRunsMillis} 517 * has a positive value. 518 * 519 * @param minIdle the new value for minIdle 520 * @see GenericObjectPool#setMinIdle(int) 521 */ 522 public synchronized void setMinIdle(final int minIdle) { 523 this.minIdle = minIdle; 524 if (connectionPool != null) { 525 connectionPool.setMinIdle(minIdle); 526 } 527 } 528 529 /** 530 * The initial number of connections that are created when the pool 531 * is started. 532 */ 533 private int initialSize = 0; 534 535 /** 536 * Returns the initial size of the connection pool. 537 * 538 * @return the number of connections created when the pool is initialized 539 */ 540 @Override 541 public synchronized int getInitialSize() { 542 return this.initialSize; 543 } 544 545 /** 546 * <p>Sets the initial size of the connection pool.</p> 547 * <p> 548 * Note: this method currently has no effect once the pool has been 549 * initialized. The pool is initialized the first time one of the 550 * following methods is invoked: <code>getConnection, setLogwriter, 551 * setLoginTimeout, getLoginTimeout, getLogWriter.</code></p> 552 * 553 * @param initialSize the number of connections created when the pool 554 * is initialized 555 */ 556 public synchronized void setInitialSize(final int initialSize) { 557 this.initialSize = initialSize; 558 } 559 560 /** 561 * The maximum number of milliseconds that the pool will wait (when there 562 * are no available connections) for a connection to be returned before 563 * throwing an exception, or <= 0 to wait indefinitely. 564 */ 565 private long maxWaitMillis = 566 BaseObjectPoolConfig.DEFAULT_MAX_WAIT_MILLIS; 567 568 /** 569 * Returns the maximum number of milliseconds that the pool will wait 570 * for a connection to be returned before throwing an exception. A value 571 * less than or equal to zero means the pool is set to wait indefinitely. 572 * 573 * @return the maxWaitMillis property value 574 */ 575 @Override 576 public synchronized long getMaxWaitMillis() { 577 return this.maxWaitMillis; 578 } 579 580 /** 581 * Sets the MaxWaitMillis property. Use -1 to make the pool wait 582 * indefinitely. 583 * 584 * @param maxWaitMillis the new value for MaxWaitMillis 585 * @see #getMaxWaitMillis() 586 */ 587 public synchronized void setMaxWaitMillis(final long maxWaitMillis) { 588 this.maxWaitMillis = maxWaitMillis; 589 if (connectionPool != null) { 590 connectionPool.setMaxWaitMillis(maxWaitMillis); 591 } 592 } 593 594 /** 595 * Prepared statement pooling for this pool. When this property is set to <code>true</code> 596 * both PreparedStatements and CallableStatements are pooled. 597 */ 598 private boolean poolPreparedStatements = false; 599 600 /** 601 * Returns true if we are pooling statements. 602 * 603 * @return true if prepared and callable statements are pooled 604 */ 605 @Override 606 public synchronized boolean isPoolPreparedStatements() { 607 return this.poolPreparedStatements; 608 } 609 610 /** 611 * <p>Sets whether to pool statements or not.</p> 612 * <p> 613 * Note: this method currently has no effect once the pool has been 614 * initialized. The pool is initialized the first time one of the 615 * following methods is invoked: <code>getConnection, setLogwriter, 616 * setLoginTimeout, getLoginTimeout, getLogWriter.</code></p> 617 * 618 * @param poolingStatements pooling on or off 619 */ 620 public synchronized void setPoolPreparedStatements(final boolean poolingStatements) { 621 this.poolPreparedStatements = poolingStatements; 622 } 623 624 /** 625 * <p>The maximum number of open statements that can be allocated from 626 * the statement pool at the same time, or negative for no limit. Since 627 * a connection usually only uses one or two statements at a time, this is 628 * mostly used to help detect resource leaks.</p> 629 * 630 * <p>Note: As of version 1.3, CallableStatements (those produced by {@link Connection#prepareCall}) 631 * are pooled along with PreparedStatements (produced by {@link Connection#prepareStatement}) 632 * and <code>maxOpenPreparedStatements</code> limits the total number of prepared or callable statements 633 * that may be in use at a given time.</p> 634 */ 635 private int maxOpenPreparedStatements = 636 GenericKeyedObjectPoolConfig.DEFAULT_MAX_TOTAL; 637 638 /** 639 * Gets the value of the <code>maxOpenPreparedStatements</code> property. 640 * 641 * @return the maximum number of open statements 642 */ 643 @Override 644 public synchronized int getMaxOpenPreparedStatements() { 645 return this.maxOpenPreparedStatements; 646 } 647 648 /** 649 * <p>Sets the value of the <code>maxOpenPreparedStatements</code> 650 * property.</p> 651 * <p> 652 * Note: this method currently has no effect once the pool has been 653 * initialized. The pool is initialized the first time one of the 654 * following methods is invoked: <code>getConnection, setLogwriter, 655 * setLoginTimeout, getLoginTimeout, getLogWriter.</code></p> 656 * 657 * @param maxOpenStatements the new maximum number of prepared statements 658 */ 659 public synchronized void setMaxOpenPreparedStatements(final int maxOpenStatements) { 660 this.maxOpenPreparedStatements = maxOpenStatements; 661 } 662 663 /** 664 * The indication of whether objects will be validated as soon as they have 665 * been created by the pool. If the object fails to validate, the borrow 666 * operation that triggered the creation will fail. 667 */ 668 private boolean testOnCreate = false; 669 670 /** 671 * Returns the {@link #testOnCreate} property. 672 * 673 * @return true if objects are validated immediately after they are created 674 * by the pool 675 * 676 * @see #testOnCreate 677 */ 678 @Override 679 public synchronized boolean getTestOnCreate() { 680 return this.testOnCreate; 681 } 682 683 /** 684 * Sets the {@link #testOnCreate} property. This property determines 685 * whether or not the pool will validate objects immediately after they are 686 * created by the pool 687 * 688 * @param testOnCreate new value for testOnCreate property 689 */ 690 public synchronized void setTestOnCreate(final boolean testOnCreate) { 691 this.testOnCreate = testOnCreate; 692 if (connectionPool != null) { 693 connectionPool.setTestOnCreate(testOnCreate); 694 } 695 } 696 697 /** 698 * The indication of whether objects will be validated before being 699 * borrowed from the pool. If the object fails to validate, it will be 700 * dropped from the pool, and we will attempt to borrow another. 701 */ 702 private boolean testOnBorrow = true; 703 704 /** 705 * Returns the {@link #testOnBorrow} property. 706 * 707 * @return true if objects are validated before being borrowed from the 708 * pool 709 * 710 * @see #testOnBorrow 711 */ 712 @Override 713 public synchronized boolean getTestOnBorrow() { 714 return this.testOnBorrow; 715 } 716 717 /** 718 * Sets the {@link #testOnBorrow} property. This property determines 719 * whether or not the pool will validate objects before they are borrowed 720 * from the pool. 721 * 722 * @param testOnBorrow new value for testOnBorrow property 723 */ 724 public synchronized void setTestOnBorrow(final boolean testOnBorrow) { 725 this.testOnBorrow = testOnBorrow; 726 if (connectionPool != null) { 727 connectionPool.setTestOnBorrow(testOnBorrow); 728 } 729 } 730 731 /** 732 * The indication of whether objects will be validated before being 733 * returned to the pool. 734 */ 735 private boolean testOnReturn = false; 736 737 /** 738 * Returns the value of the {@link #testOnReturn} property. 739 * 740 * @return true if objects are validated before being returned to the 741 * pool 742 * @see #testOnReturn 743 */ 744 public synchronized boolean getTestOnReturn() { 745 return this.testOnReturn; 746 } 747 748 /** 749 * Sets the <code>testOnReturn</code> property. This property determines 750 * whether or not the pool will validate objects before they are returned 751 * to the pool. 752 * 753 * @param testOnReturn new value for testOnReturn property 754 */ 755 public synchronized void setTestOnReturn(final boolean testOnReturn) { 756 this.testOnReturn = testOnReturn; 757 if (connectionPool != null) { 758 connectionPool.setTestOnReturn(testOnReturn); 759 } 760 } 761 762 /** 763 * The number of milliseconds to sleep between runs of the idle object 764 * evictor thread. When non-positive, no idle object evictor thread will 765 * be run. 766 */ 767 private long timeBetweenEvictionRunsMillis = 768 BaseObjectPoolConfig.DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS; 769 770 /** 771 * Returns the value of the {@link #timeBetweenEvictionRunsMillis} 772 * property. 773 * 774 * @return the time (in milliseconds) between evictor runs 775 * @see #timeBetweenEvictionRunsMillis 776 */ 777 @Override 778 public synchronized long getTimeBetweenEvictionRunsMillis() { 779 return this.timeBetweenEvictionRunsMillis; 780 } 781 782 /** 783 * Sets the {@link #timeBetweenEvictionRunsMillis} property. 784 * 785 * @param timeBetweenEvictionRunsMillis the new time between evictor runs 786 * @see #timeBetweenEvictionRunsMillis 787 */ 788 public synchronized void setTimeBetweenEvictionRunsMillis(final long timeBetweenEvictionRunsMillis) { 789 this.timeBetweenEvictionRunsMillis = timeBetweenEvictionRunsMillis; 790 if (connectionPool != null) { 791 connectionPool.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis); 792 } 793 } 794 795 /** 796 * The number of objects to examine during each run of the idle object 797 * evictor thread (if any). 798 */ 799 private int numTestsPerEvictionRun = 800 BaseObjectPoolConfig.DEFAULT_NUM_TESTS_PER_EVICTION_RUN; 801 802 /** 803 * Returns the value of the {@link #numTestsPerEvictionRun} property. 804 * 805 * @return the number of objects to examine during idle object evictor 806 * runs 807 * @see #numTestsPerEvictionRun 808 */ 809 @Override 810 public synchronized int getNumTestsPerEvictionRun() { 811 return this.numTestsPerEvictionRun; 812 } 813 814 /** 815 * Sets the value of the {@link #numTestsPerEvictionRun} property. 816 * 817 * @param numTestsPerEvictionRun the new {@link #numTestsPerEvictionRun} 818 * value 819 * @see #numTestsPerEvictionRun 820 */ 821 public synchronized void setNumTestsPerEvictionRun(final int numTestsPerEvictionRun) { 822 this.numTestsPerEvictionRun = numTestsPerEvictionRun; 823 if (connectionPool != null) { 824 connectionPool.setNumTestsPerEvictionRun(numTestsPerEvictionRun); 825 } 826 } 827 828 /** 829 * The minimum amount of time an object may sit idle in the pool before it 830 * is eligible for eviction by the idle object evictor (if any). 831 */ 832 private long minEvictableIdleTimeMillis = 833 BaseObjectPoolConfig.DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS; 834 835 /** 836 * Returns the {@link #minEvictableIdleTimeMillis} property. 837 * 838 * @return the value of the {@link #minEvictableIdleTimeMillis} property 839 * @see #minEvictableIdleTimeMillis 840 */ 841 @Override 842 public synchronized long getMinEvictableIdleTimeMillis() { 843 return this.minEvictableIdleTimeMillis; 844 } 845 846 /** 847 * Sets the {@link #minEvictableIdleTimeMillis} property. 848 * 849 * @param minEvictableIdleTimeMillis the minimum amount of time an object 850 * may sit idle in the pool 851 * @see #minEvictableIdleTimeMillis 852 */ 853 public synchronized void setMinEvictableIdleTimeMillis(final long minEvictableIdleTimeMillis) { 854 this.minEvictableIdleTimeMillis = minEvictableIdleTimeMillis; 855 if (connectionPool != null) { 856 connectionPool.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis); 857 } 858 } 859 860 /** 861 * The minimum amount of time a connection may sit idle in the pool before 862 * it is eligible for eviction by the idle object evictor, with the extra 863 * condition that at least "minIdle" connections remain in the pool. 864 * Note that {@code minEvictableIdleTimeMillis} takes precedence over this 865 * parameter. See {@link #getSoftMinEvictableIdleTimeMillis()}. 866 */ 867 private long softMinEvictableIdleTimeMillis = 868 BaseObjectPoolConfig.DEFAULT_SOFT_MIN_EVICTABLE_IDLE_TIME_MILLIS; 869 870 /** 871 * Sets the minimum amount of time a connection may sit idle in the pool 872 * before it is eligible for eviction by the idle object evictor, with the 873 * extra condition that at least "minIdle" connections remain in the pool. 874 * 875 * @param softMinEvictableIdleTimeMillis minimum amount of time a 876 * connection may sit idle in the pool before it is eligible for eviction, 877 * assuming there are minIdle idle connections in the pool. 878 * @see #getSoftMinEvictableIdleTimeMillis 879 */ 880 public synchronized void setSoftMinEvictableIdleTimeMillis(final long softMinEvictableIdleTimeMillis) { 881 this.softMinEvictableIdleTimeMillis = softMinEvictableIdleTimeMillis; 882 if (connectionPool != null) { 883 connectionPool.setSoftMinEvictableIdleTimeMillis(softMinEvictableIdleTimeMillis); 884 } 885 } 886 887 /** 888 * <p>Returns the minimum amount of time a connection may sit idle in the 889 * pool before it is eligible for eviction by the idle object evictor, with 890 * the extra condition that at least "minIdle" connections remain in the 891 * pool.</p> 892 * 893 * <p>When {@link #getMinEvictableIdleTimeMillis() minEvictableIdleTimeMillis} 894 * is set to a positive value, minEvictableIdleTimeMillis is examined 895 * first by the idle connection evictor - i.e. when idle connections are 896 * visited by the evictor, idle time is first compared against 897 * {@code minEvictableIdleTimeMillis} (without considering the number of idle 898 * connections in the pool) and then against 899 * {@code softMinEvictableIdleTimeMillis}, including the {@code minIdle}, 900 * constraint.</p> 901 * 902 * @return minimum amount of time a connection may sit idle in the pool before 903 * it is eligible for eviction, assuming there are minIdle idle connections 904 * in the pool 905 */ 906 @Override 907 public synchronized long getSoftMinEvictableIdleTimeMillis() { 908 return softMinEvictableIdleTimeMillis; 909 } 910 911 private String evictionPolicyClassName = 912 BaseObjectPoolConfig.DEFAULT_EVICTION_POLICY_CLASS_NAME; 913 914 /** 915 * Gets the EvictionPolicy implementation in use with this connection pool. 916 */ 917 public synchronized String getEvictionPolicyClassName() { 918 return evictionPolicyClassName; 919 } 920 921 /** 922 * Sets the EvictionPolicy implementation to use with this connection pool. 923 * 924 * @param evictionPolicyClassName The fully qualified class name of the 925 * EvictionPolicy implementation 926 */ 927 public synchronized void setEvictionPolicyClassName( 928 final String evictionPolicyClassName) { 929 if (connectionPool != null) { 930 connectionPool.setEvictionPolicyClassName(evictionPolicyClassName); 931 } 932 this.evictionPolicyClassName = evictionPolicyClassName; 933 } 934 935 /** 936 * The indication of whether objects will be validated by the idle object 937 * evictor (if any). If an object fails to validate, it will be dropped 938 * from the pool. 939 */ 940 private boolean testWhileIdle = false; 941 942 /** 943 * Returns the value of the {@link #testWhileIdle} property. 944 * 945 * @return true if objects examined by the idle object evictor are 946 * validated 947 * @see #testWhileIdle 948 */ 949 @Override 950 public synchronized boolean getTestWhileIdle() { 951 return this.testWhileIdle; 952 } 953 954 /** 955 * Sets the <code>testWhileIdle</code> property. This property determines 956 * whether or not the idle object evictor will validate connections. 957 * 958 * @param testWhileIdle new value for testWhileIdle property 959 */ 960 public synchronized void setTestWhileIdle(final boolean testWhileIdle) { 961 this.testWhileIdle = testWhileIdle; 962 if (connectionPool != null) { 963 connectionPool.setTestWhileIdle(testWhileIdle); 964 } 965 } 966 967 /** 968 * [Read Only] The current number of active connections that have been 969 * allocated from this data source. 970 * 971 * @return the current number of active connections 972 */ 973 @Override 974 public int getNumActive() { 975 // Copy reference to avoid NPE if close happens after null check 976 final GenericObjectPool<PoolableConnection> pool = connectionPool; 977 if (pool != null) { 978 return pool.getNumActive(); 979 } 980 return 0; 981 } 982 983 984 /** 985 * [Read Only] The current number of idle connections that are waiting 986 * to be allocated from this data source. 987 * 988 * @return the current number of idle connections 989 */ 990 @Override 991 public int getNumIdle() { 992 // Copy reference to avoid NPE if close happens after null check 993 final GenericObjectPool<PoolableConnection> pool = connectionPool; 994 if (pool != null) { 995 return pool.getNumIdle(); 996 } 997 return 0; 998 } 999 1000 /** 1001 * The connection password to be passed to our JDBC driver to establish 1002 * a connection. 1003 */ 1004 private volatile String password; 1005 1006 /** 1007 * Returns the password passed to the JDBC driver to establish connections. 1008 * 1009 * @return the connection password 1010 */ 1011 @Override 1012 public String getPassword() { 1013 return this.password; 1014 } 1015 1016 /** 1017 * <p>Sets the {@link #password}.</p> 1018 * <p> 1019 * Note: this method currently has no effect once the pool has been 1020 * initialized. The pool is initialized the first time one of the 1021 * following methods is invoked: <code>getConnection, setLogwriter, 1022 * setLoginTimeout, getLoginTimeout, getLogWriter.</code></p> 1023 * 1024 * @param password new value for the password 1025 */ 1026 public void setPassword(final String password) { 1027 this.password = password; 1028 } 1029 1030 /** 1031 * The connection URL to be passed to our JDBC driver to establish 1032 * a connection. 1033 */ 1034 private String url; 1035 1036 /** 1037 * Returns the JDBC connection {@link #url} property. 1038 * 1039 * @return the {@link #url} passed to the JDBC driver to establish 1040 * connections 1041 */ 1042 @Override 1043 public synchronized String getUrl() { 1044 return this.url; 1045 } 1046 1047 /** 1048 * <p>Sets the {@link #url}.</p> 1049 * <p> 1050 * Note: this method currently has no effect once the pool has been 1051 * initialized. The pool is initialized the first time one of the 1052 * following methods is invoked: <code>getConnection, setLogwriter, 1053 * setLoginTimeout, getLoginTimeout, getLogWriter.</code></p> 1054 * 1055 * @param url the new value for the JDBC connection url 1056 */ 1057 public synchronized void setUrl(final String url) { 1058 this.url = url; 1059 } 1060 1061 /** 1062 * The connection username to be passed to our JDBC driver to 1063 * establish a connection. 1064 */ 1065 private String username; 1066 1067 /** 1068 * Returns the JDBC connection {@link #username} property. 1069 * 1070 * @return the {@link #username} passed to the JDBC driver to establish 1071 * connections 1072 */ 1073 @Override 1074 public String getUsername() { 1075 return this.username; 1076 } 1077 1078 /** 1079 * <p>Sets the {@link #username}.</p> 1080 * <p> 1081 * Note: this method currently has no effect once the pool has been 1082 * initialized. The pool is initialized the first time one of the 1083 * following methods is invoked: <code>getConnection, setLogwriter, 1084 * setLoginTimeout, getLoginTimeout, getLogWriter.</code></p> 1085 * 1086 * @param username the new value for the JDBC connection username 1087 */ 1088 public void setUsername(final String username) { 1089 this.username = username; 1090 } 1091 1092 /** 1093 * The SQL query that will be used to validate connections from this pool 1094 * before returning them to the caller. If specified, this query 1095 * <strong>MUST</strong> be an SQL SELECT statement that returns at least 1096 * one row. If not specified, {@link Connection#isValid(int)} will be used 1097 * to validate connections. 1098 */ 1099 private volatile String validationQuery; 1100 1101 /** 1102 * Returns the validation query used to validate connections before 1103 * returning them. 1104 * 1105 * @return the SQL validation query 1106 * @see #validationQuery 1107 */ 1108 @Override 1109 public String getValidationQuery() { 1110 return this.validationQuery; 1111 } 1112 1113 /** 1114 * <p>Sets the {@link #validationQuery}.</p> 1115 * <p> 1116 * Note: this method currently has no effect once the pool has been 1117 * initialized. The pool is initialized the first time one of the 1118 * following methods is invoked: <code>getConnection, setLogwriter, 1119 * setLoginTimeout, getLoginTimeout, getLogWriter.</code></p> 1120 * 1121 * @param validationQuery the new value for the validation query 1122 */ 1123 public void setValidationQuery(final String validationQuery) { 1124 if (validationQuery != null && validationQuery.trim().length() > 0) { 1125 this.validationQuery = validationQuery; 1126 } else { 1127 this.validationQuery = null; 1128 } 1129 } 1130 1131 /** 1132 * Timeout in seconds before connection validation queries fail. 1133 */ 1134 private volatile int validationQueryTimeout = -1; 1135 1136 /** 1137 * Returns the validation query timeout. 1138 * 1139 * @return the timeout in seconds before connection validation queries fail. 1140 */ 1141 @Override 1142 public int getValidationQueryTimeout() { 1143 return validationQueryTimeout; 1144 } 1145 1146 /** 1147 * Sets the validation query timeout, the amount of time, in seconds, that 1148 * connection validation will wait for a response from the database when 1149 * executing a validation query. Use a value less than or equal to 0 for 1150 * no timeout. 1151 * <p> 1152 * Note: this method currently has no effect once the pool has been 1153 * initialized. The pool is initialized the first time one of the 1154 * following methods is invoked: <code>getConnection, setLogwriter, 1155 * setLoginTimeout, getLoginTimeout, getLogWriter.</code></p> 1156 * 1157 * @param timeout new validation query timeout value in seconds 1158 */ 1159 public void setValidationQueryTimeout(final int timeout) { 1160 this.validationQueryTimeout = timeout; 1161 } 1162 1163 /** 1164 * These SQL statements run once after a Connection is created. 1165 * <p> 1166 * This property can be used for example to run ALTER SESSION SET 1167 * NLS_SORT=XCYECH in an Oracle Database only once after connection 1168 * creation. 1169 * </p> 1170 */ 1171 private volatile List<String> connectionInitSqls; 1172 1173 /** 1174 * Returns the list of SQL statements executed when a physical connection 1175 * is first created. Returns an empty list if there are no initialization 1176 * statements configured. 1177 * 1178 * @return initialization SQL statements 1179 */ 1180 public List<String> getConnectionInitSqls() { 1181 final List<String> result = connectionInitSqls; 1182 if (result == null) { 1183 return Collections.emptyList(); 1184 } 1185 return result; 1186 } 1187 1188 /** 1189 * Provides the same data as {@link #getConnectionInitSqls()} but in an 1190 * array so it is accessible via JMX. 1191 */ 1192 @Override 1193 public String[] getConnectionInitSqlsAsArray() { 1194 final Collection<String> result = getConnectionInitSqls(); 1195 return result.toArray(new String[result.size()]); 1196 } 1197 1198 /** 1199 * Sets the list of SQL statements to be executed when a physical 1200 * connection is first created. 1201 * <p> 1202 * Note: this method currently has no effect once the pool has been 1203 * initialized. The pool is initialized the first time one of the 1204 * following methods is invoked: <code>getConnection, setLogwriter, 1205 * setLoginTimeout, getLoginTimeout, getLogWriter.</code></p> 1206 * 1207 * @param connectionInitSqls Collection of SQL statements to execute 1208 * on connection creation 1209 */ 1210 public void setConnectionInitSqls(final Collection<String> connectionInitSqls) { 1211 if (connectionInitSqls != null && connectionInitSqls.size() > 0) { 1212 ArrayList<String> newVal = null; 1213 for (final String s : connectionInitSqls) { 1214 if (s != null && s.trim().length() > 0) { 1215 if (newVal == null) { 1216 newVal = new ArrayList<>(); 1217 } 1218 newVal.add(s); 1219 } 1220 } 1221 this.connectionInitSqls = newVal; 1222 } else { 1223 this.connectionInitSqls = null; 1224 } 1225 } 1226 1227 1228 /** 1229 * Controls access to the underlying connection. 1230 */ 1231 private boolean accessToUnderlyingConnectionAllowed = false; 1232 1233 /** 1234 * Returns the value of the accessToUnderlyingConnectionAllowed property. 1235 * 1236 * @return true if access to the underlying connection is allowed, false 1237 * otherwise. 1238 */ 1239 @Override 1240 public synchronized boolean isAccessToUnderlyingConnectionAllowed() { 1241 return this.accessToUnderlyingConnectionAllowed; 1242 } 1243 1244 /** 1245 * <p>Sets the value of the accessToUnderlyingConnectionAllowed property. 1246 * It controls if the PoolGuard allows access to the underlying connection. 1247 * (Default: false)</p> 1248 * <p> 1249 * Note: this method currently has no effect once the pool has been 1250 * initialized. The pool is initialized the first time one of the 1251 * following methods is invoked: <code>getConnection, setLogwriter, 1252 * setLoginTimeout, getLoginTimeout, getLogWriter.</code></p> 1253 * 1254 * @param allow Access to the underlying connection is granted when true. 1255 */ 1256 public synchronized void setAccessToUnderlyingConnectionAllowed(final boolean allow) { 1257 this.accessToUnderlyingConnectionAllowed = allow; 1258 } 1259 1260 1261 private long maxConnLifetimeMillis = -1; 1262 1263 /** 1264 * Returns the maximum permitted lifetime of a connection in milliseconds. A 1265 * value of zero or less indicates an infinite lifetime. 1266 */ 1267 @Override 1268 public long getMaxConnLifetimeMillis() { 1269 return maxConnLifetimeMillis; 1270 } 1271 1272 private boolean logExpiredConnections = true; 1273 1274 /** 1275 * When {@link #getMaxConnLifetimeMillis()} is set to limit connection lifetime, 1276 * this property determines whether or not log messages are generated when the 1277 * pool closes connections due to maximum lifetime exceeded. 1278 * 1279 * @since 2.1 1280 */ 1281 @Override 1282 public boolean getLogExpiredConnections() { 1283 return logExpiredConnections; 1284 } 1285 1286 /** 1287 * <p>Sets the maximum permitted lifetime of a connection in 1288 * milliseconds. A value of zero or less indicates an infinite lifetime.</p> 1289 * <p> 1290 * Note: this method currently has no effect once the pool has been 1291 * initialized. The pool is initialized the first time one of the 1292 * following methods is invoked: <code>getConnection, setLogwriter, 1293 * setLoginTimeout, getLoginTimeout, getLogWriter.</code></p> 1294 */ 1295 public void setMaxConnLifetimeMillis(final long maxConnLifetimeMillis) { 1296 this.maxConnLifetimeMillis = maxConnLifetimeMillis; 1297 } 1298 1299 /** 1300 * When {@link #getMaxConnLifetimeMillis()} is set to limit connection lifetime, 1301 * this property determines whether or not log messages are generated when the 1302 * pool closes connections due to maximum lifetime exceeded. Set this property 1303 * to false to suppress log messages when connections expire. 1304 */ 1305 public void setLogExpiredConnections(final boolean logExpiredConnections) { 1306 this.logExpiredConnections = logExpiredConnections; 1307 } 1308 1309 private String jmxName; 1310 1311 /** 1312 * Returns the JMX name that has been requested for this DataSource. If the 1313 * requested name is not valid, an alternative may be chosen. 1314 */ 1315 public String getJmxName() { 1316 return jmxName; 1317 } 1318 1319 /** 1320 * Sets the JMX name that has been requested for this DataSource. If the 1321 * requested name is not valid, an alternative may be chosen. This 1322 * DataSource will attempt to register itself using this name. If another 1323 * component registers this DataSource with JMX and this name is valid this 1324 * name will be used in preference to any specified by the other component. 1325 */ 1326 public void setJmxName(final String jmxName) { 1327 this.jmxName = jmxName; 1328 } 1329 1330 1331 private boolean enableAutoCommitOnReturn = true; 1332 1333 /** 1334 * Returns the value of the flag that controls whether or not connections 1335 * being returned to the pool will be checked and configured with 1336 * {@link Connection#setAutoCommit(boolean) Connection.setAutoCommit(true)} 1337 * if the auto commit setting is {@code false} when the connection 1338 * is returned. It is <code>true</code> by default. 1339 */ 1340 public boolean getEnableAutoCommitOnReturn() { 1341 return enableAutoCommitOnReturn; 1342 } 1343 1344 /** 1345 * Sets the value of the flag that controls whether or not connections 1346 * being returned to the pool will be checked and configured with 1347 * {@link Connection#setAutoCommit(boolean) Connection.setAutoCommit(true)} 1348 * if the auto commit setting is {@code false} when the connection 1349 * is returned. It is <code>true</code> by default. 1350 */ 1351 public void setEnableAutoCommitOnReturn(final boolean enableAutoCommitOnReturn) { 1352 this.enableAutoCommitOnReturn = enableAutoCommitOnReturn; 1353 } 1354 1355 private boolean rollbackOnReturn = true; 1356 1357 /** 1358 * Gets the current value of the flag that controls if a connection will be 1359 * rolled back when it is returned to the pool if auto commit is not enabled 1360 * and the connection is not read only. 1361 */ 1362 public boolean getRollbackOnReturn() { 1363 return rollbackOnReturn; 1364 } 1365 1366 /** 1367 * Sets the flag that controls if a connection will be rolled back when it 1368 * is returned to the pool if auto commit is not enabled and the connection 1369 * is not read only. 1370 */ 1371 public void setRollbackOnReturn(final boolean rollbackOnReturn) { 1372 this.rollbackOnReturn = rollbackOnReturn; 1373 } 1374 1375 private volatile Set<String> disconnectionSqlCodes; 1376 1377 /** 1378 * Returns the set of SQL_STATE codes considered to signal fatal conditions. 1379 * @return fatal disconnection state codes 1380 * @see #setDisconnectionSqlCodes(Collection) 1381 * @since 2.1 1382 */ 1383 public Set<String> getDisconnectionSqlCodes() { 1384 final Set<String> result = disconnectionSqlCodes; 1385 if (result == null) { 1386 return Collections.emptySet(); 1387 } 1388 return result; 1389 } 1390 1391 /** 1392 * Provides the same data as {@link #getDisconnectionSqlCodes} but in an 1393 * array so it is accessible via JMX. 1394 * @since 2.1 1395 */ 1396 @Override 1397 public String[] getDisconnectionSqlCodesAsArray() { 1398 final Collection<String> result = getDisconnectionSqlCodes(); 1399 return result.toArray(new String[result.size()]); 1400 } 1401 1402 /** 1403 * Sets the SQL_STATE codes considered to signal fatal conditions. 1404 * <p> 1405 * Overrides the defaults in {@link Utils#DISCONNECTION_SQL_CODES} 1406 * (plus anything starting with {@link Utils#DISCONNECTION_SQL_CODE_PREFIX}). 1407 * If this property is non-null and {@link #getFastFailValidation()} is 1408 * {@code true}, whenever connections created by this datasource generate exceptions 1409 * with SQL_STATE codes in this list, they will be marked as "fatally disconnected" 1410 * and subsequent validations will fail fast (no attempt at isValid or validation 1411 * query).</p> 1412 * <p> 1413 * If {@link #getFastFailValidation()} is {@code false} setting this property has no 1414 * effect.</p> 1415 * <p> 1416 * Note: this method currently has no effect once the pool has been 1417 * initialized. The pool is initialized the first time one of the 1418 * following methods is invoked: {@code getConnection, setLogwriter, 1419 * setLoginTimeout, getLoginTimeout, getLogWriter}.</p> 1420 * 1421 * @param disconnectionSqlCodes SQL_STATE codes considered to signal fatal conditions 1422 * @since 2.1 1423 */ 1424 public void setDisconnectionSqlCodes(final Collection<String> disconnectionSqlCodes) { 1425 if (disconnectionSqlCodes != null && disconnectionSqlCodes.size() > 0) { 1426 HashSet<String> newVal = null; 1427 for (final String s : disconnectionSqlCodes) { 1428 if (s != null && s.trim().length() > 0) { 1429 if (newVal == null) { 1430 newVal = new HashSet<>(); 1431 } 1432 newVal.add(s); 1433 } 1434 } 1435 this.disconnectionSqlCodes = newVal; 1436 } else { 1437 this.disconnectionSqlCodes = null; 1438 } 1439 } 1440 1441 private boolean fastFailValidation; 1442 1443 /** 1444 * True means that validation will fail immediately for connections that 1445 * have previously thrown SQLExceptions with SQL_STATE indicating fatal 1446 * disconnection errors. 1447 * 1448 * @return true if connections created by this datasource will fast fail validation. 1449 * @see #setDisconnectionSqlCodes(Collection) 1450 * @since 2.1 1451 */ 1452 @Override 1453 public boolean getFastFailValidation() { 1454 return fastFailValidation; 1455 } 1456 1457 /** 1458 * @see #getFastFailValidation() 1459 * @param fastFailValidation true means connections created by this factory will 1460 * fast fail validation 1461 * @since 2.1 1462 */ 1463 public void setFastFailValidation(final boolean fastFailValidation) { 1464 this.fastFailValidation = fastFailValidation; 1465 } 1466 1467 // ----------------------------------------------------- Instance Variables 1468 1469 /** 1470 * The object pool that internally manages our connections. 1471 */ 1472 private volatile GenericObjectPool<PoolableConnection> connectionPool; 1473 1474 protected GenericObjectPool<PoolableConnection> getConnectionPool() { 1475 return connectionPool; 1476 } 1477 1478 /** 1479 * The connection properties that will be sent to our JDBC driver when 1480 * establishing new connections. <strong>NOTE</strong> - The "user" and 1481 * "password" properties will be passed explicitly, so they do not need 1482 * to be included here. 1483 */ 1484 private Properties connectionProperties = new Properties(); 1485 1486 // For unit testing 1487 Properties getConnectionProperties() { 1488 return connectionProperties; 1489 } 1490 1491 /** 1492 * The data source we will use to manage connections. This object should 1493 * be acquired <strong>ONLY</strong> by calls to the 1494 * <code>createDataSource()</code> method. 1495 */ 1496 private volatile DataSource dataSource; 1497 1498 /** 1499 * The PrintWriter to which log messages should be directed. 1500 */ 1501 private volatile PrintWriter logWriter = new PrintWriter(new OutputStreamWriter( 1502 System.out, StandardCharsets.UTF_8)); 1503 1504 1505 // ----------------------------------------------------- DataSource Methods 1506 1507 1508 /** 1509 * Create (if necessary) and return a connection to the database. 1510 * 1511 * @throws SQLException if a database access error occurs 1512 * @return a database connection 1513 */ 1514 @Override 1515 public Connection getConnection() throws SQLException { 1516 if (Utils.IS_SECURITY_ENABLED) { 1517 final PrivilegedExceptionAction<Connection> action = new PaGetConnection(); 1518 try { 1519 return AccessController.doPrivileged(action); 1520 } catch (final PrivilegedActionException e) { 1521 final Throwable cause = e.getCause(); 1522 if (cause instanceof SQLException) { 1523 throw (SQLException) cause; 1524 } 1525 throw new SQLException(e); 1526 } 1527 } 1528 return createDataSource().getConnection(); 1529 } 1530 1531 1532 /** 1533 * <strong>BasicDataSource does NOT support this method. </strong> 1534 * 1535 * @param user Database user on whose behalf the Connection 1536 * is being made 1537 * @param pass The database user's password 1538 * 1539 * @throws UnsupportedOperationException 1540 * @throws SQLException if a database access error occurs 1541 * @return nothing - always throws UnsupportedOperationException 1542 */ 1543 @Override 1544 public Connection getConnection(final String user, final String pass) throws SQLException { 1545 // This method isn't supported by the PoolingDataSource returned by 1546 // the createDataSource 1547 throw new UnsupportedOperationException("Not supported by BasicDataSource"); 1548 } 1549 1550 1551 /** 1552 * <strong>BasicDataSource does NOT support this method. </strong> 1553 * 1554 * <p>Returns the login timeout (in seconds) for connecting to the database. 1555 * </p> 1556 * <p>Calls {@link #createDataSource()}, so has the side effect 1557 * of initializing the connection pool.</p> 1558 * 1559 * @throws SQLException if a database access error occurs 1560 * @throws UnsupportedOperationException If the DataSource implementation 1561 * does not support the login timeout feature. 1562 * @return login timeout in seconds 1563 */ 1564 @Override 1565 public int getLoginTimeout() throws SQLException { 1566 // This method isn't supported by the PoolingDataSource returned by 1567 // the createDataSource 1568 throw new UnsupportedOperationException("Not supported by BasicDataSource"); 1569 } 1570 1571 1572 /** 1573 * <p>Returns the log writer being used by this data source.</p> 1574 * <p> 1575 * Calls {@link #createDataSource()}, so has the side effect 1576 * of initializing the connection pool.</p> 1577 * 1578 * @throws SQLException if a database access error occurs 1579 * @return log writer in use 1580 */ 1581 @Override 1582 public PrintWriter getLogWriter() throws SQLException { 1583 return createDataSource().getLogWriter(); 1584 } 1585 1586 1587 /** 1588 * <strong>BasicDataSource does NOT support this method. </strong> 1589 * 1590 * <p>Set the login timeout (in seconds) for connecting to the 1591 * database.</p> 1592 * <p> 1593 * Calls {@link #createDataSource()}, so has the side effect 1594 * of initializing the connection pool.</p> 1595 * 1596 * @param loginTimeout The new login timeout, or zero for no timeout 1597 * @throws UnsupportedOperationException If the DataSource implementation 1598 * does not support the login timeout feature. 1599 * @throws SQLException if a database access error occurs 1600 */ 1601 @Override 1602 public void setLoginTimeout(final int loginTimeout) throws SQLException { 1603 // This method isn't supported by the PoolingDataSource returned by 1604 // the createDataSource 1605 throw new UnsupportedOperationException("Not supported by BasicDataSource"); 1606 } 1607 1608 1609 /** 1610 * <p>Sets the log writer being used by this data source.</p> 1611 * <p> 1612 * Calls {@link #createDataSource()}, so has the side effect 1613 * of initializing the connection pool.</p> 1614 * 1615 * @param logWriter The new log writer 1616 * @throws SQLException if a database access error occurs 1617 */ 1618 @Override 1619 public void setLogWriter(final PrintWriter logWriter) throws SQLException { 1620 createDataSource().setLogWriter(logWriter); 1621 this.logWriter = logWriter; 1622 } 1623 1624 private AbandonedConfig abandonedConfig; 1625 1626 /** 1627 * <p>Flag to remove abandoned connections if they exceed the 1628 * removeAbandonedTimeout when borrowObject is invoked.</p> 1629 * 1630 * <p>The default value is false.</p> 1631 * 1632 * <p>If set to true a connection is considered abandoned and eligible 1633 * for removal if it has not been used for more than 1634 * {@link #getRemoveAbandonedTimeout() removeAbandonedTimeout} seconds.</p> 1635 * 1636 * <p>Abandoned connections are identified and removed when 1637 * {@link #getConnection()} is invoked and all of the following conditions hold: 1638 * </p> 1639 * <ul><li>{@link #getRemoveAbandonedOnBorrow()} </li> 1640 * <li>{@link #getNumActive()} > {@link #getMaxTotal()} - 3 </li> 1641 * <li>{@link #getNumIdle()} < 2 </li></ul> 1642 * 1643 * @see #getRemoveAbandonedTimeout() 1644 */ 1645 @Override 1646 public boolean getRemoveAbandonedOnBorrow() { 1647 if (abandonedConfig != null) { 1648 return abandonedConfig.getRemoveAbandonedOnBorrow(); 1649 } 1650 return false; 1651 } 1652 1653 /** 1654 * @param removeAbandonedOnMaintenance true means abandoned connections may 1655 * be removed on pool maintenance. 1656 * @see #getRemoveAbandonedOnMaintenance() 1657 */ 1658 public void setRemoveAbandonedOnMaintenance( 1659 final boolean removeAbandonedOnMaintenance) { 1660 if (abandonedConfig == null) { 1661 abandonedConfig = new AbandonedConfig(); 1662 } 1663 abandonedConfig.setRemoveAbandonedOnMaintenance( 1664 removeAbandonedOnMaintenance); 1665 final GenericObjectPool<?> gop = this.connectionPool; 1666 if (gop != null) { 1667 gop.setAbandonedConfig(abandonedConfig); 1668 } 1669 } 1670 1671 /** 1672 * <p>Flag to remove abandoned connections if they exceed the 1673 * removeAbandonedTimeout during pool maintenance.</p> 1674 * 1675 * <p>The default value is false.</p> 1676 * 1677 * <p>If set to true a connection is considered abandoned and eligible 1678 * for removal if it has not been used for more than 1679 * {@link #getRemoveAbandonedTimeout() removeAbandonedTimeout} seconds.</p> 1680 * 1681 * @see #getRemoveAbandonedTimeout() 1682 */ 1683 @Override 1684 public boolean getRemoveAbandonedOnMaintenance() { 1685 if (abandonedConfig != null) { 1686 return abandonedConfig.getRemoveAbandonedOnMaintenance(); 1687 } 1688 return false; 1689 } 1690 1691 /** 1692 * @param removeAbandonedOnBorrow true means abandoned connections may be 1693 * removed when connections are borrowed from the pool. 1694 * @see #getRemoveAbandonedOnBorrow() 1695 */ 1696 public void setRemoveAbandonedOnBorrow(final boolean removeAbandonedOnBorrow) { 1697 if (abandonedConfig == null) { 1698 abandonedConfig = new AbandonedConfig(); 1699 } 1700 abandonedConfig.setRemoveAbandonedOnBorrow(removeAbandonedOnBorrow); 1701 final GenericObjectPool<?> gop = this.connectionPool; 1702 if (gop != null) { 1703 gop.setAbandonedConfig(abandonedConfig); 1704 } 1705 } 1706 1707 /** 1708 * <p>Timeout in seconds before an abandoned connection can be removed.</p> 1709 * 1710 * <p>Creating a Statement, PreparedStatement or CallableStatement or using 1711 * one of these to execute a query (using one of the execute methods) 1712 * resets the lastUsed property of the parent connection.</p> 1713 * 1714 * <p>Abandoned connection cleanup happens when:</p> 1715 * <ul> 1716 * <li>{@link #getRemoveAbandonedOnBorrow()} or 1717 * {@link #getRemoveAbandonedOnMaintenance()} = true</li> 1718 * <li>{@link #getNumIdle() numIdle} < 2</li> 1719 * <li>{@link #getNumActive() numActive} > {@link #getMaxTotal() maxTotal} - 3</li> 1720 * </ul> 1721 * 1722 * <p>The default value is 300 seconds.</p> 1723 */ 1724 @Override 1725 public int getRemoveAbandonedTimeout() { 1726 if (abandonedConfig != null) { 1727 return abandonedConfig.getRemoveAbandonedTimeout(); 1728 } 1729 return 300; 1730 } 1731 1732 /** 1733 * <p>Sets the timeout in seconds before an abandoned connection can be 1734 * removed.</p> 1735 * 1736 * <p>Setting this property has no effect if 1737 * {@link #getRemoveAbandonedOnBorrow()} and 1738 * {@link #getRemoveAbandonedOnMaintenance()} are false.</p> 1739 * 1740 * @param removeAbandonedTimeout new abandoned timeout in seconds 1741 * @see #getRemoveAbandonedTimeout() 1742 * @see #getRemoveAbandonedOnBorrow() 1743 * @see #getRemoveAbandonedOnMaintenance() 1744 */ 1745 public void setRemoveAbandonedTimeout(final int removeAbandonedTimeout) { 1746 if (abandonedConfig == null) { 1747 abandonedConfig = new AbandonedConfig(); 1748 } 1749 abandonedConfig.setRemoveAbandonedTimeout(removeAbandonedTimeout); 1750 final GenericObjectPool<?> gop = this.connectionPool; 1751 if (gop != null) { 1752 gop.setAbandonedConfig(abandonedConfig); 1753 } 1754 } 1755 1756 /** 1757 * <p>Flag to log stack traces for application code which abandoned 1758 * a Statement or Connection. 1759 * </p> 1760 * <p>Defaults to false. 1761 * </p> 1762 * <p>Logging of abandoned Statements and Connections adds overhead 1763 * for every Connection open or new Statement because a stack 1764 * trace has to be generated. </p> 1765 */ 1766 @Override 1767 public boolean getLogAbandoned() { 1768 if (abandonedConfig != null) { 1769 return abandonedConfig.getLogAbandoned(); 1770 } 1771 return false; 1772 } 1773 1774 /** 1775 * @param logAbandoned new logAbandoned property value 1776 */ 1777 public void setLogAbandoned(final boolean logAbandoned) { 1778 if (abandonedConfig == null) { 1779 abandonedConfig = new AbandonedConfig(); 1780 } 1781 abandonedConfig.setLogAbandoned(logAbandoned); 1782 final GenericObjectPool<?> gop = this.connectionPool; 1783 if (gop != null) { 1784 gop.setAbandonedConfig(abandonedConfig); 1785 } 1786 } 1787 1788 /** 1789 * Gets the log writer to be used by this configuration to log 1790 * information on abandoned objects. 1791 */ 1792 public PrintWriter getAbandonedLogWriter() { 1793 if (abandonedConfig != null) { 1794 return abandonedConfig.getLogWriter(); 1795 } 1796 return null; 1797 } 1798 1799 /** 1800 * Sets the log writer to be used by this configuration to log 1801 * information on abandoned objects. 1802 * 1803 * @param logWriter The new log writer 1804 */ 1805 public void setAbandonedLogWriter(final PrintWriter logWriter) { 1806 if (abandonedConfig == null) { 1807 abandonedConfig = new AbandonedConfig(); 1808 } 1809 abandonedConfig.setLogWriter(logWriter); 1810 final GenericObjectPool<?> gop = this.connectionPool; 1811 if (gop != null) { 1812 gop.setAbandonedConfig(abandonedConfig); 1813 } 1814 } 1815 1816 /** 1817 * If the connection pool implements {@link org.apache.commons.pool2.UsageTracking UsageTracking}, should the 1818 * connection pool record a stack trace every time a method is called on a 1819 * pooled connection and retain the most recent stack trace to aid debugging 1820 * of abandoned connections? 1821 * 1822 * @return <code>true</code> if usage tracking is enabled 1823 */ 1824 @Override 1825 public boolean getAbandonedUsageTracking() { 1826 if (abandonedConfig != null) { 1827 return abandonedConfig.getUseUsageTracking(); 1828 } 1829 return false; 1830 } 1831 1832 /** 1833 * If the connection pool implements {@link org.apache.commons.pool2.UsageTracking UsageTracking}, configure 1834 * whether the connection pool should record a stack trace every time a 1835 * method is called on a pooled connection and retain the most recent stack 1836 * trace to aid debugging of abandoned connections. 1837 * 1838 * @param usageTracking A value of <code>true</code> will enable 1839 * the recording of a stack trace on every use 1840 * of a pooled connection 1841 */ 1842 public void setAbandonedUsageTracking(final boolean usageTracking) { 1843 if (abandonedConfig == null) { 1844 abandonedConfig = new AbandonedConfig(); 1845 } 1846 abandonedConfig.setUseUsageTracking(usageTracking); 1847 final GenericObjectPool<?> gop = this.connectionPool; 1848 if (gop != null) { 1849 gop.setAbandonedConfig(abandonedConfig); 1850 } 1851 } 1852 1853 // --------------------------------------------------------- Public Methods 1854 1855 /** 1856 * Add a custom connection property to the set that will be passed to our 1857 * JDBC driver. This <strong>MUST</strong> be called before the first 1858 * connection is retrieved (along with all the other configuration 1859 * property setters). Calls to this method after the connection pool 1860 * has been initialized have no effect. 1861 * 1862 * @param name Name of the custom connection property 1863 * @param value Value of the custom connection property 1864 */ 1865 public void addConnectionProperty(final String name, final String value) { 1866 connectionProperties.put(name, value); 1867 } 1868 1869 /** 1870 * Remove a custom connection property. 1871 * 1872 * @param name Name of the custom connection property to remove 1873 * @see #addConnectionProperty(String, String) 1874 */ 1875 public void removeConnectionProperty(final String name) { 1876 connectionProperties.remove(name); 1877 } 1878 1879 /** 1880 * Sets the connection properties passed to driver.connect(...). 1881 * 1882 * Format of the string must be [propertyName=property;]* 1883 * 1884 * NOTE - The "user" and "password" properties will be added 1885 * explicitly, so they do not need to be included here. 1886 * 1887 * @param connectionProperties the connection properties used to 1888 * create new connections 1889 */ 1890 public void setConnectionProperties(final String connectionProperties) { 1891 if (connectionProperties == null) { 1892 throw new NullPointerException("connectionProperties is null"); 1893 } 1894 1895 final String[] entries = connectionProperties.split(";"); 1896 final Properties properties = new Properties(); 1897 for (final String entry : entries) { 1898 if (entry.length() > 0) { 1899 final int index = entry.indexOf('='); 1900 if (index > 0) { 1901 final String name = entry.substring(0, index); 1902 final String value = entry.substring(index + 1); 1903 properties.setProperty(name, value); 1904 } else { 1905 // no value is empty string which is how java.util.Properties works 1906 properties.setProperty(entry, ""); 1907 } 1908 } 1909 } 1910 this.connectionProperties = properties; 1911 } 1912 1913 private boolean closed; 1914 1915 /** 1916 * <p>Closes and releases all idle connections that are currently stored in the connection pool 1917 * associated with this data source.</p> 1918 * 1919 * <p>Connections that are checked out to clients when this method is invoked are not affected. 1920 * When client applications subsequently invoke {@link Connection#close()} to return 1921 * these connections to the pool, the underlying JDBC connections are closed.</p> 1922 * 1923 * <p>Attempts to acquire connections using {@link #getConnection()} after this method has been 1924 * invoked result in SQLExceptions.</p> 1925 * 1926 * <p>This method is idempotent - i.e., closing an already closed BasicDataSource has no effect 1927 * and does not generate exceptions.</p> 1928 * 1929 * @throws SQLException if an error occurs closing idle connections 1930 */ 1931 @Override 1932 public synchronized void close() throws SQLException { 1933 if (registeredJmxObjectName != null) { 1934 registeredJmxObjectName.unregisterMBean(); 1935 registeredJmxObjectName = null; 1936 } 1937 closed = true; 1938 final GenericObjectPool<?> oldpool = connectionPool; 1939 connectionPool = null; 1940 dataSource = null; 1941 try { 1942 if (oldpool != null) { 1943 oldpool.close(); 1944 } 1945 } catch(final RuntimeException e) { 1946 throw e; 1947 } catch(final Exception e) { 1948 throw new SQLException(Utils.getMessage("pool.close.fail"), e); 1949 } 1950 } 1951 1952 /** 1953 * If true, this data source is closed and no more connections can be retrieved from this datasource. 1954 * @return true, if the data source is closed; false otherwise 1955 */ 1956 @Override 1957 public synchronized boolean isClosed() { 1958 return closed; 1959 } 1960 1961 @Override 1962 public boolean isWrapperFor(final Class<?> iface) throws SQLException { 1963 return false; 1964 } 1965 1966 @Override 1967 public <T> T unwrap(final Class<T> iface) throws SQLException { 1968 throw new SQLException("BasicDataSource is not a wrapper."); 1969 } 1970 1971 @Override 1972 public Logger getParentLogger() throws SQLFeatureNotSupportedException { 1973 throw new SQLFeatureNotSupportedException(); 1974 } 1975 1976 /** 1977 * Manually invalidates a connection, effectively requesting the pool to try 1978 * to close it, remove it from the pool and reclaim pool capacity. 1979 * 1980 * @throws IllegalStateException 1981 * if invalidating the connection failed. 1982 * @since 2.1 1983 */ 1984 public void invalidateConnection(final Connection connection) throws IllegalStateException { 1985 if (connection == null) { 1986 return; 1987 } 1988 if (connectionPool == null) { 1989 throw new IllegalStateException("Cannot invalidate connection: ConnectionPool is null."); 1990 } 1991 1992 final PoolableConnection poolableConnection; 1993 try { 1994 poolableConnection = connection.unwrap(PoolableConnection.class); 1995 if (poolableConnection == null) { 1996 throw new IllegalStateException( 1997 "Cannot invalidate connection: Connection is not a poolable connection."); 1998 } 1999 } catch (final SQLException e) { 2000 throw new IllegalStateException("Cannot invalidate connection: Unwrapping poolable connection failed.", e); 2001 } 2002 2003 try { 2004 connectionPool.invalidateObject(poolableConnection); 2005 } catch (final Exception e) { 2006 throw new IllegalStateException("Invalidating connection threw unexpected exception", e); 2007 } 2008 } 2009 2010 // ------------------------------------------------------ Protected Methods 2011 2012 2013 /** 2014 * <p>Create (if necessary) and return the internal data source we are 2015 * using to manage our connections.</p> 2016 * 2017 * @throws SQLException if the object pool cannot be created. 2018 */ 2019 protected DataSource createDataSource() 2020 throws SQLException { 2021 if (closed) { 2022 throw new SQLException("Data source is closed"); 2023 } 2024 2025 // Return the pool if we have already created it 2026 // This is double-checked locking. This is safe since dataSource is 2027 // volatile and the code is targeted at Java 5 onwards. 2028 if (dataSource != null) { 2029 return dataSource; 2030 } 2031 synchronized (this) { 2032 if (dataSource != null) { 2033 return dataSource; 2034 } 2035 2036 jmxRegister(); 2037 2038 // create factory which returns raw physical connections 2039 final ConnectionFactory driverConnectionFactory = createConnectionFactory(); 2040 2041 // Set up the poolable connection factory 2042 boolean success = false; 2043 PoolableConnectionFactory poolableConnectionFactory; 2044 try { 2045 poolableConnectionFactory = createPoolableConnectionFactory( 2046 driverConnectionFactory); 2047 poolableConnectionFactory.setPoolStatements( 2048 poolPreparedStatements); 2049 poolableConnectionFactory.setMaxOpenPreparedStatements( 2050 maxOpenPreparedStatements); 2051 success = true; 2052 } catch (final SQLException se) { 2053 throw se; 2054 } catch (final RuntimeException rte) { 2055 throw rte; 2056 } catch (final Exception ex) { 2057 throw new SQLException("Error creating connection factory", ex); 2058 } 2059 2060 if (success) { 2061 // create a pool for our connections 2062 createConnectionPool(poolableConnectionFactory); 2063 } 2064 2065 // Create the pooling data source to manage connections 2066 DataSource newDataSource; 2067 success = false; 2068 try { 2069 newDataSource = createDataSourceInstance(); 2070 newDataSource.setLogWriter(logWriter); 2071 success = true; 2072 } catch (final SQLException se) { 2073 throw se; 2074 } catch (final RuntimeException rte) { 2075 throw rte; 2076 } catch (final Exception ex) { 2077 throw new SQLException("Error creating datasource", ex); 2078 } finally { 2079 if (!success) { 2080 closeConnectionPool(); 2081 } 2082 } 2083 2084 // If initialSize > 0, preload the pool 2085 try { 2086 for (int i = 0 ; i < initialSize ; i++) { 2087 connectionPool.addObject(); 2088 } 2089 } catch (final Exception e) { 2090 closeConnectionPool(); 2091 throw new SQLException("Error preloading the connection pool", e); 2092 } 2093 2094 // If timeBetweenEvictionRunsMillis > 0, start the pool's evictor task 2095 startPoolMaintenance(); 2096 2097 dataSource = newDataSource; 2098 return dataSource; 2099 } 2100 } 2101 2102 /** 2103 * Creates a JDBC connection factory for this datasource. The JDBC driver 2104 * is loaded using the following algorithm: 2105 * <ol> 2106 * <li>If a Driver instance has been specified via 2107 * {@link #setDriver(Driver)} use it</li> 2108 * <li>If no Driver instance was specified and {@link #driverClassName} is 2109 * specified that class is loaded using the {@link ClassLoader} of this 2110 * class or, if {@link #driverClassLoader} is set, {@link #driverClassName} 2111 * is loaded with the specified {@link ClassLoader}.</li> 2112 * <li>If {@link #driverClassName} is specified and the previous attempt 2113 * fails, the class is loaded using the context class loader of the current 2114 * thread.</li> 2115 * <li>If a driver still isn't loaded one is loaded via the 2116 * {@link DriverManager} using the specified {@link #url}. 2117 * </ol> 2118 * This method exists so subclasses can replace the implementation class. 2119 */ 2120 protected ConnectionFactory createConnectionFactory() throws SQLException { 2121 // Load the JDBC driver class 2122 Driver driverToUse = this.driver; 2123 2124 if (driverToUse == null) { 2125 Class<?> driverFromCCL = null; 2126 if (driverClassName != null) { 2127 try { 2128 try { 2129 if (driverClassLoader == null) { 2130 driverFromCCL = Class.forName(driverClassName); 2131 } else { 2132 driverFromCCL = Class.forName( 2133 driverClassName, true, driverClassLoader); 2134 } 2135 } catch (final ClassNotFoundException cnfe) { 2136 driverFromCCL = Thread.currentThread( 2137 ).getContextClassLoader().loadClass( 2138 driverClassName); 2139 } 2140 } catch (final Exception t) { 2141 final String message = "Cannot load JDBC driver class '" + 2142 driverClassName + "'"; 2143 logWriter.println(message); 2144 t.printStackTrace(logWriter); 2145 throw new SQLException(message, t); 2146 } 2147 } 2148 2149 try { 2150 if (driverFromCCL == null) { 2151 driverToUse = DriverManager.getDriver(url); 2152 } else { 2153 // Usage of DriverManager is not possible, as it does not 2154 // respect the ContextClassLoader 2155 // N.B. This cast may cause ClassCastException which is handled below 2156 driverToUse = (Driver) driverFromCCL.getConstructor().newInstance(); 2157 if (!driverToUse.acceptsURL(url)) { 2158 throw new SQLException("No suitable driver", "08001"); 2159 } 2160 } 2161 } catch (final Exception t) { 2162 final String message = "Cannot create JDBC driver of class '" + 2163 (driverClassName != null ? driverClassName : "") + 2164 "' for connect URL '" + url + "'"; 2165 logWriter.println(message); 2166 t.printStackTrace(logWriter); 2167 throw new SQLException(message, t); 2168 } 2169 } 2170 2171 // Set up the driver connection factory we will use 2172 final String user = username; 2173 if (user != null) { 2174 connectionProperties.put("user", user); 2175 } else { 2176 log("DBCP DataSource configured without a 'username'"); 2177 } 2178 2179 final String pwd = password; 2180 if (pwd != null) { 2181 connectionProperties.put("password", pwd); 2182 } else { 2183 log("DBCP DataSource configured without a 'password'"); 2184 } 2185 2186 final ConnectionFactory driverConnectionFactory = 2187 new DriverConnectionFactory(driverToUse, url, connectionProperties); 2188 return driverConnectionFactory; 2189 } 2190 2191 /** 2192 * Creates a connection pool for this datasource. This method only exists 2193 * so subclasses can replace the implementation class. 2194 * 2195 * This implementation configures all pool properties other than 2196 * timeBetweenEvictionRunsMillis. Setting that property is deferred to 2197 * {@link #startPoolMaintenance()}, since setting timeBetweenEvictionRunsMillis 2198 * to a positive value causes {@link GenericObjectPool}'s eviction timer 2199 * to be started. 2200 */ 2201 protected void createConnectionPool(final PoolableConnectionFactory factory) { 2202 // Create an object pool to contain our active connections 2203 final GenericObjectPoolConfig config = new GenericObjectPoolConfig(); 2204 updateJmxName(config); 2205 config.setJmxEnabled(registeredJmxObjectName != null); // Disable JMX on the underlying pool if the DS is not registered. 2206 final GenericObjectPool<PoolableConnection> gop = createObjectPool(factory, config, abandonedConfig); 2207 gop.setMaxTotal(maxTotal); 2208 gop.setMaxIdle(maxIdle); 2209 gop.setMinIdle(minIdle); 2210 gop.setMaxWaitMillis(maxWaitMillis); 2211 gop.setTestOnCreate(testOnCreate); 2212 gop.setTestOnBorrow(testOnBorrow); 2213 gop.setTestOnReturn(testOnReturn); 2214 gop.setNumTestsPerEvictionRun(numTestsPerEvictionRun); 2215 gop.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis); 2216 gop.setSoftMinEvictableIdleTimeMillis(softMinEvictableIdleTimeMillis); 2217 gop.setTestWhileIdle(testWhileIdle); 2218 gop.setLifo(lifo); 2219 gop.setSwallowedExceptionListener(new SwallowedExceptionLogger(log, logExpiredConnections)); 2220 gop.setEvictionPolicyClassName(evictionPolicyClassName); 2221 factory.setPool(gop); 2222 connectionPool = gop; 2223 } 2224 2225 /** 2226 * Creates an object pool used to provide pooling support for {@link Connection JDBC connections}. 2227 * 2228 * @param factory the object factory 2229 * @param poolConfig the object pool configuration 2230 * @param abandonedConfig the abandoned objects configuration 2231 * @return a non-null instance 2232 */ 2233 protected GenericObjectPool<PoolableConnection> createObjectPool( 2234 final PoolableConnectionFactory factory, final GenericObjectPoolConfig poolConfig, 2235 final AbandonedConfig abandonedConfig) { 2236 GenericObjectPool<PoolableConnection> gop; 2237 if (abandonedConfig != null && 2238 (abandonedConfig.getRemoveAbandonedOnBorrow() || 2239 abandonedConfig.getRemoveAbandonedOnMaintenance())) { 2240 gop = new GenericObjectPool<>(factory, poolConfig, abandonedConfig); 2241 } 2242 else { 2243 gop = new GenericObjectPool<>(factory, poolConfig); 2244 } 2245 return gop; 2246 } 2247 2248 /** 2249 * Closes the connection pool, silently swallowing any exception that occurs. 2250 */ 2251 private void closeConnectionPool() { 2252 final GenericObjectPool<?> oldpool = connectionPool; 2253 connectionPool = null; 2254 try { 2255 if (oldpool != null) { 2256 oldpool.close(); 2257 } 2258 } catch(final Exception e) { 2259 /* Ignore */ 2260 } 2261 } 2262 2263 /** 2264 * Starts the connection pool maintenance task, if configured. 2265 */ 2266 protected void startPoolMaintenance() { 2267 if (connectionPool != null && timeBetweenEvictionRunsMillis > 0) { 2268 connectionPool.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis); 2269 } 2270 } 2271 2272 /** 2273 * Creates the actual data source instance. This method only exists so 2274 * that subclasses can replace the implementation class. 2275 * 2276 * @throws SQLException if unable to create a datasource instance 2277 */ 2278 protected DataSource createDataSourceInstance() throws SQLException { 2279 final PoolingDataSource<PoolableConnection> pds = new PoolingDataSource<>(connectionPool); 2280 pds.setAccessToUnderlyingConnectionAllowed(isAccessToUnderlyingConnectionAllowed()); 2281 return pds; 2282 } 2283 2284 /** 2285 * Creates the PoolableConnectionFactory and attaches it to the connection pool. This method only exists 2286 * so subclasses can replace the default implementation. 2287 * 2288 * @param driverConnectionFactory JDBC connection factory 2289 * @throws SQLException if an error occurs creating the PoolableConnectionFactory 2290 */ 2291 protected PoolableConnectionFactory createPoolableConnectionFactory( 2292 final ConnectionFactory driverConnectionFactory) throws SQLException { 2293 PoolableConnectionFactory connectionFactory = null; 2294 try { 2295 connectionFactory = new PoolableConnectionFactory(driverConnectionFactory, ObjectNameWrapper.unwrap(registeredJmxObjectName)); 2296 connectionFactory.setValidationQuery(validationQuery); 2297 connectionFactory.setValidationQueryTimeout(validationQueryTimeout); 2298 connectionFactory.setConnectionInitSql(connectionInitSqls); 2299 connectionFactory.setDefaultReadOnly(defaultReadOnly); 2300 connectionFactory.setDefaultAutoCommit(defaultAutoCommit); 2301 connectionFactory.setDefaultTransactionIsolation(defaultTransactionIsolation); 2302 connectionFactory.setDefaultCatalog(defaultCatalog); 2303 connectionFactory.setCacheState(cacheState); 2304 connectionFactory.setPoolStatements(poolPreparedStatements); 2305 connectionFactory.setMaxOpenPreparedStatements(maxOpenPreparedStatements); 2306 connectionFactory.setMaxConnLifetimeMillis(maxConnLifetimeMillis); 2307 connectionFactory.setRollbackOnReturn(getRollbackOnReturn()); 2308 connectionFactory.setEnableAutoCommitOnReturn(getEnableAutoCommitOnReturn()); 2309 connectionFactory.setDefaultQueryTimeout(getDefaultQueryTimeout()); 2310 connectionFactory.setFastFailValidation(fastFailValidation); 2311 connectionFactory.setDisconnectionSqlCodes(disconnectionSqlCodes); 2312 validateConnectionFactory(connectionFactory); 2313 } catch (final RuntimeException e) { 2314 throw e; 2315 } catch (final Exception e) { 2316 throw new SQLException("Cannot create PoolableConnectionFactory (" + e.getMessage() + ")", e); 2317 } 2318 return connectionFactory; 2319 } 2320 2321 protected static void validateConnectionFactory( 2322 final PoolableConnectionFactory connectionFactory) throws Exception { 2323 PoolableConnection conn = null; 2324 PooledObject<PoolableConnection> p = null; 2325 try { 2326 p = connectionFactory.makeObject(); 2327 conn = p.getObject(); 2328 connectionFactory.activateObject(p); 2329 connectionFactory.validateConnection(conn); 2330 connectionFactory.passivateObject(p); 2331 } 2332 finally { 2333 if (p != null) { 2334 connectionFactory.destroyObject(p); 2335 } 2336 } 2337 } 2338 2339 protected void log(final String message) { 2340 if (logWriter != null) { 2341 logWriter.println(message); 2342 } 2343 } 2344 2345 /** 2346 * Actual name under which this component has been registered. 2347 */ 2348 private ObjectNameWrapper registeredJmxObjectName; 2349 2350 private void jmxRegister() { 2351 // Return immediately if this DataSource has already been registered 2352 if (registeredJmxObjectName != null) { 2353 return; 2354 } 2355 // Return immediately if no JMX name has been specified 2356 final String requestedName = getJmxName(); 2357 if (requestedName == null) { 2358 return; 2359 } 2360 try { 2361 ObjectNameWrapper.wrap(requestedName).registerMBean(this); 2362 } catch (MalformedObjectNameException e) { 2363 log.warn("The requested JMX name [" + requestedName + "] was not valid and will be ignored."); 2364 } 2365 } 2366 2367 @Override 2368 public ObjectName preRegister(final MBeanServer server, final ObjectName objectName) { 2369 final String requestedName = getJmxName(); 2370 if (requestedName != null) { 2371 try { 2372 registeredJmxObjectName = ObjectNameWrapper.wrap(requestedName); 2373 } catch (final MalformedObjectNameException e) { 2374 log.warn("The requested JMX name [" + requestedName + "] was not valid and will be ignored."); 2375 } 2376 } 2377 if (registeredJmxObjectName == null) { 2378 registeredJmxObjectName = ObjectNameWrapper.wrap(objectName); 2379 } 2380 return ObjectNameWrapper.unwrap(registeredJmxObjectName); 2381 } 2382 2383 @Override 2384 public void postRegister(final Boolean registrationDone) { 2385 // NO-OP 2386 } 2387 2388 @Override 2389 public void preDeregister() throws Exception { 2390 // NO-OP 2391 } 2392 2393 @Override 2394 public void postDeregister() { 2395 // NO-OP 2396 } 2397 2398 private void updateJmxName(final GenericObjectPoolConfig config) { 2399 if (registeredJmxObjectName == null) { 2400 return; 2401 } 2402 final StringBuilder base = new StringBuilder(registeredJmxObjectName.toString()); 2403 base.append(Constants.JMX_CONNECTION_POOL_BASE_EXT); 2404 config.setJmxNameBase(base.toString()); 2405 config.setJmxNamePrefix(Constants.JMX_CONNECTION_POOL_PREFIX); 2406 } 2407 2408 protected ObjectName getRegisteredJmxName() { 2409 return ObjectNameWrapper.unwrap(registeredJmxObjectName); 2410 } 2411 2412 /** 2413 * @since 2.0 2414 */ 2415 private class PaGetConnection implements PrivilegedExceptionAction<Connection> { 2416 2417 @Override 2418 public Connection run() throws SQLException { 2419 return createDataSource().getConnection(); 2420 } 2421 } 2422}