Repository: commons-dbcp Updated Branches: refs/heads/master b8a36ca91 -> 53b6258b2
No functional changes: Add missing Javadocs tags, skip some compiler warnings about resources, sort methods, longer lines for code and Javadocs. Project: http://git-wip-us.apache.org/repos/asf/commons-dbcp/repo Commit: http://git-wip-us.apache.org/repos/asf/commons-dbcp/commit/53b6258b Tree: http://git-wip-us.apache.org/repos/asf/commons-dbcp/tree/53b6258b Diff: http://git-wip-us.apache.org/repos/asf/commons-dbcp/diff/53b6258b Branch: refs/heads/master Commit: 53b6258b2465362ccfa3f85a482a9d54425b6d93 Parents: b8a36ca Author: Gary Gregory <garydgreg...@gmail.com> Authored: Sat Jun 9 08:43:05 2018 -0600 Committer: Gary Gregory <garydgreg...@gmail.com> Committed: Sat Jun 9 08:43:05 2018 -0600 ---------------------------------------------------------------------- .../datasources/PerUserPoolDataSource.java | 1417 +++++++++--------- 1 file changed, 749 insertions(+), 668 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/commons-dbcp/blob/53b6258b/src/main/java/org/apache/commons/dbcp2/datasources/PerUserPoolDataSource.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/commons/dbcp2/datasources/PerUserPoolDataSource.java b/src/main/java/org/apache/commons/dbcp2/datasources/PerUserPoolDataSource.java index 1c6cb0c..d8b273a 100644 --- a/src/main/java/org/apache/commons/dbcp2/datasources/PerUserPoolDataSource.java +++ b/src/main/java/org/apache/commons/dbcp2/datasources/PerUserPoolDataSource.java @@ -60,36 +60,34 @@ 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 */ - private transient Map<PoolKey, PooledConnectionManager> managers = - new HashMap<>(); + private transient Map<PoolKey, PooledConnectionManager> managers = new HashMap<>(); /** * Default no-arg constructor for Serialization @@ -134,15 +132,66 @@ public class PerUserPoolDataSource extends InstanceKeyDataSource { // ------------------------------------------------------------------- // Properties + @Override + protected PooledConnectionManager getConnectionManager(final UserPassKey upkey) { + return managers.get(getPoolKey(upkey.getUsername())); + } + + /** + * 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. + * 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(); @@ -150,83 +199,85 @@ public class PerUserPoolDataSource extends InstanceKeyDataSource { return value.booleanValue(); } + /** - * Sets a user specific value for - * {@link GenericObjectPool#getBlockWhenExhausted()} for the specified - * user's pool. + * 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. + * 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. + * 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. + * 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(); @@ -235,38 +286,17 @@ public class PerUserPoolDataSource extends InstanceKeyDataSource { } /** - * Sets a user specific value for - * {@link GenericObjectPool#getLifo()} for the specified - * user's pool. - */ - 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. + * 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(); @@ -274,39 +304,19 @@ public class PerUserPoolDataSource extends InstanceKeyDataSource { return value.intValue(); } - /** - * Sets a user specific value for - * {@link GenericObjectPool#getMaxIdle()} for the specified - * user's pool. - */ - 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. + * 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(); @@ -315,38 +325,17 @@ public class PerUserPoolDataSource extends InstanceKeyDataSource { } /** - * Sets a user specific value for - * {@link GenericObjectPool#getMaxTotal()} for the specified - * user's pool. - */ - 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. + * 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(); @@ -355,39 +344,17 @@ public class PerUserPoolDataSource extends InstanceKeyDataSource { } /** - * Sets a user specific value for - * {@link GenericObjectPool#getMaxWaitMillis()} for the specified - * user's pool. - */ - 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. + * 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(); @@ -395,42 +362,19 @@ public class PerUserPoolDataSource extends InstanceKeyDataSource { return value.longValue(); } - /** - * Sets a user specific value for - * {@link GenericObjectPool#getMinEvictableIdleTimeMillis()} for the - * specified user's pool. - */ - 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. + * 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(); @@ -439,38 +383,17 @@ public class PerUserPoolDataSource extends InstanceKeyDataSource { } /** - * Sets a user specific value for - * {@link GenericObjectPool#getMinIdle()} for the specified - * user's pool. - */ - 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. + * 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(); @@ -479,40 +402,17 @@ public class PerUserPoolDataSource extends InstanceKeyDataSource { } /** - * Sets a user specific value for - * {@link GenericObjectPool#getNumTestsPerEvictionRun()} for the specified - * user's pool. - */ - 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. + * 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(); @@ -520,41 +420,38 @@ public class PerUserPoolDataSource extends InstanceKeyDataSource { return value.longValue(); } + /** - * Sets a user specific value for - * {@link GenericObjectPool#getSoftMinEvictableIdleTimeMillis()} for the - * specified user's pool. + * 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. + * 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(); @@ -563,420 +460,711 @@ public class PerUserPoolDataSource extends InstanceKeyDataSource { } /** - * Sets a user specific value for - * {@link GenericObjectPool#getTestOnCreate()} for the specified - * user's pool. + * 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); } - perUserTestOnCreate.put(username, value); - } - - void setPerUserTestOnCreate(final Map<String,Boolean> userDefaultTestOnCreate) { - assertInitializationAllowed(); - if (perUserTestOnCreate == null) { - perUserTestOnCreate = new HashMap<>(); - } else { - perUserTestOnCreate.clear(); + if (value == null) { + return getDefaultTestOnReturn(); } - perUserTestOnCreate.putAll(userDefaultTestOnCreate); + return value.booleanValue(); } /** - * 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. + * 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. + * 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 = ((CPDSConnectionFactory) manager).getPool(); } - 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. + * 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 = new HashMap<>(); + } else { + perUserBlockWhenExhausted.clear(); + } + perUserBlockWhenExhausted.putAll(userDefaultBlockWhenExhausted); + } + + /** - * Sets a user specific value for - * {@link GenericObjectPool#getTestOnReturn()} for the specified - * user's pool. + * 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 = new HashMap<>(); } - 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 = new HashMap<>(); } 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. + * 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 = new HashMap<>(); } - if (value == null) { - return getDefaultTestWhileIdle(); + perUserDefaultAutoCommit.put(userName, value); + } + + + void setPerUserDefaultReadOnly(final Map<String, Boolean> userDefaultReadOnly) { + assertInitializationAllowed(); + if (perUserDefaultReadOnly == null) { + perUserDefaultReadOnly = new HashMap<>(); + } else { + perUserDefaultReadOnly.clear(); } - return value.booleanValue(); + perUserDefaultReadOnly.putAll(userDefaultReadOnly); } /** - * Sets a user specific value for - * {@link GenericObjectPool#getTestWhileIdle()} for the specified - * user's pool. + * 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 = new HashMap<>(); } - 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. + * 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. + * 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 = new HashMap<>(); } 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. + * 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 = new HashMap<>(); } - 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. + * 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. + * 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. + * 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. + * 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. + * 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 - /** - * Gets 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); } /** - * Gets 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 = new HashMap<>(); + } else { + perUserTestOnBorrow.clear(); + } + perUserTestOnBorrow.putAll(userDefaultTestOnBorrow); } /** - * Gets 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 = new HashMap<>(); + } + perUserTestOnBorrow.put(userName, value); + } + + void setPerUserTestOnCreate(final Map<String,Boolean> userDefaultTestOnCreate) { + assertInitializationAllowed(); + if (perUserTestOnCreate == null) { + perUserTestOnCreate = new HashMap<>(); + } else { + perUserTestOnCreate.clear(); + } + perUserTestOnCreate.putAll(userDefaultTestOnCreate); } + /** - * Gets 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 = new HashMap<>(); + } + perUserTestOnCreate.put(userName, value); } + void setPerUserTestOnReturn( + final Map<String,Boolean> userDefaultTestOnReturn) { + assertInitializationAllowed(); + if (perUserTestOnReturn == null) { + perUserTestOnReturn = new HashMap<>(); + } 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 = new HashMap<>(); + } + 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 = new HashMap<>(); + } 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 = new HashMap<>(); } - 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) + 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(); } @@ -996,111 +1184,4 @@ public class PerUserPoolDataSource extends InstanceKeyDataSource { con.setReadOnly(defaultReadOnly.booleanValue()); } } - - @Override - protected PooledConnectionManager getConnectionManager(final UserPassKey upkey) { - return managers.get(getPoolKey(upkey.getUsername())); - } - - /** - * Returns a <code>PerUserPoolDataSource</code> {@link Reference}. - */ - @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; - } - - /** - * 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); - } - - 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(); - } }