You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by ma...@apache.org on 2013/07/24 23:58:57 UTC
svn commit: r1506741 - in
/commons/proper/dbcp/trunk/src/java/org/apache/commons/dbcp2: ./
datasources/ managed/
Author: markt
Date: Wed Jul 24 21:58:57 2013
New Revision: 1506741
URL: http://svn.apache.org/r1506741
Log:
DBCP-156
Implement a configuration option - disabled by default - that sets a maximum permitted lifetime for a connection after which the connection will automatically fail the next validation, activation or passivation.
Modified:
commons/proper/dbcp/trunk/src/java/org/apache/commons/dbcp2/BasicDataSource.java
commons/proper/dbcp/trunk/src/java/org/apache/commons/dbcp2/BasicDataSourceFactory.java
commons/proper/dbcp/trunk/src/java/org/apache/commons/dbcp2/LocalStrings.properties
commons/proper/dbcp/trunk/src/java/org/apache/commons/dbcp2/PoolableConnectionFactory.java
commons/proper/dbcp/trunk/src/java/org/apache/commons/dbcp2/datasources/CPDSConnectionFactory.java
commons/proper/dbcp/trunk/src/java/org/apache/commons/dbcp2/datasources/InstanceKeyDataSource.java
commons/proper/dbcp/trunk/src/java/org/apache/commons/dbcp2/datasources/KeyedCPDSConnectionFactory.java
commons/proper/dbcp/trunk/src/java/org/apache/commons/dbcp2/datasources/PerUserPoolDataSource.java
commons/proper/dbcp/trunk/src/java/org/apache/commons/dbcp2/datasources/SharedPoolDataSource.java
commons/proper/dbcp/trunk/src/java/org/apache/commons/dbcp2/managed/BasicManagedDataSource.java
Modified: commons/proper/dbcp/trunk/src/java/org/apache/commons/dbcp2/BasicDataSource.java
URL: http://svn.apache.org/viewvc/commons/proper/dbcp/trunk/src/java/org/apache/commons/dbcp2/BasicDataSource.java?rev=1506741&r1=1506740&r2=1506741&view=diff
==============================================================================
--- commons/proper/dbcp/trunk/src/java/org/apache/commons/dbcp2/BasicDataSource.java (original)
+++ commons/proper/dbcp/trunk/src/java/org/apache/commons/dbcp2/BasicDataSource.java Wed Jul 24 21:58:57 2013
@@ -1103,6 +1103,31 @@ public class BasicDataSource implements
this.restartNeeded = true;
}
+
+ private long maxConnLifetimeMillis = -1;
+
+ /**
+ * Returns the maximum permitted lifetime of a connection in milliseconds. A
+ * value of zero or less indicates an infinite lifetime.
+ */
+ public long getMaxConnLifetimeMillis() {
+ return maxConnLifetimeMillis;
+ }
+
+ /**
+ * <p>Sets the maximum permitted lifetime of a connection in
+ * milliseconds. A value of zero or less indicates an infinite lifetime.</p>
+ * <p>
+ * Note: this method currently has no effect once the pool has been
+ * initialized. The pool is initialized the first time one of the
+ * following methods is invoked: <code>getConnection, setLogwriter,
+ * setLoginTimeout, getLoginTimeout, getLogWriter.</code></p>
+ */
+ public void setMaxConnLifetimeMillis(long maxConnLifetimeMillis) {
+ this.maxConnLifetimeMillis = maxConnLifetimeMillis;
+ }
+
+
// ----------------------------------------------------- Instance Variables
// TODO: review & make isRestartNeeded() public, restartNeeded protected
@@ -1833,6 +1858,7 @@ public class BasicDataSource implements
connectionFactory.setPoolStatements(poolPreparedStatements);
connectionFactory.setMaxOpenPrepatedStatements(
maxOpenPreparedStatements);
+ connectionFactory.setMaxConnLifetimeMillis(maxConnLifetimeMillis);
validateConnectionFactory(connectionFactory);
} catch (RuntimeException e) {
throw e;
Modified: commons/proper/dbcp/trunk/src/java/org/apache/commons/dbcp2/BasicDataSourceFactory.java
URL: http://svn.apache.org/viewvc/commons/proper/dbcp/trunk/src/java/org/apache/commons/dbcp2/BasicDataSourceFactory.java?rev=1506741&r1=1506740&r2=1506741&view=diff
==============================================================================
--- commons/proper/dbcp/trunk/src/java/org/apache/commons/dbcp2/BasicDataSourceFactory.java (original)
+++ commons/proper/dbcp/trunk/src/java/org/apache/commons/dbcp2/BasicDataSourceFactory.java Wed Jul 24 21:58:57 2013
@@ -5,9 +5,9 @@
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -84,6 +84,7 @@ public class BasicDataSourceFactory impl
private final static String PROP_POOLPREPAREDSTATEMENTS = "poolPreparedStatements";
private final static String PROP_MAXOPENPREPAREDSTATEMENTS = "maxOpenPreparedStatements";
private final static String PROP_CONNECTIONPROPERTIES = "connectionProperties";
+ private final static String PROP_MAXCONNLIFETIMEMILLIS = "maxConnLifetimeMillis";
private final static String[] ALL_PROPERTIES = {
PROP_DEFAULTAUTOCOMMIT,
@@ -118,7 +119,8 @@ public class BasicDataSourceFactory impl
PROP_LOGABANDONED,
PROP_POOLPREPAREDSTATEMENTS,
PROP_MAXOPENPREPAREDSTATEMENTS,
- PROP_CONNECTIONPROPERTIES
+ PROP_CONNECTIONPROPERTIES,
+ PROP_MAXCONNLIFETIMEMILLIS
};
// -------------------------------------------------- ObjectFactory Methods
@@ -169,7 +171,7 @@ public class BasicDataSourceFactory impl
/**
* Creates and configures a {@link BasicDataSource} instance based on the
* given properties.
- *
+ *
* @param properties the datasource configuration properties
* @throws Exception if an error occurs creating the data source
*/
@@ -237,7 +239,7 @@ public class BasicDataSourceFactory impl
if (value != null) {
dataSource.setLifo(Boolean.valueOf(value).booleanValue());
}
-
+
value = properties.getProperty(PROP_MAXACTIVE);
if (value != null) {
dataSource.setMaxTotal(Integer.parseInt(value));
@@ -287,7 +289,7 @@ public class BasicDataSourceFactory impl
if (value != null) {
dataSource.setMinEvictableIdleTimeMillis(Long.parseLong(value));
}
-
+
value = properties.getProperty(PROP_SOFTMINEVICTABLEIDLETIMEMILLIS);
if (value != null) {
dataSource.setSoftMinEvictableIdleTimeMillis(Long.parseLong(value));
@@ -322,7 +324,7 @@ public class BasicDataSourceFactory impl
if (value != null) {
dataSource.setValidationQueryTimeout(Integer.parseInt(value));
}
-
+
value = properties.getProperty(PROP_ACCESSTOUNDERLYINGCONNECTIONALLOWED);
if (value != null) {
dataSource.setAccessToUnderlyingConnectionAllowed(Boolean.valueOf(value).booleanValue());
@@ -339,7 +341,7 @@ public class BasicDataSourceFactory impl
}
value = properties.getProperty(PROP_REMOVEABANDONEDTIMEOUT);
- if (value != null) {
+ if (value != null) {
dataSource.setRemoveAbandonedTimeout(Integer.parseInt(value));
}
@@ -381,6 +383,11 @@ public class BasicDataSourceFactory impl
}
}
+ value = properties.getProperty(PROP_MAXCONNLIFETIMEMILLIS);
+ if (value != null) {
+ dataSource.setMaxConnLifetimeMillis(Long.parseLong(value));
+ }
+
// DBCP-215
// Trick to make sure that initialSize connections are created
if (dataSource.getInitialSize() > 0) {
Modified: commons/proper/dbcp/trunk/src/java/org/apache/commons/dbcp2/LocalStrings.properties
URL: http://svn.apache.org/viewvc/commons/proper/dbcp/trunk/src/java/org/apache/commons/dbcp2/LocalStrings.properties?rev=1506741&r1=1506740&r2=1506741&view=diff
==============================================================================
--- commons/proper/dbcp/trunk/src/java/org/apache/commons/dbcp2/LocalStrings.properties (original)
+++ commons/proper/dbcp/trunk/src/java/org/apache/commons/dbcp2/LocalStrings.properties Wed Jul 24 21:58:57 2013
@@ -13,4 +13,6 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+connectionFactory.lifetimeExceeded=The lifetime of the connection [{0}] milliseconds exceeds the maximum permitted value of [{1}] milliseconds
+
poolableConnectionFactory.validateObject.fail=Failed to validate a poolable connection
\ No newline at end of file
Modified: commons/proper/dbcp/trunk/src/java/org/apache/commons/dbcp2/PoolableConnectionFactory.java
URL: http://svn.apache.org/viewvc/commons/proper/dbcp/trunk/src/java/org/apache/commons/dbcp2/PoolableConnectionFactory.java?rev=1506741&r1=1506740&r2=1506741&view=diff
==============================================================================
--- commons/proper/dbcp/trunk/src/java/org/apache/commons/dbcp2/PoolableConnectionFactory.java (original)
+++ commons/proper/dbcp/trunk/src/java/org/apache/commons/dbcp2/PoolableConnectionFactory.java Wed Jul 24 21:58:57 2013
@@ -167,6 +167,16 @@ public class PoolableConnectionFactory
this.maxOpenPreparedStatements = maxOpenPreparedStatements;
}
+ /**
+ * Sets the maximum lifetime in milliseconds of a connection after which the
+ * connection will always fail activation, passivation and validation. A
+ * value of zero or less indicates an infinite lifetime. The default value
+ * is -1.
+ */
+ public void setMaxConnLifetimeMillis(long maxConnLifetimeMillis) {
+ this.maxConnLifetimeMillis = maxConnLifetimeMillis;
+ }
+
@Override
public PooledObject<PoolableConnection> makeObject() throws Exception {
Connection conn = _connFactory.createConnection();
@@ -228,9 +238,11 @@ public class PoolableConnectionFactory
@Override
public boolean validateObject(PooledObject<PoolableConnection> p) {
try {
+ validateLifetime(p);
+
validateConnection(p.getObject());
return true;
- } catch(Exception e) {
+ } catch (Exception e) {
if (log.isDebugEnabled()) {
log.debug(Utils.getMessage(
"poolableConnectionFactory.validateObject.fail"), e);
@@ -278,6 +290,9 @@ public class PoolableConnectionFactory
@Override
public void passivateObject(PooledObject<PoolableConnection> p)
throws Exception {
+
+ validateLifetime(p);
+
PoolableConnection conn = p.getObject();
if(!conn.getAutoCommit() && !conn.isReadOnly()) {
conn.rollback();
@@ -294,6 +309,8 @@ public class PoolableConnectionFactory
public void activateObject(PooledObject<PoolableConnection> p)
throws Exception {
+ validateLifetime(p);
+
PoolableConnection conn = p.getObject();
conn.activate();
@@ -315,6 +332,20 @@ public class PoolableConnectionFactory
}
}
+ private void validateLifetime(PooledObject<PoolableConnection> p)
+ throws Exception {
+ if (maxConnLifetimeMillis > 0) {
+ long lifetime = System.currentTimeMillis() - p.getCreateTime();
+ if (lifetime > maxConnLifetimeMillis) {
+ throw new Exception(Utils.getMessage(
+ "connectionFactory.lifetimeExceeded",
+ Long.valueOf(lifetime),
+ Long.valueOf(maxConnLifetimeMillis)));
+ }
+ }
+ }
+
+
protected volatile ConnectionFactory _connFactory = null;
protected volatile String _validationQuery = null;
protected volatile int _validationQueryTimeout = -1;
@@ -328,6 +359,7 @@ public class PoolableConnectionFactory
protected boolean poolStatements = false;
protected int maxOpenPreparedStatements =
GenericKeyedObjectPoolConfig.DEFAULT_MAX_TOTAL_PER_KEY;
+ private long maxConnLifetimeMillis = -1;
/**
* Internal constant to indicate the level is not set.
Modified: commons/proper/dbcp/trunk/src/java/org/apache/commons/dbcp2/datasources/CPDSConnectionFactory.java
URL: http://svn.apache.org/viewvc/commons/proper/dbcp/trunk/src/java/org/apache/commons/dbcp2/datasources/CPDSConnectionFactory.java?rev=1506741&r1=1506740&r2=1506741&view=diff
==============================================================================
--- commons/proper/dbcp/trunk/src/java/org/apache/commons/dbcp2/datasources/CPDSConnectionFactory.java (original)
+++ commons/proper/dbcp/trunk/src/java/org/apache/commons/dbcp2/datasources/CPDSConnectionFactory.java Wed Jul 24 21:58:57 2013
@@ -30,6 +30,7 @@ import javax.sql.ConnectionEventListener
import javax.sql.ConnectionPoolDataSource;
import javax.sql.PooledConnection;
+import org.apache.commons.dbcp2.PoolableConnection;
import org.apache.commons.dbcp2.Utils;
import org.apache.commons.pool2.ObjectPool;
import org.apache.commons.pool2.PoolableObjectFactory;
@@ -58,6 +59,8 @@ class CPDSConnectionFactory
private ObjectPool<PooledConnectionAndInfo> _pool;
private final String _username;
private String _password = null;
+ private long maxConnLifetimeMillis = -1;
+
/**
* Map of PooledConnections for which close events are ignored.
@@ -157,6 +160,11 @@ class CPDSConnectionFactory
@Override
public boolean validateObject(PooledObject<PooledConnectionAndInfo> p) {
+ try {
+ validateLifetime(p);
+ } catch (Exception e) {
+ return false;
+ }
boolean valid = false;
PooledConnection pconn = p.getObject().getPooledConnection();
String query = _validationQuery;
@@ -196,11 +204,15 @@ class CPDSConnectionFactory
}
@Override
- public void passivateObject(PooledObject<PooledConnectionAndInfo> p) {
+ public void passivateObject(PooledObject<PooledConnectionAndInfo> p)
+ throws Exception {
+ validateLifetime(p);
}
@Override
- public void activateObject(PooledObject<PooledConnectionAndInfo> p) {
+ public void activateObject(PooledObject<PooledConnectionAndInfo> p)
+ throws Exception {
+ validateLifetime(p);
}
// ***********************************************************************
@@ -302,6 +314,16 @@ class CPDSConnectionFactory
}
/**
+ * Sets the maximum lifetime in milliseconds of a connection after which the
+ * connection will always fail activation, passivation and validation. A
+ * value of zero or less indicates an infinite lifetime. The default value
+ * is -1.
+ */
+ public void setMaxConnLifetimeMillis(long maxConnLifetimeMillis) {
+ this.maxConnLifetimeMillis = maxConnLifetimeMillis;
+ }
+
+ /**
* Verifies that the username matches the user whose connections are being managed by this
* factory and closes the pool if this is the case; otherwise does nothing.
*/
@@ -319,4 +341,16 @@ class CPDSConnectionFactory
}
}
+ private void validateLifetime(PooledObject<PooledConnectionAndInfo> p)
+ throws Exception {
+ if (maxConnLifetimeMillis > 0) {
+ long lifetime = System.currentTimeMillis() - p.getCreateTime();
+ if (lifetime > maxConnLifetimeMillis) {
+ throw new Exception(Utils.getMessage(
+ "connectionFactory.lifetimeExceeded",
+ Long.valueOf(lifetime),
+ Long.valueOf(maxConnLifetimeMillis)));
+ }
+ }
+ }
}
Modified: commons/proper/dbcp/trunk/src/java/org/apache/commons/dbcp2/datasources/InstanceKeyDataSource.java
URL: http://svn.apache.org/viewvc/commons/proper/dbcp/trunk/src/java/org/apache/commons/dbcp2/datasources/InstanceKeyDataSource.java?rev=1506741&r1=1506740&r2=1506741&view=diff
==============================================================================
--- commons/proper/dbcp/trunk/src/java/org/apache/commons/dbcp2/datasources/InstanceKeyDataSource.java (original)
+++ commons/proper/dbcp/trunk/src/java/org/apache/commons/dbcp2/datasources/InstanceKeyDataSource.java Wed Jul 24 21:58:57 2013
@@ -5,9 +5,9 @@
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -39,7 +39,7 @@ import javax.sql.PooledConnection;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
/**
- * <p>The base class for <code>SharedPoolDataSource</code> and
+ * <p>The base class for <code>SharedPoolDataSource</code> and
* <code>PerUserPoolDataSource</code>. Many of the configuration properties
* are shared and defined here. This class is declared public in order
* to allow particular usage with commons-beanutils; do not make direct
@@ -50,7 +50,7 @@ import org.apache.commons.pool2.impl.Gen
* A J2EE container will normally provide some method of initializing the
* <code>DataSource</code> whose attributes are presented
* as bean getters/setters and then deploying it via JNDI. It is then
- * available to an application as a source of pooled logical connections to
+ * available to an application as a source of pooled logical connections to
* the database. The pool needs a source of physical connections. This
* source is in the form of a <code>ConnectionPoolDataSource</code> that
* can be specified via the {@link #setDataSourceName(String)} used to
@@ -59,25 +59,25 @@ import org.apache.commons.pool2.impl.Gen
*
* <p>
* Although normally used within a JNDI environment, A DataSource
- * can be instantiated and initialized as any bean. In this case the
+ * can be instantiated and initialized as any bean. In this case the
* <code>ConnectionPoolDataSource</code> will likely be instantiated in
* a similar manner. This class allows the physical source of connections
- * to be attached directly to this pool using the
+ * to be attached directly to this pool using the
* {@link #setConnectionPoolDataSource(ConnectionPoolDataSource)} method.
* </p>
*
* <p>
- * The dbcp package contains an adapter,
+ * The dbcp package contains an adapter,
* {@link org.apache.commons.dbcp2.cpdsadapter.DriverAdapterCPDS},
* that can be used to allow the use of <code>DataSource</code>'s based on this
- * class with jdbc driver implementations that do not supply a
+ * class with jdbc driver implementations that do not supply a
* <code>ConnectionPoolDataSource</code>, but still
* provide a {@link java.sql.Driver} implementation.
* </p>
*
* <p>
- * The <a href="package-summary.html">package documentation</a> contains an
- * example using Apache Tomcat and JNDI and it also contains a non-JNDI example.
+ * The <a href="package-summary.html">package documentation</a> contains an
+ * example using Apache Tomcat and JNDI and it also contains a non-JNDI example.
* </p>
*
* @author John D. McNally
@@ -86,42 +86,42 @@ import org.apache.commons.pool2.impl.Gen
public abstract class InstanceKeyDataSource
implements DataSource, Referenceable, Serializable {
private static final long serialVersionUID = -4243533936955098795L;
- private static final String GET_CONNECTION_CALLED
- = "A Connection was already requested from this source, "
+ private static final String GET_CONNECTION_CALLED
+ = "A Connection was already requested from this source, "
+ "further initialization is not allowed.";
private static final String BAD_TRANSACTION_ISOLATION
= "The requested TransactionIsolation level is invalid.";
/**
- * Internal constant to indicate the level is not set.
+ * Internal constant to indicate the level is not set.
*/
protected static final int UNKNOWN_TRANSACTIONISOLATION = -1;
-
+
/** Guards property setters - once true, setters throw IllegalStateException */
private volatile boolean getConnectionCalled = false;
/** Underlying source of PooledConnections */
private ConnectionPoolDataSource dataSource = null;
-
+
/** DataSource Name used to find the ConnectionPoolDataSource */
private String dataSourceName = null;
-
+
// Default connection properties
private boolean defaultAutoCommit = false;
private int defaultTransactionIsolation = UNKNOWN_TRANSACTIONISOLATION;
private boolean defaultReadOnly = false;
-
+
/** Description */
private String description = null;
-
+
/** Environment that may be used to set up a jndi initial context. */
Properties jndiEnvironment = null;
-
+
/** Login TimeOut in seconds */
private int loginTimeout = 0;
-
+
/** Log stream */
private PrintWriter logWriter = null;
-
+
// Pool properties
private boolean _testOnBorrow =
GenericObjectPoolConfig.DEFAULT_TEST_ON_BORROW;
@@ -130,7 +130,7 @@ public abstract class InstanceKeyDataSou
private int _timeBetweenEvictionRunsMillis = (int)
Math.min(Integer.MAX_VALUE,
GenericObjectPoolConfig.DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS);
- private int _numTestsPerEvictionRun =
+ private int _numTestsPerEvictionRun =
GenericObjectPoolConfig.DEFAULT_NUM_TESTS_PER_EVICTION_RUN;
private int _minEvictableIdleTimeMillis = (int)
Math.min(Integer.MAX_VALUE,
@@ -139,7 +139,9 @@ public abstract class InstanceKeyDataSou
GenericObjectPoolConfig.DEFAULT_TEST_WHILE_IDLE;
private String validationQuery = null;
private boolean rollbackAfterValidation = false;
-
+ private long maxConnLifetimeMillis = -1;
+
+
/** true iff one of the setters for testOnBorrow, testOnReturn, testWhileIdle has been called. */
private boolean testPositionSet = false;
@@ -168,7 +170,7 @@ public abstract class InstanceKeyDataSou
* Close the connection pool being maintained by this datasource.
*/
public abstract void close() throws Exception;
-
+
protected abstract PooledConnectionManager getConnectionManager(UserPassKey upkey);
/* JDBC_4_ANT_KEY_BEGIN */
@@ -200,7 +202,7 @@ public abstract class InstanceKeyDataSou
public ConnectionPoolDataSource getConnectionPoolDataSource() {
return dataSource;
}
-
+
/**
* Set the backend ConnectionPoolDataSource. This property should not be
* set if using jndi to access the datasource.
@@ -213,7 +215,7 @@ public abstract class InstanceKeyDataSou
throw new IllegalStateException(
"Cannot set the DataSource, if JNDI is used.");
}
- if (dataSource != null)
+ if (dataSource != null)
{
throw new IllegalStateException(
"The CPDS has already been set. It cannot be altered.");
@@ -224,7 +226,7 @@ public abstract class InstanceKeyDataSou
/**
* Get the name of the ConnectionPoolDataSource which backs this pool.
- * This name is used to look up the datasource from a jndi service
+ * This name is used to look up the datasource from a jndi service
* provider.
*
* @return value of dataSourceName.
@@ -232,10 +234,10 @@ public abstract class InstanceKeyDataSou
public String getDataSourceName() {
return dataSourceName;
}
-
+
/**
* Set the name of the ConnectionPoolDataSource which backs this pool.
- * This name is used to look up the datasource from a jndi service
+ * This name is used to look up the datasource from a jndi service
* provider.
*
* @param v Value to assign to dataSourceName.
@@ -247,18 +249,18 @@ public abstract class InstanceKeyDataSou
"Cannot set the JNDI name for the DataSource, if already " +
"set using setConnectionPoolDataSource.");
}
- if (dataSourceName != null)
+ if (dataSourceName != null)
{
throw new IllegalStateException(
- "The DataSourceName has already been set. " +
+ "The DataSourceName has already been set. " +
"It cannot be altered.");
}
this.dataSourceName = v;
instanceKey = InstanceKeyObjectFactory.registerNewInstance(this);
}
- /**
- * Get the value of defaultAutoCommit, which defines the state of
+ /**
+ * Get the value of defaultAutoCommit, which defines the state of
* connections handed out from this pool. The value can be changed
* on the Connection using Connection.setAutoCommit(boolean).
* The default is true.
@@ -268,9 +270,9 @@ public abstract class InstanceKeyDataSou
public boolean isDefaultAutoCommit() {
return defaultAutoCommit;
}
-
+
/**
- * Set the value of defaultAutoCommit, which defines the state of
+ * Set the value of defaultAutoCommit, which defines the state of
* connections handed out from this pool. The value can be changed
* on the Connection using Connection.setAutoCommit(boolean).
* The default is true.
@@ -283,7 +285,7 @@ public abstract class InstanceKeyDataSou
}
/**
- * Get the value of defaultReadOnly, which defines the state of
+ * Get the value of defaultReadOnly, which defines the state of
* connections handed out from this pool. The value can be changed
* on the Connection using Connection.setReadOnly(boolean).
* The default is false.
@@ -293,9 +295,9 @@ public abstract class InstanceKeyDataSou
public boolean isDefaultReadOnly() {
return defaultReadOnly;
}
-
+
/**
- * Set the value of defaultReadOnly, which defines the state of
+ * Set the value of defaultReadOnly, which defines the state of
* connections handed out from this pool. The value can be changed
* on the Connection using Connection.setReadOnly(boolean).
* The default is false.
@@ -312,7 +314,7 @@ public abstract class InstanceKeyDataSou
* connections handed out from this pool. The value can be changed
* on the Connection using Connection.setTransactionIsolation(int).
* If this method returns -1, the default is JDBC driver dependent.
- *
+ *
* @return value of defaultTransactionIsolation.
*/
public int getDefaultTransactionIsolation() {
@@ -324,7 +326,7 @@ public abstract class InstanceKeyDataSou
* connections handed out from this pool. The value can be changed
* on the Connection using Connection.setTransactionIsolation(int).
* The default is JDBC driver dependent.
- *
+ *
* @param v Value to assign to defaultTransactionIsolation
*/
public void setDefaultTransactionIsolation(int v) {
@@ -341,7 +343,7 @@ public abstract class InstanceKeyDataSou
}
this.defaultTransactionIsolation = v;
}
-
+
/**
* Get the description. This property is defined by jdbc as for use with
* GUI (or other) tools that might deploy the datasource. It serves no
@@ -352,18 +354,18 @@ public abstract class InstanceKeyDataSou
public String getDescription() {
return description;
}
-
+
/**
* Set the description. This property is defined by jdbc as for use with
* GUI (or other) tools that might deploy the datasource. It serves no
* internal purpose.
- *
+ *
* @param v Value to assign to description.
*/
public void setDescription(String v) {
this.description = v;
}
-
+
/**
* Get the value of jndiEnvironment which is used when instantiating
* a jndi InitialContext. This InitialContext is used to locate the
@@ -378,12 +380,12 @@ public abstract class InstanceKeyDataSou
}
return value;
}
-
+
/**
* Sets the value of the given JNDI environment property to be used when
* instantiating a JNDI InitialContext. This InitialContext is used to
* locate the backend ConnectionPoolDataSource.
- *
+ *
* @param key the JNDI environment property to set.
* @param value the value assigned to specified JNDI environment property.
*/
@@ -393,7 +395,7 @@ public abstract class InstanceKeyDataSou
}
jndiEnvironment.setProperty(key, value);
}
-
+
/**
* Get the value of loginTimeout.
* @return value of loginTimeout.
@@ -402,7 +404,7 @@ public abstract class InstanceKeyDataSou
public int getLoginTimeout() {
return loginTimeout;
}
-
+
/**
* Set the value of loginTimeout.
* @param v Value to assign to loginTimeout.
@@ -411,7 +413,7 @@ public abstract class InstanceKeyDataSou
public void setLoginTimeout(int v) {
this.loginTimeout = v;
}
-
+
/**
* Get the value of logWriter.
* @return value of logWriter.
@@ -420,10 +422,10 @@ public abstract class InstanceKeyDataSou
public PrintWriter getLogWriter() {
if (logWriter == null) {
logWriter = new PrintWriter(System.out);
- }
+ }
return logWriter;
}
-
+
/**
* Set the value of logWriter.
* @param v Value to assign to logWriter.
@@ -432,14 +434,14 @@ public abstract class InstanceKeyDataSou
public void setLogWriter(PrintWriter v) {
this.logWriter = v;
}
-
+
/**
* @see #getTestOnBorrow
*/
public final boolean isTestOnBorrow() {
return getTestOnBorrow();
}
-
+
/**
* When <tt>true</tt>, objects will be
* {*link PoolableObjectFactory#validateObject validated}
@@ -478,7 +480,7 @@ public abstract class InstanceKeyDataSou
public final boolean isTestOnReturn() {
return getTestOnReturn();
}
-
+
/**
* When <tt>true</tt>, objects will be
* {*link PoolableObjectFactory#validateObject validated}
@@ -527,7 +529,7 @@ public abstract class InstanceKeyDataSou
*
* @see #getTimeBetweenEvictionRunsMillis
*/
- public void
+ public void
setTimeBetweenEvictionRunsMillis(int timeBetweenEvictionRunsMillis) {
assertInitializationAllowed();
_timeBetweenEvictionRunsMillis = timeBetweenEvictionRunsMillis;
@@ -593,7 +595,7 @@ public abstract class InstanceKeyDataSou
public final boolean isTestWhileIdle() {
return getTestWhileIdle();
}
-
+
/**
* When <tt>true</tt>, objects will be
* {*link PoolableObjectFactory#validateObject validated}
@@ -651,10 +653,10 @@ public abstract class InstanceKeyDataSou
}
/**
- * Whether a rollback will be issued after executing the SQL query
+ * Whether a rollback will be issued after executing the SQL query
* that will be used to validate connections from this pool
* before returning them to the caller.
- *
+ *
* @return true if a rollback will be issued after executing the
* validation query
* @since 1.2.2
@@ -664,12 +666,12 @@ public abstract class InstanceKeyDataSou
}
/**
- * Whether a rollback will be issued after executing the SQL query
+ * Whether a rollback will be issued after executing the SQL query
* that will be used to validate connections from this pool
* before returning them to the caller. Default behavior is NOT
* to issue a rollback. The setting will only have an effect
* if a validation query is set
- *
+ *
* @param rollbackAfterValidation new property value
* @since 1.2.2
*/
@@ -678,11 +680,32 @@ public abstract class InstanceKeyDataSou
this.rollbackAfterValidation = rollbackAfterValidation;
}
+ /**
+ * Returns the maximum permitted lifetime of a connection in milliseconds. A
+ * value of zero or less indicates an infinite lifetime.
+ */
+ public long getMaxConnLifetimeMillis() {
+ return maxConnLifetimeMillis;
+ }
+
+ /**
+ * <p>Sets the maximum permitted lifetime of a connection in
+ * milliseconds. A value of zero or less indicates an infinite lifetime.</p>
+ * <p>
+ * Note: this method currently has no effect once the pool has been
+ * initialized. The pool is initialized the first time one of the
+ * following methods is invoked: <code>getConnection, setLogwriter,
+ * setLoginTimeout, getLoginTimeout, getLogWriter.</code></p>
+ */
+ public void setMaxConnLifetimeMillis(long maxConnLifetimeMillis) {
+ this.maxConnLifetimeMillis = maxConnLifetimeMillis;
+ }
+
// ----------------------------------------------------------------------
// Instrumentation Methods
// ----------------------------------------------------------------------
- // DataSource implementation
+ // DataSource implementation
/**
* Attempt to establish a database connection.
@@ -701,14 +724,14 @@ public abstract class InstanceKeyDataSou
* did not match the password used to create the pooled connection. If the connection attempt succeeds, this
* means that the database password has been changed. In this case, the <code>PooledConnectionAndInfo</code>
* instance retrieved with the old password is destroyed and the <code>getPooledConnectionAndInfo</code> is
- * repeatedly invoked until a <code>PooledConnectionAndInfo</code> instance with the new password is returned.
- *
+ * repeatedly invoked until a <code>PooledConnectionAndInfo</code> instance with the new password is returned.
+ *
*/
@Override
public Connection getConnection(String username, String password)
- throws SQLException {
+ throws SQLException {
if (instanceKey == null) {
- throw new SQLException("Must set the ConnectionPoolDataSource "
+ throw new SQLException("Must set the ConnectionPoolDataSource "
+ "through setDataSourceName or setConnectionPoolDataSource"
+ " before calling getConnection.");
}
@@ -722,15 +745,15 @@ public abstract class InstanceKeyDataSou
} catch (RuntimeException e) {
closeDueToException(info);
throw e;
- } catch (SQLException e) {
+ } catch (SQLException e) {
closeDueToException(info);
throw e;
} catch (Exception e) {
closeDueToException(info);
throw new SQLException("Cannot borrow connection from pool", e);
}
-
- if (!(null == password ? null == info.getPassword()
+
+ if (!(null == password ? null == info.getPassword()
: password.equals(info.getPassword()))) { // Password on PooledConnectionAndInfo does not match
try { // See if password has changed by attempting connection
testCPDS(username, password);
@@ -752,7 +775,7 @@ public abstract class InstanceKeyDataSou
manager.invalidate(info.getPooledConnection()); // Destroy and remove from pool
manager.setPassword(upkey.getPassword()); // Reset the password on the factory if using CPDSConnectionFactory
info = null;
- for (int i = 0; i < 10; i++) { // Bound the number of retries - only needed if bad instances return
+ for (int i = 0; i < 10; i++) { // Bound the number of retries - only needed if bad instances return
try {
info = getPooledConnectionAndInfo(username, password);
} catch (NoSuchElementException e) {
@@ -761,7 +784,7 @@ public abstract class InstanceKeyDataSou
} catch (RuntimeException e) {
closeDueToException(info);
throw e;
- } catch (SQLException e) {
+ } catch (SQLException e) {
closeDueToException(info);
throw e;
} catch (Exception e) {
@@ -776,21 +799,21 @@ public abstract class InstanceKeyDataSou
}
info = null;
}
- }
+ }
if (info == null) {
throw new SQLException("Cannot borrow connection from pool - password change failure.");
}
}
Connection con = info.getPooledConnection().getConnection();
- try {
+ try {
setupDefaults(con, username);
con.clearWarnings();
return con;
- } catch (SQLException ex) {
+ } catch (SQLException ex) {
try {
con.close();
- } catch (Exception exc) {
+ } catch (Exception exc) {
getLogWriter().println(
"ignoring exception during close: " + exc);
}
@@ -798,14 +821,14 @@ public abstract class InstanceKeyDataSou
}
}
- protected abstract PooledConnectionAndInfo
+ protected abstract PooledConnectionAndInfo
getPooledConnectionAndInfo(String username, String password)
throws SQLException;
- protected abstract void setupDefaults(Connection con, String username)
+ protected abstract void setupDefaults(Connection con, String username)
throws SQLException;
-
+
private void closeDueToException(PooledConnectionAndInfo info) {
if (info != null) {
try {
@@ -815,20 +838,20 @@ public abstract class InstanceKeyDataSou
// of handling another exception. But record it because
// it potentially leaks connections from the pool.
getLogWriter().println("[ERROR] Could not return connection to "
- + "pool during exception handling. " + e.getMessage());
+ + "pool during exception handling. " + e.getMessage());
}
}
}
- protected ConnectionPoolDataSource
+ protected ConnectionPoolDataSource
testCPDS(String username, String password)
throws javax.naming.NamingException, SQLException {
// The source of physical db connections
ConnectionPoolDataSource cpds = this.dataSource;
- if (cpds == null) {
+ if (cpds == null) {
Context ctx = null;
if (jndiEnvironment == null) {
- ctx = new InitialContext();
+ ctx = new InitialContext();
} else {
ctx = new InitialContext(jndiEnvironment);
}
@@ -842,7 +865,7 @@ public abstract class InstanceKeyDataSou
+ " doesn't implement javax.sql.ConnectionPoolDataSource");
}
}
-
+
// try to get a connection with the supplied username/password
PooledConnection conn = null;
try {
@@ -871,7 +894,7 @@ public abstract class InstanceKeyDataSou
}
// ----------------------------------------------------------------------
- // Referenceable implementation
+ // Referenceable implementation
/**
* Retrieves the Reference of this object.
@@ -886,11 +909,11 @@ public abstract class InstanceKeyDataSou
*/
// TODO: Remove the implementation of this method at next major
// version release.
-
+
@Override
public Reference getReference() throws NamingException {
final String className = getClass().getName();
- final String factoryName = className + "Factory"; // XXX: not robust
+ final String factoryName = className + "Factory"; // XXX: not robust
Reference ref = new Reference(className, factoryName, null);
ref.add(new StringRefAddr("instanceKey", instanceKey));
return ref;
Modified: commons/proper/dbcp/trunk/src/java/org/apache/commons/dbcp2/datasources/KeyedCPDSConnectionFactory.java
URL: http://svn.apache.org/viewvc/commons/proper/dbcp/trunk/src/java/org/apache/commons/dbcp2/datasources/KeyedCPDSConnectionFactory.java?rev=1506741&r1=1506740&r2=1506741&view=diff
==============================================================================
--- commons/proper/dbcp/trunk/src/java/org/apache/commons/dbcp2/datasources/KeyedCPDSConnectionFactory.java (original)
+++ commons/proper/dbcp/trunk/src/java/org/apache/commons/dbcp2/datasources/KeyedCPDSConnectionFactory.java Wed Jul 24 21:58:57 2013
@@ -55,6 +55,7 @@ class KeyedCPDSConnectionFactory
private final String _validationQuery;
private final boolean _rollbackAfterValidation;
private KeyedObjectPool<UserPassKey,PooledConnectionAndInfo> _pool;
+ private long maxConnLifetimeMillis = -1;
/**
* Map of PooledConnections for which close events are ignored.
@@ -165,6 +166,11 @@ class KeyedCPDSConnectionFactory
@Override
public boolean validateObject(UserPassKey key,
PooledObject<PooledConnectionAndInfo> p) {
+ try {
+ validateLifetime(p);
+ } catch (Exception e) {
+ return false;
+ }
boolean valid = false;
PooledConnection pconn = p.getObject().getPooledConnection();
String query = _validationQuery;
@@ -204,11 +210,15 @@ class KeyedCPDSConnectionFactory
}
@Override
- public void passivateObject(UserPassKey key, PooledObject<PooledConnectionAndInfo> p) {
+ public void passivateObject(UserPassKey key,
+ PooledObject<PooledConnectionAndInfo> p) throws Exception {
+ validateLifetime(p);
}
@Override
- public void activateObject(UserPassKey key, PooledObject<PooledConnectionAndInfo> p) {
+ public void activateObject(UserPassKey key,
+ PooledObject<PooledConnectionAndInfo> p) throws Exception {
+ validateLifetime(p);
}
// ***********************************************************************
@@ -309,6 +319,16 @@ class KeyedCPDSConnectionFactory
}
/**
+ * Sets the maximum lifetime in milliseconds of a connection after which the
+ * connection will always fail activation, passivation and validation. A
+ * value of zero or less indicates an infinite lifetime. The default value
+ * is -1.
+ */
+ public void setMaxConnLifetimeMillis(long maxConnLifetimeMillis) {
+ this.maxConnLifetimeMillis = maxConnLifetimeMillis;
+ }
+
+ /**
* This implementation does not fully close the KeyedObjectPool, as
* this would affect all users. Instead, it clears the pool associated
* with the given user. This method is not currently used.
@@ -322,4 +342,16 @@ class KeyedCPDSConnectionFactory
}
}
+ private void validateLifetime(PooledObject<PooledConnectionAndInfo> p)
+ throws Exception {
+ if (maxConnLifetimeMillis > 0) {
+ long lifetime = System.currentTimeMillis() - p.getCreateTime();
+ if (lifetime > maxConnLifetimeMillis) {
+ throw new Exception(Utils.getMessage(
+ "connectionFactory.lifetimeExceeded",
+ Long.valueOf(lifetime),
+ Long.valueOf(maxConnLifetimeMillis)));
+ }
+ }
+ }
}
Modified: commons/proper/dbcp/trunk/src/java/org/apache/commons/dbcp2/datasources/PerUserPoolDataSource.java
URL: http://svn.apache.org/viewvc/commons/proper/dbcp/trunk/src/java/org/apache/commons/dbcp2/datasources/PerUserPoolDataSource.java?rev=1506741&r1=1506740&r2=1506741&view=diff
==============================================================================
--- commons/proper/dbcp/trunk/src/java/org/apache/commons/dbcp2/datasources/PerUserPoolDataSource.java (original)
+++ commons/proper/dbcp/trunk/src/java/org/apache/commons/dbcp2/datasources/PerUserPoolDataSource.java Wed Jul 24 21:58:57 2013
@@ -519,6 +519,7 @@ public class PerUserPoolDataSource exten
CPDSConnectionFactory factory = new CPDSConnectionFactory(cpds,
getValidationQuery(), isRollbackAfterValidation(), username,
password);
+ factory.setMaxConnLifetimeMillis(getMaxConnLifetimeMillis());
// Create an object pool to contain our PooledConnections
GenericObjectPool<PooledConnectionAndInfo> pool =
Modified: commons/proper/dbcp/trunk/src/java/org/apache/commons/dbcp2/datasources/SharedPoolDataSource.java
URL: http://svn.apache.org/viewvc/commons/proper/dbcp/trunk/src/java/org/apache/commons/dbcp2/datasources/SharedPoolDataSource.java?rev=1506741&r1=1506740&r2=1506741&view=diff
==============================================================================
--- commons/proper/dbcp/trunk/src/java/org/apache/commons/dbcp2/datasources/SharedPoolDataSource.java (original)
+++ commons/proper/dbcp/trunk/src/java/org/apache/commons/dbcp2/datasources/SharedPoolDataSource.java Wed Jul 24 21:58:57 2013
@@ -5,9 +5,9 @@
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -35,11 +35,11 @@ import org.apache.commons.pool2.impl.Gen
/**
* <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. All users (based on username) share a single
+ * defined in the parent class. All users (based on username) share a single
* maximum number of Connections in this datasource.</p>
- *
+ *
* <p>User passwords can be changed without re-initializing the datasource.
- * When a <code>getConnection(username, password)</code> request is processed
+ * 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, idle connections
@@ -120,7 +120,7 @@ public class SharedPoolDataSource
/**
* The maximum number of milliseconds that the pool will wait (when there
* are no available connections) for a connection to be returned before
- * throwing an exception, or -1 to wait indefinitely. Will fail
+ * throwing an exception, or -1 to wait indefinitely. Will fail
* immediately if value is 0.
* The default is -1.
*/
@@ -131,7 +131,7 @@ public class SharedPoolDataSource
/**
* The maximum number of milliseconds that the pool will wait (when there
* are no available connections) for a connection to be returned before
- * throwing an exception, or -1 to wait indefinitely. Will fail
+ * throwing an exception, or -1 to wait indefinitely. Will fail
* immediately if value is 0.
* The default is -1.
*/
@@ -161,10 +161,10 @@ public class SharedPoolDataSource
// Inherited abstract methods
@Override
- protected PooledConnectionAndInfo
+ protected PooledConnectionAndInfo
getPooledConnectionAndInfo(String username, String password)
throws SQLException {
-
+
synchronized(this) {
if (pool == null) {
try {
@@ -176,9 +176,9 @@ public class SharedPoolDataSource
}
PooledConnectionAndInfo info = null;
-
+
UserPassKey key = new UserPassKey(username, password);
-
+
try {
info = pool.borrowObject(key);
}
@@ -188,7 +188,7 @@ public class SharedPoolDataSource
}
return info;
}
-
+
@Override
protected PooledConnectionManager getConnectionManager(UserPassKey upkey) {
return factory;
@@ -196,7 +196,7 @@ public class SharedPoolDataSource
/**
* Returns a <code>SharedPoolDataSource</code> {@link Reference}.
- *
+ *
* @since 1.2.2
*/
@Override
@@ -206,9 +206,9 @@ public class SharedPoolDataSource
ref.add(new StringRefAddr("instanceKey", instanceKey));
return ref;
}
-
+
private void registerPool(
- String username, String password)
+ String username, String password)
throws javax.naming.NamingException, SQLException {
ConnectionPoolDataSource cpds = testCPDS(username, password);
@@ -216,6 +216,7 @@ public class SharedPoolDataSource
// Create an object pool to contain our PooledConnections
factory = new KeyedCPDSConnectionFactory(cpds, getValidationQuery(),
isRollbackAfterValidation());
+ factory.setMaxConnLifetimeMillis(getMaxConnLifetimeMillis());
GenericKeyedObjectPoolConfig config = new GenericKeyedObjectPoolConfig();
config.setMaxTotalPerKey(getMaxTotal());
config.setMaxIdlePerKey(getMaxIdle());
@@ -268,7 +269,7 @@ public class SharedPoolDataSource
*/
private void readObject(ObjectInputStream in)
throws IOException, ClassNotFoundException {
- try
+ try
{
in.defaultReadObject();
SharedPoolDataSource oldDS = (SharedPoolDataSource)
Modified: commons/proper/dbcp/trunk/src/java/org/apache/commons/dbcp2/managed/BasicManagedDataSource.java
URL: http://svn.apache.org/viewvc/commons/proper/dbcp/trunk/src/java/org/apache/commons/dbcp2/managed/BasicManagedDataSource.java?rev=1506741&r1=1506740&r2=1506741&view=diff
==============================================================================
--- commons/proper/dbcp/trunk/src/java/org/apache/commons/dbcp2/managed/BasicManagedDataSource.java (original)
+++ commons/proper/dbcp/trunk/src/java/org/apache/commons/dbcp2/managed/BasicManagedDataSource.java Wed Jul 24 21:58:57 2013
@@ -61,7 +61,7 @@ public class BasicManagedDataSource exte
/**
* Gets the XADataSource instance used by the XAConnectionFactory.
- *
+ *
* @return the XADataSource
*/
public synchronized XADataSource getXaDataSourceInstance() {
@@ -75,7 +75,7 @@ public class BasicManagedDataSource exte
* initialized. The pool is initialized the first time one of the
* following methods is invoked: <code>getConnection, setLogwriter,
* setLoginTimeout, getLoginTimeout, getLogWriter.</code></p>
- *
+ *
* @param xaDataSourceInstance XADataSource instance
*/
public synchronized void setXaDataSourceInstance(XADataSource xaDataSourceInstance) {
@@ -90,7 +90,7 @@ public class BasicManagedDataSource exte
public TransactionManager getTransactionManager() {
return transactionManager;
}
-
+
/**
* Gets the transaction registry.
* @return the transaction registry associating XAResources with managed connections
@@ -146,7 +146,7 @@ public class BasicManagedDataSource exte
String message = "Cannot load XA data source class '" + xaDataSource + "'";
throw (SQLException)new SQLException(message).initCause(t);
}
-
+
try {
xaDataSourceInstance = (XADataSource) xaDataSourceClass.newInstance();
} catch (Exception t) {
@@ -166,9 +166,9 @@ public class BasicManagedDataSource exte
PoolingDataSource pds = new ManagedDataSource(connectionPool, transactionRegistry);
pds.setAccessToUnderlyingConnectionAllowed(isAccessToUnderlyingConnectionAllowed());
pds.setLogWriter(logWriter);
- dataSource = pds;
+ dataSource = pds;
}
-
+
/**
* Creates the PoolableConnectionFactory and attaches it to the connection pool.
*
@@ -195,6 +195,7 @@ public class BasicManagedDataSource exte
connectionFactory.setPoolStatements(poolPreparedStatements);
connectionFactory.setMaxOpenPrepatedStatements(
maxOpenPreparedStatements);
+ connectionFactory.setMaxConnLifetimeMillis(getMaxConnLifetimeMillis());
validateConnectionFactory(connectionFactory);
} catch (RuntimeException e) {
throw e;