Fix https://issues.apache.org/bugzilla/show_bug.cgi?id=48817
authormarkt <markt@13f79535-47bb-0310-9956-ffa450edef68>
Thu, 5 Aug 2010 22:27:53 +0000 (22:27 +0000)
committermarkt <markt@13f79535-47bb-0310-9956-ffa450edef68>
Thu, 5 Aug 2010 22:27:53 +0000 (22:27 +0000)
Add Validator interface and allow users to configure a Validator class name

git-svn-id: https://svn.apache.org/repos/asf/tomcat/trunk@982811 13f79535-47bb-0310-9956-ffa450edef68

modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/DataSourceFactory.java
modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/DataSourceProxy.java
modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/PoolConfiguration.java
modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/PoolProperties.java
modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/PooledConnection.java
modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/Validator.java [new file with mode: 0644]
modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/jmx/ConnectionPool.java

index 5aec25a..87eea63 100644 (file)
@@ -81,6 +81,7 @@ public class DataSourceFactory implements ObjectFactory {
     protected final static String PROP_TESTWHILEIDLE = "testWhileIdle";
     protected final static String PROP_TESTONCONNECT = "testOnConnect";
     protected final static String PROP_VALIDATIONQUERY = "validationQuery";
+    protected final static String PROP_VALIDATOR_CLASS_NAME = "validatorClassName";
     
     protected final static String PROP_TIMEBETWEENEVICTIONRUNSMILLIS = "timeBetweenEvictionRunsMillis";
     protected final static String PROP_NUMTESTSPEREVICTIONRUN = "numTestsPerEvictionRun";
@@ -347,6 +348,11 @@ public class DataSourceFactory implements ObjectFactory {
         if (value != null) {
             poolProperties.setValidationQuery(value);
         }
+        
+        value = properties.getProperty(PROP_VALIDATOR_CLASS_NAME);
+        if (value != null) {
+            poolProperties.setValidatorClassName(value);
+        }
 
         value = properties.getProperty(PROP_VALIDATIONINTERVAL);
         if (value != null) {
index 0f84ceb..17f831c 100644 (file)
@@ -390,6 +390,14 @@ public class DataSourceProxy implements PoolConfiguration {
         this.poolProperties.setValidationQuery(validationQuery);
     }
 
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void setValidatorClassName(String className) {
+        this.poolProperties.setValidatorClassName(className);
+    }
+
     /** 
      * {@inheritDoc}
      */
@@ -818,6 +826,22 @@ public class DataSourceProxy implements PoolConfiguration {
         return getPoolProperties().getValidationQuery();
     }
 
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public String getValidatorClassName() {
+        return getPoolProperties().getValidatorClassName();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public Validator getValidator() {
+        return getPoolProperties().getValidator();
+    }
+
     /** 
      * {@inheritDoc}
      */
index f923ddf..7e4cd74 100644 (file)
@@ -522,9 +522,28 @@ public interface PoolConfiguration {
      * @param validationQuery the query used for validation or null if no validation is performed
      */
     public void setValidationQuery(String validationQuery);
-
     
     /**
+     * Return the name of the optional validator class - may be null.
+     *  
+     * @return the name of the optional validator class - may be null
+     */
+    public String getValidatorClassName();
+    
+    /**
+     * Set the name for an optional validator class which will be used in place of test queries. If set to
+     * null, standard validation will be used.
+     * 
+     * @param className the name of the optional validator class
+     */
+    public void setValidatorClassName(String className);
+    
+    /**
+     * @return the optional validator object - may be null
+     */
+    public Validator getValidator();
+
+    /**
      * avoid excess validation, only run validation at most at this frequency - time in milliseconds. 
      * If a connection is due for validation, but has been validated previously 
      * within this interval, it will not be validated again. 
index e960727..ba1eab0 100644 (file)
@@ -51,6 +51,8 @@ public class PoolProperties implements PoolConfiguration {
     protected int minIdle = initialSize;
     protected int maxWait = 30000;
     protected String validationQuery;
+    protected String validatorClassName;
+    protected Validator validator;
     protected boolean testOnBorrow = false;
     protected boolean testOnReturn = false;
     protected boolean testWhileIdle = false;
@@ -338,6 +340,22 @@ public class PoolProperties implements PoolConfiguration {
         return validationQuery;
     }
 
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public String getValidatorClassName() {
+        return validatorClassName;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public Validator getValidator() {
+        return validator;
+    }
+
     /** 
      * {@inheritDoc}
      */
@@ -631,6 +649,34 @@ public class PoolProperties implements PoolConfiguration {
         this.validationQuery = validationQuery;
     }
 
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void setValidatorClassName(String className) {
+        this.validatorClassName = className;
+        
+        validator = null;
+        
+        if (className == null) {
+            return;
+        }
+        
+        try {
+            Class<Validator> validatorClass = (Class<Validator>)Class.forName(className);
+            validator = validatorClass.newInstance();
+        } catch (ClassNotFoundException e) {
+            log.warn("The class "+className+" cannot be found.", e);
+        } catch (ClassCastException e) {
+            log.warn("The class "+className+" does not implement the Validator interface.", e);
+        } catch (InstantiationException e) {
+            log.warn("An object of class "+className+" cannot be instantiated. Make sure that "+
+                     "it includes an implicit or explicit no-arg constructor.", e);
+        } catch (IllegalAccessException e) {
+            log.warn("The class "+className+" or its no-arg constructor are inaccessible.", e);
+        }
+    }
+
     /** 
      * {@inheritDoc}
      */
index 6132936..dad20d9 100644 (file)
@@ -362,21 +362,29 @@ public class PooledConnection {
             return true;
         }
 
-        String query = (VALIDATE_INIT==validateAction && (poolProperties.getInitSQL()!=null))?poolProperties.getInitSQL():sql;
-
-        if (query==null) query = poolProperties.getValidationQuery();
-
-        if (query == null) {
-            //no validation possible
-            return true;
-        }
+        //Don't bother validating if already have recently enough
         long now = System.currentTimeMillis();
-        if (this.poolProperties.getValidationInterval() > 0 &&
-            (validateAction!=VALIDATE_INIT) &&    
+        if (validateAction!=VALIDATE_INIT &&
+            poolProperties.getValidationInterval() > 0 &&
             (now - this.lastValidated) <
-            this.poolProperties.getValidationInterval()) {
+            poolProperties.getValidationInterval()) {
             return true;
         }
+
+        if (poolProperties.getValidator() != null) {
+            return poolProperties.getValidator().validate(connection, validateAction);
+        }
+        
+        String query = sql;
+        
+        if (validateAction == VALIDATE_INIT && poolProperties.getInitSQL() != null) {
+            query = poolProperties.getInitSQL();
+        }
+
+        if (query == null) {
+            query = poolProperties.getValidationQuery();
+        }
+        
         Statement stmt = null;
         try {
             stmt = connection.createStatement();
diff --git a/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/Validator.java b/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/Validator.java
new file mode 100644 (file)
index 0000000..4f286ef
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * 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.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.tomcat.jdbc.pool;
+
+import java.sql.Connection;
+
+/**
+ * Interface to be implemented by custom validator classes.
+ * 
+ * @author mpassell
+ */
+public interface Validator {
+    /**
+     * Validate a connection and return a boolean to indicate if it's valid.
+     * 
+     * @param connection the Connection object to test
+     * @param validateAction the action used. One of {@link PooledConnection#VALIDATE_BORROW},
+     *   {@link PooledConnection#VALIDATE_IDLE}, {@link PooledConnection#VALIDATE_INIT} or
+     *   {@link PooledConnection#VALIDATE_RETURN}
+     * @return true if the connection is valid
+     */
+    public boolean validate(Connection connection, int validateAction);
+}
index 1a4b947..b5bd411 100644 (file)
@@ -29,6 +29,7 @@ import javax.management.NotificationListener;
 import org.apache.juli.logging.Log;
 import org.apache.juli.logging.LogFactory;
 import org.apache.tomcat.jdbc.pool.PoolConfiguration;
+import org.apache.tomcat.jdbc.pool.Validator;
 import org.apache.tomcat.jdbc.pool.PoolProperties.InterceptorDefinition;
 
 public class ConnectionPool extends NotificationBroadcasterSupport implements ConnectionPoolMBean  {
@@ -278,6 +279,22 @@ public class ConnectionPool extends NotificationBroadcasterSupport implements Co
         return getPoolProperties().getValidationQuery();
     }
 
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public String getValidatorClassName() {
+        return getPoolProperties().getValidatorClassName();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public Validator getValidator() {
+        return getPoolProperties().getValidator();
+    }
+
     public boolean isAccessToUnderlyingConnectionAllowed() {
         return getPoolProperties().isAccessToUnderlyingConnectionAllowed();
     }
@@ -557,48 +574,56 @@ public class ConnectionPool extends NotificationBroadcasterSupport implements Co
     }
     
     /**
-    * {@inheritDoc}
-    */
-   @Override
-   public int getSuspectTimeout() {
-       return getPoolProperties().getSuspectTimeout(); 
-   }
-
-   /**
-    * {@inheritDoc}
-    */
-   @Override
-   public void setSuspectTimeout(int seconds) {
-       //no op
-   }
-   
-   /** 
-    * {@inheritDoc}
-    */
-   public void setDataSource(Object ds) {
-       getPoolProperties().setDataSource(ds);
-   }
-   
-   /** 
-    * {@inheritDoc}
-    */
-   public Object getDataSource() {
-       return getPoolProperties().getDataSource();
-   }
-   
-   
-   /** 
-    * {@inheritDoc}
-    */
-   public void setDataSourceJNDI(String jndiDS) {
-       //noop
-   }
-   
-   /** 
-    * {@inheritDoc}
-    */
-   public String getDataSourceJNDI() {
-       return getPoolProperties().getDataSourceJNDI();
-   }
+     * {@inheritDoc}
+     */
+    @Override
+    public void setValidatorClassName(String className) {
+        getPoolProperties().setValidatorClassName(className);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int getSuspectTimeout() {
+        return getPoolProperties().getSuspectTimeout(); 
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void setSuspectTimeout(int seconds) {
+        //no op
+    }
+
+    /** 
+     * {@inheritDoc}
+     */
+    public void setDataSource(Object ds) {
+        getPoolProperties().setDataSource(ds);
+    }
+
+    /** 
+     * {@inheritDoc}
+     */
+    public Object getDataSource() {
+        return getPoolProperties().getDataSource();
+    }
+
+
+    /** 
+     * {@inheritDoc}
+     */
+    public void setDataSourceJNDI(String jndiDS) {
+        //noop
+    }
+
+    /** 
+     * {@inheritDoc}
+     */
+    public String getDataSourceJNDI() {
+        return getPoolProperties().getDataSourceJNDI();
+    }
 
 }