--- src/main/java/org/apache/tomcat/jdbc/pool/PoolConfiguration.java (revision 1456054)
+++ src/main/java/org/apache/tomcat/jdbc/pool/PoolConfiguration.java (working copy)
@@ -524,6 +524,19 @@
public void setValidationQuery(String validationQuery);
/**
+ * The timeout in seconds before a connection validation queries fail.
+ * A value less than or equal to zero will disable this feature. Defaults to -1.
+ * @return the timeout value in seconds
+ */
+ public int getValidationQueryTimeout();
+
+ /**
+ * The timeout in seconds before a connection validation queries fail.
+ * A value less than or equal to zero will disable this feature. Defaults to -1.
+ */
+ public void setValidationQueryTimeout(int validationQueryTimeout);
+
+ /**
* Return the name of the optional validator class - may be null.
*
* @return the name of the optional validator class - may be null
--- src/main/java/org/apache/tomcat/jdbc/pool/PooledConnection.java (revision 1456054)
+++ src/main/java/org/apache/tomcat/jdbc/pool/PooledConnection.java (working copy)
@@ -451,6 +451,12 @@
Statement stmt = null;
try {
stmt = connection.createStatement();
+
+ int validationQueryTimeout = poolProperties.getValidationQueryTimeout();
+ if (validationQueryTimeout > 0) {
+ stmt.setQueryTimeout(validationQueryTimeout);
+ }
+
stmt.execute(query);
stmt.close();
this.lastValidated = now;
--- src/main/java/org/apache/tomcat/jdbc/pool/jmx/ConnectionPool.java (revision 1456054)
+++ src/main/java/org/apache/tomcat/jdbc/pool/jmx/ConnectionPool.java (working copy)
@@ -310,6 +310,11 @@
public String getValidationQuery() {
return getPoolProperties().getValidationQuery();
}
+
+ @Override
+ public int getValidationQueryTimeout() {
+ return getPoolProperties().getValidationQueryTimeout();
+ }
/**
* {@inheritDoc}
@@ -664,6 +669,11 @@
getPoolProperties().setValidationQuery(validationQuery);
}
+ @Override
+ public void setValidationQueryTimeout(int validationQueryTimeout) {
+ getPoolProperties().setValidationQueryTimeout(validationQueryTimeout);
+ }
+
/**
* {@inheritDoc}
*/
--- src/main/java/org/apache/tomcat/jdbc/pool/DataSourceFactory.java (revision 1456054)
+++ src/main/java/org/apache/tomcat/jdbc/pool/DataSourceFactory.java (working copy)
@@ -80,6 +80,7 @@
protected static final String PROP_TESTWHILEIDLE = "testWhileIdle";
protected static final String PROP_TESTONCONNECT = "testOnConnect";
protected static final String PROP_VALIDATIONQUERY = "validationQuery";
+ protected static final String PROP_VALIDATIONQUERY_TIMEOUT = "validationQueryTimeout";
protected static final String PROP_VALIDATOR_CLASS_NAME = "validatorClassName";
protected static final String PROP_NUMTESTSPEREVICTIONRUN = "numTestsPerEvictionRun";
@@ -149,6 +150,7 @@
PROP_URL,
PROP_USERNAME,
PROP_VALIDATIONQUERY,
+ PROP_VALIDATIONQUERY_TIMEOUT,
PROP_VALIDATOR_CLASS_NAME,
PROP_VALIDATIONINTERVAL,
PROP_ACCESSTOUNDERLYINGCONNECTIONALLOWED,
@@ -366,6 +368,11 @@
if (value != null) {
poolProperties.setValidationQuery(value);
}
+
+ value = properties.getProperty(PROP_VALIDATIONQUERY_TIMEOUT);
+ if (value != null) {
+ poolProperties.setValidationQueryTimeout(Integer.parseInt(value));
+ }
value = properties.getProperty(PROP_VALIDATOR_CLASS_NAME);
if (value != null) {
--- src/main/java/org/apache/tomcat/jdbc/pool/PoolProperties.java (revision 1456054)
+++ src/main/java/org/apache/tomcat/jdbc/pool/PoolProperties.java (working copy)
@@ -57,6 +57,7 @@
private volatile int minIdle = initialSize;
private volatile int maxWait = 30000;
private volatile String validationQuery;
+ private volatile int validationQueryTimeout = -1;
private volatile String validatorClassName;
private volatile Validator validator;
private volatile boolean testOnBorrow = false;
@@ -382,6 +383,22 @@
/**
* {@inheritDoc}
*/
+ @Override
+ public int getValidationQueryTimeout() {
+ return validationQueryTimeout;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void setValidationQueryTimeout(int validationQueryTimeout) {
+ this.validationQueryTimeout = validationQueryTimeout;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
@Override
public String getValidatorClassName() {
--- src/main/java/org/apache/tomcat/jdbc/pool/DataSourceProxy.java (revision 1456054)
+++ src/main/java/org/apache/tomcat/jdbc/pool/DataSourceProxy.java (working copy)
@@ -452,6 +452,15 @@
public void setValidatorClassName(String className) {
this.poolProperties.setValidatorClassName(className);
}
+
+ /**
+ * {@inheritDoc}
+ */
+
+ @Override
+ public void setValidationQueryTimeout(int validationQueryTimeout) {
+ this.poolProperties.setValidationQueryTimeout(validationQueryTimeout);
+ }
/**
* {@inheritDoc}
@@ -928,6 +937,15 @@
/**
* {@inheritDoc}
*/
+
+ @Override
+ public int getValidationQueryTimeout() {
+ return getPoolProperties().getValidationQueryTimeout();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
@Override
public String getValidatorClassName() {
--- src/main/java/org/apache/tomcat/jdbc/pool/mbeans-descriptors.xml (revision 1456054)
+++ src/main/java/org/apache/tomcat/jdbc/pool/mbeans-descriptors.xml (working copy)
@@ -125,6 +125,11 @@
description="The query to run during validation"
type="java.lang.String"
writeable="false"/>
+
+ select 1 from dual
(oracle), SELECT 1
(MS Sql Server)
(int) The timeout in seconds before a connection validation queries fail. This works by calling
+ java.sql.Statement.setQueryTimeout(seconds)
on the statement that executes the validationQuery
.
+ The pool itself doesn't timeout the query, it is still up to the JDBC driver to enforce query timeouts.
+ A value less than or equal to zero will disable this feature.
+ The default value is -1
.
+
(String) The name of a class which implements the --- src/test/java/org/apache/tomcat/jdbc/test/TestValidationQueryTimeout.java (revision 0) +++ src/test/java/org/apache/tomcat/jdbc/test/TestValidationQueryTimeout.java (revision 0) @@ -0,0 +1,133 @@ +package org.apache.tomcat.jdbc.test; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.DriverPropertyInfo; +import java.sql.SQLException; +import java.sql.SQLFeatureNotSupportedException; +import java.sql.Statement; +import java.util.Properties; +import java.util.logging.Logger; + +import junit.framework.Assert; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +public class TestValidationQueryTimeout extends DefaultTestCase { + + private static final int TIMEOUT = 10; + private static boolean isTimeoutSet; + + @Before + public void setUp() throws SQLException { + DriverManager.registerDriver(new MockDriver()); + isTimeoutSet = false; + } + + @After + public void tearDown() throws SQLException { + DriverManager.deregisterDriver(new MockDriver()); + } + + @Test + public void testValidationQueryTimeoutEnabled() throws Exception { + // use our mock driver + this.datasource.setDriverClassName(MockDriver.class.getName()); + this.datasource.setUrl(MockDriver.url); + + // Required to trigger validation query's execution + this.datasource.setTestOnBorrow(true); + this.datasource.setValidationInterval(-1); + this.datasource.setValidationQuery("SELECT 1"); + this.datasource.setValidationQueryTimeout(TIMEOUT); + + // because testOnBorrow is true, this triggers the validation query + this.datasource.getConnection(); + Assert.assertTrue(isTimeoutSet); + } + + @Test + public void testValidationQueryTimeoutDisabled() throws Exception { + // use our mock driver + this.datasource.setDriverClassName(MockDriver.class.getName()); + this.datasource.setUrl(MockDriver.url); + + // Required to trigger validation query's execution + this.datasource.setTestOnBorrow(true); + this.datasource.setValidationInterval(-1); + this.datasource.setValidationQuery("SELECT 1"); + this.datasource.setValidationQueryTimeout(-1); + + // because testOnBorrow is true, this triggers the validation query + this.datasource.getConnection(); + Assert.assertFalse(isTimeoutSet); + } + + /** + * Mock Driver, Connection and Statement implementations use to verify setQueryTimeout was called. + */ + public static class MockDriver implements java.sql.Driver { + public static final String url = "jdbc:tomcat:mock"; + + public MockDriver() { + } + + @Override + public boolean acceptsURL(String url) throws SQLException { + return url!=null && url.equals(MockDriver.url); + } + + @Override + public Connection connect(String url, Properties info) throws SQLException { + return new MockConnection(info); + } + + @Override + public int getMajorVersion() { + return 0; + } + + @Override + public int getMinorVersion() { + return 0; + } + + @Override + public DriverPropertyInfo[] getPropertyInfo(String url, Properties info) throws SQLException { + return null; + } + + @Override + public boolean jdbcCompliant() { + return false; + } + + @Override + public Logger getParentLogger() throws SQLFeatureNotSupportedException { + return null; + } + } + + public static class MockConnection extends org.apache.tomcat.jdbc.test.driver.Connection { + public MockConnection(Properties info) { + super(info); + } + + @Override + public Statement createStatement() throws SQLException { + return new MockStatement(); + } + } + + public static class MockStatement extends org.apache.tomcat.jdbc.test.driver.Statement { + @Override + public void setQueryTimeout(int seconds) throws SQLException { + super.setQueryTimeout(seconds); + Assert.assertEquals(TIMEOUT, seconds); + isTimeoutSet = true; + } + } + +}