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