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