001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.commons.dbcp2.datasources; 018 019import java.io.IOException; 020import java.io.ObjectInputStream; 021import java.sql.Connection; 022import java.sql.SQLException; 023import java.util.HashMap; 024import java.util.Map; 025import java.util.NoSuchElementException; 026 027import javax.naming.NamingException; 028import javax.naming.Reference; 029import javax.naming.StringRefAddr; 030import javax.sql.ConnectionPoolDataSource; 031 032import org.apache.commons.dbcp2.SwallowedExceptionLogger; 033import org.apache.commons.dbcp2.Utils; 034import org.apache.commons.logging.Log; 035import org.apache.commons.logging.LogFactory; 036import org.apache.commons.pool2.ObjectPool; 037import org.apache.commons.pool2.impl.GenericObjectPool; 038 039/** 040 * <p> 041 * A pooling <code>DataSource</code> appropriate for deployment within J2EE environment. There are many configuration 042 * options, most of which are defined in the parent class. This datasource uses individual pools per user, and some 043 * properties can be set specifically for a given user, if the deployment environment can support initialization of 044 * mapped properties. So for example, a pool of admin or write-access Connections can be guaranteed a certain number of 045 * connections, separate from a maximum set for users with read-only connections. 046 * </p> 047 * 048 * <p> 049 * User passwords can be changed without re-initializing the datasource. When a 050 * <code>getConnection(userName, password)</code> request is processed with a password that is different from those used 051 * to create connections in the pool associated with <code>userName</code>, an attempt is made to create a new 052 * connection using the supplied password and if this succeeds, the existing pool is cleared and a new pool is created 053 * for connections using the new password. 054 * </p> 055 * 056 * @since 2.0 057 */ 058public class PerUserPoolDataSource extends InstanceKeyDataSource { 059 060 private static final long serialVersionUID = 7872747993848065028L; 061 062 private static final Log log = LogFactory.getLog(PerUserPoolDataSource.class); 063 064 // Per user pool properties 065 private Map<String, Boolean> perUserBlockWhenExhausted; 066 private Map<String, String> perUserEvictionPolicyClassName; 067 private Map<String, Boolean> perUserLifo; 068 private Map<String, Integer> perUserMaxIdle; 069 private Map<String, Integer> perUserMaxTotal; 070 private Map<String, Long> perUserMaxWaitMillis; 071 private Map<String, Long> perUserMinEvictableIdleTimeMillis; 072 private Map<String, Integer> perUserMinIdle; 073 private Map<String, Integer> perUserNumTestsPerEvictionRun; 074 private Map<String, Long> perUserSoftMinEvictableIdleTimeMillis; 075 private Map<String, Boolean> perUserTestOnCreate; 076 private Map<String, Boolean> perUserTestOnBorrow; 077 private Map<String, Boolean> perUserTestOnReturn; 078 private Map<String, Boolean> perUserTestWhileIdle; 079 private Map<String, Long> perUserTimeBetweenEvictionRunsMillis; 080 081 // Per user connection properties 082 private Map<String, Boolean> perUserDefaultAutoCommit; 083 private Map<String, Integer> perUserDefaultTransactionIsolation; 084 private Map<String, Boolean> perUserDefaultReadOnly; 085 086 /** 087 * Map to keep track of Pools for a given user. 088 */ 089 private transient Map<PoolKey, PooledConnectionManager> managers = new HashMap<>(); 090 091 /** 092 * Default no-arg constructor for Serialization. 093 */ 094 public PerUserPoolDataSource() { 095 } 096 097 /** 098 * Clears pool(s) maintained by this data source. 099 * 100 * @see org.apache.commons.pool2.ObjectPool#clear() 101 * @since 2.3.0 102 */ 103 public void clear() { 104 for (final PooledConnectionManager manager : managers.values()) { 105 try { 106 getCPDSConnectionFactoryPool(manager).clear(); 107 } catch (final Exception closePoolException) { 108 // ignore and try to close others. 109 } 110 } 111 InstanceKeyDataSourceFactory.removeInstance(getInstanceKey()); 112 } 113 114 /** 115 * Closes pool(s) maintained by this data source. 116 * 117 * @see org.apache.commons.pool2.ObjectPool#close() 118 */ 119 @SuppressWarnings("resource") 120 @Override 121 public void close() { 122 for (final PooledConnectionManager manager : managers.values()) { 123 Utils.closeQuietly(getCPDSConnectionFactoryPool(manager)); 124 } 125 InstanceKeyDataSourceFactory.removeInstance(getInstanceKey()); 126 } 127 128 private HashMap<String, Boolean> createMap() { 129 // Should there be a default size different than what this ctor provides? 130 return new HashMap<>(); 131 } 132 133 @Override 134 protected PooledConnectionManager getConnectionManager(final UserPassKey upKey) { 135 return managers.get(getPoolKey(upKey.getUserName())); 136 } 137 138 private ObjectPool<PooledConnectionAndInfo> getCPDSConnectionFactoryPool(final PooledConnectionManager manager) { 139 return ((CPDSConnectionFactory) manager).getPool(); 140 } 141 142 /** 143 * Gets the number of active connections in the default pool. 144 * 145 * @return The number of active connections in the default pool. 146 */ 147 public int getNumActive() { 148 return getNumActive(null); 149 } 150 151 /** 152 * Gets the number of active connections in the pool for a given user. 153 * 154 * @param userName 155 * The user name key. 156 * @return The user specific value. 157 */ 158 @SuppressWarnings("resource") 159 public int getNumActive(final String userName) { 160 final ObjectPool<PooledConnectionAndInfo> pool = getPool(getPoolKey(userName)); 161 return pool == null ? 0 : pool.getNumActive(); 162 } 163 164 /** 165 * Gets the number of idle connections in the default pool. 166 * 167 * @return The number of idle connections in the default pool. 168 */ 169 public int getNumIdle() { 170 return getNumIdle(null); 171 } 172 173 /** 174 * Gets the number of idle connections in the pool for a given user. 175 * 176 * @param userName 177 * The user name key. 178 * @return The user specific value. 179 */ 180 @SuppressWarnings("resource") 181 public int getNumIdle(final String userName) { 182 final ObjectPool<PooledConnectionAndInfo> pool = getPool(getPoolKey(userName)); 183 return pool == null ? 0 : pool.getNumIdle(); 184 } 185 186 /** 187 * Gets the user specific value for {@link GenericObjectPool#getBlockWhenExhausted()} for the specified user's pool 188 * or the default if no user specific value is defined. 189 * 190 * @param userName 191 * The user name key. 192 * @return The user specific value. 193 */ 194 public boolean getPerUserBlockWhenExhausted(final String userName) { 195 Boolean value = null; 196 if (perUserBlockWhenExhausted != null) { 197 value = perUserBlockWhenExhausted.get(userName); 198 } 199 if (value == null) { 200 return getDefaultBlockWhenExhausted(); 201 } 202 return value; 203 } 204 205 /** 206 * Gets the user specific default value for {@link Connection#setAutoCommit(boolean)} for the specified user's pool. 207 * 208 * @param userName 209 * The user name key. 210 * @return The user specific value. 211 */ 212 public Boolean getPerUserDefaultAutoCommit(final String userName) { 213 Boolean value = null; 214 if (perUserDefaultAutoCommit != null) { 215 value = perUserDefaultAutoCommit.get(userName); 216 } 217 return value; 218 } 219 220 /** 221 * Gets the user specific default value for {@link Connection#setReadOnly(boolean)} for the specified user's pool. 222 * 223 * @param userName 224 * The user name key. 225 * @return The user specific value. 226 */ 227 public Boolean getPerUserDefaultReadOnly(final String userName) { 228 Boolean value = null; 229 if (perUserDefaultReadOnly != null) { 230 value = perUserDefaultReadOnly.get(userName); 231 } 232 return value; 233 } 234 235 /** 236 * Gets the user specific default value for {@link Connection#setTransactionIsolation(int)} for the specified user's 237 * pool. 238 * 239 * @param userName 240 * The user name key. 241 * @return The user specific value. 242 */ 243 public Integer getPerUserDefaultTransactionIsolation(final String userName) { 244 Integer value = null; 245 if (perUserDefaultTransactionIsolation != null) { 246 value = perUserDefaultTransactionIsolation.get(userName); 247 } 248 return value; 249 } 250 251 /** 252 * Gets the user specific value for {@link GenericObjectPool#getEvictionPolicyClassName()} for the specified user's 253 * pool or the default if no user specific value is defined. 254 * 255 * @param userName 256 * The user name key. 257 * @return The user specific value. 258 */ 259 public String getPerUserEvictionPolicyClassName(final String userName) { 260 String value = null; 261 if (perUserEvictionPolicyClassName != null) { 262 value = perUserEvictionPolicyClassName.get(userName); 263 } 264 if (value == null) { 265 return getDefaultEvictionPolicyClassName(); 266 } 267 return value; 268 } 269 270 /** 271 * Gets the user specific value for {@link GenericObjectPool#getLifo()} for the specified user's pool or the default 272 * if no user specific value is defined. 273 * 274 * @param userName 275 * The user name key. 276 * @return The user specific value. 277 */ 278 public boolean getPerUserLifo(final String userName) { 279 Boolean value = null; 280 if (perUserLifo != null) { 281 value = perUserLifo.get(userName); 282 } 283 if (value == null) { 284 return getDefaultLifo(); 285 } 286 return value; 287 } 288 289 /** 290 * Gets the user specific value for {@link GenericObjectPool#getMaxIdle()} for the specified user's pool or the 291 * default if no user specific value is defined. 292 * 293 * @param userName 294 * The user name key. 295 * @return The user specific value. 296 */ 297 public int getPerUserMaxIdle(final String userName) { 298 Integer value = null; 299 if (perUserMaxIdle != null) { 300 value = perUserMaxIdle.get(userName); 301 } 302 if (value == null) { 303 return getDefaultMaxIdle(); 304 } 305 return value; 306 } 307 308 /** 309 * Gets the user specific value for {@link GenericObjectPool#getMaxTotal()} for the specified user's pool or the 310 * default if no user specific value is defined. 311 * 312 * @param userName 313 * The user name key. 314 * @return The user specific value. 315 */ 316 public int getPerUserMaxTotal(final String userName) { 317 Integer value = null; 318 if (perUserMaxTotal != null) { 319 value = perUserMaxTotal.get(userName); 320 } 321 if (value == null) { 322 return getDefaultMaxTotal(); 323 } 324 return value; 325 } 326 327 /** 328 * Gets the user specific value for {@link GenericObjectPool#getMaxWaitMillis()} for the specified user's pool or 329 * the default if no user specific value is defined. 330 * 331 * @param userName 332 * The user name key. 333 * @return The user specific value. 334 */ 335 public long getPerUserMaxWaitMillis(final String userName) { 336 Long value = null; 337 if (perUserMaxWaitMillis != null) { 338 value = perUserMaxWaitMillis.get(userName); 339 } 340 if (value == null) { 341 return getDefaultMaxWaitMillis(); 342 } 343 return value; 344 } 345 346 /** 347 * Gets the user specific value for {@link GenericObjectPool#getMinEvictableIdleTime()} for the specified 348 * user's pool or the default if no user specific value is defined. 349 * 350 * @param userName 351 * The user name key. 352 * @return The user specific value. 353 */ 354 public long getPerUserMinEvictableIdleTimeMillis(final String userName) { 355 Long value = null; 356 if (perUserMinEvictableIdleTimeMillis != null) { 357 value = perUserMinEvictableIdleTimeMillis.get(userName); 358 } 359 if (value == null) { 360 return getDefaultMinEvictableIdleTimeMillis(); 361 } 362 return value; 363 } 364 365 /** 366 * Gets the user specific value for {@link GenericObjectPool#getMinIdle()} for the specified user's pool or the 367 * default if no user specific value is defined. 368 * 369 * @param userName 370 * The user name key. 371 * @return The user specific value. 372 */ 373 public int getPerUserMinIdle(final String userName) { 374 Integer value = null; 375 if (perUserMinIdle != null) { 376 value = perUserMinIdle.get(userName); 377 } 378 if (value == null) { 379 return getDefaultMinIdle(); 380 } 381 return value; 382 } 383 384 /** 385 * Gets the user specific value for {@link GenericObjectPool#getNumTestsPerEvictionRun()} for the specified user's 386 * pool or the default if no user specific value is defined. 387 * 388 * @param userName 389 * The user name key. 390 * @return The user specific value. 391 */ 392 public int getPerUserNumTestsPerEvictionRun(final String userName) { 393 Integer value = null; 394 if (perUserNumTestsPerEvictionRun != null) { 395 value = perUserNumTestsPerEvictionRun.get(userName); 396 } 397 if (value == null) { 398 return getDefaultNumTestsPerEvictionRun(); 399 } 400 return value; 401 } 402 403 /** 404 * Gets the user specific value for {@link GenericObjectPool#getSoftMinEvictableIdleTime()} for the specified 405 * user's pool or the default if no user specific value is defined. 406 * 407 * @param userName 408 * The user name key. 409 * @return The user specific value. 410 */ 411 public long getPerUserSoftMinEvictableIdleTimeMillis(final String userName) { 412 Long value = null; 413 if (perUserSoftMinEvictableIdleTimeMillis != null) { 414 value = perUserSoftMinEvictableIdleTimeMillis.get(userName); 415 } 416 if (value == null) { 417 return getDefaultSoftMinEvictableIdleTimeMillis(); 418 } 419 return value; 420 } 421 422 /** 423 * Gets the user specific value for {@link GenericObjectPool#getTestOnBorrow()} for the specified user's pool or the 424 * default if no user specific value is defined. 425 * 426 * @param userName 427 * The user name key. 428 * @return The user specific value. 429 */ 430 public boolean getPerUserTestOnBorrow(final String userName) { 431 Boolean value = null; 432 if (perUserTestOnBorrow != null) { 433 value = perUserTestOnBorrow.get(userName); 434 } 435 if (value == null) { 436 return getDefaultTestOnBorrow(); 437 } 438 return value; 439 } 440 441 /** 442 * Gets the user specific value for {@link GenericObjectPool#getTestOnCreate()} for the specified user's pool or the 443 * default if no user specific value is defined. 444 * 445 * @param userName 446 * The user name key. 447 * @return The user specific value. 448 */ 449 public boolean getPerUserTestOnCreate(final String userName) { 450 Boolean value = null; 451 if (perUserTestOnCreate != null) { 452 value = perUserTestOnCreate.get(userName); 453 } 454 if (value == null) { 455 return getDefaultTestOnCreate(); 456 } 457 return value; 458 } 459 460 /** 461 * Gets the user specific value for {@link GenericObjectPool#getTestOnReturn()} for the specified user's pool or the 462 * default if no user specific value is defined. 463 * 464 * @param userName 465 * The user name key. 466 * @return The user specific value. 467 */ 468 public boolean getPerUserTestOnReturn(final String userName) { 469 Boolean value = null; 470 if (perUserTestOnReturn != null) { 471 value = perUserTestOnReturn.get(userName); 472 } 473 if (value == null) { 474 return getDefaultTestOnReturn(); 475 } 476 return value; 477 } 478 479 /** 480 * Gets the user specific value for {@link GenericObjectPool#getTestWhileIdle()} for the specified user's pool or 481 * the default if no user specific value is defined. 482 * 483 * @param userName 484 * The user name key. 485 * @return The user specific value. 486 */ 487 public boolean getPerUserTestWhileIdle(final String userName) { 488 Boolean value = null; 489 if (perUserTestWhileIdle != null) { 490 value = perUserTestWhileIdle.get(userName); 491 } 492 if (value == null) { 493 return getDefaultTestWhileIdle(); 494 } 495 return value; 496 } 497 498 /** 499 * Gets the user specific value for {@link GenericObjectPool#getTimeBetweenEvictionRuns()} for the specified 500 * user's pool or the default if no user specific value is defined. 501 * 502 * @param userName 503 * The user name key. 504 * @return The user specific value. 505 */ 506 public long getPerUserTimeBetweenEvictionRunsMillis(final String userName) { 507 Long value = null; 508 if (perUserTimeBetweenEvictionRunsMillis != null) { 509 value = perUserTimeBetweenEvictionRunsMillis.get(userName); 510 } 511 if (value == null) { 512 return getDefaultTimeBetweenEvictionRunsMillis(); 513 } 514 return value; 515 } 516 517 /** 518 * Returns the object pool associated with the given PoolKey. 519 * 520 * @param poolKey 521 * PoolKey identifying the pool 522 * @return the GenericObjectPool pooling connections for the userName and datasource specified by the PoolKey 523 */ 524 private ObjectPool<PooledConnectionAndInfo> getPool(final PoolKey poolKey) { 525 final CPDSConnectionFactory mgr = (CPDSConnectionFactory) managers.get(poolKey); 526 return mgr == null ? null : mgr.getPool(); 527 } 528 529 @Override 530 protected PooledConnectionAndInfo getPooledConnectionAndInfo(final String userName, final String password) 531 throws SQLException { 532 533 final PoolKey key = getPoolKey(userName); 534 ObjectPool<PooledConnectionAndInfo> pool; 535 PooledConnectionManager manager; 536 synchronized (this) { 537 manager = managers.get(key); 538 if (manager == null) { 539 try { 540 registerPool(userName, password); 541 manager = managers.get(key); 542 } catch (final NamingException e) { 543 throw new SQLException("RegisterPool failed", e); 544 } 545 } 546 pool = getCPDSConnectionFactoryPool(manager); 547 } 548 549 PooledConnectionAndInfo info = null; 550 try { 551 info = pool.borrowObject(); 552 } catch (final NoSuchElementException ex) { 553 throw new SQLException("Could not retrieve connection info from pool", ex); 554 } catch (final Exception e) { 555 // See if failure is due to CPDSConnectionFactory authentication failure 556 try { 557 testCPDS(userName, password); 558 } catch (final Exception ex) { 559 throw new SQLException("Could not retrieve connection info from pool", ex); 560 } 561 // New password works, so kill the old pool, create a new one, and borrow 562 manager.closePool(userName); 563 synchronized (this) { 564 managers.remove(key); 565 } 566 try { 567 registerPool(userName, password); 568 pool = getPool(key); 569 } catch (final NamingException ne) { 570 throw new SQLException("RegisterPool failed", ne); 571 } 572 try { 573 info = pool.borrowObject(); 574 } catch (final Exception ex) { 575 throw new SQLException("Could not retrieve connection info from pool", ex); 576 } 577 } 578 return info; 579 } 580 581 /** 582 * Creates a pool key from the provided parameters. 583 * 584 * @param userName 585 * User name 586 * @return The pool key 587 */ 588 private PoolKey getPoolKey(final String userName) { 589 return new PoolKey(getDataSourceName(), userName); 590 } 591 592 /** 593 * Returns a <code>PerUserPoolDataSource</code> {@link Reference}. 594 */ 595 @Override 596 public Reference getReference() throws NamingException { 597 final Reference ref = new Reference(getClass().getName(), PerUserPoolDataSourceFactory.class.getName(), null); 598 ref.add(new StringRefAddr("instanceKey", getInstanceKey())); 599 return ref; 600 } 601 602 /** 603 * Supports Serialization interface. 604 * 605 * @param in 606 * a <code>java.io.ObjectInputStream</code> value 607 * @throws IOException 608 * if an error occurs 609 * @throws ClassNotFoundException 610 * if an error occurs 611 */ 612 private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException { 613 try { 614 in.defaultReadObject(); 615 final PerUserPoolDataSource oldDS = (PerUserPoolDataSource) new PerUserPoolDataSourceFactory() 616 .getObjectInstance(getReference(), null, null, null); 617 this.managers = oldDS.managers; 618 } catch (final NamingException e) { 619 throw new IOException("NamingException: " + e); 620 } 621 } 622 623 private synchronized void registerPool(final String userName, final String password) 624 throws NamingException, SQLException { 625 626 final ConnectionPoolDataSource cpds = testCPDS(userName, password); 627 628 // Set up the factory we will use (passing the pool associates 629 // the factory with the pool, so we do not have to do so 630 // explicitly) 631 final CPDSConnectionFactory factory = new CPDSConnectionFactory(cpds, getValidationQuery(), 632 getValidationQueryTimeout(), isRollbackAfterValidation(), userName, password); 633 factory.setMaxConnLifetime(getMaxConnLifetime()); 634 635 // Create an object pool to contain our PooledConnections 636 final GenericObjectPool<PooledConnectionAndInfo> pool = new GenericObjectPool<>(factory); 637 factory.setPool(pool); 638 pool.setBlockWhenExhausted(getPerUserBlockWhenExhausted(userName)); 639 pool.setEvictionPolicyClassName(getPerUserEvictionPolicyClassName(userName)); 640 pool.setLifo(getPerUserLifo(userName)); 641 pool.setMaxIdle(getPerUserMaxIdle(userName)); 642 pool.setMaxTotal(getPerUserMaxTotal(userName)); 643 pool.setMaxWaitMillis(getPerUserMaxWaitMillis(userName)); 644 pool.setMinEvictableIdleTimeMillis(getPerUserMinEvictableIdleTimeMillis(userName)); 645 pool.setMinIdle(getPerUserMinIdle(userName)); 646 pool.setNumTestsPerEvictionRun(getPerUserNumTestsPerEvictionRun(userName)); 647 pool.setSoftMinEvictableIdleTimeMillis(getPerUserSoftMinEvictableIdleTimeMillis(userName)); 648 pool.setTestOnCreate(getPerUserTestOnCreate(userName)); 649 pool.setTestOnBorrow(getPerUserTestOnBorrow(userName)); 650 pool.setTestOnReturn(getPerUserTestOnReturn(userName)); 651 pool.setTestWhileIdle(getPerUserTestWhileIdle(userName)); 652 pool.setTimeBetweenEvictionRunsMillis(getPerUserTimeBetweenEvictionRunsMillis(userName)); 653 654 pool.setSwallowedExceptionListener(new SwallowedExceptionLogger(log)); 655 656 final Object old = managers.put(getPoolKey(userName), factory); 657 if (old != null) { 658 throw new IllegalStateException("Pool already contains an entry for this user/password: " + userName); 659 } 660 } 661 662 void setPerUserBlockWhenExhausted(final Map<String, Boolean> userDefaultBlockWhenExhausted) { 663 assertInitializationAllowed(); 664 if (perUserBlockWhenExhausted == null) { 665 perUserBlockWhenExhausted = createMap(); 666 } else { 667 perUserBlockWhenExhausted.clear(); 668 } 669 perUserBlockWhenExhausted.putAll(userDefaultBlockWhenExhausted); 670 } 671 672 /** 673 * Sets a user specific value for {@link GenericObjectPool#getBlockWhenExhausted()} for the specified user's pool. 674 * 675 * @param userName 676 * The user name key. 677 * @param value 678 * The user specific value. 679 */ 680 public void setPerUserBlockWhenExhausted(final String userName, final Boolean value) { 681 assertInitializationAllowed(); 682 if (perUserBlockWhenExhausted == null) { 683 perUserBlockWhenExhausted = createMap(); 684 } 685 perUserBlockWhenExhausted.put(userName, value); 686 } 687 688 void setPerUserDefaultAutoCommit(final Map<String, Boolean> userDefaultAutoCommit) { 689 assertInitializationAllowed(); 690 if (perUserDefaultAutoCommit == null) { 691 perUserDefaultAutoCommit = createMap(); 692 } else { 693 perUserDefaultAutoCommit.clear(); 694 } 695 perUserDefaultAutoCommit.putAll(userDefaultAutoCommit); 696 } 697 698 /** 699 * Sets a user specific default value for {@link Connection#setAutoCommit(boolean)} for the specified user's pool. 700 * 701 * @param userName 702 * The user name key. 703 * @param value 704 * The user specific value. 705 */ 706 public void setPerUserDefaultAutoCommit(final String userName, final Boolean value) { 707 assertInitializationAllowed(); 708 if (perUserDefaultAutoCommit == null) { 709 perUserDefaultAutoCommit = createMap(); 710 } 711 perUserDefaultAutoCommit.put(userName, value); 712 } 713 714 void setPerUserDefaultReadOnly(final Map<String, Boolean> userDefaultReadOnly) { 715 assertInitializationAllowed(); 716 if (perUserDefaultReadOnly == null) { 717 perUserDefaultReadOnly = createMap(); 718 } else { 719 perUserDefaultReadOnly.clear(); 720 } 721 perUserDefaultReadOnly.putAll(userDefaultReadOnly); 722 } 723 724 /** 725 * Sets a user specific default value for {@link Connection#setReadOnly(boolean)} for the specified user's pool. 726 * 727 * @param userName 728 * The user name key. 729 * @param value 730 * The user specific value. 731 */ 732 public void setPerUserDefaultReadOnly(final String userName, final Boolean value) { 733 assertInitializationAllowed(); 734 if (perUserDefaultReadOnly == null) { 735 perUserDefaultReadOnly = createMap(); 736 } 737 perUserDefaultReadOnly.put(userName, value); 738 } 739 740 void setPerUserDefaultTransactionIsolation(final Map<String, Integer> userDefaultTransactionIsolation) { 741 assertInitializationAllowed(); 742 if (perUserDefaultTransactionIsolation == null) { 743 perUserDefaultTransactionIsolation = new HashMap<>(); 744 } else { 745 perUserDefaultTransactionIsolation.clear(); 746 } 747 perUserDefaultTransactionIsolation.putAll(userDefaultTransactionIsolation); 748 } 749 750 /** 751 * Sets a user specific default value for {@link Connection#setTransactionIsolation(int)} for the specified user's 752 * pool. 753 * 754 * @param userName 755 * The user name key. 756 * @param value 757 * The user specific value. 758 */ 759 public void setPerUserDefaultTransactionIsolation(final String userName, final Integer value) { 760 assertInitializationAllowed(); 761 if (perUserDefaultTransactionIsolation == null) { 762 perUserDefaultTransactionIsolation = new HashMap<>(); 763 } 764 perUserDefaultTransactionIsolation.put(userName, value); 765 } 766 767 void setPerUserEvictionPolicyClassName(final Map<String, String> userDefaultEvictionPolicyClassName) { 768 assertInitializationAllowed(); 769 if (perUserEvictionPolicyClassName == null) { 770 perUserEvictionPolicyClassName = new HashMap<>(); 771 } else { 772 perUserEvictionPolicyClassName.clear(); 773 } 774 perUserEvictionPolicyClassName.putAll(userDefaultEvictionPolicyClassName); 775 } 776 777 /** 778 * Sets a user specific value for {@link GenericObjectPool#getEvictionPolicyClassName()} for the specified user's 779 * pool. 780 * 781 * @param userName 782 * The user name key. 783 * @param value 784 * The user specific value. 785 */ 786 public void setPerUserEvictionPolicyClassName(final String userName, final String value) { 787 assertInitializationAllowed(); 788 if (perUserEvictionPolicyClassName == null) { 789 perUserEvictionPolicyClassName = new HashMap<>(); 790 } 791 perUserEvictionPolicyClassName.put(userName, value); 792 } 793 794 void setPerUserLifo(final Map<String, Boolean> userDefaultLifo) { 795 assertInitializationAllowed(); 796 if (perUserLifo == null) { 797 perUserLifo = createMap(); 798 } else { 799 perUserLifo.clear(); 800 } 801 perUserLifo.putAll(userDefaultLifo); 802 } 803 804 /** 805 * Sets a user specific value for {@link GenericObjectPool#getLifo()} for the specified user's pool. 806 * 807 * @param userName 808 * The user name key. 809 * @param value 810 * The user specific value. 811 */ 812 public void setPerUserLifo(final String userName, final Boolean value) { 813 assertInitializationAllowed(); 814 if (perUserLifo == null) { 815 perUserLifo = createMap(); 816 } 817 perUserLifo.put(userName, value); 818 } 819 820 void setPerUserMaxIdle(final Map<String, Integer> userDefaultMaxIdle) { 821 assertInitializationAllowed(); 822 if (perUserMaxIdle == null) { 823 perUserMaxIdle = new HashMap<>(); 824 } else { 825 perUserMaxIdle.clear(); 826 } 827 perUserMaxIdle.putAll(userDefaultMaxIdle); 828 } 829 830 /** 831 * Sets a user specific value for {@link GenericObjectPool#getMaxIdle()} for the specified user's pool. 832 * 833 * @param userName 834 * The user name key. 835 * @param value 836 * The user specific value. 837 */ 838 public void setPerUserMaxIdle(final String userName, final Integer value) { 839 assertInitializationAllowed(); 840 if (perUserMaxIdle == null) { 841 perUserMaxIdle = new HashMap<>(); 842 } 843 perUserMaxIdle.put(userName, value); 844 } 845 846 void setPerUserMaxTotal(final Map<String, Integer> userDefaultMaxTotal) { 847 assertInitializationAllowed(); 848 if (perUserMaxTotal == null) { 849 perUserMaxTotal = new HashMap<>(); 850 } else { 851 perUserMaxTotal.clear(); 852 } 853 perUserMaxTotal.putAll(userDefaultMaxTotal); 854 } 855 856 /** 857 * Sets a user specific value for {@link GenericObjectPool#getMaxTotal()} for the specified user's pool. 858 * 859 * @param userName 860 * The user name key. 861 * @param value 862 * The user specific value. 863 */ 864 public void setPerUserMaxTotal(final String userName, final Integer value) { 865 assertInitializationAllowed(); 866 if (perUserMaxTotal == null) { 867 perUserMaxTotal = new HashMap<>(); 868 } 869 perUserMaxTotal.put(userName, value); 870 } 871 872 void setPerUserMaxWaitMillis(final Map<String, Long> userDefaultMaxWaitMillis) { 873 assertInitializationAllowed(); 874 if (perUserMaxWaitMillis == null) { 875 perUserMaxWaitMillis = new HashMap<>(); 876 } else { 877 perUserMaxWaitMillis.clear(); 878 } 879 perUserMaxWaitMillis.putAll(userDefaultMaxWaitMillis); 880 } 881 882 /** 883 * Sets a user specific value for {@link GenericObjectPool#getMaxWaitMillis()} for the specified user's pool. 884 * 885 * @param userName 886 * The user name key. 887 * @param value 888 * The user specific value. 889 */ 890 public void setPerUserMaxWaitMillis(final String userName, final Long value) { 891 assertInitializationAllowed(); 892 if (perUserMaxWaitMillis == null) { 893 perUserMaxWaitMillis = new HashMap<>(); 894 } 895 perUserMaxWaitMillis.put(userName, value); 896 } 897 898 void setPerUserMinEvictableIdleTimeMillis(final Map<String, Long> userDefaultMinEvictableIdleTimeMillis) { 899 assertInitializationAllowed(); 900 if (perUserMinEvictableIdleTimeMillis == null) { 901 perUserMinEvictableIdleTimeMillis = new HashMap<>(); 902 } else { 903 perUserMinEvictableIdleTimeMillis.clear(); 904 } 905 perUserMinEvictableIdleTimeMillis.putAll(userDefaultMinEvictableIdleTimeMillis); 906 } 907 908 /** 909 * Sets a user specific value for {@link GenericObjectPool#getMinEvictableIdleTime()} for the specified user's 910 * pool. 911 * 912 * @param userName 913 * The user name key. 914 * @param value 915 * The user specific value. 916 */ 917 public void setPerUserMinEvictableIdleTimeMillis(final String userName, final Long value) { 918 assertInitializationAllowed(); 919 if (perUserMinEvictableIdleTimeMillis == null) { 920 perUserMinEvictableIdleTimeMillis = new HashMap<>(); 921 } 922 perUserMinEvictableIdleTimeMillis.put(userName, value); 923 } 924 925 void setPerUserMinIdle(final Map<String, Integer> userDefaultMinIdle) { 926 assertInitializationAllowed(); 927 if (perUserMinIdle == null) { 928 perUserMinIdle = new HashMap<>(); 929 } else { 930 perUserMinIdle.clear(); 931 } 932 perUserMinIdle.putAll(userDefaultMinIdle); 933 } 934 935 /** 936 * Sets a user specific value for {@link GenericObjectPool#getMinIdle()} for the specified user's pool. 937 * 938 * @param userName 939 * The user name key. 940 * @param value 941 * The user specific value. 942 */ 943 public void setPerUserMinIdle(final String userName, final Integer value) { 944 assertInitializationAllowed(); 945 if (perUserMinIdle == null) { 946 perUserMinIdle = new HashMap<>(); 947 } 948 perUserMinIdle.put(userName, value); 949 } 950 951 void setPerUserNumTestsPerEvictionRun(final Map<String, Integer> userDefaultNumTestsPerEvictionRun) { 952 assertInitializationAllowed(); 953 if (perUserNumTestsPerEvictionRun == null) { 954 perUserNumTestsPerEvictionRun = new HashMap<>(); 955 } else { 956 perUserNumTestsPerEvictionRun.clear(); 957 } 958 perUserNumTestsPerEvictionRun.putAll(userDefaultNumTestsPerEvictionRun); 959 } 960 961 /** 962 * Sets a user specific value for {@link GenericObjectPool#getNumTestsPerEvictionRun()} for the specified user's 963 * pool. 964 * 965 * @param userName 966 * The user name key. 967 * @param value 968 * The user specific value. 969 */ 970 public void setPerUserNumTestsPerEvictionRun(final String userName, final Integer value) { 971 assertInitializationAllowed(); 972 if (perUserNumTestsPerEvictionRun == null) { 973 perUserNumTestsPerEvictionRun = new HashMap<>(); 974 } 975 perUserNumTestsPerEvictionRun.put(userName, value); 976 } 977 978 void setPerUserSoftMinEvictableIdleTimeMillis(final Map<String, Long> userDefaultSoftMinEvictableIdleTimeMillis) { 979 assertInitializationAllowed(); 980 if (perUserSoftMinEvictableIdleTimeMillis == null) { 981 perUserSoftMinEvictableIdleTimeMillis = new HashMap<>(); 982 } else { 983 perUserSoftMinEvictableIdleTimeMillis.clear(); 984 } 985 perUserSoftMinEvictableIdleTimeMillis.putAll(userDefaultSoftMinEvictableIdleTimeMillis); 986 } 987 988 /** 989 * Sets a user specific value for {@link GenericObjectPool#getSoftMinEvictableIdleTime()} for the specified 990 * user's pool. 991 * 992 * @param userName 993 * The user name key. 994 * @param value 995 * The user specific value. 996 */ 997 public void setPerUserSoftMinEvictableIdleTimeMillis(final String userName, final Long value) { 998 assertInitializationAllowed(); 999 if (perUserSoftMinEvictableIdleTimeMillis == null) { 1000 perUserSoftMinEvictableIdleTimeMillis = new HashMap<>(); 1001 } 1002 perUserSoftMinEvictableIdleTimeMillis.put(userName, value); 1003 } 1004 1005 void setPerUserTestOnBorrow(final Map<String, Boolean> userDefaultTestOnBorrow) { 1006 assertInitializationAllowed(); 1007 if (perUserTestOnBorrow == null) { 1008 perUserTestOnBorrow = createMap(); 1009 } else { 1010 perUserTestOnBorrow.clear(); 1011 } 1012 perUserTestOnBorrow.putAll(userDefaultTestOnBorrow); 1013 } 1014 1015 /** 1016 * Sets a user specific value for {@link GenericObjectPool#getTestOnBorrow()} for the specified user's pool. 1017 * 1018 * @param userName 1019 * The user name key. 1020 * @param value 1021 * The user specific value. 1022 */ 1023 public void setPerUserTestOnBorrow(final String userName, final Boolean value) { 1024 assertInitializationAllowed(); 1025 if (perUserTestOnBorrow == null) { 1026 perUserTestOnBorrow = createMap(); 1027 } 1028 perUserTestOnBorrow.put(userName, value); 1029 } 1030 1031 void setPerUserTestOnCreate(final Map<String, Boolean> userDefaultTestOnCreate) { 1032 assertInitializationAllowed(); 1033 if (perUserTestOnCreate == null) { 1034 perUserTestOnCreate = createMap(); 1035 } else { 1036 perUserTestOnCreate.clear(); 1037 } 1038 perUserTestOnCreate.putAll(userDefaultTestOnCreate); 1039 } 1040 1041 /** 1042 * Sets a user specific value for {@link GenericObjectPool#getTestOnCreate()} for the specified user's pool. 1043 * 1044 * @param userName 1045 * The user name key. 1046 * @param value 1047 * The user specific value. 1048 */ 1049 public void setPerUserTestOnCreate(final String userName, final Boolean value) { 1050 assertInitializationAllowed(); 1051 if (perUserTestOnCreate == null) { 1052 perUserTestOnCreate = createMap(); 1053 } 1054 perUserTestOnCreate.put(userName, value); 1055 } 1056 1057 void setPerUserTestOnReturn(final Map<String, Boolean> userDefaultTestOnReturn) { 1058 assertInitializationAllowed(); 1059 if (perUserTestOnReturn == null) { 1060 perUserTestOnReturn = createMap(); 1061 } else { 1062 perUserTestOnReturn.clear(); 1063 } 1064 perUserTestOnReturn.putAll(userDefaultTestOnReturn); 1065 } 1066 1067 /** 1068 * Sets a user specific value for {@link GenericObjectPool#getTestOnReturn()} for the specified user's pool. 1069 * 1070 * @param userName 1071 * The user name key. 1072 * @param value 1073 * The user specific value. 1074 */ 1075 public void setPerUserTestOnReturn(final String userName, final Boolean value) { 1076 assertInitializationAllowed(); 1077 if (perUserTestOnReturn == null) { 1078 perUserTestOnReturn = createMap(); 1079 } 1080 perUserTestOnReturn.put(userName, value); 1081 } 1082 1083 void setPerUserTestWhileIdle(final Map<String, Boolean> userDefaultTestWhileIdle) { 1084 assertInitializationAllowed(); 1085 if (perUserTestWhileIdle == null) { 1086 perUserTestWhileIdle = createMap(); 1087 } else { 1088 perUserTestWhileIdle.clear(); 1089 } 1090 perUserTestWhileIdle.putAll(userDefaultTestWhileIdle); 1091 } 1092 1093 /** 1094 * Sets a user specific value for {@link GenericObjectPool#getTestWhileIdle()} for the specified user's pool. 1095 * 1096 * @param userName 1097 * The user name key. 1098 * @param value 1099 * The user specific value. 1100 */ 1101 public void setPerUserTestWhileIdle(final String userName, final Boolean value) { 1102 assertInitializationAllowed(); 1103 if (perUserTestWhileIdle == null) { 1104 perUserTestWhileIdle = createMap(); 1105 } 1106 perUserTestWhileIdle.put(userName, value); 1107 } 1108 1109 void setPerUserTimeBetweenEvictionRunsMillis(final Map<String, Long> userDefaultTimeBetweenEvictionRunsMillis) { 1110 assertInitializationAllowed(); 1111 if (perUserTimeBetweenEvictionRunsMillis == null) { 1112 perUserTimeBetweenEvictionRunsMillis = new HashMap<>(); 1113 } else { 1114 perUserTimeBetweenEvictionRunsMillis.clear(); 1115 } 1116 perUserTimeBetweenEvictionRunsMillis.putAll(userDefaultTimeBetweenEvictionRunsMillis); 1117 } 1118 1119 /** 1120 * Sets a user specific value for {@link GenericObjectPool#getTimeBetweenEvictionRuns()} for the specified 1121 * user's pool. 1122 * 1123 * @param userName 1124 * The user name key. 1125 * @param value 1126 * The user specific value. 1127 */ 1128 public void setPerUserTimeBetweenEvictionRunsMillis(final String userName, final Long value) { 1129 assertInitializationAllowed(); 1130 if (perUserTimeBetweenEvictionRunsMillis == null) { 1131 perUserTimeBetweenEvictionRunsMillis = new HashMap<>(); 1132 } 1133 perUserTimeBetweenEvictionRunsMillis.put(userName, value); 1134 } 1135 1136 @Override 1137 protected void setupDefaults(final Connection con, final String userName) throws SQLException { 1138 Boolean defaultAutoCommit = isDefaultAutoCommit(); 1139 if (userName != null) { 1140 final Boolean userMax = getPerUserDefaultAutoCommit(userName); 1141 if (userMax != null) { 1142 defaultAutoCommit = userMax; 1143 } 1144 } 1145 1146 Boolean defaultReadOnly = isDefaultReadOnly(); 1147 if (userName != null) { 1148 final Boolean userMax = getPerUserDefaultReadOnly(userName); 1149 if (userMax != null) { 1150 defaultReadOnly = userMax; 1151 } 1152 } 1153 1154 int defaultTransactionIsolation = getDefaultTransactionIsolation(); 1155 if (userName != null) { 1156 final Integer userMax = getPerUserDefaultTransactionIsolation(userName); 1157 if (userMax != null) { 1158 defaultTransactionIsolation = userMax; 1159 } 1160 } 1161 1162 if (defaultAutoCommit != null && con.getAutoCommit() != defaultAutoCommit) { 1163 con.setAutoCommit(defaultAutoCommit); 1164 } 1165 1166 if (defaultTransactionIsolation != UNKNOWN_TRANSACTIONISOLATION) { 1167 con.setTransactionIsolation(defaultTransactionIsolation); 1168 } 1169 1170 if (defaultReadOnly != null && con.isReadOnly() != defaultReadOnly) { 1171 con.setReadOnly(defaultReadOnly); 1172 } 1173 } 1174}