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 */ 017 018package org.apache.commons.dbcp2.datasources; 019 020import java.io.OutputStreamWriter; 021import java.io.PrintWriter; 022import java.io.Serializable; 023import java.nio.charset.StandardCharsets; 024import java.sql.Connection; 025import java.sql.SQLException; 026import java.sql.SQLFeatureNotSupportedException; 027import java.time.Duration; 028import java.util.Properties; 029import java.util.logging.Logger; 030 031import javax.naming.Context; 032import javax.naming.InitialContext; 033import javax.naming.Referenceable; 034import javax.sql.ConnectionPoolDataSource; 035import javax.sql.DataSource; 036import javax.sql.PooledConnection; 037 038import org.apache.commons.pool2.impl.BaseObjectPoolConfig; 039import org.apache.commons.pool2.impl.GenericKeyedObjectPoolConfig; 040 041/** 042 * <p> 043 * The base class for <code>SharedPoolDataSource</code> and <code>PerUserPoolDataSource</code>. Many of the 044 * configuration properties are shared and defined here. This class is declared public in order to allow particular 045 * usage with commons-beanutils; do not make direct use of it outside of <em>commons-dbcp2</em>. 046 * </p> 047 * 048 * <p> 049 * A J2EE container will normally provide some method of initializing the <code>DataSource</code> whose attributes are 050 * presented as bean getters/setters and then deploying it via JNDI. It is then available to an application as a source 051 * of pooled logical connections to the database. The pool needs a source of physical connections. This source is in the 052 * form of a <code>ConnectionPoolDataSource</code> that can be specified via the {@link #setDataSourceName(String)} used 053 * to lookup the source via JNDI. 054 * </p> 055 * 056 * <p> 057 * Although normally used within a JNDI environment, A DataSource can be instantiated and initialized as any bean. In 058 * this case the <code>ConnectionPoolDataSource</code> will likely be instantiated in a similar manner. This class 059 * allows the physical source of connections to be attached directly to this pool using the 060 * {@link #setConnectionPoolDataSource(ConnectionPoolDataSource)} method. 061 * </p> 062 * 063 * <p> 064 * The dbcp package contains an adapter, {@link org.apache.commons.dbcp2.cpdsadapter.DriverAdapterCPDS}, that can be 065 * used to allow the use of <code>DataSource</code>'s based on this class with JDBC driver implementations that do not 066 * supply a <code>ConnectionPoolDataSource</code>, but still provide a {@link java.sql.Driver} implementation. 067 * </p> 068 * 069 * <p> 070 * The <a href="package-summary.html">package documentation</a> contains an example using Apache Tomcat and JNDI and it 071 * also contains a non-JNDI example. 072 * </p> 073 * 074 * @since 2.0 075 */ 076public abstract class InstanceKeyDataSource implements DataSource, Referenceable, Serializable, AutoCloseable { 077 078 private static final long serialVersionUID = -6819270431752240878L; 079 080 private static final String GET_CONNECTION_CALLED = "A Connection was already requested from this source, " 081 + "further initialization is not allowed."; 082 private static final String BAD_TRANSACTION_ISOLATION = "The requested TransactionIsolation level is invalid."; 083 084 /** 085 * Internal constant to indicate the level is not set. 086 */ 087 protected static final int UNKNOWN_TRANSACTIONISOLATION = -1; 088 089 /** Guards property setters - once true, setters throw IllegalStateException */ 090 private volatile boolean getConnectionCalled; 091 092 /** Underlying source of PooledConnections */ 093 private ConnectionPoolDataSource dataSource; 094 095 /** DataSource Name used to find the ConnectionPoolDataSource */ 096 private String dataSourceName; 097 098 /** Description */ 099 private String description; 100 101 /** Environment that may be used to set up a JNDI initial context. */ 102 private Properties jndiEnvironment; 103 104 /** Login TimeOut in seconds */ 105 private int loginTimeout; 106 107 /** Log stream */ 108 private PrintWriter logWriter; 109 110 /** Instance key */ 111 private String instanceKey; 112 113 // Pool properties 114 private boolean defaultBlockWhenExhausted = BaseObjectPoolConfig.DEFAULT_BLOCK_WHEN_EXHAUSTED; 115 private String defaultEvictionPolicyClassName = BaseObjectPoolConfig.DEFAULT_EVICTION_POLICY_CLASS_NAME; 116 private boolean defaultLifo = BaseObjectPoolConfig.DEFAULT_LIFO; 117 private int defaultMaxIdle = GenericKeyedObjectPoolConfig.DEFAULT_MAX_IDLE_PER_KEY; 118 private int defaultMaxTotal = GenericKeyedObjectPoolConfig.DEFAULT_MAX_TOTAL; 119 private Duration defaultMaxWaitDuration = BaseObjectPoolConfig.DEFAULT_MAX_WAIT; 120 private long defaultMinEvictableIdleTimeMillis = BaseObjectPoolConfig.DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS; 121 private int defaultMinIdle = GenericKeyedObjectPoolConfig.DEFAULT_MIN_IDLE_PER_KEY; 122 private int defaultNumTestsPerEvictionRun = BaseObjectPoolConfig.DEFAULT_NUM_TESTS_PER_EVICTION_RUN; 123 private long defaultSoftMinEvictableIdleTimeMillis = BaseObjectPoolConfig.DEFAULT_SOFT_MIN_EVICTABLE_IDLE_TIME_MILLIS; 124 private boolean defaultTestOnCreate = BaseObjectPoolConfig.DEFAULT_TEST_ON_CREATE; 125 private boolean defaultTestOnBorrow = BaseObjectPoolConfig.DEFAULT_TEST_ON_BORROW; 126 private boolean defaultTestOnReturn = BaseObjectPoolConfig.DEFAULT_TEST_ON_RETURN; 127 private boolean defaultTestWhileIdle = BaseObjectPoolConfig.DEFAULT_TEST_WHILE_IDLE; 128 private long defaultTimeBetweenEvictionRunsMillis = BaseObjectPoolConfig.DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS; 129 130 // Connection factory properties 131 private String validationQuery; 132 private int validationQueryTimeoutSeconds = -1; 133 private boolean rollbackAfterValidation; 134 private Duration maxConnLifetimeMillis = Duration.ofMillis(-1); 135 136 // Connection properties 137 private Boolean defaultAutoCommit; 138 private int defaultTransactionIsolation = UNKNOWN_TRANSACTIONISOLATION; 139 private Boolean defaultReadOnly; 140 141 /** 142 * Default no-arg constructor for Serialization. 143 */ 144 public InstanceKeyDataSource() { 145 } 146 147 /** 148 * Throws an IllegalStateException, if a PooledConnection has already been requested. 149 * 150 * @throws IllegalStateException Thrown if a PooledConnection has already been requested. 151 */ 152 protected void assertInitializationAllowed() throws IllegalStateException { 153 if (getConnectionCalled) { 154 throw new IllegalStateException(GET_CONNECTION_CALLED); 155 } 156 } 157 158 /** 159 * Closes the connection pool being maintained by this datasource. 160 */ 161 @Override 162 public abstract void close() throws Exception; 163 164 private void closeDueToException(final PooledConnectionAndInfo info) { 165 if (info != null) { 166 try { 167 info.getPooledConnection().getConnection().close(); 168 } catch (final Exception e) { 169 // do not throw this exception because we are in the middle 170 // of handling another exception. But record it because 171 // it potentially leaks connections from the pool. 172 getLogWriter().println("[ERROR] Could not return connection to " + "pool during exception handling. " 173 + e.getMessage()); 174 } 175 } 176 } 177 178 /** 179 * Attempts to establish a database connection. 180 */ 181 @Override 182 public Connection getConnection() throws SQLException { 183 return getConnection(null, null); 184 } 185 186 /** 187 * Attempts to retrieve a database connection using {@link #getPooledConnectionAndInfo(String, String)} with the 188 * provided user name and password. The password on the {@code PooledConnectionAndInfo} instance returned by 189 * <code>getPooledConnectionAndInfo</code> is compared to the <code>password</code> parameter. If the comparison 190 * fails, a database connection using the supplied user name and password is attempted. If the connection attempt 191 * fails, an SQLException is thrown, indicating that the given password did not match the password used to create 192 * the pooled connection. If the connection attempt succeeds, this means that the database password has been 193 * changed. In this case, the <code>PooledConnectionAndInfo</code> instance retrieved with the old password is 194 * destroyed and the <code>getPooledConnectionAndInfo</code> is repeatedly invoked until a 195 * <code>PooledConnectionAndInfo</code> instance with the new password is returned. 196 */ 197 @Override 198 public Connection getConnection(final String userName, final String userPassword) throws SQLException { 199 if (instanceKey == null) { 200 throw new SQLException("Must set the ConnectionPoolDataSource " 201 + "through setDataSourceName or setConnectionPoolDataSource" + " before calling getConnection."); 202 } 203 getConnectionCalled = true; 204 PooledConnectionAndInfo info = null; 205 try { 206 info = getPooledConnectionAndInfo(userName, userPassword); 207 } catch (final RuntimeException | SQLException e) { 208 closeDueToException(info); 209 throw e; 210 } catch (final Exception e) { 211 closeDueToException(info); 212 throw new SQLException("Cannot borrow connection from pool", e); 213 } 214 215 // Password on PooledConnectionAndInfo does not match 216 if (!(null == userPassword ? null == info.getPassword() : userPassword.equals(info.getPassword()))) { 217 try { // See if password has changed by attempting connection 218 testCPDS(userName, userPassword); 219 } catch (final SQLException ex) { 220 // Password has not changed, so refuse client, but return connection to the pool 221 closeDueToException(info); 222 throw new SQLException( 223 "Given password did not match password used" + " to create the PooledConnection.", ex); 224 } catch (final javax.naming.NamingException ne) { 225 throw new SQLException("NamingException encountered connecting to database", ne); 226 } 227 /* 228 * Password must have changed -> destroy connection and keep retrying until we get a new, good one, 229 * destroying any idle connections with the old password as we pull them from the pool. 230 */ 231 final UserPassKey upkey = info.getUserPassKey(); 232 final PooledConnectionManager manager = getConnectionManager(upkey); 233 // Destroy and remove from pool 234 manager.invalidate(info.getPooledConnection()); 235 // Reset the password on the factory if using CPDSConnectionFactory 236 manager.setPassword(upkey.getPassword()); 237 info = null; 238 for (int i = 0; i < 10; i++) { // Bound the number of retries - only needed if bad instances return 239 try { 240 info = getPooledConnectionAndInfo(userName, userPassword); 241 } catch (final RuntimeException | SQLException e) { 242 closeDueToException(info); 243 throw e; 244 } catch (final Exception e) { 245 closeDueToException(info); 246 throw new SQLException("Cannot borrow connection from pool", e); 247 } 248 if (info != null && userPassword != null && userPassword.equals(info.getPassword())) { 249 break; 250 } 251 if (info != null) { 252 manager.invalidate(info.getPooledConnection()); 253 } 254 info = null; 255 } 256 if (info == null) { 257 throw new SQLException("Cannot borrow connection from pool - password change failure."); 258 } 259 } 260 261 final Connection connection = info.getPooledConnection().getConnection(); 262 try { 263 setupDefaults(connection, userName); 264 connection.clearWarnings(); 265 return connection; 266 } catch (final SQLException ex) { 267 try { 268 connection.close(); 269 } catch (final Exception exc) { 270 getLogWriter().println("ignoring exception during close: " + exc); 271 } 272 throw ex; 273 } 274 } 275 276 protected abstract PooledConnectionManager getConnectionManager(UserPassKey upkey); 277 278 /** 279 * Gets the value of connectionPoolDataSource. This method will return null, if the backing data source is being 280 * accessed via JNDI. 281 * 282 * @return value of connectionPoolDataSource. 283 */ 284 public ConnectionPoolDataSource getConnectionPoolDataSource() { 285 return dataSource; 286 } 287 288 /** 289 * Gets the name of the ConnectionPoolDataSource which backs this pool. This name is used to look up the data source 290 * from a JNDI service provider. 291 * 292 * @return value of dataSourceName. 293 */ 294 public String getDataSourceName() { 295 return dataSourceName; 296 } 297 298 /** 299 * Gets the default value for {@link GenericKeyedObjectPoolConfig#getBlockWhenExhausted()} for each per user pool. 300 * 301 * @return The default value for {@link GenericKeyedObjectPoolConfig#getBlockWhenExhausted()} for each per user 302 * pool. 303 */ 304 public boolean getDefaultBlockWhenExhausted() { 305 return this.defaultBlockWhenExhausted; 306 } 307 308 /** 309 * Gets the default value for {@link GenericKeyedObjectPoolConfig#getEvictionPolicyClassName()} for each per user 310 * pool. 311 * 312 * @return The default value for {@link GenericKeyedObjectPoolConfig#getEvictionPolicyClassName()} for each per user 313 * pool. 314 */ 315 public String getDefaultEvictionPolicyClassName() { 316 return this.defaultEvictionPolicyClassName; 317 } 318 319 /** 320 * Gets the default value for {@link GenericKeyedObjectPoolConfig#getLifo()} for each per user pool. 321 * 322 * @return The default value for {@link GenericKeyedObjectPoolConfig#getLifo()} for each per user pool. 323 */ 324 public boolean getDefaultLifo() { 325 return this.defaultLifo; 326 } 327 328 /** 329 * Gets the default value for {@link GenericKeyedObjectPoolConfig#getMaxIdlePerKey()} for each per user pool. 330 * 331 * @return The default value for {@link GenericKeyedObjectPoolConfig#getMaxIdlePerKey()} for each per user pool. 332 */ 333 public int getDefaultMaxIdle() { 334 return this.defaultMaxIdle; 335 } 336 337 /** 338 * Gets the default value for {@link GenericKeyedObjectPoolConfig#getMaxTotalPerKey()} for each per user pool. 339 * 340 * @return The default value for {@link GenericKeyedObjectPoolConfig#getMaxTotalPerKey()} for each per user pool. 341 */ 342 public int getDefaultMaxTotal() { 343 return this.defaultMaxTotal; 344 } 345 346 /** 347 * Gets the default value for {@link GenericKeyedObjectPoolConfig#getMaxWaitMillis()} for each per user pool. 348 * 349 * @return The default value for {@link GenericKeyedObjectPoolConfig#getMaxWaitMillis()} for each per user pool. 350 * @since 2.9.0 351 */ 352 public Duration getDefaultMaxWait() { 353 return this.defaultMaxWaitDuration; 354 } 355 356 /** 357 * Gets the default value for {@link GenericKeyedObjectPoolConfig#getMaxWaitMillis()} for each per user pool. 358 * 359 * @return The default value for {@link GenericKeyedObjectPoolConfig#getMaxWaitMillis()} for each per user pool. 360 * @deprecated Use {@link #getDefaultMaxWait()}. 361 */ 362 @Deprecated 363 public long getDefaultMaxWaitMillis() { 364 return getDefaultMaxWait().toMillis(); 365 } 366 367 /** 368 * Gets the default value for {@link GenericKeyedObjectPoolConfig#getMinEvictableIdleTime()} for each per user 369 * pool. 370 * 371 * @return The default value for {@link GenericKeyedObjectPoolConfig#getMinEvictableIdleTime()} for each per 372 * user pool. 373 */ 374 public long getDefaultMinEvictableIdleTimeMillis() { 375 return this.defaultMinEvictableIdleTimeMillis; 376 } 377 378 /** 379 * Gets the default value for {@link GenericKeyedObjectPoolConfig#getMinIdlePerKey()} for each per user pool. 380 * 381 * @return The default value for {@link GenericKeyedObjectPoolConfig#getMinIdlePerKey()} for each per user pool. 382 */ 383 public int getDefaultMinIdle() { 384 return this.defaultMinIdle; 385 } 386 387 /** 388 * Gets the default value for {@link GenericKeyedObjectPoolConfig#getNumTestsPerEvictionRun()} for each per user 389 * pool. 390 * 391 * @return The default value for {@link GenericKeyedObjectPoolConfig#getNumTestsPerEvictionRun()} for each per user 392 * pool. 393 */ 394 public int getDefaultNumTestsPerEvictionRun() { 395 return this.defaultNumTestsPerEvictionRun; 396 } 397 398 /** 399 * Gets the default value for {@link org.apache.commons.pool2.impl.GenericObjectPool 400 * GenericObjectPool#getSoftMinEvictableIdleTimeMillis()} for each per user pool. 401 * 402 * @return The default value for {@link org.apache.commons.pool2.impl.GenericObjectPool 403 * GenericObjectPool#getSoftMinEvictableIdleTimeMillis()} for each per user pool. 404 */ 405 public long getDefaultSoftMinEvictableIdleTimeMillis() { 406 return this.defaultSoftMinEvictableIdleTimeMillis; 407 } 408 409 /** 410 * Gets the default value for {@link org.apache.commons.pool2.impl.GenericObjectPool 411 * GenericObjectPool#getTestOnBorrow()} for each per user pool. 412 * 413 * @return The default value for {@link org.apache.commons.pool2.impl.GenericObjectPool 414 * GenericObjectPool#getTestOnBorrow()} for each per user pool. 415 */ 416 public boolean getDefaultTestOnBorrow() { 417 return this.defaultTestOnBorrow; 418 } 419 420 /** 421 * Gets the default value for {@link org.apache.commons.pool2.impl.GenericObjectPool 422 * GenericObjectPool#getTestOnCreate()} for each per user pool. 423 * 424 * @return The default value for {@link org.apache.commons.pool2.impl.GenericObjectPool 425 * GenericObjectPool#getTestOnCreate()} for each per user pool. 426 */ 427 public boolean getDefaultTestOnCreate() { 428 return this.defaultTestOnCreate; 429 } 430 431 /** 432 * Gets the default value for {@link org.apache.commons.pool2.impl.GenericObjectPool 433 * GenericObjectPool#getTestOnReturn()} for each per user pool. 434 * 435 * @return The default value for {@link org.apache.commons.pool2.impl.GenericObjectPool 436 * GenericObjectPool#getTestOnReturn()} for each per user pool. 437 */ 438 public boolean getDefaultTestOnReturn() { 439 return this.defaultTestOnReturn; 440 } 441 442 /** 443 * Gets the default value for {@link org.apache.commons.pool2.impl.GenericObjectPool 444 * GenericObjectPool#getTestWhileIdle()} for each per user pool. 445 * 446 * @return The default value for {@link org.apache.commons.pool2.impl.GenericObjectPool 447 * GenericObjectPool#getTestWhileIdle()} for each per user pool. 448 */ 449 public boolean getDefaultTestWhileIdle() { 450 return this.defaultTestWhileIdle; 451 } 452 453 /** 454 * Gets the default value for {@link org.apache.commons.pool2.impl.GenericObjectPool 455 * GenericObjectPool#getTimeBetweenEvictionRunsMillis ()} for each per user pool. 456 * 457 * @return The default value for {@link org.apache.commons.pool2.impl.GenericObjectPool 458 * GenericObjectPool#getTimeBetweenEvictionRunsMillis ()} for each per user pool. 459 */ 460 public long getDefaultTimeBetweenEvictionRunsMillis() { 461 return this.defaultTimeBetweenEvictionRunsMillis; 462 } 463 464 /** 465 * Gets the value of defaultTransactionIsolation, which defines the state of connections handed out from this pool. 466 * The value can be changed on the Connection using Connection.setTransactionIsolation(int). If this method returns 467 * -1, the default is JDBC driver dependent. 468 * 469 * @return value of defaultTransactionIsolation. 470 */ 471 public int getDefaultTransactionIsolation() { 472 return defaultTransactionIsolation; 473 } 474 475 /** 476 * Gets the description. This property is defined by JDBC as for use with GUI (or other) tools that might deploy the 477 * datasource. It serves no internal purpose. 478 * 479 * @return value of description. 480 */ 481 public String getDescription() { 482 return description; 483 } 484 485 protected String getInstanceKey() { 486 return instanceKey; 487 } 488 489 /** 490 * Gets the value of jndiEnvironment which is used when instantiating a JNDI InitialContext. This InitialContext is 491 * used to locate the back end ConnectionPoolDataSource. 492 * 493 * @param key 494 * JNDI environment key. 495 * @return value of jndiEnvironment. 496 */ 497 public String getJndiEnvironment(final String key) { 498 String value = null; 499 if (jndiEnvironment != null) { 500 value = jndiEnvironment.getProperty(key); 501 } 502 return value; 503 } 504 505 /** 506 * Gets the value of loginTimeout. 507 * 508 * @return value of loginTimeout. 509 */ 510 @Override 511 public int getLoginTimeout() { 512 return loginTimeout; 513 } 514 515 /** 516 * Gets the value of logWriter. 517 * 518 * @return value of logWriter. 519 */ 520 @Override 521 public PrintWriter getLogWriter() { 522 if (logWriter == null) { 523 logWriter = new PrintWriter(new OutputStreamWriter(System.out, StandardCharsets.UTF_8)); 524 } 525 return logWriter; 526 } 527 528 /** 529 * Gets the maximum permitted lifetime of a connection. A value of zero or less indicates an 530 * infinite lifetime. 531 * 532 * @return The maximum permitted lifetime of a connection. A value of zero or less indicates an 533 * infinite lifetime. 534 */ 535 public Duration getMaxConnLifetime() { 536 return maxConnLifetimeMillis; 537 } 538 539 /** 540 * Gets the maximum permitted lifetime of a connection in milliseconds. A value of zero or less indicates an 541 * infinite lifetime. 542 * 543 * @return The maximum permitted lifetime of a connection in milliseconds. A value of zero or less indicates an 544 * infinite lifetime. 545 * @deprecated Use {@link #getMaxConnLifetime()}. 546 */ 547 @Deprecated 548 public long getMaxConnLifetimeMillis() { 549 return maxConnLifetimeMillis.toMillis(); 550 } 551 552 @Override 553 public Logger getParentLogger() throws SQLFeatureNotSupportedException { 554 throw new SQLFeatureNotSupportedException(); 555 } 556 557 /** 558 * This method is protected but can only be implemented in this package because PooledConnectionAndInfo is a package 559 * private type. 560 * 561 * @param userName The user name. 562 * @param userPassword The user password. 563 * @return Matching PooledConnectionAndInfo. 564 * @throws SQLException Connection or registration failure. 565 */ 566 protected abstract PooledConnectionAndInfo getPooledConnectionAndInfo(String userName, String userPassword) 567 throws SQLException; 568 569 /** 570 * Gets the SQL query that will be used to validate connections from this pool before returning them to the caller. 571 * If specified, this query <strong>MUST</strong> be an SQL SELECT statement that returns at least one row. If not 572 * specified, {@link Connection#isValid(int)} will be used to validate connections. 573 * 574 * @return The SQL query that will be used to validate connections from this pool before returning them to the 575 * caller. 576 */ 577 public String getValidationQuery() { 578 return this.validationQuery; 579 } 580 581 /** 582 * Returns the timeout in seconds before the validation query fails. 583 * 584 * @return The timeout in seconds before the validation query fails. 585 */ 586 public int getValidationQueryTimeout() { 587 return validationQueryTimeoutSeconds; 588 } 589 590 /** 591 * Gets the value of defaultAutoCommit, which defines the state of connections handed out from this pool. The value 592 * can be changed on the Connection using Connection.setAutoCommit(boolean). The default is <code>null</code> which 593 * will use the default value for the drive. 594 * 595 * @return value of defaultAutoCommit. 596 */ 597 public Boolean isDefaultAutoCommit() { 598 return defaultAutoCommit; 599 } 600 601 /** 602 * Gets the value of defaultReadOnly, which defines the state of connections handed out from this pool. The value 603 * can be changed on the Connection using Connection.setReadOnly(boolean). The default is <code>null</code> which 604 * will use the default value for the drive. 605 * 606 * @return value of defaultReadOnly. 607 */ 608 public Boolean isDefaultReadOnly() { 609 return defaultReadOnly; 610 } 611 612 /** 613 * Whether a rollback will be issued after executing the SQL query that will be used to validate connections from 614 * this pool before returning them to the caller. 615 * 616 * @return true if a rollback will be issued after executing the validation query 617 */ 618 public boolean isRollbackAfterValidation() { 619 return this.rollbackAfterValidation; 620 } 621 622 @Override 623 public boolean isWrapperFor(final Class<?> iface) throws SQLException { 624 return iface.isInstance(this); 625 } 626 627 /** 628 * Sets the back end ConnectionPoolDataSource. This property should not be set if using JNDI to access the 629 * data source. 630 * 631 * @param dataSource 632 * Value to assign to connectionPoolDataSource. 633 */ 634 public void setConnectionPoolDataSource(final ConnectionPoolDataSource dataSource) { 635 assertInitializationAllowed(); 636 if (dataSourceName != null) { 637 throw new IllegalStateException("Cannot set the DataSource, if JNDI is used."); 638 } 639 if (this.dataSource != null) { 640 throw new IllegalStateException("The CPDS has already been set. It cannot be altered."); 641 } 642 this.dataSource = dataSource; 643 instanceKey = InstanceKeyDataSourceFactory.registerNewInstance(this); 644 } 645 646 /** 647 * Sets the name of the ConnectionPoolDataSource which backs this pool. This name is used to look up the data source 648 * from a JNDI service provider. 649 * 650 * @param dataSourceName 651 * Value to assign to dataSourceName. 652 */ 653 public void setDataSourceName(final String dataSourceName) { 654 assertInitializationAllowed(); 655 if (dataSource != null) { 656 throw new IllegalStateException("Cannot set the JNDI name for the DataSource, if already " 657 + "set using setConnectionPoolDataSource."); 658 } 659 if (this.dataSourceName != null) { 660 throw new IllegalStateException("The DataSourceName has already been set. " + "It cannot be altered."); 661 } 662 this.dataSourceName = dataSourceName; 663 instanceKey = InstanceKeyDataSourceFactory.registerNewInstance(this); 664 } 665 666 /** 667 * Sets the value of defaultAutoCommit, which defines the state of connections handed out from this pool. The value 668 * can be changed on the Connection using Connection.setAutoCommit(boolean). The default is <code>null</code> which 669 * will use the default value for the drive. 670 * 671 * @param defaultAutoCommit 672 * Value to assign to defaultAutoCommit. 673 */ 674 public void setDefaultAutoCommit(final Boolean defaultAutoCommit) { 675 assertInitializationAllowed(); 676 this.defaultAutoCommit = defaultAutoCommit; 677 } 678 679 /** 680 * Sets the default value for {@link GenericKeyedObjectPoolConfig#getBlockWhenExhausted()} for each per user pool. 681 * 682 * @param blockWhenExhausted 683 * The default value for {@link GenericKeyedObjectPoolConfig#getBlockWhenExhausted()} for each per user 684 * pool. 685 */ 686 public void setDefaultBlockWhenExhausted(final boolean blockWhenExhausted) { 687 assertInitializationAllowed(); 688 this.defaultBlockWhenExhausted = blockWhenExhausted; 689 } 690 691 /** 692 * Sets the default value for {@link GenericKeyedObjectPoolConfig#getEvictionPolicyClassName()} for each per user 693 * pool. 694 * 695 * @param evictionPolicyClassName 696 * The default value for {@link GenericKeyedObjectPoolConfig#getEvictionPolicyClassName()} for each per 697 * user pool. 698 */ 699 public void setDefaultEvictionPolicyClassName(final String evictionPolicyClassName) { 700 assertInitializationAllowed(); 701 this.defaultEvictionPolicyClassName = evictionPolicyClassName; 702 } 703 704 /** 705 * Sets the default value for {@link GenericKeyedObjectPoolConfig#getLifo()} for each per user pool. 706 * 707 * @param lifo 708 * The default value for {@link GenericKeyedObjectPoolConfig#getLifo()} for each per user pool. 709 */ 710 public void setDefaultLifo(final boolean lifo) { 711 assertInitializationAllowed(); 712 this.defaultLifo = lifo; 713 } 714 715 /** 716 * Sets the default value for {@link GenericKeyedObjectPoolConfig#getMaxIdlePerKey()} for each per user pool. 717 * 718 * @param maxIdle 719 * The default value for {@link GenericKeyedObjectPoolConfig#getMaxIdlePerKey()} for each per user pool. 720 */ 721 public void setDefaultMaxIdle(final int maxIdle) { 722 assertInitializationAllowed(); 723 this.defaultMaxIdle = maxIdle; 724 } 725 726 /** 727 * Sets the default value for {@link GenericKeyedObjectPoolConfig#getMaxTotalPerKey()} for each per user pool. 728 * 729 * @param maxTotal 730 * The default value for {@link GenericKeyedObjectPoolConfig#getMaxTotalPerKey()} for each per user pool. 731 */ 732 public void setDefaultMaxTotal(final int maxTotal) { 733 assertInitializationAllowed(); 734 this.defaultMaxTotal = maxTotal; 735 } 736 737 /** 738 * Sets the default value for {@link GenericKeyedObjectPoolConfig#getMaxWaitMillis()} for each per user pool. 739 * 740 * @param maxWaitMillis 741 * The default value for {@link GenericKeyedObjectPoolConfig#getMaxWaitMillis()} for each per user pool. 742 * @since 2.9.0 743 */ 744 public void setDefaultMaxWait(final Duration maxWaitMillis) { 745 assertInitializationAllowed(); 746 this.defaultMaxWaitDuration = maxWaitMillis; 747 } 748 749 /** 750 * Sets the default value for {@link GenericKeyedObjectPoolConfig#getMaxWaitMillis()} for each per user pool. 751 * 752 * @param maxWaitMillis 753 * The default value for {@link GenericKeyedObjectPoolConfig#getMaxWaitMillis()} for each per user pool. 754 * @deprecated Use {@link #setDefaultMaxWait(Duration)}. 755 */ 756 @Deprecated 757 public void setDefaultMaxWaitMillis(final long maxWaitMillis) { 758 setDefaultMaxWait(Duration.ofMillis(maxWaitMillis)); 759 } 760 761 /** 762 * Sets the default value for {@link GenericKeyedObjectPoolConfig#getMinEvictableIdleTime()} for each per user 763 * pool. 764 * 765 * @param minEvictableIdleTimeMillis 766 * The default value for {@link GenericKeyedObjectPoolConfig#getMinEvictableIdleTime()} for each 767 * per user pool. 768 */ 769 public void setDefaultMinEvictableIdleTimeMillis(final long minEvictableIdleTimeMillis) { 770 assertInitializationAllowed(); 771 this.defaultMinEvictableIdleTimeMillis = minEvictableIdleTimeMillis; 772 } 773 774 /** 775 * Sets the default value for {@link GenericKeyedObjectPoolConfig#getMinIdlePerKey()} for each per user pool. 776 * 777 * @param minIdle 778 * The default value for {@link GenericKeyedObjectPoolConfig#getMinIdlePerKey()} for each per user pool. 779 */ 780 public void setDefaultMinIdle(final int minIdle) { 781 assertInitializationAllowed(); 782 this.defaultMinIdle = minIdle; 783 } 784 785 /** 786 * Sets the default value for {@link GenericKeyedObjectPoolConfig#getNumTestsPerEvictionRun()} for each per user 787 * pool. 788 * 789 * @param numTestsPerEvictionRun 790 * The default value for {@link GenericKeyedObjectPoolConfig#getNumTestsPerEvictionRun()} for each per 791 * user pool. 792 */ 793 public void setDefaultNumTestsPerEvictionRun(final int numTestsPerEvictionRun) { 794 assertInitializationAllowed(); 795 this.defaultNumTestsPerEvictionRun = numTestsPerEvictionRun; 796 } 797 798 /** 799 * Sets the value of defaultReadOnly, which defines the state of connections handed out from this pool. The value 800 * can be changed on the Connection using Connection.setReadOnly(boolean). The default is <code>null</code> which 801 * will use the default value for the drive. 802 * 803 * @param defaultReadOnly 804 * Value to assign to defaultReadOnly. 805 */ 806 public void setDefaultReadOnly(final Boolean defaultReadOnly) { 807 assertInitializationAllowed(); 808 this.defaultReadOnly = defaultReadOnly; 809 } 810 811 /** 812 * Sets the default value for {@link org.apache.commons.pool2.impl.GenericObjectPool 813 * GenericObjectPool#getSoftMinEvictableIdleTimeMillis()} for each per user pool. 814 * 815 * @param softMinEvictableIdleTimeMillis 816 * The default value for {@link org.apache.commons.pool2.impl.GenericObjectPool 817 * GenericObjectPool#getSoftMinEvictableIdleTimeMillis()} for each per user pool. 818 */ 819 public void setDefaultSoftMinEvictableIdleTimeMillis(final long softMinEvictableIdleTimeMillis) { 820 assertInitializationAllowed(); 821 this.defaultSoftMinEvictableIdleTimeMillis = softMinEvictableIdleTimeMillis; 822 } 823 824 /** 825 * Sets the default value for {@link org.apache.commons.pool2.impl.GenericObjectPool 826 * GenericObjectPool#getTestOnBorrow()} for each per user pool. 827 * 828 * @param testOnBorrow 829 * The default value for {@link org.apache.commons.pool2.impl.GenericObjectPool 830 * GenericObjectPool#getTestOnBorrow()} for each per user pool. 831 */ 832 public void setDefaultTestOnBorrow(final boolean testOnBorrow) { 833 assertInitializationAllowed(); 834 this.defaultTestOnBorrow = testOnBorrow; 835 } 836 837 /** 838 * Sets the default value for {@link org.apache.commons.pool2.impl.GenericObjectPool 839 * GenericObjectPool#getTestOnCreate()} for each per user pool. 840 * 841 * @param testOnCreate 842 * The default value for {@link org.apache.commons.pool2.impl.GenericObjectPool 843 * GenericObjectPool#getTestOnCreate()} for each per user pool. 844 */ 845 public void setDefaultTestOnCreate(final boolean testOnCreate) { 846 assertInitializationAllowed(); 847 this.defaultTestOnCreate = testOnCreate; 848 } 849 850 /** 851 * Sets the default value for {@link org.apache.commons.pool2.impl.GenericObjectPool 852 * GenericObjectPool#getTestOnReturn()} for each per user pool. 853 * 854 * @param testOnReturn 855 * The default value for {@link org.apache.commons.pool2.impl.GenericObjectPool 856 * GenericObjectPool#getTestOnReturn()} for each per user pool. 857 */ 858 public void setDefaultTestOnReturn(final boolean testOnReturn) { 859 assertInitializationAllowed(); 860 this.defaultTestOnReturn = testOnReturn; 861 } 862 863 /** 864 * Sets the default value for {@link org.apache.commons.pool2.impl.GenericObjectPool 865 * GenericObjectPool#getTestWhileIdle()} for each per user pool. 866 * 867 * @param testWhileIdle 868 * The default value for {@link org.apache.commons.pool2.impl.GenericObjectPool 869 * GenericObjectPool#getTestWhileIdle()} for each per user pool. 870 */ 871 public void setDefaultTestWhileIdle(final boolean testWhileIdle) { 872 assertInitializationAllowed(); 873 this.defaultTestWhileIdle = testWhileIdle; 874 } 875 876 /** 877 * Sets the default value for {@link org.apache.commons.pool2.impl.GenericObjectPool 878 * GenericObjectPool#getTimeBetweenEvictionRunsMillis ()} for each per user pool. 879 * 880 * @param timeBetweenEvictionRunsMillis 881 * The default value for {@link org.apache.commons.pool2.impl.GenericObjectPool 882 * GenericObjectPool#getTimeBetweenEvictionRunsMillis ()} for each per user pool. 883 */ 884 public void setDefaultTimeBetweenEvictionRunsMillis(final long timeBetweenEvictionRunsMillis) { 885 assertInitializationAllowed(); 886 this.defaultTimeBetweenEvictionRunsMillis = timeBetweenEvictionRunsMillis; 887 } 888 889 /** 890 * Sets the value of defaultTransactionIsolation, which defines the state of connections handed out from this pool. 891 * The value can be changed on the Connection using Connection.setTransactionIsolation(int). The default is JDBC 892 * driver dependent. 893 * 894 * @param defaultTransactionIsolation 895 * Value to assign to defaultTransactionIsolation 896 */ 897 public void setDefaultTransactionIsolation(final int defaultTransactionIsolation) { 898 assertInitializationAllowed(); 899 switch (defaultTransactionIsolation) { 900 case Connection.TRANSACTION_NONE: 901 case Connection.TRANSACTION_READ_COMMITTED: 902 case Connection.TRANSACTION_READ_UNCOMMITTED: 903 case Connection.TRANSACTION_REPEATABLE_READ: 904 case Connection.TRANSACTION_SERIALIZABLE: 905 break; 906 default: 907 throw new IllegalArgumentException(BAD_TRANSACTION_ISOLATION); 908 } 909 this.defaultTransactionIsolation = defaultTransactionIsolation; 910 } 911 912 /** 913 * Sets the description. This property is defined by JDBC as for use with GUI (or other) tools that might deploy the 914 * datasource. It serves no internal purpose. 915 * 916 * @param description 917 * Value to assign to description. 918 */ 919 public void setDescription(final String description) { 920 this.description = description; 921 } 922 923 /** 924 * Sets the JNDI environment to be used when instantiating a JNDI InitialContext. This InitialContext is used to 925 * locate the back end ConnectionPoolDataSource. 926 * 927 * @param properties 928 * the JNDI environment property to set which will overwrite any current settings 929 */ 930 void setJndiEnvironment(final Properties properties) { 931 if (jndiEnvironment == null) { 932 jndiEnvironment = new Properties(); 933 } else { 934 jndiEnvironment.clear(); 935 } 936 jndiEnvironment.putAll(properties); 937 } 938 939 /** 940 * Sets the value of the given JNDI environment property to be used when instantiating a JNDI InitialContext. This 941 * InitialContext is used to locate the back end ConnectionPoolDataSource. 942 * 943 * @param key 944 * the JNDI environment property to set. 945 * @param value 946 * the value assigned to specified JNDI environment property. 947 */ 948 public void setJndiEnvironment(final String key, final String value) { 949 if (jndiEnvironment == null) { 950 jndiEnvironment = new Properties(); 951 } 952 jndiEnvironment.setProperty(key, value); 953 } 954 955 /** 956 * Sets the value of loginTimeout. 957 * 958 * @param loginTimeout 959 * Value to assign to loginTimeout. 960 */ 961 @Override 962 public void setLoginTimeout(final int loginTimeout) { 963 this.loginTimeout = loginTimeout; 964 } 965 966 /** 967 * Sets the value of logWriter. 968 * 969 * @param logWriter 970 * Value to assign to logWriter. 971 */ 972 @Override 973 public void setLogWriter(final PrintWriter logWriter) { 974 this.logWriter = logWriter; 975 } 976 977 /** 978 * <p> 979 * Sets the maximum permitted lifetime of a connection. A value of zero or less indicates an 980 * infinite lifetime. 981 * </p> 982 * <p> 983 * Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first 984 * time one of the following methods is invoked: <code>getConnection, setLogwriter, 985 * setLoginTimeout, getLoginTimeout, getLogWriter.</code> 986 * </p> 987 * 988 * @param maxConnLifetimeMillis 989 * The maximum permitted lifetime of a connection. A value of zero or less indicates an 990 * infinite lifetime. 991 * @since 2.9.0 992 */ 993 public void setMaxConnLifetime(final Duration maxConnLifetimeMillis) { 994 this.maxConnLifetimeMillis = maxConnLifetimeMillis; 995 } 996 997 /** 998 * <p> 999 * Sets the maximum permitted lifetime of a connection in milliseconds. A value of zero or less indicates an 1000 * infinite lifetime. 1001 * </p> 1002 * <p> 1003 * Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first 1004 * time one of the following methods is invoked: <code>getConnection, setLogwriter, 1005 * setLoginTimeout, getLoginTimeout, getLogWriter.</code> 1006 * </p> 1007 * 1008 * @param maxConnLifetimeMillis 1009 * The maximum permitted lifetime of a connection in milliseconds. A value of zero or less indicates an 1010 * infinite lifetime. 1011 * @deprecated Use {@link #setMaxConnLifetime(Duration)}. 1012 */ 1013 @Deprecated 1014 public void setMaxConnLifetimeMillis(final long maxConnLifetimeMillis) { 1015 setMaxConnLifetime(Duration.ofMillis(maxConnLifetimeMillis)); 1016 } 1017 1018 /** 1019 * Whether a rollback will be issued after executing the SQL query that will be used to validate connections from 1020 * this pool before returning them to the caller. Default behavior is NOT to issue a rollback. The setting will only 1021 * have an effect if a validation query is set 1022 * 1023 * @param rollbackAfterValidation 1024 * new property value 1025 */ 1026 public void setRollbackAfterValidation(final boolean rollbackAfterValidation) { 1027 assertInitializationAllowed(); 1028 this.rollbackAfterValidation = rollbackAfterValidation; 1029 } 1030 1031 protected abstract void setupDefaults(Connection connection, String userName) throws SQLException; 1032 1033 /** 1034 * Sets the SQL query that will be used to validate connections from this pool before returning them to the caller. 1035 * If specified, this query <strong>MUST</strong> be an SQL SELECT statement that returns at least one row. If not 1036 * specified, connections will be validated using {@link Connection#isValid(int)}. 1037 * 1038 * @param validationQuery 1039 * The SQL query that will be used to validate connections from this pool before returning them to the 1040 * caller. 1041 */ 1042 public void setValidationQuery(final String validationQuery) { 1043 assertInitializationAllowed(); 1044 this.validationQuery = validationQuery; 1045 } 1046 1047 /** 1048 * Sets the timeout in seconds before the validation query fails. 1049 * 1050 * @param validationQueryTimeoutSeconds 1051 * The new timeout in seconds 1052 */ 1053 public void setValidationQueryTimeout(final int validationQueryTimeoutSeconds) { 1054 this.validationQueryTimeoutSeconds = validationQueryTimeoutSeconds; 1055 } 1056 1057 protected ConnectionPoolDataSource testCPDS(final String userName, final String userPassword) 1058 throws javax.naming.NamingException, SQLException { 1059 // The source of physical db connections 1060 ConnectionPoolDataSource cpds = this.dataSource; 1061 if (cpds == null) { 1062 Context ctx = null; 1063 if (jndiEnvironment == null) { 1064 ctx = new InitialContext(); 1065 } else { 1066 ctx = new InitialContext(jndiEnvironment); 1067 } 1068 final Object ds = ctx.lookup(dataSourceName); 1069 if (!(ds instanceof ConnectionPoolDataSource)) { 1070 throw new SQLException("Illegal configuration: " + "DataSource " + dataSourceName + " (" 1071 + ds.getClass().getName() + ")" + " doesn't implement javax.sql.ConnectionPoolDataSource"); 1072 } 1073 cpds = (ConnectionPoolDataSource) ds; 1074 } 1075 1076 // try to get a connection with the supplied userName/password 1077 PooledConnection conn = null; 1078 try { 1079 if (userName != null) { 1080 conn = cpds.getPooledConnection(userName, userPassword); 1081 } else { 1082 conn = cpds.getPooledConnection(); 1083 } 1084 if (conn == null) { 1085 throw new SQLException("Cannot connect using the supplied userName/password"); 1086 } 1087 } finally { 1088 if (conn != null) { 1089 try { 1090 conn.close(); 1091 } catch (final SQLException e) { 1092 // at least we could connect 1093 } 1094 } 1095 } 1096 return cpds; 1097 } 1098 1099 /** 1100 * @since 2.6.0 1101 */ 1102 @Override 1103 public synchronized String toString() { 1104 final StringBuilder builder = new StringBuilder(super.toString()); 1105 builder.append("["); 1106 toStringFields(builder); 1107 builder.append("]"); 1108 return builder.toString(); 1109 } 1110 1111 protected void toStringFields(final StringBuilder builder) { 1112 builder.append("getConnectionCalled="); 1113 builder.append(getConnectionCalled); 1114 builder.append(", dataSource="); 1115 builder.append(dataSource); 1116 builder.append(", dataSourceName="); 1117 builder.append(dataSourceName); 1118 builder.append(", description="); 1119 builder.append(description); 1120 builder.append(", jndiEnvironment="); 1121 builder.append(jndiEnvironment); 1122 builder.append(", loginTimeout="); 1123 builder.append(loginTimeout); 1124 builder.append(", logWriter="); 1125 builder.append(logWriter); 1126 builder.append(", instanceKey="); 1127 builder.append(instanceKey); 1128 builder.append(", defaultBlockWhenExhausted="); 1129 builder.append(defaultBlockWhenExhausted); 1130 builder.append(", defaultEvictionPolicyClassName="); 1131 builder.append(defaultEvictionPolicyClassName); 1132 builder.append(", defaultLifo="); 1133 builder.append(defaultLifo); 1134 builder.append(", defaultMaxIdle="); 1135 builder.append(defaultMaxIdle); 1136 builder.append(", defaultMaxTotal="); 1137 builder.append(defaultMaxTotal); 1138 builder.append(", defaultMaxWait="); 1139 builder.append(defaultMaxWaitDuration); 1140 builder.append(", defaultMinEvictableIdleTimeMillis="); 1141 builder.append(defaultMinEvictableIdleTimeMillis); 1142 builder.append(", defaultMinIdle="); 1143 builder.append(defaultMinIdle); 1144 builder.append(", defaultNumTestsPerEvictionRun="); 1145 builder.append(defaultNumTestsPerEvictionRun); 1146 builder.append(", defaultSoftMinEvictableIdleTimeMillis="); 1147 builder.append(defaultSoftMinEvictableIdleTimeMillis); 1148 builder.append(", defaultTestOnCreate="); 1149 builder.append(defaultTestOnCreate); 1150 builder.append(", defaultTestOnBorrow="); 1151 builder.append(defaultTestOnBorrow); 1152 builder.append(", defaultTestOnReturn="); 1153 builder.append(defaultTestOnReturn); 1154 builder.append(", defaultTestWhileIdle="); 1155 builder.append(defaultTestWhileIdle); 1156 builder.append(", defaultTimeBetweenEvictionRunsMillis="); 1157 builder.append(defaultTimeBetweenEvictionRunsMillis); 1158 builder.append(", validationQuery="); 1159 builder.append(validationQuery); 1160 builder.append(", validationQueryTimeoutSeconds="); 1161 builder.append(validationQueryTimeoutSeconds); 1162 builder.append(", rollbackAfterValidation="); 1163 builder.append(rollbackAfterValidation); 1164 builder.append(", maxConnLifetimeMillis="); 1165 builder.append(maxConnLifetimeMillis); 1166 builder.append(", defaultAutoCommit="); 1167 builder.append(defaultAutoCommit); 1168 builder.append(", defaultTransactionIsolation="); 1169 builder.append(defaultTransactionIsolation); 1170 builder.append(", defaultReadOnly="); 1171 builder.append(defaultReadOnly); 1172 } 1173 1174 @Override 1175 @SuppressWarnings("unchecked") 1176 public <T> T unwrap(final Class<T> iface) throws SQLException { 1177 if (isWrapperFor(iface)) { 1178 return (T) this; 1179 } 1180 throw new SQLException(this + " is not a wrapper for " + iface); 1181 } 1182 /* JDBC_4_ANT_KEY_END */ 1183}