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