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