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