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