You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by ma...@apache.org on 2018/06/19 10:30:31 UTC

svn commit: r1833804 [15/16] - in /tomcat/tc8.5.x/trunk: ./ java/org/apache/tomcat/dbcp/dbcp2/ java/org/apache/tomcat/dbcp/dbcp2/cpdsadapter/ java/org/apache/tomcat/dbcp/dbcp2/datasources/ webapps/docs/

Modified: tomcat/tc8.5.x/trunk/java/org/apache/tomcat/dbcp/dbcp2/datasources/PerUserPoolDataSource.java
URL: http://svn.apache.org/viewvc/tomcat/tc8.5.x/trunk/java/org/apache/tomcat/dbcp/dbcp2/datasources/PerUserPoolDataSource.java?rev=1833804&r1=1833803&r2=1833804&view=diff
==============================================================================
--- tomcat/tc8.5.x/trunk/java/org/apache/tomcat/dbcp/dbcp2/datasources/PerUserPoolDataSource.java (original)
+++ tomcat/tc8.5.x/trunk/java/org/apache/tomcat/dbcp/dbcp2/datasources/PerUserPoolDataSource.java Tue Jun 19 10:30:31 2018
@@ -36,96 +36,167 @@ import org.apache.tomcat.dbcp.pool2.Obje
 import org.apache.tomcat.dbcp.pool2.impl.GenericObjectPool;
 
 /**
- * <p>A pooling <code>DataSource</code> appropriate for deployment within
- * J2EE environment.  There are many configuration options, most of which are
- * defined in the parent class.  This datasource uses individual pools per
- * user, and some properties can be set specifically for a given user, if the
- * deployment environment can support initialization of mapped properties.
- * So for example, a pool of admin or write-access Connections can be
- * guaranteed a certain number of connections, separate from a maximum
- * set for users with read-only connections.</p>
+ * <p>
+ * A pooling <code>DataSource</code> appropriate for deployment within J2EE environment. There are many configuration
+ * options, most of which are defined in the parent class. This datasource uses individual pools per user, and some
+ * properties can be set specifically for a given user, if the deployment environment can support initialization of
+ * mapped properties. So for example, a pool of admin or write-access Connections can be guaranteed a certain number of
+ * connections, separate from a maximum set for users with read-only connections.
+ * </p>
  *
- * <p>User passwords can be changed without re-initializing the datasource.
- * When a <code>getConnection(username, password)</code> request is processed
- * with a password that is different from those used to create connections in
- * the pool associated with <code>username</code>, an attempt is made to create
- * a new connection using the supplied password and if this succeeds, the
- * existing pool is cleared and a new pool is created for connections using the
- * new password.</p>
+ * <p>
+ * User passwords can be changed without re-initializing the datasource. When a
+ * <code>getConnection(userName, password)</code> request is processed with a password that is different from those used
+ * to create connections in the pool associated with <code>userName</code>, an attempt is made to create a new
+ * connection using the supplied password and if this succeeds, the existing pool is cleared and a new pool is created
+ * for connections using the new password.
+ * </p>
  *
- * @author John D. McNally
  * @since 2.0
  */
 public class PerUserPoolDataSource extends InstanceKeyDataSource {
 
     private static final long serialVersionUID = 7872747993848065028L;
 
-    private static final Log log =
-            LogFactory.getLog(PerUserPoolDataSource.class);
+    private static final Log log = LogFactory.getLog(PerUserPoolDataSource.class);
 
     // Per user pool properties
-    private Map<String,Boolean> perUserBlockWhenExhausted = null;
-    private Map<String,String> perUserEvictionPolicyClassName = null;
-    private Map<String,Boolean> perUserLifo = null;
-    private Map<String,Integer> perUserMaxIdle = null;
-    private Map<String,Integer> perUserMaxTotal = null;
-    private Map<String,Long> perUserMaxWaitMillis = null;
-    private Map<String,Long> perUserMinEvictableIdleTimeMillis = null;
-    private Map<String,Integer> perUserMinIdle = null;
-    private Map<String,Integer> perUserNumTestsPerEvictionRun = null;
-    private Map<String,Long> perUserSoftMinEvictableIdleTimeMillis = null;
-    private Map<String,Boolean> perUserTestOnCreate = null;
-    private Map<String,Boolean> perUserTestOnBorrow = null;
-    private Map<String,Boolean> perUserTestOnReturn = null;
-    private Map<String,Boolean> perUserTestWhileIdle = null;
-    private Map<String,Long> perUserTimeBetweenEvictionRunsMillis = null;
+    private Map<String, Boolean> perUserBlockWhenExhausted;
+    private Map<String, String> perUserEvictionPolicyClassName;
+    private Map<String, Boolean> perUserLifo;
+    private Map<String, Integer> perUserMaxIdle;
+    private Map<String, Integer> perUserMaxTotal;
+    private Map<String, Long> perUserMaxWaitMillis;
+    private Map<String, Long> perUserMinEvictableIdleTimeMillis;
+    private Map<String, Integer> perUserMinIdle;
+    private Map<String, Integer> perUserNumTestsPerEvictionRun;
+    private Map<String, Long> perUserSoftMinEvictableIdleTimeMillis;
+    private Map<String, Boolean> perUserTestOnCreate;
+    private Map<String, Boolean> perUserTestOnBorrow;
+    private Map<String, Boolean> perUserTestOnReturn;
+    private Map<String, Boolean> perUserTestWhileIdle;
+    private Map<String, Long> perUserTimeBetweenEvictionRunsMillis;
 
     // Per user connection properties
-    private Map<String,Boolean> perUserDefaultAutoCommit = null;
-    private Map<String,Integer> perUserDefaultTransactionIsolation = null;
-    private Map<String,Boolean> perUserDefaultReadOnly = null;
+    private Map<String, Boolean> perUserDefaultAutoCommit;
+    private Map<String, Integer> perUserDefaultTransactionIsolation;
+    private Map<String, Boolean> perUserDefaultReadOnly;
 
     /**
-     * Map to keep track of Pools for a given user
+     * Map to keep track of Pools for a given user.
      */
-    private transient Map<PoolKey, PooledConnectionManager> managers =
-            new HashMap<>();
+    private transient Map<PoolKey, PooledConnectionManager> managers = new HashMap<>();
 
     /**
-     * Default no-arg constructor for Serialization
+     * Default no-arg constructor for Serialization.
      */
     public PerUserPoolDataSource() {
     }
 
     /**
-     * Close pool(s) being maintained by this datasource.
+     * Clears pool(s) maintained by this data source.
+     *
+     * @see org.apache.tomcat.dbcp.pool2.ObjectPool#clear()
+     * @since 2.3.0
+     */
+    public void clear() {
+        for (final PooledConnectionManager manager : managers.values()) {
+            try {
+                getCPDSConnectionFactoryPool(manager).clear();
+            } catch (final Exception closePoolException) {
+                // ignore and try to close others.
+            }
+        }
+        InstanceKeyDataSourceFactory.removeInstance(getInstanceKey());
+    }
+
+    /**
+     * Closes pool(s) maintained by this data source.
+     *
+     * @see org.apache.tomcat.dbcp.pool2.ObjectPool#close()
      */
     @Override
     public void close() {
         for (final PooledConnectionManager manager : managers.values()) {
             try {
-              ((CPDSConnectionFactory) manager).getPool().close();
+                getCPDSConnectionFactoryPool(manager).close();
             } catch (final Exception closePoolException) {
-                    //ignore and try to close others.
+                // ignore and try to close others.
             }
         }
         InstanceKeyDataSourceFactory.removeInstance(getInstanceKey());
     }
 
-    // -------------------------------------------------------------------
-    // Properties
+    private HashMap<String, Boolean> createMap() {
+        // Should there be a default size different than what this ctor provides?
+        return new HashMap<>();
+    }
+
+    @Override
+    protected PooledConnectionManager getConnectionManager(final UserPassKey upKey) {
+        return managers.get(getPoolKey(upKey.getUsername()));
+    }
+
+    private ObjectPool<PooledConnectionAndInfo> getCPDSConnectionFactoryPool(final PooledConnectionManager manager) {
+        return ((CPDSConnectionFactory) manager).getPool();
+    }
+
+    /**
+     * Gets the number of active connections in the default pool.
+     *
+     * @return The number of active connections in the default pool.
+     */
+    public int getNumActive() {
+        return getNumActive(null);
+    }
+
+    /**
+     * Gets the number of active connections in the pool for a given user.
+     *
+     * @param userName
+     *            The user name key.
+     * @return The user specific value.
+     */
+    @SuppressWarnings("resource")
+    public int getNumActive(final String userName) {
+        final ObjectPool<PooledConnectionAndInfo> pool = getPool(getPoolKey(userName));
+        return pool == null ? 0 : pool.getNumActive();
+    }
+
+    /**
+     * Gets the number of idle connections in the default pool.
+     *
+     * @return The number of idle connections in the default pool.
+     */
+    public int getNumIdle() {
+        return getNumIdle(null);
+    }
+
+    /**
+     * Gets the number of idle connections in the pool for a given user.
+     *
+     * @param userName
+     *            The user name key.
+     * @return The user specific value.
+     */
+    @SuppressWarnings("resource")
+    public int getNumIdle(final String userName) {
+        final ObjectPool<PooledConnectionAndInfo> pool = getPool(getPoolKey(userName));
+        return pool == null ? 0 : pool.getNumIdle();
+    }
 
     /**
-     * Gets the user specific value for
-     * {@link GenericObjectPool#getBlockWhenExhausted()} for the
-     * specified user's pool or the default if no user specific value is defined.
-     * @param key The user
-     * @return <code>true</code> to block
+     * Gets the user specific value for {@link GenericObjectPool#getBlockWhenExhausted()} for the specified user's pool
+     * or the default if no user specific value is defined.
+     *
+     * @param userName
+     *            The user name key.
+     * @return The user specific value.
      */
-    public boolean getPerUserBlockWhenExhausted(final String key) {
+    public boolean getPerUserBlockWhenExhausted(final String userName) {
         Boolean value = null;
         if (perUserBlockWhenExhausted != null) {
-            value = perUserBlockWhenExhausted.get(key);
+            value = perUserBlockWhenExhausted.get(userName);
         }
         if (value == null) {
             return getDefaultBlockWhenExhausted();
@@ -134,90 +205,82 @@ public class PerUserPoolDataSource exten
     }
 
     /**
-     * Sets a user specific value for
-     * {@link GenericObjectPool#getBlockWhenExhausted()} for the specified
-     * user's pool.
-     * @param username The user
-     * @param value The value
+     * Gets the user specific default value for {@link Connection#setAutoCommit(boolean)} for the specified user's pool.
+     *
+     * @param userName
+     *            The user name key.
+     * @return The user specific value.
      */
-    public void setPerUserBlockWhenExhausted(final String username,
-            final Boolean value) {
-        assertInitializationAllowed();
-        if (perUserBlockWhenExhausted == null) {
-            perUserBlockWhenExhausted = new HashMap<>();
+    public Boolean getPerUserDefaultAutoCommit(final String userName) {
+        Boolean value = null;
+        if (perUserDefaultAutoCommit != null) {
+            value = perUserDefaultAutoCommit.get(userName);
         }
-        perUserBlockWhenExhausted.put(username, value);
+        return value;
     }
 
-    void setPerUserBlockWhenExhausted(
-            final Map<String,Boolean> userDefaultBlockWhenExhausted) {
-        assertInitializationAllowed();
-        if (perUserBlockWhenExhausted == null) {
-            perUserBlockWhenExhausted = new HashMap<>();
-        } else {
-            perUserBlockWhenExhausted.clear();
+    /**
+     * Gets the user specific default value for {@link Connection#setReadOnly(boolean)} for the specified user's pool.
+     *
+     * @param userName
+     *            The user name key.
+     * @return The user specific value.
+     */
+    public Boolean getPerUserDefaultReadOnly(final String userName) {
+        Boolean value = null;
+        if (perUserDefaultReadOnly != null) {
+            value = perUserDefaultReadOnly.get(userName);
         }
-        perUserBlockWhenExhausted.putAll(userDefaultBlockWhenExhausted);
+        return value;
     }
 
-
     /**
-     * Gets the user specific value for
-     * {@link GenericObjectPool#getEvictionPolicyClassName()} for the
-     * specified user's pool or the default if no user specific value is defined.
-     * @param key The user
-     * @return the policy class name
+     * Gets the user specific default value for {@link Connection#setTransactionIsolation(int)} for the specified user's
+     * pool.
+     *
+     * @param userName
+     *            The user name key.
+     * @return The user specific value.
      */
-    public String getPerUserEvictionPolicyClassName(final String key) {
-        String value = null;
-        if (perUserEvictionPolicyClassName != null) {
-            value = perUserEvictionPolicyClassName.get(key);
-        }
-        if (value == null) {
-            return getDefaultEvictionPolicyClassName();
+    public Integer getPerUserDefaultTransactionIsolation(final String userName) {
+        Integer value = null;
+        if (perUserDefaultTransactionIsolation != null) {
+            value = perUserDefaultTransactionIsolation.get(userName);
         }
         return value;
     }
 
     /**
-     * Sets a user specific value for
-     * {@link GenericObjectPool#getEvictionPolicyClassName()} for the specified
-     * user's pool.
-     * @param username The user
-     * @param value The value
+     * Gets the user specific value for {@link GenericObjectPool#getEvictionPolicyClassName()} for the specified user's
+     * pool or the default if no user specific value is defined.
+     *
+     * @param userName
+     *            The user name key.
+     * @return The user specific value.
      */
-    public void setPerUserEvictionPolicyClassName(final String username,
-            final String value) {
-        assertInitializationAllowed();
-        if (perUserEvictionPolicyClassName == null) {
-            perUserEvictionPolicyClassName = new HashMap<>();
+    public String getPerUserEvictionPolicyClassName(final String userName) {
+        String value = null;
+        if (perUserEvictionPolicyClassName != null) {
+            value = perUserEvictionPolicyClassName.get(userName);
         }
-        perUserEvictionPolicyClassName.put(username, value);
-    }
-
-    void setPerUserEvictionPolicyClassName(
-            final Map<String,String> userDefaultEvictionPolicyClassName) {
-        assertInitializationAllowed();
-        if (perUserEvictionPolicyClassName == null) {
-            perUserEvictionPolicyClassName = new HashMap<>();
-        } else {
-            perUserEvictionPolicyClassName.clear();
+        if (value == null) {
+            return getDefaultEvictionPolicyClassName();
         }
-        perUserEvictionPolicyClassName.putAll(userDefaultEvictionPolicyClassName);
+        return value;
     }
 
-
     /**
-     * Gets the user specific value for {@link GenericObjectPool#getLifo()} for
-     * the specified user's pool or the default if no user specific value is
-     * defined.
-     * @param key The user
-     * @return <code>true</code> to use LIFO
+     * Gets the user specific value for {@link GenericObjectPool#getLifo()} for the specified user's pool or the default
+     * if no user specific value is defined.
+     *
+     * @param userName
+     *            The user name key.
+     * @return The user specific value.
      */
-    public boolean getPerUserLifo(final String key) {
+    public boolean getPerUserLifo(final String userName) {
         Boolean value = null;
         if (perUserLifo != null) {
-            value = perUserLifo.get(key);
+            value = perUserLifo.get(userName);
         }
         if (value == null) {
             return getDefaultLifo();
@@ -226,42 +289,17 @@ public class PerUserPoolDataSource exten
     }
 
     /**
-     * Sets a user specific value for
-     * {@link GenericObjectPool#getLifo()} for the specified
-     * user's pool.
-     * @param username The user
-     * @param value The value
-     */
-    public void setPerUserLifo(final String username, final Boolean value) {
-        assertInitializationAllowed();
-        if (perUserLifo == null) {
-            perUserLifo = new HashMap<>();
-        }
-        perUserLifo.put(username, value);
-    }
-
-    void setPerUserLifo(final Map<String,Boolean> userDefaultLifo) {
-        assertInitializationAllowed();
-        if (perUserLifo == null) {
-            perUserLifo = new HashMap<>();
-        } else {
-            perUserLifo.clear();
-        }
-        perUserLifo.putAll(userDefaultLifo);
-    }
-
-
-    /**
-     * Gets the user specific value for
-     * {@link GenericObjectPool#getMaxIdle()} for the
-     * specified user's pool or the default if no user specific value is defined.
-     * @param key The user
-     * @return the maximum idle
+     * Gets the user specific value for {@link GenericObjectPool#getMaxIdle()} for the specified user's pool or the
+     * default if no user specific value is defined.
+     *
+     * @param userName
+     *            The user name key.
+     * @return The user specific value.
      */
-    public int getPerUserMaxIdle(final String key) {
+    public int getPerUserMaxIdle(final String userName) {
         Integer value = null;
         if (perUserMaxIdle != null) {
-            value = perUserMaxIdle.get(key);
+            value = perUserMaxIdle.get(userName);
         }
         if (value == null) {
             return getDefaultMaxIdle();
@@ -270,42 +308,17 @@ public class PerUserPoolDataSource exten
     }
 
     /**
-     * Sets a user specific value for
-     * {@link GenericObjectPool#getMaxIdle()} for the specified
-     * user's pool.
-     * @param username The user
-     * @param value The value
-     */
-    public void setPerUserMaxIdle(final String username, final Integer value) {
-        assertInitializationAllowed();
-        if (perUserMaxIdle == null) {
-            perUserMaxIdle = new HashMap<>();
-        }
-        perUserMaxIdle.put(username, value);
-    }
-
-    void setPerUserMaxIdle(final Map<String,Integer> userDefaultMaxIdle) {
-        assertInitializationAllowed();
-        if (perUserMaxIdle == null) {
-            perUserMaxIdle = new HashMap<>();
-        } else {
-            perUserMaxIdle.clear();
-        }
-        perUserMaxIdle.putAll(userDefaultMaxIdle);
-    }
-
-
-    /**
-     * Gets the user specific value for
-     * {@link GenericObjectPool#getMaxTotal()} for the
-     * specified user's pool or the default if no user specific value is defined.
-     * @param key The user
-     * @return the maximum total
+     * Gets the user specific value for {@link GenericObjectPool#getMaxTotal()} for the specified user's pool or the
+     * default if no user specific value is defined.
+     *
+     * @param userName
+     *            The user name key.
+     * @return The user specific value.
      */
-    public int getPerUserMaxTotal(final String key) {
+    public int getPerUserMaxTotal(final String userName) {
         Integer value = null;
         if (perUserMaxTotal != null) {
-            value = perUserMaxTotal.get(key);
+            value = perUserMaxTotal.get(userName);
         }
         if (value == null) {
             return getDefaultMaxTotal();
@@ -314,42 +327,17 @@ public class PerUserPoolDataSource exten
     }
 
     /**
-     * Sets a user specific value for
-     * {@link GenericObjectPool#getMaxTotal()} for the specified
-     * user's pool.
-     * @param username The user
-     * @param value The value
-     */
-    public void setPerUserMaxTotal(final String username, final Integer value) {
-        assertInitializationAllowed();
-        if (perUserMaxTotal == null) {
-            perUserMaxTotal = new HashMap<>();
-        }
-        perUserMaxTotal.put(username, value);
-    }
-
-    void setPerUserMaxTotal(final Map<String,Integer> userDefaultMaxTotal) {
-        assertInitializationAllowed();
-        if (perUserMaxTotal == null) {
-            perUserMaxTotal = new HashMap<>();
-        } else {
-            perUserMaxTotal.clear();
-        }
-        perUserMaxTotal.putAll(userDefaultMaxTotal);
-    }
-
-
-    /**
-     * Gets the user specific value for
-     * {@link GenericObjectPool#getMaxWaitMillis()} for the
-     * specified user's pool or the default if no user specific value is defined.
-     * @param key The user
-     * @return the maximum wait time
+     * Gets the user specific value for {@link GenericObjectPool#getMaxWaitMillis()} for the specified user's pool or
+     * the default if no user specific value is defined.
+     *
+     * @param userName
+     *            The user name key.
+     * @return The user specific value.
      */
-    public long getPerUserMaxWaitMillis(final String key) {
+    public long getPerUserMaxWaitMillis(final String userName) {
         Long value = null;
         if (perUserMaxWaitMillis != null) {
-            value = perUserMaxWaitMillis.get(key);
+            value = perUserMaxWaitMillis.get(userName);
         }
         if (value == null) {
             return getDefaultMaxWaitMillis();
@@ -358,43 +346,17 @@ public class PerUserPoolDataSource exten
     }
 
     /**
-     * Sets a user specific value for
-     * {@link GenericObjectPool#getMaxWaitMillis()} for the specified
-     * user's pool.
-     * @param username The user
-     * @param value The value
-     */
-    public void setPerUserMaxWaitMillis(final String username, final Long value) {
-        assertInitializationAllowed();
-        if (perUserMaxWaitMillis == null) {
-            perUserMaxWaitMillis = new HashMap<>();
-        }
-        perUserMaxWaitMillis.put(username, value);
-    }
-
-    void setPerUserMaxWaitMillis(
-            final Map<String,Long> userDefaultMaxWaitMillis) {
-        assertInitializationAllowed();
-        if (perUserMaxWaitMillis == null) {
-            perUserMaxWaitMillis = new HashMap<>();
-        } else {
-            perUserMaxWaitMillis.clear();
-        }
-        perUserMaxWaitMillis.putAll(userDefaultMaxWaitMillis);
-    }
-
-
-    /**
-     * Gets the user specific value for
-     * {@link GenericObjectPool#getMinEvictableIdleTimeMillis()} for the
-     * specified user's pool or the default if no user specific value is defined.
-     * @param key The user
-     * @return the minimum idle time for eviction
+     * Gets the user specific value for {@link GenericObjectPool#getMinEvictableIdleTimeMillis()} for the specified
+     * user's pool or the default if no user specific value is defined.
+     *
+     * @param userName
+     *            The user name key.
+     * @return The user specific value.
      */
-    public long getPerUserMinEvictableIdleTimeMillis(final String key) {
+    public long getPerUserMinEvictableIdleTimeMillis(final String userName) {
         Long value = null;
         if (perUserMinEvictableIdleTimeMillis != null) {
-            value = perUserMinEvictableIdleTimeMillis.get(key);
+            value = perUserMinEvictableIdleTimeMillis.get(userName);
         }
         if (value == null) {
             return getDefaultMinEvictableIdleTimeMillis();
@@ -403,45 +365,17 @@ public class PerUserPoolDataSource exten
     }
 
     /**
-     * Sets a user specific value for
-     * {@link GenericObjectPool#getMinEvictableIdleTimeMillis()} for the
-     * specified user's pool.
-     * @param username The user
-     * @param value The value
-     */
-    public void setPerUserMinEvictableIdleTimeMillis(final String username,
-            final Long value) {
-        assertInitializationAllowed();
-        if (perUserMinEvictableIdleTimeMillis == null) {
-            perUserMinEvictableIdleTimeMillis = new HashMap<>();
-        }
-        perUserMinEvictableIdleTimeMillis.put(username, value);
-    }
-
-    void setPerUserMinEvictableIdleTimeMillis(
-            final Map<String,Long> userDefaultMinEvictableIdleTimeMillis) {
-        assertInitializationAllowed();
-        if (perUserMinEvictableIdleTimeMillis == null) {
-            perUserMinEvictableIdleTimeMillis = new HashMap<>();
-        } else {
-            perUserMinEvictableIdleTimeMillis.clear();
-        }
-        perUserMinEvictableIdleTimeMillis.putAll(
-                userDefaultMinEvictableIdleTimeMillis);
-    }
-
-
-    /**
-     * Gets the user specific value for
-     * {@link GenericObjectPool#getMinIdle()} for the
-     * specified user's pool or the default if no user specific value is defined.
-     * @param key The user
-     * @return the minimum idle count
+     * Gets the user specific value for {@link GenericObjectPool#getMinIdle()} for the specified user's pool or the
+     * default if no user specific value is defined.
+     *
+     * @param userName
+     *            The user name key.
+     * @return The user specific value.
      */
-    public int getPerUserMinIdle(final String key) {
+    public int getPerUserMinIdle(final String userName) {
         Integer value = null;
         if (perUserMinIdle != null) {
-            value = perUserMinIdle.get(key);
+            value = perUserMinIdle.get(userName);
         }
         if (value == null) {
             return getDefaultMinIdle();
@@ -450,42 +384,17 @@ public class PerUserPoolDataSource exten
     }
 
     /**
-     * Sets a user specific value for
-     * {@link GenericObjectPool#getMinIdle()} for the specified
-     * user's pool.
-     * @param username The user
-     * @param value The value
-     */
-    public void setPerUserMinIdle(final String username, final Integer value) {
-        assertInitializationAllowed();
-        if (perUserMinIdle == null) {
-            perUserMinIdle = new HashMap<>();
-        }
-        perUserMinIdle.put(username, value);
-    }
-
-    void setPerUserMinIdle(final Map<String,Integer> userDefaultMinIdle) {
-        assertInitializationAllowed();
-        if (perUserMinIdle == null) {
-            perUserMinIdle = new HashMap<>();
-        } else {
-            perUserMinIdle.clear();
-        }
-        perUserMinIdle.putAll(userDefaultMinIdle);
-    }
-
-
-    /**
-     * Gets the user specific value for
-     * {@link GenericObjectPool#getNumTestsPerEvictionRun()} for the
-     * specified user's pool or the default if no user specific value is defined.
-     * @param key The user
-     * @return the tests count
+     * Gets the user specific value for {@link GenericObjectPool#getNumTestsPerEvictionRun()} for the specified user's
+     * pool or the default if no user specific value is defined.
+     *
+     * @param userName
+     *            The user name key.
+     * @return The user specific value.
      */
-    public int getPerUserNumTestsPerEvictionRun(final String key) {
+    public int getPerUserNumTestsPerEvictionRun(final String userName) {
         Integer value = null;
         if (perUserNumTestsPerEvictionRun != null) {
-            value = perUserNumTestsPerEvictionRun.get(key);
+            value = perUserNumTestsPerEvictionRun.get(userName);
         }
         if (value == null) {
             return getDefaultNumTestsPerEvictionRun();
@@ -494,44 +403,17 @@ public class PerUserPoolDataSource exten
     }
 
     /**
-     * Sets a user specific value for
-     * {@link GenericObjectPool#getNumTestsPerEvictionRun()} for the specified
-     * user's pool.
-     * @param username The user
-     * @param value The value
-     */
-    public void setPerUserNumTestsPerEvictionRun(final String username,
-            final Integer value) {
-        assertInitializationAllowed();
-        if (perUserNumTestsPerEvictionRun == null) {
-            perUserNumTestsPerEvictionRun = new HashMap<>();
-        }
-        perUserNumTestsPerEvictionRun.put(username, value);
-    }
-
-    void setPerUserNumTestsPerEvictionRun(
-            final Map<String,Integer> userDefaultNumTestsPerEvictionRun) {
-        assertInitializationAllowed();
-        if (perUserNumTestsPerEvictionRun == null) {
-            perUserNumTestsPerEvictionRun = new HashMap<>();
-        } else {
-            perUserNumTestsPerEvictionRun.clear();
-        }
-        perUserNumTestsPerEvictionRun.putAll(userDefaultNumTestsPerEvictionRun);
-    }
-
-
-    /**
-     * Gets the user specific value for
-     * {@link GenericObjectPool#getSoftMinEvictableIdleTimeMillis()} for the
-     * specified user's pool or the default if no user specific value is defined.
-     * @param key The user
-     * @return the soft minimum idle time for eviction
+     * Gets the user specific value for {@link GenericObjectPool#getSoftMinEvictableIdleTimeMillis()} for the specified
+     * user's pool or the default if no user specific value is defined.
+     *
+     * @param userName
+     *            The user name key.
+     * @return The user specific value.
      */
-    public long getPerUserSoftMinEvictableIdleTimeMillis(final String key) {
+    public long getPerUserSoftMinEvictableIdleTimeMillis(final String userName) {
         Long value = null;
         if (perUserSoftMinEvictableIdleTimeMillis != null) {
-            value = perUserSoftMinEvictableIdleTimeMillis.get(key);
+            value = perUserSoftMinEvictableIdleTimeMillis.get(userName);
         }
         if (value == null) {
             return getDefaultSoftMinEvictableIdleTimeMillis();
@@ -540,44 +422,36 @@ public class PerUserPoolDataSource exten
     }
 
     /**
-     * Sets a user specific value for
-     * {@link GenericObjectPool#getSoftMinEvictableIdleTimeMillis()} for the
-     * specified user's pool.
-     * @param username The user
-     * @param value The value
+     * Gets the user specific value for {@link GenericObjectPool#getTestOnBorrow()} for the specified user's pool or the
+     * default if no user specific value is defined.
+     *
+     * @param userName
+     *            The user name key.
+     * @return The user specific value.
      */
-    public void setPerUserSoftMinEvictableIdleTimeMillis(final String username,
-            final Long value) {
-        assertInitializationAllowed();
-        if (perUserSoftMinEvictableIdleTimeMillis == null) {
-            perUserSoftMinEvictableIdleTimeMillis = new HashMap<>();
+    public boolean getPerUserTestOnBorrow(final String userName) {
+        Boolean value = null;
+        if (perUserTestOnBorrow != null) {
+            value = perUserTestOnBorrow.get(userName);
         }
-        perUserSoftMinEvictableIdleTimeMillis.put(username, value);
-    }
-
-    void setPerUserSoftMinEvictableIdleTimeMillis(
-            final Map<String,Long> userDefaultSoftMinEvictableIdleTimeMillis) {
-        assertInitializationAllowed();
-        if (perUserSoftMinEvictableIdleTimeMillis == null) {
-            perUserSoftMinEvictableIdleTimeMillis = new HashMap<>();
-        } else {
-            perUserSoftMinEvictableIdleTimeMillis.clear();
+        if (value == null) {
+            return getDefaultTestOnBorrow();
         }
-        perUserSoftMinEvictableIdleTimeMillis.putAll(userDefaultSoftMinEvictableIdleTimeMillis);
+        return value.booleanValue();
     }
 
-
     /**
-     * Gets the user specific value for
-     * {@link GenericObjectPool#getTestOnCreate()} for the
-     * specified user's pool or the default if no user specific value is defined.
-     * @param key The user
-     * @return <code>true</code> to test on create
+     * Gets the user specific value for {@link GenericObjectPool#getTestOnCreate()} for the specified user's pool or the
+     * default if no user specific value is defined.
+     *
+     * @param userName
+     *            The user name key.
+     * @return The user specific value.
      */
-    public boolean getPerUserTestOnCreate(final String key) {
+    public boolean getPerUserTestOnCreate(final String userName) {
         Boolean value = null;
         if (perUserTestOnCreate != null) {
-            value = perUserTestOnCreate.get(key);
+            value = perUserTestOnCreate.get(userName);
         }
         if (value == null) {
             return getDefaultTestOnCreate();
@@ -586,459 +460,708 @@ public class PerUserPoolDataSource exten
     }
 
     /**
-     * Sets a user specific value for
-     * {@link GenericObjectPool#getTestOnCreate()} for the specified
-     * user's pool.
-     * @param username The user
-     * @param value The value
+     * Gets the user specific value for {@link GenericObjectPool#getTestOnReturn()} for the specified user's pool or the
+     * default if no user specific value is defined.
+     *
+     * @param userName
+     *            The user name key.
+     * @return The user specific value.
      */
-    public void setPerUserTestOnCreate(final String username, final Boolean value) {
-        assertInitializationAllowed();
-        if (perUserTestOnCreate == null) {
-            perUserTestOnCreate = new HashMap<>();
+    public boolean getPerUserTestOnReturn(final String userName) {
+        Boolean value = null;
+        if (perUserTestOnReturn != null) {
+            value = perUserTestOnReturn.get(userName);
+        }
+        if (value == null) {
+            return getDefaultTestOnReturn();
         }
-        perUserTestOnCreate.put(username, value);
+        return value.booleanValue();
     }
 
-    void setPerUserTestOnCreate(final Map<String,Boolean> userDefaultTestOnCreate) {
-        assertInitializationAllowed();
-        if (perUserTestOnCreate == null) {
-            perUserTestOnCreate = new HashMap<>();
-        } else {
-            perUserTestOnCreate.clear();
-        }
-        perUserTestOnCreate.putAll(userDefaultTestOnCreate);
-    }
-
-
     /**
-     * Gets the user specific value for
-     * {@link GenericObjectPool#getTestOnBorrow()} for the
-     * specified user's pool or the default if no user specific value is defined.
-     * @param key The user
-     * @return <code>true</code> to test on borrow
+     * Gets the user specific value for {@link GenericObjectPool#getTestWhileIdle()} for the specified user's pool or
+     * the default if no user specific value is defined.
+     *
+     * @param userName
+     *            The user name key.
+     * @return The user specific value.
      */
-    public boolean getPerUserTestOnBorrow(final String key) {
+    public boolean getPerUserTestWhileIdle(final String userName) {
         Boolean value = null;
-        if (perUserTestOnBorrow != null) {
-            value = perUserTestOnBorrow.get(key);
+        if (perUserTestWhileIdle != null) {
+            value = perUserTestWhileIdle.get(userName);
         }
         if (value == null) {
-            return getDefaultTestOnBorrow();
+            return getDefaultTestWhileIdle();
         }
         return value.booleanValue();
     }
 
     /**
-     * Sets a user specific value for
-     * {@link GenericObjectPool#getTestOnBorrow()} for the specified
-     * user's pool.
-     * @param username The user
-     * @param value The value
+     * Gets the user specific value for {@link GenericObjectPool#getTimeBetweenEvictionRunsMillis()} for the specified
+     * user's pool or the default if no user specific value is defined.
+     *
+     * @param userName
+     *            The user name key.
+     * @return The user specific value.
      */
-    public void setPerUserTestOnBorrow(final String username, final Boolean value) {
-        assertInitializationAllowed();
-        if (perUserTestOnBorrow == null) {
-            perUserTestOnBorrow = new HashMap<>();
+    public long getPerUserTimeBetweenEvictionRunsMillis(final String userName) {
+        Long value = null;
+        if (perUserTimeBetweenEvictionRunsMillis != null) {
+            value = perUserTimeBetweenEvictionRunsMillis.get(userName);
+        }
+        if (value == null) {
+            return getDefaultTimeBetweenEvictionRunsMillis();
         }
-        perUserTestOnBorrow.put(username, value);
+        return value.longValue();
     }
 
-    void setPerUserTestOnBorrow(final Map<String,Boolean> userDefaultTestOnBorrow) {
-        assertInitializationAllowed();
-        if (perUserTestOnBorrow == null) {
-            perUserTestOnBorrow = new HashMap<>();
-        } else {
-            perUserTestOnBorrow.clear();
+    /**
+     * Returns the object pool associated with the given PoolKey.
+     *
+     * @param poolKey
+     *            PoolKey identifying the pool
+     * @return the GenericObjectPool pooling connections for the userName and datasource specified by the PoolKey
+     */
+    private ObjectPool<PooledConnectionAndInfo> getPool(final PoolKey poolKey) {
+        final CPDSConnectionFactory mgr = (CPDSConnectionFactory) managers.get(poolKey);
+        return mgr == null ? null : mgr.getPool();
+    }
+
+    @Override
+    protected PooledConnectionAndInfo getPooledConnectionAndInfo(final String userName, final String password)
+            throws SQLException {
+
+        final PoolKey key = getPoolKey(userName);
+        ObjectPool<PooledConnectionAndInfo> pool;
+        PooledConnectionManager manager;
+        synchronized (this) {
+            manager = managers.get(key);
+            if (manager == null) {
+                try {
+                    registerPool(userName, password);
+                    manager = managers.get(key);
+                } catch (final NamingException e) {
+                    throw new SQLException("RegisterPool failed", e);
+                }
+            }
+            pool = getCPDSConnectionFactoryPool(manager);
         }
-        perUserTestOnBorrow.putAll(userDefaultTestOnBorrow);
+
+        PooledConnectionAndInfo info = null;
+        try {
+            info = pool.borrowObject();
+        } catch (final NoSuchElementException ex) {
+            throw new SQLException("Could not retrieve connection info from pool", ex);
+        } catch (final Exception e) {
+            // See if failure is due to CPDSConnectionFactory authentication failure
+            try {
+                testCPDS(userName, password);
+            } catch (final Exception ex) {
+                throw new SQLException("Could not retrieve connection info from pool", ex);
+            }
+            // New password works, so kill the old pool, create a new one, and borrow
+            manager.closePool(userName);
+            synchronized (this) {
+                managers.remove(key);
+            }
+            try {
+                registerPool(userName, password);
+                pool = getPool(key);
+            } catch (final NamingException ne) {
+                throw new SQLException("RegisterPool failed", ne);
+            }
+            try {
+                info = pool.borrowObject();
+            } catch (final Exception ex) {
+                throw new SQLException("Could not retrieve connection info from pool", ex);
+            }
+        }
+        return info;
     }
 
+    /**
+     * Creates a pool key from the provided parameters.
+     *
+     * @param userName
+     *            User name
+     * @return The pool key
+     */
+    private PoolKey getPoolKey(final String userName) {
+        return new PoolKey(getDataSourceName(), userName);
+    }
 
     /**
-     * Gets the user specific value for
-     * {@link GenericObjectPool#getTestOnReturn()} for the
-     * specified user's pool or the default if no user specific value is defined.
-     * @param key The user
-     * @return <code>true</code> to test on return
+     * Returns a <code>PerUserPoolDataSource</code> {@link Reference}.
      */
-    public boolean getPerUserTestOnReturn(final String key) {
-        Boolean value = null;
-        if (perUserTestOnReturn != null) {
-            value = perUserTestOnReturn.get(key);
+    @Override
+    public Reference getReference() throws NamingException {
+        final Reference ref = new Reference(getClass().getName(), PerUserPoolDataSourceFactory.class.getName(), null);
+        ref.add(new StringRefAddr("instanceKey", getInstanceKey()));
+        return ref;
+    }
+
+    /**
+     * Supports Serialization interface.
+     *
+     * @param in
+     *            a <code>java.io.ObjectInputStream</code> value
+     * @throws IOException
+     *             if an error occurs
+     * @throws ClassNotFoundException
+     *             if an error occurs
+     */
+    private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException {
+        try {
+            in.defaultReadObject();
+            final PerUserPoolDataSource oldDS = (PerUserPoolDataSource) new PerUserPoolDataSourceFactory()
+                    .getObjectInstance(getReference(), null, null, null);
+            this.managers = oldDS.managers;
+        } catch (final NamingException e) {
+            throw new IOException("NamingException: " + e);
         }
-        if (value == null) {
-            return getDefaultTestOnReturn();
+    }
+
+    private synchronized void registerPool(final String userName, final String password)
+            throws NamingException, SQLException {
+
+        final ConnectionPoolDataSource cpds = testCPDS(userName, password);
+
+        // Set up the factory we will use (passing the pool associates
+        // the factory with the pool, so we do not have to do so
+        // explicitly)
+        final CPDSConnectionFactory factory = new CPDSConnectionFactory(cpds, getValidationQuery(),
+                getValidationQueryTimeout(), isRollbackAfterValidation(), userName, password);
+        factory.setMaxConnLifetimeMillis(getMaxConnLifetimeMillis());
+
+        // Create an object pool to contain our PooledConnections
+        final GenericObjectPool<PooledConnectionAndInfo> pool = new GenericObjectPool<>(factory);
+        factory.setPool(pool);
+        pool.setBlockWhenExhausted(getPerUserBlockWhenExhausted(userName));
+        pool.setEvictionPolicyClassName(getPerUserEvictionPolicyClassName(userName));
+        pool.setLifo(getPerUserLifo(userName));
+        pool.setMaxIdle(getPerUserMaxIdle(userName));
+        pool.setMaxTotal(getPerUserMaxTotal(userName));
+        pool.setMaxWaitMillis(getPerUserMaxWaitMillis(userName));
+        pool.setMinEvictableIdleTimeMillis(getPerUserMinEvictableIdleTimeMillis(userName));
+        pool.setMinIdle(getPerUserMinIdle(userName));
+        pool.setNumTestsPerEvictionRun(getPerUserNumTestsPerEvictionRun(userName));
+        pool.setSoftMinEvictableIdleTimeMillis(getPerUserSoftMinEvictableIdleTimeMillis(userName));
+        pool.setTestOnCreate(getPerUserTestOnCreate(userName));
+        pool.setTestOnBorrow(getPerUserTestOnBorrow(userName));
+        pool.setTestOnReturn(getPerUserTestOnReturn(userName));
+        pool.setTestWhileIdle(getPerUserTestWhileIdle(userName));
+        pool.setTimeBetweenEvictionRunsMillis(getPerUserTimeBetweenEvictionRunsMillis(userName));
+
+        pool.setSwallowedExceptionListener(new SwallowedExceptionLogger(log));
+
+        final Object old = managers.put(getPoolKey(userName), factory);
+        if (old != null) {
+            throw new IllegalStateException("Pool already contains an entry for this user/password: " + userName);
         }
-        return value.booleanValue();
+    }
+
+    void setPerUserBlockWhenExhausted(final Map<String, Boolean> userDefaultBlockWhenExhausted) {
+        assertInitializationAllowed();
+        if (perUserBlockWhenExhausted == null) {
+            perUserBlockWhenExhausted = createMap();
+        } else {
+            perUserBlockWhenExhausted.clear();
+        }
+        perUserBlockWhenExhausted.putAll(userDefaultBlockWhenExhausted);
     }
 
     /**
-     * Sets a user specific value for
-     * {@link GenericObjectPool#getTestOnReturn()} for the specified
-     * user's pool.
-     * @param username The user
-     * @param value The value
+     * Sets a user specific value for {@link GenericObjectPool#getBlockWhenExhausted()} for the specified user's pool.
+     *
+     * @param userName
+     *            The user name key.
+     * @param value
+     *            The user specific value.
      */
-    public void setPerUserTestOnReturn(final String username, final Boolean value) {
+    public void setPerUserBlockWhenExhausted(final String userName, final Boolean value) {
         assertInitializationAllowed();
-        if (perUserTestOnReturn == null) {
-            perUserTestOnReturn = new HashMap<>();
+        if (perUserBlockWhenExhausted == null) {
+            perUserBlockWhenExhausted = createMap();
         }
-        perUserTestOnReturn.put(username, value);
+        perUserBlockWhenExhausted.put(userName, value);
     }
 
-    void setPerUserTestOnReturn(
-            final Map<String,Boolean> userDefaultTestOnReturn) {
+    void setPerUserDefaultAutoCommit(final Map<String, Boolean> userDefaultAutoCommit) {
         assertInitializationAllowed();
-        if (perUserTestOnReturn == null) {
-            perUserTestOnReturn = new HashMap<>();
+        if (perUserDefaultAutoCommit == null) {
+            perUserDefaultAutoCommit = createMap();
         } else {
-            perUserTestOnReturn.clear();
+            perUserDefaultAutoCommit.clear();
         }
-        perUserTestOnReturn.putAll(userDefaultTestOnReturn);
+        perUserDefaultAutoCommit.putAll(userDefaultAutoCommit);
     }
 
-
     /**
-     * Gets the user specific value for
-     * {@link GenericObjectPool#getTestWhileIdle()} for the
-     * specified user's pool or the default if no user specific value is defined.
-     * @param key The user
-     * @return <code>true</code> to test while idle
+     * Sets a user specific default value for {@link Connection#setAutoCommit(boolean)} for the specified user's pool.
+     *
+     * @param userName
+     *            The user name key.
+     * @param value
+     *            The user specific value.
      */
-    public boolean getPerUserTestWhileIdle(final String key) {
-        Boolean value = null;
-        if (perUserTestWhileIdle != null) {
-            value = perUserTestWhileIdle.get(key);
+    public void setPerUserDefaultAutoCommit(final String userName, final Boolean value) {
+        assertInitializationAllowed();
+        if (perUserDefaultAutoCommit == null) {
+            perUserDefaultAutoCommit = createMap();
         }
-        if (value == null) {
-            return getDefaultTestWhileIdle();
+        perUserDefaultAutoCommit.put(userName, value);
+    }
+
+    void setPerUserDefaultReadOnly(final Map<String, Boolean> userDefaultReadOnly) {
+        assertInitializationAllowed();
+        if (perUserDefaultReadOnly == null) {
+            perUserDefaultReadOnly = createMap();
+        } else {
+            perUserDefaultReadOnly.clear();
         }
-        return value.booleanValue();
+        perUserDefaultReadOnly.putAll(userDefaultReadOnly);
     }
 
     /**
-     * Sets a user specific value for
-     * {@link GenericObjectPool#getTestWhileIdle()} for the specified
-     * user's pool.
-     * @param username The user
-     * @param value The value
+     * Sets a user specific default value for {@link Connection#setReadOnly(boolean)} for the specified user's pool.
+     *
+     * @param userName
+     *            The user name key.
+     * @param value
+     *            The user specific value.
      */
-    public void setPerUserTestWhileIdle(final String username, final Boolean value) {
+    public void setPerUserDefaultReadOnly(final String userName, final Boolean value) {
         assertInitializationAllowed();
-        if (perUserTestWhileIdle == null) {
-            perUserTestWhileIdle = new HashMap<>();
+        if (perUserDefaultReadOnly == null) {
+            perUserDefaultReadOnly = createMap();
         }
-        perUserTestWhileIdle.put(username, value);
+        perUserDefaultReadOnly.put(userName, value);
     }
 
-    void setPerUserTestWhileIdle(
-            final Map<String,Boolean> userDefaultTestWhileIdle) {
+    void setPerUserDefaultTransactionIsolation(final Map<String, Integer> userDefaultTransactionIsolation) {
         assertInitializationAllowed();
-        if (perUserTestWhileIdle == null) {
-            perUserTestWhileIdle = new HashMap<>();
+        if (perUserDefaultTransactionIsolation == null) {
+            perUserDefaultTransactionIsolation = new HashMap<>();
         } else {
-            perUserTestWhileIdle.clear();
+            perUserDefaultTransactionIsolation.clear();
         }
-        perUserTestWhileIdle.putAll(userDefaultTestWhileIdle);
+        perUserDefaultTransactionIsolation.putAll(userDefaultTransactionIsolation);
     }
 
-
     /**
-     * Gets the user specific value for
-     * {@link GenericObjectPool#getTimeBetweenEvictionRunsMillis()} for the
-     * specified user's pool or the default if no user specific value is defined.
-     * @param key The user
-     * @return time between eviction runs
+     * Sets a user specific default value for {@link Connection#setTransactionIsolation(int)} for the specified user's
+     * pool.
+     *
+     * @param userName
+     *            The user name key.
+     * @param value
+     *            The user specific value.
      */
-    public long getPerUserTimeBetweenEvictionRunsMillis(final String key) {
-        Long value = null;
-        if (perUserTimeBetweenEvictionRunsMillis != null) {
-            value = perUserTimeBetweenEvictionRunsMillis.get(key);
+    public void setPerUserDefaultTransactionIsolation(final String userName, final Integer value) {
+        assertInitializationAllowed();
+        if (perUserDefaultTransactionIsolation == null) {
+            perUserDefaultTransactionIsolation = new HashMap<>();
         }
-        if (value == null) {
-            return getDefaultTimeBetweenEvictionRunsMillis();
+        perUserDefaultTransactionIsolation.put(userName, value);
+    }
+
+    void setPerUserEvictionPolicyClassName(final Map<String, String> userDefaultEvictionPolicyClassName) {
+        assertInitializationAllowed();
+        if (perUserEvictionPolicyClassName == null) {
+            perUserEvictionPolicyClassName = new HashMap<>();
+        } else {
+            perUserEvictionPolicyClassName.clear();
         }
-        return value.longValue();
+        perUserEvictionPolicyClassName.putAll(userDefaultEvictionPolicyClassName);
     }
 
     /**
-     * Sets a user specific value for
-     * {@link GenericObjectPool#getTimeBetweenEvictionRunsMillis ()} for the specified
-     * user's pool.
-     * @param username The user
-     * @param value The value
+     * Sets a user specific value for {@link GenericObjectPool#getEvictionPolicyClassName()} for the specified user's
+     * pool.
+     *
+     * @param userName
+     *            The user name key.
+     * @param value
+     *            The user specific value.
      */
-    public void setPerUserTimeBetweenEvictionRunsMillis(final String username,
-            final Long value) {
+    public void setPerUserEvictionPolicyClassName(final String userName, final String value) {
         assertInitializationAllowed();
-        if (perUserTimeBetweenEvictionRunsMillis == null) {
-            perUserTimeBetweenEvictionRunsMillis = new HashMap<>();
+        if (perUserEvictionPolicyClassName == null) {
+            perUserEvictionPolicyClassName = new HashMap<>();
         }
-        perUserTimeBetweenEvictionRunsMillis.put(username, value);
+        perUserEvictionPolicyClassName.put(userName, value);
     }
 
-    void setPerUserTimeBetweenEvictionRunsMillis(
-            final Map<String,Long> userDefaultTimeBetweenEvictionRunsMillis ) {
+    void setPerUserLifo(final Map<String, Boolean> userDefaultLifo) {
         assertInitializationAllowed();
-        if (perUserTimeBetweenEvictionRunsMillis == null) {
-            perUserTimeBetweenEvictionRunsMillis = new HashMap<>();
+        if (perUserLifo == null) {
+            perUserLifo = createMap();
         } else {
-            perUserTimeBetweenEvictionRunsMillis.clear();
+            perUserLifo.clear();
         }
-        perUserTimeBetweenEvictionRunsMillis.putAll(
-                userDefaultTimeBetweenEvictionRunsMillis );
+        perUserLifo.putAll(userDefaultLifo);
     }
 
-
     /**
-     * Gets the user specific default value for
-     * {@link Connection#setAutoCommit(boolean)} for the specified user's pool.
-     * @param key The user
-     * @return <code>true</code> to commit automatically
+     * Sets a user specific value for {@link GenericObjectPool#getLifo()} for the specified user's pool.
+     *
+     * @param userName
+     *            The user name key.
+     * @param value
+     *            The user specific value.
      */
-    public Boolean getPerUserDefaultAutoCommit(final String key) {
-        Boolean value = null;
-        if (perUserDefaultAutoCommit != null) {
-            value = perUserDefaultAutoCommit.get(key);
+    public void setPerUserLifo(final String userName, final Boolean value) {
+        assertInitializationAllowed();
+        if (perUserLifo == null) {
+            perUserLifo = createMap();
         }
-        return value;
+        perUserLifo.put(userName, value);
+    }
+
+    void setPerUserMaxIdle(final Map<String, Integer> userDefaultMaxIdle) {
+        assertInitializationAllowed();
+        if (perUserMaxIdle == null) {
+            perUserMaxIdle = new HashMap<>();
+        } else {
+            perUserMaxIdle.clear();
+        }
+        perUserMaxIdle.putAll(userDefaultMaxIdle);
     }
 
     /**
-     * Sets a user specific default value for
-     * {@link Connection#setAutoCommit(boolean)} for the specified user's pool.
-     * @param username The user
-     * @param value The value
+     * Sets a user specific value for {@link GenericObjectPool#getMaxIdle()} for the specified user's pool.
+     *
+     * @param userName
+     *            The user name key.
+     * @param value
+     *            The user specific value.
      */
-    public void setPerUserDefaultAutoCommit(final String username, final Boolean value) {
+    public void setPerUserMaxIdle(final String userName, final Integer value) {
         assertInitializationAllowed();
-        if (perUserDefaultAutoCommit == null) {
-            perUserDefaultAutoCommit = new HashMap<>();
+        if (perUserMaxIdle == null) {
+            perUserMaxIdle = new HashMap<>();
         }
-        perUserDefaultAutoCommit.put(username, value);
+        perUserMaxIdle.put(userName, value);
     }
 
-    void setPerUserDefaultAutoCommit(final Map<String,Boolean> userDefaultAutoCommit) {
+    void setPerUserMaxTotal(final Map<String, Integer> userDefaultMaxTotal) {
         assertInitializationAllowed();
-        if (perUserDefaultAutoCommit == null) {
-            perUserDefaultAutoCommit = new HashMap<>();
+        if (perUserMaxTotal == null) {
+            perUserMaxTotal = new HashMap<>();
         } else {
-            perUserDefaultAutoCommit.clear();
+            perUserMaxTotal.clear();
         }
-        perUserDefaultAutoCommit.putAll(userDefaultAutoCommit);
+        perUserMaxTotal.putAll(userDefaultMaxTotal);
     }
 
-
     /**
-     * Gets the user specific default value for
-     * {@link Connection#setReadOnly(boolean)} for the specified user's pool.
-     * @param key The user
-     * @return <code>true</code> is read only by default
+     * Sets a user specific value for {@link GenericObjectPool#getMaxTotal()} for the specified user's pool.
+     *
+     * @param userName
+     *            The user name key.
+     * @param value
+     *            The user specific value.
      */
-    public Boolean getPerUserDefaultReadOnly(final String key) {
-        Boolean value = null;
-        if (perUserDefaultReadOnly != null) {
-            value = perUserDefaultReadOnly.get(key);
+    public void setPerUserMaxTotal(final String userName, final Integer value) {
+        assertInitializationAllowed();
+        if (perUserMaxTotal == null) {
+            perUserMaxTotal = new HashMap<>();
         }
-        return value;
+        perUserMaxTotal.put(userName, value);
+    }
+
+    void setPerUserMaxWaitMillis(final Map<String, Long> userDefaultMaxWaitMillis) {
+        assertInitializationAllowed();
+        if (perUserMaxWaitMillis == null) {
+            perUserMaxWaitMillis = new HashMap<>();
+        } else {
+            perUserMaxWaitMillis.clear();
+        }
+        perUserMaxWaitMillis.putAll(userDefaultMaxWaitMillis);
     }
 
     /**
-     * Sets a user specific default value for
-     * {@link Connection#setReadOnly(boolean)} for the specified user's pool.
-     * @param username The user
-     * @param value The value
+     * Sets a user specific value for {@link GenericObjectPool#getMaxWaitMillis()} for the specified user's pool.
+     *
+     * @param userName
+     *            The user name key.
+     * @param value
+     *            The user specific value.
      */
-    public void setPerUserDefaultReadOnly(final String username, final Boolean value) {
+    public void setPerUserMaxWaitMillis(final String userName, final Long value) {
         assertInitializationAllowed();
-        if (perUserDefaultReadOnly == null) {
-            perUserDefaultReadOnly = new HashMap<>();
+        if (perUserMaxWaitMillis == null) {
+            perUserMaxWaitMillis = new HashMap<>();
         }
-        perUserDefaultReadOnly.put(username, value);
+        perUserMaxWaitMillis.put(userName, value);
     }
 
-    void setPerUserDefaultReadOnly(final Map<String,Boolean> userDefaultReadOnly) {
+    void setPerUserMinEvictableIdleTimeMillis(final Map<String, Long> userDefaultMinEvictableIdleTimeMillis) {
         assertInitializationAllowed();
-        if (perUserDefaultReadOnly == null) {
-            perUserDefaultReadOnly = new HashMap<>();
+        if (perUserMinEvictableIdleTimeMillis == null) {
+            perUserMinEvictableIdleTimeMillis = new HashMap<>();
         } else {
-            perUserDefaultReadOnly.clear();
+            perUserMinEvictableIdleTimeMillis.clear();
         }
-        perUserDefaultReadOnly.putAll(userDefaultReadOnly);
+        perUserMinEvictableIdleTimeMillis.putAll(userDefaultMinEvictableIdleTimeMillis);
     }
 
-
     /**
-     * Gets the user specific default value for
-     * {@link Connection#setTransactionIsolation(int)} for the specified user's pool.
-     * @param key The user
-     * @return the default transaction isolation
+     * Sets a user specific value for {@link GenericObjectPool#getMinEvictableIdleTimeMillis()} for the specified user's
+     * pool.
+     *
+     * @param userName
+     *            The user name key.
+     * @param value
+     *            The user specific value.
      */
-    public Integer getPerUserDefaultTransactionIsolation(final String key) {
-        Integer value = null;
-        if (perUserDefaultTransactionIsolation != null) {
-            value = perUserDefaultTransactionIsolation.get(key);
+    public void setPerUserMinEvictableIdleTimeMillis(final String userName, final Long value) {
+        assertInitializationAllowed();
+        if (perUserMinEvictableIdleTimeMillis == null) {
+            perUserMinEvictableIdleTimeMillis = new HashMap<>();
         }
-        return value;
+        perUserMinEvictableIdleTimeMillis.put(userName, value);
+    }
+
+    void setPerUserMinIdle(final Map<String, Integer> userDefaultMinIdle) {
+        assertInitializationAllowed();
+        if (perUserMinIdle == null) {
+            perUserMinIdle = new HashMap<>();
+        } else {
+            perUserMinIdle.clear();
+        }
+        perUserMinIdle.putAll(userDefaultMinIdle);
     }
 
     /**
-     * Sets a user specific default value for
-     * {@link Connection#setTransactionIsolation(int)} for the specified user's pool.
-     * @param username The user
-     * @param value The value
+     * Sets a user specific value for {@link GenericObjectPool#getMinIdle()} for the specified user's pool.
+     *
+     * @param userName
+     *            The user name key.
+     * @param value
+     *            The user specific value.
      */
-    public void setPerUserDefaultTransactionIsolation(final String username,
-            final Integer value) {
+    public void setPerUserMinIdle(final String userName, final Integer value) {
         assertInitializationAllowed();
-        if (perUserDefaultTransactionIsolation == null) {
-            perUserDefaultTransactionIsolation = new HashMap<>();
+        if (perUserMinIdle == null) {
+            perUserMinIdle = new HashMap<>();
         }
-        perUserDefaultTransactionIsolation.put(username, value);
+        perUserMinIdle.put(userName, value);
     }
 
-    void setPerUserDefaultTransactionIsolation(
-            final Map<String,Integer> userDefaultTransactionIsolation) {
+    void setPerUserNumTestsPerEvictionRun(final Map<String, Integer> userDefaultNumTestsPerEvictionRun) {
         assertInitializationAllowed();
-        if (perUserDefaultTransactionIsolation == null) {
-            perUserDefaultTransactionIsolation = new HashMap<>();
+        if (perUserNumTestsPerEvictionRun == null) {
+            perUserNumTestsPerEvictionRun = new HashMap<>();
         } else {
-            perUserDefaultTransactionIsolation.clear();
+            perUserNumTestsPerEvictionRun.clear();
         }
-        perUserDefaultTransactionIsolation.putAll(userDefaultTransactionIsolation);
+        perUserNumTestsPerEvictionRun.putAll(userDefaultNumTestsPerEvictionRun);
     }
 
-
-    // ----------------------------------------------------------------------
-    // Instrumentation Methods
-
     /**
-     * @return the number of active connections in the default pool.
+     * Sets a user specific value for {@link GenericObjectPool#getNumTestsPerEvictionRun()} for the specified user's
+     * pool.
+     *
+     * @param userName
+     *            The user name key.
+     * @param value
+     *            The user specific value.
      */
-    public int getNumActive() {
-        return getNumActive(null);
+    public void setPerUserNumTestsPerEvictionRun(final String userName, final Integer value) {
+        assertInitializationAllowed();
+        if (perUserNumTestsPerEvictionRun == null) {
+            perUserNumTestsPerEvictionRun = new HashMap<>();
+        }
+        perUserNumTestsPerEvictionRun.put(userName, value);
+    }
+
+    void setPerUserSoftMinEvictableIdleTimeMillis(final Map<String, Long> userDefaultSoftMinEvictableIdleTimeMillis) {
+        assertInitializationAllowed();
+        if (perUserSoftMinEvictableIdleTimeMillis == null) {
+            perUserSoftMinEvictableIdleTimeMillis = new HashMap<>();
+        } else {
+            perUserSoftMinEvictableIdleTimeMillis.clear();
+        }
+        perUserSoftMinEvictableIdleTimeMillis.putAll(userDefaultSoftMinEvictableIdleTimeMillis);
     }
 
     /**
-     * @param username The user
-     * @return the number of active connections in the pool for a given user.
+     * Sets a user specific value for {@link GenericObjectPool#getSoftMinEvictableIdleTimeMillis()} for the specified
+     * user's pool.
+     *
+     * @param userName
+     *            The user name key.
+     * @param value
+     *            The user specific value.
      */
-    public int getNumActive(final String username) {
-        final ObjectPool<PooledConnectionAndInfo> pool =
-            getPool(getPoolKey(username));
-        return pool == null ? 0 : pool.getNumActive();
+    public void setPerUserSoftMinEvictableIdleTimeMillis(final String userName, final Long value) {
+        assertInitializationAllowed();
+        if (perUserSoftMinEvictableIdleTimeMillis == null) {
+            perUserSoftMinEvictableIdleTimeMillis = new HashMap<>();
+        }
+        perUserSoftMinEvictableIdleTimeMillis.put(userName, value);
+    }
+
+    void setPerUserTestOnBorrow(final Map<String, Boolean> userDefaultTestOnBorrow) {
+        assertInitializationAllowed();
+        if (perUserTestOnBorrow == null) {
+            perUserTestOnBorrow = createMap();
+        } else {
+            perUserTestOnBorrow.clear();
+        }
+        perUserTestOnBorrow.putAll(userDefaultTestOnBorrow);
     }
 
     /**
-     * @return the number of idle connections in the default pool.
+     * Sets a user specific value for {@link GenericObjectPool#getTestOnBorrow()} for the specified user's pool.
+     *
+     * @param userName
+     *            The user name key.
+     * @param value
+     *            The user specific value.
      */
-    public int getNumIdle() {
-        return getNumIdle(null);
+    public void setPerUserTestOnBorrow(final String userName, final Boolean value) {
+        assertInitializationAllowed();
+        if (perUserTestOnBorrow == null) {
+            perUserTestOnBorrow = createMap();
+        }
+        perUserTestOnBorrow.put(userName, value);
+    }
+
+    void setPerUserTestOnCreate(final Map<String, Boolean> userDefaultTestOnCreate) {
+        assertInitializationAllowed();
+        if (perUserTestOnCreate == null) {
+            perUserTestOnCreate = createMap();
+        } else {
+            perUserTestOnCreate.clear();
+        }
+        perUserTestOnCreate.putAll(userDefaultTestOnCreate);
     }
 
     /**
-     * @param username The user
-     * @return the number of idle connections in the pool for a given user.
+     * Sets a user specific value for {@link GenericObjectPool#getTestOnCreate()} for the specified user's pool.
+     *
+     * @param userName
+     *            The user name key.
+     * @param value
+     *            The user specific value.
      */
-    public int getNumIdle(final String username) {
-        final ObjectPool<PooledConnectionAndInfo> pool =
-            getPool(getPoolKey(username));
-        return pool == null ? 0 : pool.getNumIdle();
+    public void setPerUserTestOnCreate(final String userName, final Boolean value) {
+        assertInitializationAllowed();
+        if (perUserTestOnCreate == null) {
+            perUserTestOnCreate = createMap();
+        }
+        perUserTestOnCreate.put(userName, value);
     }
 
+    void setPerUserTestOnReturn(final Map<String, Boolean> userDefaultTestOnReturn) {
+        assertInitializationAllowed();
+        if (perUserTestOnReturn == null) {
+            perUserTestOnReturn = createMap();
+        } else {
+            perUserTestOnReturn.clear();
+        }
+        perUserTestOnReturn.putAll(userDefaultTestOnReturn);
+    }
 
-    // ----------------------------------------------------------------------
-    // Inherited abstract methods
-
-    @Override
-    protected PooledConnectionAndInfo
-        getPooledConnectionAndInfo(final String username, final String password)
-        throws SQLException {
+    /**
+     * Sets a user specific value for {@link GenericObjectPool#getTestOnReturn()} for the specified user's pool.
+     *
+     * @param userName
+     *            The user name key.
+     * @param value
+     *            The user specific value.
+     */
+    public void setPerUserTestOnReturn(final String userName, final Boolean value) {
+        assertInitializationAllowed();
+        if (perUserTestOnReturn == null) {
+            perUserTestOnReturn = createMap();
+        }
+        perUserTestOnReturn.put(userName, value);
+    }
 
-        final PoolKey key = getPoolKey(username);
-        ObjectPool<PooledConnectionAndInfo> pool;
-        PooledConnectionManager manager;
-        synchronized(this) {
-            manager = managers.get(key);
-            if (manager == null) {
-                try {
-                    registerPool(username, password);
-                    manager = managers.get(key);
-                } catch (final NamingException e) {
-                    throw new SQLException("RegisterPool failed", e);
-                }
-            }
-            pool = ((CPDSConnectionFactory) manager).getPool();
+    void setPerUserTestWhileIdle(final Map<String, Boolean> userDefaultTestWhileIdle) {
+        assertInitializationAllowed();
+        if (perUserTestWhileIdle == null) {
+            perUserTestWhileIdle = createMap();
+        } else {
+            perUserTestWhileIdle.clear();
         }
+        perUserTestWhileIdle.putAll(userDefaultTestWhileIdle);
+    }
 
-        PooledConnectionAndInfo info = null;
-        try {
-            info = pool.borrowObject();
+    /**
+     * Sets a user specific value for {@link GenericObjectPool#getTestWhileIdle()} for the specified user's pool.
+     *
+     * @param userName
+     *            The user name key.
+     * @param value
+     *            The user specific value.
+     */
+    public void setPerUserTestWhileIdle(final String userName, final Boolean value) {
+        assertInitializationAllowed();
+        if (perUserTestWhileIdle == null) {
+            perUserTestWhileIdle = createMap();
         }
-        catch (final NoSuchElementException ex) {
-            throw new SQLException(
-                    "Could not retrieve connection info from pool", ex);
+        perUserTestWhileIdle.put(userName, value);
+    }
+
+    void setPerUserTimeBetweenEvictionRunsMillis(final Map<String, Long> userDefaultTimeBetweenEvictionRunsMillis) {
+        assertInitializationAllowed();
+        if (perUserTimeBetweenEvictionRunsMillis == null) {
+            perUserTimeBetweenEvictionRunsMillis = new HashMap<>();
+        } else {
+            perUserTimeBetweenEvictionRunsMillis.clear();
         }
-        catch (final Exception e) {
-            // See if failure is due to CPDSConnectionFactory authentication failure
-            try {
-                testCPDS(username, password);
-            } catch (final Exception ex) {
-                throw new SQLException(
-                        "Could not retrieve connection info from pool", ex);
-            }
-            // New password works, so kill the old pool, create a new one, and borrow
-            manager.closePool(username);
-            synchronized (this) {
-                managers.remove(key);
-            }
-            try {
-                registerPool(username, password);
-                pool = getPool(key);
-            } catch (final NamingException ne) {
-                throw new SQLException("RegisterPool failed", ne);
-            }
-            try {
-                info = pool.borrowObject();
-            } catch (final Exception ex) {
-                throw new SQLException(
-                        "Could not retrieve connection info from pool", ex);
-            }
+        perUserTimeBetweenEvictionRunsMillis.putAll(userDefaultTimeBetweenEvictionRunsMillis);
+    }
+
+    /**
+     * Sets a user specific value for {@link GenericObjectPool#getTimeBetweenEvictionRunsMillis ()} for the specified
+     * user's pool.
+     *
+     * @param userName
+     *            The user name key.
+     * @param value
+     *            The user specific value.
+     */
+    public void setPerUserTimeBetweenEvictionRunsMillis(final String userName, final Long value) {
+        assertInitializationAllowed();
+        if (perUserTimeBetweenEvictionRunsMillis == null) {
+            perUserTimeBetweenEvictionRunsMillis = new HashMap<>();
         }
-        return info;
+        perUserTimeBetweenEvictionRunsMillis.put(userName, value);
     }
 
     @Override
-    protected void setupDefaults(final Connection con, final String username)
-        throws SQLException {
+    protected void setupDefaults(final Connection con, final String userName) throws SQLException {
         Boolean defaultAutoCommit = isDefaultAutoCommit();
-        if (username != null) {
-            final Boolean userMax = getPerUserDefaultAutoCommit(username);
+        if (userName != null) {
+            final Boolean userMax = getPerUserDefaultAutoCommit(userName);
             if (userMax != null) {
                 defaultAutoCommit = userMax;
             }
         }
 
         Boolean defaultReadOnly = isDefaultReadOnly();
-        if (username != null) {
-            final Boolean userMax = getPerUserDefaultReadOnly(username);
+        if (userName != null) {
+            final Boolean userMax = getPerUserDefaultReadOnly(userName);
             if (userMax != null) {
                 defaultReadOnly = userMax;
             }
         }
 
         int defaultTransactionIsolation = getDefaultTransactionIsolation();
-        if (username != null) {
-            final Integer userMax = getPerUserDefaultTransactionIsolation(username);
+        if (userName != null) {
+            final Integer userMax = getPerUserDefaultTransactionIsolation(userName);
             if (userMax != null) {
                 defaultTransactionIsolation = userMax.intValue();
             }
         }
 
-        if (defaultAutoCommit != null &&
-                con.getAutoCommit() != defaultAutoCommit.booleanValue()) {
+        if (defaultAutoCommit != null && con.getAutoCommit() != defaultAutoCommit.booleanValue()) {
             con.setAutoCommit(defaultAutoCommit.booleanValue());
         }
 
@@ -1046,117 +1169,8 @@ public class PerUserPoolDataSource exten
             con.setTransactionIsolation(defaultTransactionIsolation);
         }
 
-        if (defaultReadOnly != null &&
-                con.isReadOnly() != defaultReadOnly.booleanValue()) {
+        if (defaultReadOnly != null && con.isReadOnly() != defaultReadOnly.booleanValue()) {
             con.setReadOnly(defaultReadOnly.booleanValue());
         }
     }
-
-    @Override
-    protected PooledConnectionManager getConnectionManager(final UserPassKey upkey) {
-        return managers.get(getPoolKey(upkey.getUsername()));
-    }
-
-    /**
-     * @return a <code>PerUserPoolDataSource</code> {@link Reference}.
-     * @throws NamingException Should not happen
-     */
-    @Override
-    public Reference getReference() throws NamingException {
-        final Reference ref = new Reference(getClass().getName(),
-                PerUserPoolDataSourceFactory.class.getName(), null);
-        ref.add(new StringRefAddr("instanceKey", getInstanceKey()));
-        return ref;
-    }
-
-    /**
-     * Create a pool key from the provided parameters.
-     *
-     * @param username  User name
-     * @return the pool key
-     */
-    private PoolKey getPoolKey(final String username) {
-        return new PoolKey(getDataSourceName(), username);
-    }
-
-    private synchronized void registerPool(final String username, final String password)
-            throws NamingException, SQLException {
-
-        final ConnectionPoolDataSource cpds = testCPDS(username, password);
-
-        // Set up the factory we will use (passing the pool associates
-        // the factory with the pool, so we do not have to do so
-        // explicitly)
-        final CPDSConnectionFactory factory = new CPDSConnectionFactory(cpds,
-                getValidationQuery(), getValidationQueryTimeout(),
-                isRollbackAfterValidation(), username, password);
-        factory.setMaxConnLifetimeMillis(getMaxConnLifetimeMillis());
-
-        // Create an object pool to contain our PooledConnections
-        final GenericObjectPool<PooledConnectionAndInfo> pool =
-                new GenericObjectPool<>(factory);
-        factory.setPool(pool);
-        pool.setBlockWhenExhausted(getPerUserBlockWhenExhausted(username));
-        pool.setEvictionPolicyClassName(
-                getPerUserEvictionPolicyClassName(username));
-        pool.setLifo(getPerUserLifo(username));
-        pool.setMaxIdle(getPerUserMaxIdle(username));
-        pool.setMaxTotal(getPerUserMaxTotal(username));
-        pool.setMaxWaitMillis(getPerUserMaxWaitMillis(username));
-        pool.setMinEvictableIdleTimeMillis(
-                getPerUserMinEvictableIdleTimeMillis(username));
-        pool.setMinIdle(getPerUserMinIdle(username));
-        pool.setNumTestsPerEvictionRun(
-                getPerUserNumTestsPerEvictionRun(username));
-        pool.setSoftMinEvictableIdleTimeMillis(
-                getPerUserSoftMinEvictableIdleTimeMillis(username));
-        pool.setTestOnCreate(getPerUserTestOnCreate(username));
-        pool.setTestOnBorrow(getPerUserTestOnBorrow(username));
-        pool.setTestOnReturn(getPerUserTestOnReturn(username));
-        pool.setTestWhileIdle(getPerUserTestWhileIdle(username));
-        pool.setTimeBetweenEvictionRunsMillis(
-                getPerUserTimeBetweenEvictionRunsMillis(username));
-
-        pool.setSwallowedExceptionListener(new SwallowedExceptionLogger(log));
-
-        final Object old = managers.put(getPoolKey(username), factory);
-        if (old != null) {
-            throw new IllegalStateException("Pool already contains an entry for this user/password: " + username);
-        }
-    }
-
-    /**
-     * Supports Serialization interface.
-     *
-     * @param in a <code>java.io.ObjectInputStream</code> value
-     * @throws IOException if an error occurs
-     * @throws ClassNotFoundException if an error occurs
-     */
-    private void readObject(final ObjectInputStream in)
-        throws IOException, ClassNotFoundException {
-        try
-        {
-            in.defaultReadObject();
-            final PerUserPoolDataSource oldDS = (PerUserPoolDataSource)
-                new PerUserPoolDataSourceFactory()
-                    .getObjectInstance(getReference(), null, null, null);
-            this.managers = oldDS.managers;
-        }
-        catch (final NamingException e)
-        {
-            throw new IOException("NamingException: " + e);
-        }
-    }
-
-    /**
-     * Returns the object pool associated with the given PoolKey.
-     *
-     * @param key PoolKey identifying the pool
-     * @return the GenericObjectPool pooling connections for the username and datasource
-     * specified by the PoolKey
-     */
-    private ObjectPool<PooledConnectionAndInfo> getPool(final PoolKey key) {
-        final CPDSConnectionFactory mgr = (CPDSConnectionFactory) managers.get(key);
-        return mgr == null ? null : mgr.getPool();
-    }
 }

Modified: tomcat/tc8.5.x/trunk/java/org/apache/tomcat/dbcp/dbcp2/datasources/PerUserPoolDataSourceFactory.java
URL: http://svn.apache.org/viewvc/tomcat/tc8.5.x/trunk/java/org/apache/tomcat/dbcp/dbcp2/datasources/PerUserPoolDataSourceFactory.java?rev=1833804&r1=1833803&r2=1833804&view=diff
==============================================================================
--- tomcat/tc8.5.x/trunk/java/org/apache/tomcat/dbcp/dbcp2/datasources/PerUserPoolDataSourceFactory.java (original)
+++ tomcat/tc8.5.x/trunk/java/org/apache/tomcat/dbcp/dbcp2/datasources/PerUserPoolDataSourceFactory.java Tue Jun 19 10:30:31 2018
@@ -28,11 +28,8 @@ import javax.naming.Reference;
  *
  * @since 2.0
  */
-public class PerUserPoolDataSourceFactory
-    extends InstanceKeyDataSourceFactory
-{
-    private static final String PER_USER_POOL_CLASSNAME =
-        PerUserPoolDataSource.class.getName();
+public class PerUserPoolDataSourceFactory extends InstanceKeyDataSourceFactory {
+    private static final String PER_USER_POOL_CLASSNAME = PerUserPoolDataSource.class.getName();
 
     @Override
     protected boolean isCorrectClass(final String className) {
@@ -41,69 +38,58 @@ public class PerUserPoolDataSourceFactor
 
     @SuppressWarnings("unchecked") // Avoid warnings on deserialization
     @Override
-    protected InstanceKeyDataSource getNewInstance(final Reference ref)
-        throws IOException, ClassNotFoundException {
-        final PerUserPoolDataSource pupds =  new PerUserPoolDataSource();
+    protected InstanceKeyDataSource getNewInstance(final Reference ref) throws IOException, ClassNotFoundException {
+        final PerUserPoolDataSource pupds = new PerUserPoolDataSource();
         RefAddr ra = ref.get("defaultMaxTotal");
         if (ra != null && ra.getContent() != null) {
-            pupds.setDefaultMaxTotal(
-                Integer.parseInt(ra.getContent().toString()));
+            pupds.setDefaultMaxTotal(Integer.parseInt(ra.getContent().toString()));
         }
 
         ra = ref.get("defaultMaxIdle");
         if (ra != null && ra.getContent() != null) {
-            pupds.setDefaultMaxIdle(
-                Integer.parseInt(ra.getContent().toString()));
+            pupds.setDefaultMaxIdle(Integer.parseInt(ra.getContent().toString()));
         }
 
         ra = ref.get("defaultMaxWaitMillis");
         if (ra != null && ra.getContent() != null) {
-            pupds.setDefaultMaxWaitMillis(
-                Integer.parseInt(ra.getContent().toString()));
+            pupds.setDefaultMaxWaitMillis(Integer.parseInt(ra.getContent().toString()));
         }
 
         ra = ref.get("perUserDefaultAutoCommit");
-        if (ra != null  && ra.getContent() != null) {
+        if (ra != null && ra.getContent() != null) {
             final byte[] serialized = (byte[]) ra.getContent();
-            pupds.setPerUserDefaultAutoCommit(
-                    (Map<String,Boolean>) deserialize(serialized));
+            pupds.setPerUserDefaultAutoCommit((Map<String, Boolean>) deserialize(serialized));
         }
 
         ra = ref.get("perUserDefaultTransactionIsolation");
-        if (ra != null  && ra.getContent() != null) {
+        if (ra != null && ra.getContent() != null) {
             final byte[] serialized = (byte[]) ra.getContent();
-            pupds.setPerUserDefaultTransactionIsolation(
-                    (Map<String,Integer>) deserialize(serialized));
+            pupds.setPerUserDefaultTransactionIsolation((Map<String, Integer>) deserialize(serialized));
         }
 
         ra = ref.get("perUserMaxTotal");
-        if (ra != null  && ra.getContent() != null) {
+        if (ra != null && ra.getContent() != null) {
             final byte[] serialized = (byte[]) ra.getContent();
-            pupds.setPerUserMaxTotal(
-                    (Map<String,Integer>) deserialize(serialized));
+            pupds.setPerUserMaxTotal((Map<String, Integer>) deserialize(serialized));
         }
 
         ra = ref.get("perUserMaxIdle");
-        if (ra != null  && ra.getContent() != null) {
+        if (ra != null && ra.getContent() != null) {
             final byte[] serialized = (byte[]) ra.getContent();
-            pupds.setPerUserMaxIdle(
-                    (Map<String,Integer>) deserialize(serialized));
+            pupds.setPerUserMaxIdle((Map<String, Integer>) deserialize(serialized));
         }
 
         ra = ref.get("perUserMaxWaitMillis");
-        if (ra != null  && ra.getContent() != null) {
+        if (ra != null && ra.getContent() != null) {
             final byte[] serialized = (byte[]) ra.getContent();
-            pupds.setPerUserMaxWaitMillis(
-                    (Map<String,Long>) deserialize(serialized));
+            pupds.setPerUserMaxWaitMillis((Map<String, Long>) deserialize(serialized));
         }
 
         ra = ref.get("perUserDefaultReadOnly");
-        if (ra != null  && ra.getContent() != null) {
+        if (ra != null && ra.getContent() != null) {
             final byte[] serialized = (byte[]) ra.getContent();
-            pupds.setPerUserDefaultReadOnly(
-                    (Map<String,Boolean>) deserialize(serialized));
+            pupds.setPerUserDefaultReadOnly((Map<String, Boolean>) deserialize(serialized));
         }
         return pupds;
     }
 }
-

Modified: tomcat/tc8.5.x/trunk/java/org/apache/tomcat/dbcp/dbcp2/datasources/PoolKey.java
URL: http://svn.apache.org/viewvc/tomcat/tc8.5.x/trunk/java/org/apache/tomcat/dbcp/dbcp2/datasources/PoolKey.java?rev=1833804&r1=1833803&r2=1833804&view=diff
==============================================================================
--- tomcat/tc8.5.x/trunk/java/org/apache/tomcat/dbcp/dbcp2/datasources/PoolKey.java (original)
+++ tomcat/tc8.5.x/trunk/java/org/apache/tomcat/dbcp/dbcp2/datasources/PoolKey.java Tue Jun 19 10:30:31 2018
@@ -25,41 +25,57 @@ import java.io.Serializable;
 class PoolKey implements Serializable {
     private static final long serialVersionUID = 2252771047542484533L;
 
-    private final String datasourceName;
-    private final String username;
+    private final String dataSourceName;
+    private final String userName;
 
-    PoolKey(final String datasourceName, final String username) {
-        this.datasourceName = datasourceName;
-        this.username = username;
+    PoolKey(final String dataSourceName, final String userName) {
+        this.dataSourceName = dataSourceName;
+        this.userName = userName;
     }
 
     @Override
     public boolean equals(final Object obj) {
-        if (obj instanceof PoolKey) {
-            final PoolKey pk = (PoolKey)obj;
-            return (null == datasourceName ? null == pk.datasourceName : datasourceName.equals(pk.datasourceName)) &&
-                (null == username ? null == pk.username : username.equals(pk.username));
+        if (this == obj) {
+            return true;
         }
-        return false;
+        if (obj == null) {
+            return false;
+        }
+        if (getClass() != obj.getClass()) {
+            return false;
+        }
+        final PoolKey other = (PoolKey) obj;
+        if (dataSourceName == null) {
+            if (other.dataSourceName != null) {
+                return false;
+            }
+        } else if (!dataSourceName.equals(other.dataSourceName)) {
+            return false;
+        }
+        if (userName == null) {
+            if (other.userName != null) {
+                return false;
+            }
+        } else if (!userName.equals(other.userName)) {
+            return false;
+        }
+        return true;
     }
 
     @Override
     public int hashCode() {
-        int h = 0;
-        if (datasourceName != null) {
-            h += datasourceName.hashCode();
-        }
-        if (username != null) {
-            h = 29 * h + username.hashCode();
-        }
-        return h;
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((dataSourceName == null) ? 0 : dataSourceName.hashCode());
+        result = prime * result + ((userName == null) ? 0 : userName.hashCode());
+        return result;
     }
 
     @Override
     public String toString() {
         final StringBuffer sb = new StringBuffer(50);
         sb.append("PoolKey(");
-        sb.append(username).append(", ").append(datasourceName);
+        sb.append(userName).append(", ").append(dataSourceName);
         sb.append(')');
         return sb.toString();
     }

Modified: tomcat/tc8.5.x/trunk/java/org/apache/tomcat/dbcp/dbcp2/datasources/PooledConnectionAndInfo.java
URL: http://svn.apache.org/viewvc/tomcat/tc8.5.x/trunk/java/org/apache/tomcat/dbcp/dbcp2/datasources/PooledConnectionAndInfo.java?rev=1833804&r1=1833803&r2=1833804&view=diff
==============================================================================
--- tomcat/tc8.5.x/trunk/java/org/apache/tomcat/dbcp/dbcp2/datasources/PooledConnectionAndInfo.java (original)
+++ tomcat/tc8.5.x/trunk/java/org/apache/tomcat/dbcp/dbcp2/datasources/PooledConnectionAndInfo.java Tue Jun 19 10:30:31 2018
@@ -19,23 +19,36 @@ package org.apache.tomcat.dbcp.dbcp2.dat
 
 import javax.sql.PooledConnection;
 
+import org.apache.tomcat.dbcp.dbcp2.Utils;
+
 /**
- * Immutable poolable object holding a PooledConnection along with the username and password
- * used to create the connection.
+ * Immutable poolable object holding a PooledConnection along with the user name and password used to create the
+ * connection.
  *
  * @since 2.0
  */
 final class PooledConnectionAndInfo {
     private final PooledConnection pooledConnection;
-    private final String password;
-    private final String username;
-    private final UserPassKey upkey;
+    private final char[] userPassword;
+    private final String userName;
+    private final UserPassKey upKey;
 
-    PooledConnectionAndInfo(final PooledConnection pc, final String username, final String password) {
+    /**
+     * @since 2.4.0
+     */
+    PooledConnectionAndInfo(final PooledConnection pc, final String userName, final char[] userPassword) {
         this.pooledConnection = pc;
-        this.username = username;
-        this.password = password;
-        upkey = new UserPassKey(username, password);
+        this.userName = userName;
+        this.userPassword = userPassword;
+        this.upKey = new UserPassKey(userName, userPassword);
+    }
+
+    /**
+     * @deprecated Since 2.4.0
+     */
+    @Deprecated
+    PooledConnectionAndInfo(final PooledConnection pc, final String userName, final String userPassword) {
+        this(pc, userName, Utils.toCharArray(userPassword));
     }
 
     PooledConnection getPooledConnection() {
@@ -43,22 +56,34 @@ final class PooledConnectionAndInfo {
     }
 
     UserPassKey getUserPassKey() {
-        return upkey;
+        return upKey;
     }
 
     /**
-     * Get the value of password.
+     * Gets the value of password.
+     *
      * @return value of password.
      */
     String getPassword() {
-        return password;
+        return Utils.toString(userPassword);
+    }
+
+    /**
+     * Gets the value of password.
+     *
+     * @return value of password.
+     * @since 2.4.0
+     */
+    char[] getPasswordCharArray() {
+        return userPassword;
     }
 
     /**
-     * Get the value of username.
-     * @return value of username.
+     * Gets the value of userName.
+     *
+     * @return value of userName.
      */
     String getUsername() {
-        return username;
+        return userName;
     }
 }



---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org