Author: kfujino
Date: Thu Mar 23 07:57:36 2017
New Revision: 1788184

URL: http://svn.apache.org/viewvc?rev=1788184&view=rev
Log:
Fix https://bz.apache.org/bugzilla/show_bug.cgi?id=60764
Implement equals() and hashCode() in the StatementFacade in order to enable 
these methods to be called on the closed statements if any statement proxy is 
set. This behavior can be changed with useStatementFacade attribute.

Added:
    
tomcat/tc8.5.x/trunk/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/StatementFacade.java
   (with props)
Modified:
    
tomcat/tc8.5.x/trunk/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/ConnectionPool.java
    
tomcat/tc8.5.x/trunk/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/DataSourceFactory.java
    
tomcat/tc8.5.x/trunk/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/DataSourceProxy.java
    
tomcat/tc8.5.x/trunk/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/PoolConfiguration.java
    
tomcat/tc8.5.x/trunk/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/PoolProperties.java
    
tomcat/tc8.5.x/trunk/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/jmx/ConnectionPool.java
    
tomcat/tc8.5.x/trunk/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/mbeans-descriptors.xml
    tomcat/tc8.5.x/trunk/webapps/docs/changelog.xml

Modified: 
tomcat/tc8.5.x/trunk/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/ConnectionPool.java
URL: 
http://svn.apache.org/viewvc/tomcat/tc8.5.x/trunk/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/ConnectionPool.java?rev=1788184&r1=1788183&r2=1788184&view=diff
==============================================================================
--- 
tomcat/tc8.5.x/trunk/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/ConnectionPool.java
 (original)
+++ 
tomcat/tc8.5.x/trunk/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/ConnectionPool.java
 Thu Mar 23 07:57:36 2017
@@ -327,7 +327,10 @@ public class ConnectionPool {
                 next = next.getNext();
             }
         }
-
+        // setup statement proxy
+        if (getPoolProperties().getUseStatementFacade()) {
+            handler = new StatementFacade(handler);
+        }
         try {
             getProxyConstructor(con.getXAConnection() != null);
             //create the proxy

Modified: 
tomcat/tc8.5.x/trunk/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/DataSourceFactory.java
URL: 
http://svn.apache.org/viewvc/tomcat/tc8.5.x/trunk/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/DataSourceFactory.java?rev=1788184&r1=1788183&r2=1788184&view=diff
==============================================================================
--- 
tomcat/tc8.5.x/trunk/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/DataSourceFactory.java
 (original)
+++ 
tomcat/tc8.5.x/trunk/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/DataSourceFactory.java
 Thu Mar 23 07:57:36 2017
@@ -124,6 +124,8 @@ public class DataSourceFactory implement
 
     protected static final String PROP_IGNOREEXCEPTIONONPRELOAD = 
"ignoreExceptionOnPreLoad";
 
+    protected static final String PROP_USESTATEMENTFACADE = 
"useStatementFacade";
+
     public static final int UNKNOWN_TRANSACTIONISOLATION = -1;
 
     public static final String OBJECT_NAME = "object_name";
@@ -179,7 +181,8 @@ public class DataSourceFactory implement
         PROP_USEDISPOSABLECONNECTIONFACADE,
         PROP_LOGVALIDATIONERRORS,
         PROP_PROPAGATEINTERRUPTSTATE,
-        PROP_IGNOREEXCEPTIONONPRELOAD
+        PROP_IGNOREEXCEPTIONONPRELOAD,
+        PROP_USESTATEMENTFACADE
     };
 
     // -------------------------------------------------- ObjectFactory Methods
@@ -527,7 +530,10 @@ public class DataSourceFactory implement
         if (value != null) {
             
poolProperties.setIgnoreExceptionOnPreLoad(Boolean.parseBoolean(value));
         }
-
+        value = properties.getProperty(PROP_USESTATEMENTFACADE);
+        if (value != null) {
+            poolProperties.setUseStatementFacade(Boolean.parseBoolean(value));
+        }
         return poolProperties;
     }
 

Modified: 
tomcat/tc8.5.x/trunk/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/DataSourceProxy.java
URL: 
http://svn.apache.org/viewvc/tomcat/tc8.5.x/trunk/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/DataSourceProxy.java?rev=1788184&r1=1788183&r2=1788184&view=diff
==============================================================================
--- 
tomcat/tc8.5.x/trunk/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/DataSourceProxy.java
 (original)
+++ 
tomcat/tc8.5.x/trunk/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/DataSourceProxy.java
 Thu Mar 23 07:57:36 2017
@@ -1458,6 +1458,22 @@ public class DataSourceProxy implements
         
getPoolProperties().setIgnoreExceptionOnPreLoad(ignoreExceptionOnPreLoad);
     }
 
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean getUseStatementFacade() {
+        return getPoolProperties().getUseStatementFacade();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void setUseStatementFacade(boolean useStatementFacade) {
+        getPoolProperties().setUseStatementFacade(useStatementFacade);
+    }
+
     public void purge()  {
         try {
             createPool().purge();

Modified: 
tomcat/tc8.5.x/trunk/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/PoolConfiguration.java
URL: 
http://svn.apache.org/viewvc/tomcat/tc8.5.x/trunk/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/PoolConfiguration.java?rev=1788184&r1=1788183&r2=1788184&view=diff
==============================================================================
--- 
tomcat/tc8.5.x/trunk/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/PoolConfiguration.java
 (original)
+++ 
tomcat/tc8.5.x/trunk/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/PoolConfiguration.java
 Thu Mar 23 07:57:36 2017
@@ -894,4 +894,18 @@ public interface PoolConfiguration {
      */
     public boolean isIgnoreExceptionOnPreLoad();
 
+    /**
+     * Set this to true if you wish to wrap statements in order to enable 
equals() and hashCode()
+     * methods to be called on the closed statements if any statement proxy is 
set.
+     * @param useStatementFacade set to <code>true</code> to wrap statements
+     */
+    public void setUseStatementFacade(boolean useStatementFacade);
+
+    /**
+     * Returns <code>true</code> if this connection pool is configured to wrap 
statements in order
+     * to enable equals() and hashCode() methods to be called on the closed 
statements if any
+     * statement proxy is set.
+     * @return <code>true</code> if the statements are wrapped
+     */
+    public boolean getUseStatementFacade();
 }

Modified: 
tomcat/tc8.5.x/trunk/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/PoolProperties.java
URL: 
http://svn.apache.org/viewvc/tomcat/tc8.5.x/trunk/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/PoolProperties.java?rev=1788184&r1=1788183&r2=1788184&view=diff
==============================================================================
--- 
tomcat/tc8.5.x/trunk/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/PoolProperties.java
 (original)
+++ 
tomcat/tc8.5.x/trunk/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/PoolProperties.java
 Thu Mar 23 07:57:36 2017
@@ -89,6 +89,7 @@ public class PoolProperties implements P
     private volatile boolean logValidationErrors = false;
     private volatile boolean propagateInterruptState = false;
     private volatile boolean ignoreExceptionOnPreLoad = false;
+    private volatile boolean useStatementFacade = true;
 
     /**
      * {@inheritDoc}
@@ -1301,6 +1302,22 @@ public class PoolProperties implements P
         this.ignoreExceptionOnPreLoad = ignoreExceptionOnPreLoad;
     }
 
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean getUseStatementFacade() {
+        return useStatementFacade;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void setUseStatementFacade(boolean useStatementFacade) {
+        this.useStatementFacade = useStatementFacade;
+    }
+
     @Override
     protected Object clone() throws CloneNotSupportedException {
         // TODO Auto-generated method stub

Added: 
tomcat/tc8.5.x/trunk/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/StatementFacade.java
URL: 
http://svn.apache.org/viewvc/tomcat/tc8.5.x/trunk/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/StatementFacade.java?rev=1788184&view=auto
==============================================================================
--- 
tomcat/tc8.5.x/trunk/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/StatementFacade.java
 (added)
+++ 
tomcat/tc8.5.x/trunk/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/StatementFacade.java
 Thu Mar 23 07:57:36 2017
@@ -0,0 +1,177 @@
+/*
+ * 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.lang.reflect.Constructor;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.sql.CallableStatement;
+import java.sql.PreparedStatement;
+import java.sql.Statement;
+
+import org.apache.juli.logging.Log;
+import org.apache.juli.logging.LogFactory;
+import 
org.apache.tomcat.jdbc.pool.interceptor.AbstractCreateStatementInterceptor;
+
+public class StatementFacade extends AbstractCreateStatementInterceptor {
+
+    private static final Log logger = LogFactory.getLog(StatementFacade.class);
+
+    /**
+     * the constructors that are used to create statement proxies
+     */
+    protected static final Constructor<?>[] constructors
+            = new 
Constructor[AbstractCreateStatementInterceptor.STATEMENT_TYPE_COUNT];
+
+    protected StatementFacade(JdbcInterceptor interceptor) {
+        setUseEquals(interceptor.isUseEquals());
+        setNext(interceptor);
+    }
+
+    @Override
+    public void closeInvoked() {
+        // nothing to do
+    }
+
+    /**
+     * Creates a statement interceptor to monitor query response times
+     */
+    @Override
+    public Object createStatement(Object proxy, Method method, Object[] args, 
Object statement, long time) {
+        try {
+            String name = method.getName();
+            Constructor<?> constructor = null;
+            String sql = null;
+            if (compare(CREATE_STATEMENT, name)) {
+                // createStatement
+                constructor = getConstructor(CREATE_STATEMENT_IDX, 
Statement.class);
+            } else if (compare(PREPARE_STATEMENT, name)) {
+                // prepareStatement
+                constructor = getConstructor(PREPARE_STATEMENT_IDX, 
PreparedStatement.class);
+                sql = (String)args[0];
+            } else if (compare(PREPARE_CALL, name)) {
+                // prepareCall
+                constructor = getConstructor(PREPARE_CALL_IDX, 
CallableStatement.class);
+                sql = (String)args[0];
+            } else {
+                // do nothing
+                return statement;
+            }
+            return constructor.newInstance(new Object[] { new 
StatementProxy(statement,sql) });
+        } catch (Exception x) {
+            logger.warn("Unable to create statement proxy.", x);
+        }
+        return statement;
+    }
+
+    /**
+     * Creates a constructor for a proxy class, if one doesn't already exist
+     *
+     * @param idx
+     *            - the index of the constructor
+     * @param clazz
+     *            - the interface that the proxy will implement
+     * @return - returns a constructor used to create new instances
+     * @throws NoSuchMethodException Constructor not found
+     */
+    protected Constructor<?> getConstructor(int idx, Class<?> clazz) throws 
NoSuchMethodException {
+        if (constructors[idx] == null) {
+            Class<?> proxyClass = 
Proxy.getProxyClass(StatementFacade.class.getClassLoader(),
+                    new Class[] { clazz });
+            constructors[idx] = proxyClass.getConstructor(new Class[] { 
InvocationHandler.class });
+        }
+        return constructors[idx];
+    }
+
+    /**
+     * Class to measure query execute time.
+     */
+    protected class StatementProxy implements InvocationHandler {
+        protected boolean closed = false;
+        protected Object delegate;
+        protected final String query;
+        public StatementProxy(Object parent, String query) {
+            this.delegate = parent;
+            this.query = query;
+        }
+
+        @Override
+        public Object invoke(Object proxy, Method method, Object[] args) 
throws Throwable {
+            if (compare(TOSTRING_VAL,method)) {
+                return toString();
+            }
+            if (compare(EQUALS_VAL, method)) {
+                return Boolean.valueOf(
+                        this.equals(Proxy.getInvocationHandler(args[0])));
+            }
+            if (compare(HASHCODE_VAL, method)) {
+                return Integer.valueOf(this.hashCode());
+            }
+            if (compare(CLOSE_VAL, method)) {
+                if (delegate == null) return null;
+            }
+            if (compare(ISCLOSED_VAL, method)) {
+                if (delegate == null) return true;
+            }
+
+            Object result =  null;
+            try {
+                //invoke next
+                result =  method.invoke(delegate,args);
+            } catch (Throwable t) {
+                if (t instanceof InvocationTargetException && t.getCause() != 
null) {
+                    throw t.getCause();
+                } else {
+                    throw t;
+                }
+            }
+            //perform close cleanup
+            if (compare(CLOSE_VAL, method)) {
+                delegate = null;
+            }
+            return result;
+        }
+
+        @Override
+        public int hashCode() {
+            return System.identityHashCode(this);
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            return this==obj;
+        }
+
+        @Override
+        public String toString() {
+            StringBuffer buf = new 
StringBuffer(StatementProxy.class.getName());
+            buf.append("[Proxy=");
+            buf.append(hashCode());
+            buf.append("; Query=");
+            buf.append(query);
+            buf.append("; Delegate=");
+            buf.append(delegate);
+            buf.append("]");
+            return buf.toString();
+        }
+    }
+
+}

Propchange: 
tomcat/tc8.5.x/trunk/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/StatementFacade.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: 
tomcat/tc8.5.x/trunk/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/jmx/ConnectionPool.java
URL: 
http://svn.apache.org/viewvc/tomcat/tc8.5.x/trunk/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/jmx/ConnectionPool.java?rev=1788184&r1=1788183&r2=1788184&view=diff
==============================================================================
--- 
tomcat/tc8.5.x/trunk/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/jmx/ConnectionPool.java
 (original)
+++ 
tomcat/tc8.5.x/trunk/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/jmx/ConnectionPool.java
 Thu Mar 23 07:57:36 2017
@@ -919,6 +919,22 @@ public class ConnectionPool extends Noti
      * {@inheritDoc}
      */
     @Override
+    public boolean getUseStatementFacade() {
+        return getPoolProperties().getUseStatementFacade();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void setUseStatementFacade(boolean useStatementFacade) {
+        getPoolProperties().setUseStatementFacade(useStatementFacade);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
     public void purge() {
         pool.purge();
 

Modified: 
tomcat/tc8.5.x/trunk/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/mbeans-descriptors.xml
URL: 
http://svn.apache.org/viewvc/tomcat/tc8.5.x/trunk/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/mbeans-descriptors.xml?rev=1788184&r1=1788183&r2=1788184&view=diff
==============================================================================
--- 
tomcat/tc8.5.x/trunk/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/mbeans-descriptors.xml
 (original)
+++ 
tomcat/tc8.5.x/trunk/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/mbeans-descriptors.xml
 Thu Mar 23 07:57:36 2017
@@ -330,6 +330,12 @@
                     is="true"
              writeable="false"/>
 
+    <attribute    name="useStatementFacade"
+           description="If true, connection pool is configured to wrap 
statements."
+                  type="java.lang.Boolean"
+                    is="false"
+             writeable="false"/>
+
     <attribute    name="borrowedCount"
            description="The total number of connections borrowed from this 
pool"
                   type="java.lang.Long"

Modified: tomcat/tc8.5.x/trunk/webapps/docs/changelog.xml
URL: 
http://svn.apache.org/viewvc/tomcat/tc8.5.x/trunk/webapps/docs/changelog.xml?rev=1788184&r1=1788183&r2=1788184&view=diff
==============================================================================
--- tomcat/tc8.5.x/trunk/webapps/docs/changelog.xml (original)
+++ tomcat/tc8.5.x/trunk/webapps/docs/changelog.xml Thu Mar 23 07:57:36 2017
@@ -93,6 +93,17 @@
       </fix>
     </changelog>
   </subsection>
+  <subsection name="jdbc-pool">
+    <changelog>
+      <fix>
+        <bug>60764</bug>: Implement <code>equals()</code> and
+        <code>hashCode()</code> in the <code>StatementFacade</code> in order to
+        enable these methods to be called on the closed statements if any
+        statement proxy is set. This behavior can be changed with
+        <code>useStatementFacade</code> attribute. (kfujino)
+      </fix>
+    </changelog>
+  </subsection>
   <subsection name="Other">
     <changelog>
       <fix>



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

Reply via email to