PerUserPoolDataSource.java

  1. /*
  2.  * Licensed to the Apache Software Foundation (ASF) under one or more
  3.  * contributor license agreements.  See the NOTICE file distributed with
  4.  * this work for additional information regarding copyright ownership.
  5.  * The ASF licenses this file to You under the Apache License, Version 2.0
  6.  * (the "License"); you may not use this file except in compliance with
  7.  * the License.  You may obtain a copy of the License at
  8.  *
  9.  *      http://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  * Unless required by applicable law or agreed to in writing, software
  12.  * distributed under the License is distributed on an "AS IS" BASIS,
  13.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  * See the License for the specific language governing permissions and
  15.  * limitations under the License.
  16.  */
  17. package org.apache.commons.dbcp2.datasources;

  18. import java.io.IOException;
  19. import java.io.ObjectInputStream;
  20. import java.sql.Connection;
  21. import java.sql.SQLException;
  22. import java.time.Duration;
  23. import java.util.HashMap;
  24. import java.util.Map;
  25. import java.util.NoSuchElementException;
  26. import java.util.function.Supplier;

  27. import javax.naming.NamingException;
  28. import javax.naming.Reference;
  29. import javax.naming.StringRefAddr;
  30. import javax.sql.ConnectionPoolDataSource;

  31. import org.apache.commons.dbcp2.SwallowedExceptionLogger;
  32. import org.apache.commons.dbcp2.Utils;
  33. import org.apache.commons.logging.Log;
  34. import org.apache.commons.logging.LogFactory;
  35. import org.apache.commons.pool2.ObjectPool;
  36. import org.apache.commons.pool2.impl.EvictionPolicy;
  37. import org.apache.commons.pool2.impl.GenericObjectPool;

  38. /**
  39.  * <p>
  40.  * A pooling {@code DataSource} appropriate for deployment within J2EE environment. There are many configuration
  41.  * options, most of which are defined in the parent class. This datasource uses individual pools per user, and some
  42.  * properties can be set specifically for a given user, if the deployment environment can support initialization of
  43.  * mapped properties. So for example, a pool of admin or write-access Connections can be guaranteed a certain number of
  44.  * connections, separate from a maximum set for users with read-only connections.
  45.  * </p>
  46.  *
  47.  * <p>
  48.  * User passwords can be changed without re-initializing the datasource. When a
  49.  * {@code getConnection(userName, password)} request is processed with a password that is different from those used
  50.  * to create connections in the pool associated with {@code userName}, an attempt is made to create a new
  51.  * connection using the supplied password and if this succeeds, the existing pool is cleared and a new pool is created
  52.  * for connections using the new password.
  53.  * </p>
  54.  *
  55.  * @since 2.0
  56.  */
  57. public class PerUserPoolDataSource extends InstanceKeyDataSource {

  58.     private static final long serialVersionUID = 7872747993848065028L;

  59.     private static final Log log = LogFactory.getLog(PerUserPoolDataSource.class);

  60.     private static <K, V> HashMap<K, V> createMap() {
  61.         // Should there be a default size different from what this ctor provides?
  62.         return new HashMap<>();
  63.     }

  64.     /**
  65.      * Maps user names to a data source property: BlockWhenExhausted.
  66.      */
  67.     private Map<String, Boolean> perUserBlockWhenExhausted;

  68.     /**
  69.      * Maps user names to a data source property: EvictionPolicyClassName.
  70.      */
  71.     private Map<String, String> perUserEvictionPolicyClassName;

  72.     /**
  73.      * Maps user names to a data source property: Lifo.
  74.      */
  75.     private Map<String, Boolean> perUserLifo;

  76.     /**
  77.      * Maps user names to a data source property: MaxIdle.
  78.      */
  79.     private Map<String, Integer> perUserMaxIdle;

  80.     /**
  81.      * Maps user names to a data source property: MaxTotal.
  82.      */
  83.     private Map<String, Integer> perUserMaxTotal;

  84.     /**
  85.      * Maps user names to a data source property: MaxWaitDuration.
  86.      */
  87.     private Map<String, Duration> perUserMaxWaitDuration;

  88.     /**
  89.      * Maps user names to a data source property: MinEvictableIdleDuration.
  90.      */
  91.     private Map<String, Duration> perUserMinEvictableIdleDuration;

  92.     /**
  93.      * Maps user names to a data source property: MinIdle.
  94.      */
  95.     private Map<String, Integer> perUserMinIdle;

  96.     /**
  97.      * Maps user names to a data source property: NumTestsPerEvictionRun.
  98.      */
  99.     private Map<String, Integer> perUserNumTestsPerEvictionRun;

  100.     /**
  101.      * Maps user names to a data source property: SoftMinEvictableIdleDuration.
  102.      */
  103.     private Map<String, Duration> perUserSoftMinEvictableIdleDuration;

  104.     /**
  105.      * Maps user names to a data source property: TestOnCreate.
  106.      */
  107.     private Map<String, Boolean> perUserTestOnCreate;

  108.     /**
  109.      * Maps user names to a data source property: TestOnBorrow.
  110.      */
  111.     private Map<String, Boolean> perUserTestOnBorrow;

  112.     /**
  113.      * Maps user names to a data source property: TestOnReturn.
  114.      */
  115.     private Map<String, Boolean> perUserTestOnReturn;

  116.     /**
  117.      * Maps user names to a data source property: TestWhileIdle.
  118.      */
  119.     private Map<String, Boolean> perUserTestWhileIdle;

  120.     /**
  121.      * Maps user names to a data source property: DurationBetweenEvictionRuns.
  122.      */
  123.     private Map<String, Duration> perUserDurationBetweenEvictionRuns;

  124.     /**
  125.      * Maps user names to a data source property: DefaultAutoCommit.
  126.      */
  127.     private Map<String, Boolean> perUserDefaultAutoCommit;

  128.     /**
  129.      * Maps user names to a data source property: DefaultTransactionIsolation.
  130.      */
  131.     private Map<String, Integer> perUserDefaultTransactionIsolation;

  132.     /**
  133.      * Maps user names to a data source property: DefaultReadOnly.
  134.      */
  135.     private Map<String, Boolean> perUserDefaultReadOnly;

  136.     /**
  137.      * Map to keep track of Pools for a given user.
  138.      */
  139.     private transient Map<PoolKey, PooledConnectionManager> managers = createMap();

  140.     /**
  141.      * Constructs a new instance.
  142.      */
  143.     public PerUserPoolDataSource() {
  144.     }

  145.     /**
  146.      * Clears pool(s) maintained by this data source.
  147.      *
  148.      * @see org.apache.commons.pool2.ObjectPool#clear()
  149.      * @since 2.3.0
  150.      */
  151.     @SuppressWarnings("resource") // does not allocate a pool
  152.     public void clear() {
  153.         managers.values().forEach(manager -> {
  154.             try {
  155.                 getCPDSConnectionFactoryPool(manager).clear();
  156.             } catch (final Exception ignored) {
  157.                 // ignore and try to close others.
  158.             }
  159.         });
  160.         InstanceKeyDataSourceFactory.removeInstance(getInstanceKey());
  161.     }

  162.     /**
  163.      * Closes pool(s) maintained by this data source.
  164.      *
  165.      * @see org.apache.commons.pool2.ObjectPool#close()
  166.      */
  167.     @Override
  168.     public void close() {
  169.         managers.values().forEach(manager -> Utils.closeQuietly(getCPDSConnectionFactoryPool(manager)));
  170.         InstanceKeyDataSourceFactory.removeInstance(getInstanceKey());
  171.     }

  172.     /**
  173.      * Converts a map with Long milliseconds values to another map with Duration values.
  174.      */
  175.     private Map<String, Duration> convertMap(final Map<String, Duration> currentMap, final Map<String, Long> longMap) {
  176.         final Map<String, Duration> durationMap = createMap();
  177.         longMap.forEach((k, v) -> durationMap.put(k, toDurationOrNull(v)));
  178.         if (currentMap == null) {
  179.             return durationMap;
  180.         }
  181.         currentMap.clear();
  182.         currentMap.putAll(durationMap);
  183.         return currentMap;

  184.     }

  185.     /**
  186.      * Gets the user specific default value in a map for the specified user's pool.
  187.      *
  188.      * @param userName The user name key.
  189.      * @return The user specific value.
  190.      */
  191.     private <V> V get(final Map<String, V> map, final String userName) {
  192.         return map != null ? map.get(userName) : null;
  193.     }

  194.     /**
  195.      * Gets the user specific default value in a map for the specified user's pool.
  196.      *
  197.      * @param userName The user name key.
  198.      * @return The user specific value.
  199.      */
  200.     private <V> V get(final Map<String, V> map, final String userName, final Supplier<V> defaultSupplier) {
  201.         final V v = get(map, userName);
  202.         return v != null ? v : defaultSupplier.get();
  203.     }

  204.     @Override
  205.     protected PooledConnectionManager getConnectionManager(final UserPassKey upKey) {
  206.         return managers.get(getPoolKey(upKey.getUserName()));
  207.     }

  208.     /**
  209.      * Gets the underlying pre-allocated pool (does NOT allocate).
  210.      *
  211.      * @param manager A CPDSConnectionFactory.
  212.      * @return the underlying pool.
  213.      */
  214.     private ObjectPool<PooledConnectionAndInfo> getCPDSConnectionFactoryPool(final PooledConnectionManager manager) {
  215.         return ((CPDSConnectionFactory) manager).getPool();
  216.     }

  217.     /**
  218.      * Gets the number of active connections in the default pool.
  219.      *
  220.      * @return The number of active connections in the default pool.
  221.      */
  222.     public int getNumActive() {
  223.         return getNumActive(null);
  224.     }

  225.     /**
  226.      * Gets the number of active connections in the pool for a given user.
  227.      *
  228.      * @param userName
  229.      *            The user name key.
  230.      * @return The user specific value.
  231.      */
  232.     @SuppressWarnings("resource")
  233.     public int getNumActive(final String userName) {
  234.         final ObjectPool<PooledConnectionAndInfo> pool = getPool(getPoolKey(userName));
  235.         return pool == null ? 0 : pool.getNumActive();
  236.     }

  237.     /**
  238.      * Gets the number of idle connections in the default pool.
  239.      *
  240.      * @return The number of idle connections in the default pool.
  241.      */
  242.     public int getNumIdle() {
  243.         return getNumIdle(null);
  244.     }

  245.     /**
  246.      * Gets the number of idle connections in the pool for a given user.
  247.      *
  248.      * @param userName
  249.      *            The user name key.
  250.      * @return The user specific value.
  251.      */
  252.     @SuppressWarnings("resource")
  253.     public int getNumIdle(final String userName) {
  254.         final ObjectPool<PooledConnectionAndInfo> pool = getPool(getPoolKey(userName));
  255.         return pool == null ? 0 : pool.getNumIdle();
  256.     }

  257.     /**
  258.      * Gets the user specific value for {@link GenericObjectPool#getBlockWhenExhausted()} for the specified user's pool
  259.      * or the default if no user specific value is defined.
  260.      *
  261.      * @param userName
  262.      *            The user name key.
  263.      * @return The user specific value.
  264.      */
  265.     public boolean getPerUserBlockWhenExhausted(final String userName) {
  266.         return get(perUserBlockWhenExhausted, userName, this::getDefaultBlockWhenExhausted);
  267.     }

  268.     /**
  269.      * Gets the user specific default value for {@link Connection#setAutoCommit(boolean)} for the specified user's pool.
  270.      *
  271.      * @param userName
  272.      *            The user name key.
  273.      * @return The user specific value.
  274.      */
  275.     public Boolean getPerUserDefaultAutoCommit(final String userName) {
  276.         return get(perUserDefaultAutoCommit, userName);
  277.     }

  278.     /**
  279.      * Gets the user specific default value for {@link Connection#setReadOnly(boolean)} for the specified user's pool.
  280.      *
  281.      * @param userName
  282.      *            The user name key.
  283.      * @return The user specific value.
  284.      */
  285.     public Boolean getPerUserDefaultReadOnly(final String userName) {
  286.         return get(perUserDefaultReadOnly, userName);
  287.     }

  288.     /**
  289.      * Gets the user specific default value for {@link Connection#setTransactionIsolation(int)} for the specified user's
  290.      * pool.
  291.      *
  292.      * @param userName
  293.      *            The user name key.
  294.      * @return The user specific value.
  295.      */
  296.     public Integer getPerUserDefaultTransactionIsolation(final String userName) {
  297.         return get(perUserDefaultTransactionIsolation, userName);
  298.     }

  299.     /**
  300.      * Gets the user specific value for {@link GenericObjectPool#getDurationBetweenEvictionRuns()} for the specified
  301.      * user's pool or the default if no user specific value is defined.
  302.      *
  303.      * @param userName
  304.      *            The user name key.
  305.      * @return The user specific value.
  306.      * @since 2.10.0
  307.      */
  308.     public Duration getPerUserDurationBetweenEvictionRuns(final String userName) {
  309.         return get(perUserDurationBetweenEvictionRuns, userName, this::getDefaultDurationBetweenEvictionRuns);
  310.     }

  311.     /**
  312.      * Gets the user specific value for {@link GenericObjectPool#getEvictionPolicyClassName()} for the specified user's
  313.      * pool or the default if no user specific value is defined.
  314.      * <p>
  315.      * The class must implement {@link EvictionPolicy}.
  316.      * </p>
  317.      *
  318.      * @param userName
  319.      *            The user name key.
  320.      * @return The user specific value.
  321.      */
  322.     public String getPerUserEvictionPolicyClassName(final String userName) {
  323.         return get(perUserEvictionPolicyClassName, userName, this::getDefaultEvictionPolicyClassName);
  324.     }

  325.     /**
  326.      * Gets the user specific value for {@link GenericObjectPool#getLifo()} for the specified user's pool or the default
  327.      * 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 boolean getPerUserLifo(final String userName) {
  334.         return get(perUserLifo, userName, this::getDefaultLifo);
  335.     }

  336.     /**
  337.      * Gets the user specific value for {@link GenericObjectPool#getMaxIdle()} for the specified user's pool or the
  338.      * default if no user specific value is defined.
  339.      *
  340.      * @param userName
  341.      *            The user name key.
  342.      * @return The user specific value.
  343.      */
  344.     public int getPerUserMaxIdle(final String userName) {
  345.         return get(perUserMaxIdle, userName, this::getDefaultMaxIdle);
  346.     }

  347.     /**
  348.      * Gets the user specific value for {@link GenericObjectPool#getMaxTotal()} for the specified user's pool or the
  349.      * default if no user specific value is defined.
  350.      *
  351.      * @param userName
  352.      *            The user name key.
  353.      * @return The user specific value.
  354.      */
  355.     public int getPerUserMaxTotal(final String userName) {
  356.         return get(perUserMaxTotal, userName, this::getDefaultMaxTotal);
  357.     }

  358.     /**
  359.      * Gets the user specific value for {@link GenericObjectPool#getMaxWaitDuration()} for the specified user's pool or
  360.      * the default if no user specific value is defined.
  361.      *
  362.      * @param userName
  363.      *            The user name key.
  364.      * @return The user specific value.
  365.      * @since 2.10.0
  366.      */
  367.     public Duration getPerUserMaxWaitDuration(final String userName) {
  368.         return get(perUserMaxWaitDuration, userName, this::getDefaultMaxWait);
  369.     }

  370.     /**
  371.      * Gets the user specific value for {@link GenericObjectPool#getMaxWaitDuration()} for the specified user's pool or
  372.      * the default if no user specific value is defined.
  373.      *
  374.      * @param userName
  375.      *            The user name key.
  376.      * @return The user specific value.
  377.      * @deprecated Use {@link #getPerUserMaxWaitDuration}.
  378.      */
  379.     @Deprecated
  380.     public long getPerUserMaxWaitMillis(final String userName) {
  381.         return getPerUserMaxWaitDuration(userName).toMillis();
  382.     }

  383.     /**
  384.      * Gets the user specific value for {@link GenericObjectPool#getMinEvictableIdleDuration()} for the specified
  385.      * user's pool or the default if no user specific value is defined.
  386.      *
  387.      * @param userName
  388.      *            The user name key.
  389.      * @return The user specific value, never null.
  390.      * @since 2.10.0
  391.      */
  392.     public Duration getPerUserMinEvictableIdleDuration(final String userName) {
  393.         return get(perUserMinEvictableIdleDuration, userName, this::getDefaultMinEvictableIdleDuration);
  394.     }

  395.     /**
  396.      * Gets the user specific value for {@link GenericObjectPool#getMinEvictableIdleDuration()} for the specified
  397.      * user's pool or the default if no user specific value is defined.
  398.      *
  399.      * @param userName
  400.      *            The user name key.
  401.      * @return The user specific value.
  402.      * @deprecated Use {@link #getPerUserMinEvictableIdleDuration(String)}.
  403.      */
  404.     @Deprecated
  405.     public long getPerUserMinEvictableIdleTimeMillis(final String userName) {
  406.         return getPerUserMinEvictableIdleDuration(userName).toMillis();
  407.     }

  408.     /**
  409.      * Gets the user specific value for {@link GenericObjectPool#getMinIdle()} for the specified user's pool or the
  410.      * default if no user specific value is defined.
  411.      *
  412.      * @param userName
  413.      *            The user name key.
  414.      * @return The user specific value.
  415.      */
  416.     public int getPerUserMinIdle(final String userName) {
  417.         return get(perUserMinIdle, userName, this::getDefaultMinIdle);
  418.     }

  419.     /**
  420.      * Gets the user specific value for {@link GenericObjectPool#getNumTestsPerEvictionRun()} for the specified user's
  421.      * pool or the default if no user specific value is defined.
  422.      *
  423.      * @param userName
  424.      *            The user name key.
  425.      * @return The user specific value.
  426.      */
  427.     public int getPerUserNumTestsPerEvictionRun(final String userName) {
  428.         return get(perUserNumTestsPerEvictionRun, userName, this::getDefaultNumTestsPerEvictionRun);
  429.     }

  430.     /**
  431.      * Gets the user specific value for {@link GenericObjectPool#getSoftMinEvictableIdleDuration()} for the specified
  432.      * user's pool or the default if no user specific value is defined.
  433.      *
  434.      * @param userName
  435.      *            The user name key.
  436.      * @return The user specific value.
  437.      * @since 2.10.0
  438.      */
  439.     public Duration getPerUserSoftMinEvictableIdleDuration(final String userName) {
  440.         return get(perUserSoftMinEvictableIdleDuration, userName, this::getDefaultSoftMinEvictableIdleDuration);
  441.     }

  442.     /**
  443.      * Gets the user specific value for {@link GenericObjectPool#getSoftMinEvictableIdleDuration()} for the specified
  444.      * user's pool or the default if no user specific value is defined.
  445.      *
  446.      * @param userName
  447.      *            The user name key.
  448.      * @return The user specific value.
  449.      * @deprecated Use {@link #getPerUserSoftMinEvictableIdleDuration(String)}.
  450.      */
  451.     @Deprecated
  452.     public long getPerUserSoftMinEvictableIdleTimeMillis(final String userName) {
  453.         return getPerUserSoftMinEvictableIdleDuration(userName).toMillis();
  454.     }

  455.     /**
  456.      * Gets the user specific value for {@link GenericObjectPool#getTestOnBorrow()} for the specified user's pool or the
  457.      * default if no user specific value is defined.
  458.      *
  459.      * @param userName
  460.      *            The user name key.
  461.      * @return The user specific value.
  462.      */
  463.     public boolean getPerUserTestOnBorrow(final String userName) {
  464.         return get(perUserTestOnBorrow, userName, this::getDefaultTestOnBorrow);
  465.     }

  466.     /**
  467.      * Gets the user specific value for {@link GenericObjectPool#getTestOnCreate()} for the specified user's pool or the
  468.      * default if no user specific value is defined.
  469.      *
  470.      * @param userName
  471.      *            The user name key.
  472.      * @return The user specific value.
  473.      */
  474.     public boolean getPerUserTestOnCreate(final String userName) {
  475.         return get(perUserTestOnCreate, userName, this::getDefaultTestOnCreate);
  476.     }

  477.     /**
  478.      * Gets the user specific value for {@link GenericObjectPool#getTestOnReturn()} for the specified user's pool or the
  479.      * default if no user specific value is defined.
  480.      *
  481.      * @param userName
  482.      *            The user name key.
  483.      * @return The user specific value.
  484.      */
  485.     public boolean getPerUserTestOnReturn(final String userName) {
  486.         return get(perUserTestOnReturn, userName, this::getDefaultTestOnReturn);
  487.     }

  488.     /**
  489.      * Gets the user specific value for {@link GenericObjectPool#getTestWhileIdle()} for the specified user's pool or
  490.      * the default if no user specific value is defined.
  491.      *
  492.      * @param userName
  493.      *            The user name key.
  494.      * @return The user specific value.
  495.      */
  496.     public boolean getPerUserTestWhileIdle(final String userName) {
  497.         return get(perUserTestWhileIdle, userName, this::getDefaultTestWhileIdle);
  498.     }

  499.     /**
  500.      * Gets the user specific value for {@link GenericObjectPool#getDurationBetweenEvictionRuns()} 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 #getPerUserDurationBetweenEvictionRuns(String)}.
  507.      */
  508.     @Deprecated
  509.     public long getPerUserTimeBetweenEvictionRunsMillis(final String userName) {
  510.         return getPerUserDurationBetweenEvictionRuns(userName).toMillis();
  511.     }

  512.     /**
  513.      * Returns the object pool associated with the given PoolKey.
  514.      *
  515.      * @param poolKey
  516.      *            PoolKey identifying the pool
  517.      * @return the GenericObjectPool pooling connections for the userName and datasource specified by the PoolKey
  518.      */
  519.     private ObjectPool<PooledConnectionAndInfo> getPool(final PoolKey poolKey) {
  520.         final CPDSConnectionFactory mgr = (CPDSConnectionFactory) managers.get(poolKey);
  521.         return mgr == null ? null : mgr.getPool();
  522.     }

  523.     @SuppressWarnings("resource") // does not allocate a pool
  524.     @Override
  525.     protected PooledConnectionAndInfo getPooledConnectionAndInfo(final String userName, final String password) throws SQLException {
  526.         final PoolKey key = getPoolKey(userName);
  527.         ObjectPool<PooledConnectionAndInfo> pool;
  528.         PooledConnectionManager manager;
  529.         synchronized (this) {
  530.             manager = managers.get(key);
  531.             if (manager == null) {
  532.                 try {
  533.                     registerPool(userName, password);
  534.                     manager = managers.get(key);
  535.                 } catch (final NamingException e) {
  536.                     throw new SQLException("RegisterPool failed", e);
  537.                 }
  538.             }
  539.             pool = getCPDSConnectionFactoryPool(manager);
  540.         }
  541.         PooledConnectionAndInfo info = null;
  542.         try {
  543.             info = pool.borrowObject();
  544.         } catch (final NoSuchElementException ex) {
  545.             throw new SQLException("Could not retrieve connection info from pool", ex);
  546.         } catch (final Exception e) {
  547.             // See if failure is due to CPDSConnectionFactory authentication failure
  548.             try {
  549.                 testCPDS(userName, password);
  550.             } catch (final Exception ex) {
  551.                 throw new SQLException("Could not retrieve connection info from pool", ex);
  552.             }
  553.             // New password works, so kill the old pool, create a new one, and borrow
  554.             manager.closePool(userName);
  555.             synchronized (this) {
  556.                 managers.remove(key);
  557.             }
  558.             try {
  559.                 registerPool(userName, password);
  560.                 pool = getPool(key);
  561.             } catch (final NamingException ne) {
  562.                 throw new SQLException("RegisterPool failed", ne);
  563.             }
  564.             try {
  565.                 info = pool.borrowObject();
  566.             } catch (final Exception ex) {
  567.                 throw new SQLException("Could not retrieve connection info from pool", ex);
  568.             }
  569.         }
  570.         return info;
  571.     }

  572.     /**
  573.      * Creates a pool key from the provided parameters.
  574.      *
  575.      * @param userName
  576.      *            User name
  577.      * @return The pool key
  578.      */
  579.     private PoolKey getPoolKey(final String userName) {
  580.         return new PoolKey(getDataSourceName(), userName);
  581.     }

  582.     /**
  583.      * Returns a {@code PerUserPoolDataSource} {@link Reference}.
  584.      */
  585.     @Override
  586.     public Reference getReference() throws NamingException {
  587.         final Reference ref = new Reference(getClass().getName(), PerUserPoolDataSourceFactory.class.getName(), null);
  588.         ref.add(new StringRefAddr("instanceKey", getInstanceKey()));
  589.         return ref;
  590.     }

  591.     <K, V> Map<K, V> put(Map<K, V> map, final K key, final V value) {
  592.         if (map == null) {
  593.             map = createMap();
  594.         }
  595.         map.put(key, value);
  596.         return map;
  597.     }

  598.     /**
  599.      * Deserializes an instance from an ObjectInputStream.
  600.      *
  601.      * @param in The source ObjectInputStream.
  602.      * @throws IOException            Any of the usual Input/Output related exceptions.
  603.      * @throws ClassNotFoundException A class of a serialized object cannot be found.
  604.      */
  605.     @SuppressWarnings("resource")
  606.     private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException {
  607.         in.defaultReadObject();
  608.         this.managers = readObjectImpl().managers;
  609.     }

  610.     private PerUserPoolDataSource readObjectImpl() throws IOException, ClassNotFoundException {
  611.         try {
  612.             return (PerUserPoolDataSource) new PerUserPoolDataSourceFactory().getObjectInstance(getReference(), null, null, null);
  613.         } catch (final NamingException e) {
  614.             throw new IOException("NamingException: " + e);
  615.         }
  616.     }

  617.     private synchronized void registerPool(final String userName, final String password) throws NamingException, SQLException {
  618.         final ConnectionPoolDataSource cpds = testCPDS(userName, password);
  619.         // Set up the factory we will use (passing the pool associates
  620.         // the factory with the pool, so we do not have to do so
  621.         // explicitly)
  622.         final CPDSConnectionFactory factory = new CPDSConnectionFactory(cpds, getValidationQuery(), getValidationQueryTimeoutDuration(),
  623.                 isRollbackAfterValidation(), userName, password);
  624.         factory.setMaxConn(getMaxConnDuration());
  625.         // Create an object pool to contain our PooledConnections
  626.         @SuppressWarnings("resource")
  627.         final GenericObjectPool<PooledConnectionAndInfo> pool = new GenericObjectPool<>(factory);
  628.         factory.setPool(pool);
  629.         pool.setBlockWhenExhausted(getPerUserBlockWhenExhausted(userName));
  630.         pool.setEvictionPolicyClassName(getPerUserEvictionPolicyClassName(userName));
  631.         pool.setLifo(getPerUserLifo(userName));
  632.         pool.setMaxIdle(getPerUserMaxIdle(userName));
  633.         pool.setMaxTotal(getPerUserMaxTotal(userName));
  634.         pool.setMaxWait(getPerUserMaxWaitDuration(userName));
  635.         pool.setMinEvictableIdleDuration(getPerUserMinEvictableIdleDuration(userName));
  636.         pool.setMinIdle(getPerUserMinIdle(userName));
  637.         pool.setNumTestsPerEvictionRun(getPerUserNumTestsPerEvictionRun(userName));
  638.         pool.setSoftMinEvictableIdleDuration(getPerUserSoftMinEvictableIdleDuration(userName));
  639.         pool.setTestOnCreate(getPerUserTestOnCreate(userName));
  640.         pool.setTestOnBorrow(getPerUserTestOnBorrow(userName));
  641.         pool.setTestOnReturn(getPerUserTestOnReturn(userName));
  642.         pool.setTestWhileIdle(getPerUserTestWhileIdle(userName));
  643.         pool.setDurationBetweenEvictionRuns(getPerUserDurationBetweenEvictionRuns(userName));
  644.         pool.setSwallowedExceptionListener(new SwallowedExceptionLogger(log));
  645.         final PoolKey poolKey = getPoolKey(userName);
  646.         if (managers.containsKey(poolKey)) {
  647.             pool.close();
  648.             throw new IllegalStateException("Pool already contains an entry for this user/password: " + userName);
  649.         }
  650.         managers.put(poolKey, factory);
  651.     }

  652.     private <K, V> Map<K, V> replaceAll(final Map<K, V> currentMap, final Map<K, V> newMap) {
  653.         if (currentMap == null) {
  654.             return new HashMap<>(newMap);
  655.         }
  656.         currentMap.clear();
  657.         currentMap.putAll(newMap);
  658.         return currentMap;
  659.     }

  660.     void setPerUserBlockWhenExhausted(final Map<String, Boolean> newMap) {
  661.         assertInitializationAllowed();
  662.         perUserBlockWhenExhausted = replaceAll(perUserBlockWhenExhausted, newMap);
  663.     }

  664.     /**
  665.      * Sets a user specific value for {@link GenericObjectPool#getBlockWhenExhausted()} for the specified user's pool.
  666.      *
  667.      * @param userName
  668.      *            The user name key.
  669.      * @param value
  670.      *            The user specific value.
  671.      */
  672.     public void setPerUserBlockWhenExhausted(final String userName, final Boolean value) {
  673.         assertInitializationAllowed();
  674.         perUserBlockWhenExhausted = put(perUserBlockWhenExhausted, userName, value);
  675.     }

  676.     void setPerUserDefaultAutoCommit(final Map<String, Boolean> newMap) {
  677.         assertInitializationAllowed();
  678.         perUserDefaultAutoCommit = replaceAll(perUserDefaultAutoCommit, newMap);
  679.     }

  680.     /**
  681.      * Sets a user specific default value for {@link Connection#setAutoCommit(boolean)} for the specified user's pool.
  682.      *
  683.      * @param userName
  684.      *            The user name key.
  685.      * @param value
  686.      *            The user specific value.
  687.      */
  688.     public void setPerUserDefaultAutoCommit(final String userName, final Boolean value) {
  689.         assertInitializationAllowed();
  690.         perUserDefaultAutoCommit = put(perUserDefaultAutoCommit, userName, value);

  691.     }

  692.     void setPerUserDefaultReadOnly(final Map<String, Boolean> newMap) {
  693.         assertInitializationAllowed();
  694.         perUserDefaultReadOnly = replaceAll(perUserDefaultReadOnly, newMap);
  695.     }

  696.     /**
  697.      * Sets a user specific default value for {@link Connection#setReadOnly(boolean)} for the specified user's pool.
  698.      *
  699.      * @param userName
  700.      *            The user name key.
  701.      * @param value
  702.      *            The user specific value.
  703.      */
  704.     public void setPerUserDefaultReadOnly(final String userName, final Boolean value) {
  705.         assertInitializationAllowed();
  706.         perUserDefaultReadOnly = put(perUserDefaultReadOnly, userName, value);

  707.     }

  708.     void setPerUserDefaultTransactionIsolation(final Map<String, Integer> newMap) {
  709.         assertInitializationAllowed();
  710.         perUserDefaultTransactionIsolation = replaceAll(perUserDefaultTransactionIsolation, newMap);
  711.     }

  712.     /**
  713.      * Sets a user specific default value for {@link Connection#setTransactionIsolation(int)} for the specified user's
  714.      * pool.
  715.      *
  716.      * @param userName
  717.      *            The user name key.
  718.      * @param value
  719.      *            The user specific value.
  720.      */
  721.     public void setPerUserDefaultTransactionIsolation(final String userName, final Integer value) {
  722.         assertInitializationAllowed();
  723.         perUserDefaultTransactionIsolation = put(perUserDefaultTransactionIsolation, userName, value);

  724.     }

  725.     void setPerUserDurationBetweenEvictionRuns(final Map<String, Duration> newMap) {
  726.         assertInitializationAllowed();
  727.         perUserDurationBetweenEvictionRuns = replaceAll(perUserDurationBetweenEvictionRuns, newMap);
  728.     }

  729.     /**
  730.      * Sets a user specific value for {@link GenericObjectPool#getDurationBetweenEvictionRuns()} for the specified
  731.      * user's pool.
  732.      *
  733.      * @param userName
  734.      *            The user name key.
  735.      * @param value
  736.      *            The user specific value.
  737.      * @since 2.10.0
  738.      */
  739.     public void setPerUserDurationBetweenEvictionRuns(final String userName, final Duration value) {
  740.         assertInitializationAllowed();
  741.         perUserDurationBetweenEvictionRuns = put(perUserDurationBetweenEvictionRuns, userName, value);

  742.     }

  743.     void setPerUserEvictionPolicyClassName(final Map<String, String> newMap) {
  744.         assertInitializationAllowed();
  745.         perUserEvictionPolicyClassName = replaceAll(perUserEvictionPolicyClassName, newMap);
  746.     }

  747.     /**
  748.      * Sets a user specific value for {@link GenericObjectPool#getEvictionPolicyClassName()} for the specified user's
  749.      * pool.
  750.      * <p>
  751.      * The class must implement {@link EvictionPolicy}.
  752.      * </p>
  753.      * @param userName
  754.      *            The user name key.
  755.      * @param value
  756.      *            The user specific value.
  757.      */
  758.     public void setPerUserEvictionPolicyClassName(final String userName, final String value) {
  759.         assertInitializationAllowed();
  760.         perUserEvictionPolicyClassName = put(perUserEvictionPolicyClassName, userName, value);
  761.     }

  762.     void setPerUserLifo(final Map<String, Boolean> newMap) {
  763.         assertInitializationAllowed();
  764.         perUserLifo = replaceAll(perUserLifo, newMap);
  765.     }

  766.     /**
  767.      * Sets a user specific value for {@link GenericObjectPool#getLifo()} for the specified user's pool.
  768.      *
  769.      * @param userName
  770.      *            The user name key.
  771.      * @param value
  772.      *            The user specific value.
  773.      */
  774.     public void setPerUserLifo(final String userName, final Boolean value) {
  775.         assertInitializationAllowed();
  776.         perUserLifo = put(perUserLifo, userName, value);
  777.     }

  778.     void setPerUserMaxIdle(final Map<String, Integer> newMap) {
  779.         assertInitializationAllowed();
  780.         perUserMaxIdle = replaceAll(perUserMaxIdle, newMap);
  781.     }

  782.     /**
  783.      * Sets a user specific value for {@link GenericObjectPool#getMaxIdle()} for the specified user's pool.
  784.      *
  785.      * @param userName
  786.      *            The user name key.
  787.      * @param value
  788.      *            The user specific value.
  789.      */
  790.     public void setPerUserMaxIdle(final String userName, final Integer value) {
  791.         assertInitializationAllowed();
  792.         perUserMaxIdle = put(perUserMaxIdle, userName, value);
  793.     }

  794.     void setPerUserMaxTotal(final Map<String, Integer> newMap) {
  795.         assertInitializationAllowed();
  796.         perUserMaxTotal = replaceAll(perUserMaxTotal, newMap);
  797.     }

  798.     /**
  799.      * Sets a user specific value for {@link GenericObjectPool#getMaxTotal()} for the specified user's pool.
  800.      *
  801.      * @param userName
  802.      *            The user name key.
  803.      * @param value
  804.      *            The user specific value.
  805.      */
  806.     public void setPerUserMaxTotal(final String userName, final Integer value) {
  807.         assertInitializationAllowed();
  808.         perUserMaxTotal = put(perUserMaxTotal, userName, value);
  809.     }

  810.     /**
  811.      * Sets a user specific value for {@link GenericObjectPool#getMaxWaitDuration()} for the specified user's pool.
  812.      *
  813.      * @param userName
  814.      *            The user name key.
  815.      * @param value
  816.      *            The user specific value.
  817.      * @since 2.10.0
  818.      */
  819.     public void setPerUserMaxWait(final String userName, final Duration value) {
  820.         assertInitializationAllowed();
  821.         perUserMaxWaitDuration = put(perUserMaxWaitDuration, userName, value);
  822.     }

  823.     void setPerUserMaxWaitDuration(final Map<String, Duration> newMap) {
  824.         assertInitializationAllowed();
  825.         perUserMaxWaitDuration = replaceAll(perUserMaxWaitDuration, newMap);
  826.     }

  827.     void setPerUserMaxWaitMillis(final Map<String, Long> newMap) {
  828.         assertInitializationAllowed();
  829.         perUserMaxWaitDuration = convertMap(perUserMaxWaitDuration, newMap);
  830.     }

  831.     /**
  832.      * Sets a user specific value for {@link GenericObjectPool#getMaxWaitDuration()} for the specified user's pool.
  833.      *
  834.      * @param userName
  835.      *            The user name key.
  836.      * @param value
  837.      *            The user specific value.
  838.      * @deprecated Use {@link #setPerUserMaxWait(String, Duration)}.
  839.      */
  840.     @Deprecated
  841.     public void setPerUserMaxWaitMillis(final String userName, final Long value) {
  842.         setPerUserMaxWait(userName, toDurationOrNull(value));
  843.     }

  844.     void setPerUserMinEvictableIdle(final Map<String, Duration> newMap) {
  845.         assertInitializationAllowed();
  846.         perUserMinEvictableIdleDuration = replaceAll(perUserMinEvictableIdleDuration, newMap);
  847.     }

  848.     /**
  849.      * Sets a user specific value for {@link GenericObjectPool#getMinEvictableIdleDuration()} for the specified user's
  850.      * pool.
  851.      *
  852.      * @param userName
  853.      *            The user name key.
  854.      * @param value
  855.      *            The user specific value.
  856.      * @since 2.10.0
  857.      */
  858.     public void setPerUserMinEvictableIdle(final String userName, final Duration value) {
  859.         assertInitializationAllowed();
  860.         perUserMinEvictableIdleDuration = put(perUserMinEvictableIdleDuration, userName, value);
  861.     }

  862.     /**
  863.      * Sets a user specific value for {@link GenericObjectPool#getMinEvictableIdleDuration()} for the specified user's
  864.      * pool.
  865.      *
  866.      * @param userName
  867.      *            The user name key.
  868.      * @param value
  869.      *            The user specific value.
  870.      * @deprecated Use {@link #setPerUserMinEvictableIdle(String, Duration)}.
  871.      */
  872.     @Deprecated
  873.     public void setPerUserMinEvictableIdleTimeMillis(final String userName, final Long value) {
  874.         setPerUserMinEvictableIdle(userName, toDurationOrNull(value));
  875.     }

  876.     void setPerUserMinIdle(final Map<String, Integer> newMap) {
  877.         assertInitializationAllowed();
  878.         perUserMinIdle = replaceAll(perUserMinIdle, newMap);
  879.     }

  880.     /**
  881.      * Sets a user specific value for {@link GenericObjectPool#getMinIdle()} for the specified user's pool.
  882.      *
  883.      * @param userName
  884.      *            The user name key.
  885.      * @param value
  886.      *            The user specific value.
  887.      */
  888.     public void setPerUserMinIdle(final String userName, final Integer value) {
  889.         assertInitializationAllowed();
  890.         perUserMinIdle = put(perUserMinIdle, userName, value);
  891.     }

  892.     void setPerUserNumTestsPerEvictionRun(final Map<String, Integer> newMap) {
  893.         assertInitializationAllowed();
  894.         perUserNumTestsPerEvictionRun = replaceAll(perUserNumTestsPerEvictionRun, newMap);
  895.     }

  896.     /**
  897.      * Sets a user specific value for {@link GenericObjectPool#getNumTestsPerEvictionRun()} for the specified user's
  898.      * pool.
  899.      *
  900.      * @param userName
  901.      *            The user name key.
  902.      * @param value
  903.      *            The user specific value.
  904.      */
  905.     public void setPerUserNumTestsPerEvictionRun(final String userName, final Integer value) {
  906.         assertInitializationAllowed();
  907.         perUserNumTestsPerEvictionRun = put(perUserNumTestsPerEvictionRun, userName, value);
  908.     }

  909.     void setPerUserSoftMinEvictableIdle(final Map<String, Duration> newMap) {
  910.         assertInitializationAllowed();
  911.         perUserSoftMinEvictableIdleDuration = replaceAll(perUserSoftMinEvictableIdleDuration, newMap);
  912.     }

  913.     /**
  914.      * Sets a user specific value for {@link GenericObjectPool#getSoftMinEvictableIdleDuration()} for the specified
  915.      * user's pool.
  916.      *
  917.      * @param userName
  918.      *            The user name key.
  919.      * @param value
  920.      *            The user specific value.
  921.      * @since 2.10.0
  922.      */
  923.     public void setPerUserSoftMinEvictableIdle(final String userName, final Duration value) {
  924.         assertInitializationAllowed();
  925.         perUserSoftMinEvictableIdleDuration = put(perUserSoftMinEvictableIdleDuration, userName, value);
  926.     }

  927.     /**
  928.      * Sets a user specific value for {@link GenericObjectPool#getSoftMinEvictableIdleDuration()} for the specified
  929.      * user's pool.
  930.      *
  931.      * @param userName
  932.      *            The user name key.
  933.      * @param value
  934.      *            The user specific value.
  935.      * @deprecated Use {@link #setPerUserSoftMinEvictableIdle(String, Duration)}.
  936.      */
  937.     @Deprecated
  938.     public void setPerUserSoftMinEvictableIdleTimeMillis(final String userName, final Long value) {
  939.         setPerUserSoftMinEvictableIdle(userName, toDurationOrNull(value));
  940.     }

  941.     void setPerUserTestOnBorrow(final Map<String, Boolean> newMap) {
  942.         assertInitializationAllowed();
  943.         perUserTestOnBorrow = replaceAll(perUserTestOnBorrow, newMap);
  944.     }

  945.     /**
  946.      * Sets a user specific value for {@link GenericObjectPool#getTestOnBorrow()} for the specified user's pool.
  947.      *
  948.      * @param userName
  949.      *            The user name key.
  950.      * @param value
  951.      *            The user specific value.
  952.      */
  953.     public void setPerUserTestOnBorrow(final String userName, final Boolean value) {
  954.         assertInitializationAllowed();
  955.         perUserTestOnBorrow = put(perUserTestOnBorrow, userName, value);
  956.     }

  957.     void setPerUserTestOnCreate(final Map<String, Boolean> newMap) {
  958.         assertInitializationAllowed();
  959.         perUserTestOnCreate = replaceAll(perUserTestOnCreate, newMap);
  960.     }

  961.     /**
  962.      * Sets a user specific value for {@link GenericObjectPool#getTestOnCreate()} for the specified user's pool.
  963.      *
  964.      * @param userName
  965.      *            The user name key.
  966.      * @param value
  967.      *            The user specific value.
  968.      */
  969.     public void setPerUserTestOnCreate(final String userName, final Boolean value) {
  970.         assertInitializationAllowed();
  971.         perUserTestOnCreate = put(perUserTestOnCreate, userName, value);
  972.     }

  973.     void setPerUserTestOnReturn(final Map<String, Boolean> newMap) {
  974.         assertInitializationAllowed();
  975.         perUserTestOnReturn = replaceAll(perUserTestOnReturn, newMap);
  976.     }

  977.     /**
  978.      * Sets a user specific value for {@link GenericObjectPool#getTestOnReturn()} for the specified user's pool.
  979.      *
  980.      * @param userName
  981.      *            The user name key.
  982.      * @param value
  983.      *            The user specific value.
  984.      */
  985.     public void setPerUserTestOnReturn(final String userName, final Boolean value) {
  986.         assertInitializationAllowed();
  987.         perUserTestOnReturn = put(perUserTestOnReturn, userName, value);
  988.     }

  989.     void setPerUserTestWhileIdle(final Map<String, Boolean> newMap) {
  990.         assertInitializationAllowed();
  991.         perUserTestWhileIdle = replaceAll(perUserTestWhileIdle, newMap);
  992.     }

  993.     /**
  994.      * Sets a user specific value for {@link GenericObjectPool#getTestWhileIdle()} for the specified user's pool.
  995.      *
  996.      * @param userName
  997.      *            The user name key.
  998.      * @param value
  999.      *            The user specific value.
  1000.      */
  1001.     public void setPerUserTestWhileIdle(final String userName, final Boolean value) {
  1002.         assertInitializationAllowed();
  1003.         perUserTestWhileIdle = put(perUserTestWhileIdle, userName, value);
  1004.     }

  1005.     /**
  1006.      * Sets a user specific value for {@link GenericObjectPool#getDurationBetweenEvictionRuns()} for the specified
  1007.      * user's pool.
  1008.      *
  1009.      * @param userName
  1010.      *            The user name key.
  1011.      * @param value
  1012.      *            The user specific value.
  1013.      * @deprecated Use {@link #setPerUserDurationBetweenEvictionRuns(String, Duration)}.
  1014.      */
  1015.     @Deprecated
  1016.     public void setPerUserTimeBetweenEvictionRunsMillis(final String userName, final Long value) {
  1017.         setPerUserDurationBetweenEvictionRuns(userName, toDurationOrNull(value));
  1018.     }

  1019.     @Override
  1020.     protected void setupDefaults(final Connection con, final String userName) throws SQLException {
  1021.         Boolean defaultAutoCommit = isDefaultAutoCommit();
  1022.         if (userName != null) {
  1023.             final Boolean userMax = getPerUserDefaultAutoCommit(userName);
  1024.             if (userMax != null) {
  1025.                 defaultAutoCommit = userMax;
  1026.             }
  1027.         }

  1028.         Boolean defaultReadOnly = isDefaultReadOnly();
  1029.         if (userName != null) {
  1030.             final Boolean userMax = getPerUserDefaultReadOnly(userName);
  1031.             if (userMax != null) {
  1032.                 defaultReadOnly = userMax;
  1033.             }
  1034.         }

  1035.         int defaultTransactionIsolation = getDefaultTransactionIsolation();
  1036.         if (userName != null) {
  1037.             final Integer userMax = getPerUserDefaultTransactionIsolation(userName);
  1038.             if (userMax != null) {
  1039.                 defaultTransactionIsolation = userMax;
  1040.             }
  1041.         }

  1042.         if (defaultAutoCommit != null && con.getAutoCommit() != defaultAutoCommit) {
  1043.             con.setAutoCommit(defaultAutoCommit);
  1044.         }

  1045.         if (defaultTransactionIsolation != UNKNOWN_TRANSACTIONISOLATION) {
  1046.             con.setTransactionIsolation(defaultTransactionIsolation);
  1047.         }

  1048.         if (defaultReadOnly != null && con.isReadOnly() != defaultReadOnly) {
  1049.             con.setReadOnly(defaultReadOnly);
  1050.         }
  1051.     }

  1052.     private Duration toDurationOrNull(final Long millis) {
  1053.         return millis == null ? null : Duration.ofMillis(millis);
  1054.     }
  1055. }