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