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