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