Added an interceptor that keeps track of statements, and if they are not closed,...
authorfhanik <fhanik@13f79535-47bb-0310-9956-ffa450edef68>
Sun, 16 Nov 2008 03:26:29 +0000 (03:26 +0000)
committerfhanik <fhanik@13f79535-47bb-0310-9956-ffa450edef68>
Sun, 16 Nov 2008 03:26:29 +0000 (03:26 +0000)
git-svn-id: https://svn.apache.org/repos/asf/tomcat/trunk@717972 13f79535-47bb-0310-9956-ffa450edef68

modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/interceptor/AbstractCreateStatementInterceptor.java
modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/interceptor/StatementFinalizer.java [new file with mode: 0644]
modules/jdbc-pool/test/org/apache/tomcat/jdbc/test/StatementFinalizerTest.java [new file with mode: 0644]

index bf5fcf1..80f04b6 100644 (file)
@@ -37,15 +37,21 @@ public abstract class  AbstractCreateStatementInterceptor extends JdbcIntercepto
     public  AbstractCreateStatementInterceptor() {
         super();
     }
-
+    
+    @Override
     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
-        boolean process = false;
-        process = process(statements, method, process);
-        if (process) {
-            Object statement = super.invoke(proxy,method,args);
-            return createStatement(proxy,method,args,statement);
+        if (CLOSE_VAL==method.getName()) {
+            closeInvoked();
+            return super.invoke(proxy, method, args);
         } else {
-            return super.invoke(proxy,method,args);
+            boolean process = false;
+            process = process(statements, method, process);
+            if (process) {
+                Object statement = super.invoke(proxy,method,args);
+                return createStatement(proxy,method,args,statement);
+            } else {
+                return super.invoke(proxy,method,args);
+            }
         }
     }
     
@@ -59,6 +65,8 @@ public abstract class  AbstractCreateStatementInterceptor extends JdbcIntercepto
      * @return
      */
     public abstract Object createStatement(Object proxy, Method method, Object[] args, Object statement);
+    
+    public abstract void closeInvoked();
 
     protected boolean process(String[] names, Method method, boolean process) {
         for (int i=0; (!process) && i<names.length; i++) {
diff --git a/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/interceptor/StatementFinalizer.java b/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/interceptor/StatementFinalizer.java
new file mode 100644 (file)
index 0000000..30447f0
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * 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.interceptor;
+
+import java.lang.ref.WeakReference;
+import java.lang.reflect.Method;
+import java.sql.Statement;
+import java.util.ArrayList;
+
+import org.apache.juli.logging.Log;
+import org.apache.juli.logging.LogFactory;
+/**
+ * Keeps track of statements associated with a connection and invokes close upon connection.close()
+ * @author fhanik
+ *
+ */
+public class StatementFinalizer extends AbstractCreateStatementInterceptor {
+    protected static Log log = LogFactory.getLog(StatementFinalizer.class);
+    
+    protected ArrayList<WeakReference<Statement>> statements = new ArrayList<WeakReference<Statement>>();
+    
+    @Override
+    public Object createStatement(Object proxy, Method method, Object[] args, Object statement) {
+        // TODO Auto-generated method stub
+        try {
+            statements.add(new WeakReference((Statement)statement));
+        }catch (ClassCastException x) {
+            //ignore this one
+        }
+        return statement;
+    }
+    
+    @Override
+    public void closeInvoked() {
+        while (statements.size()>0) {
+            WeakReference<Statement> ws = statements.remove(0);
+            Statement st = ws.get();
+            if (st!=null) {
+                try {
+                    if (!st.isClosed()) {
+                        st.close();
+                    }
+                } catch (Exception ignore) {
+                    if (log.isDebugEnabled()) {
+                        log.debug("Unable to closed statement upon connection close.",ignore);
+                    }
+                }
+            }
+        }
+    }
+
+}
diff --git a/modules/jdbc-pool/test/org/apache/tomcat/jdbc/test/StatementFinalizerTest.java b/modules/jdbc-pool/test/org/apache/tomcat/jdbc/test/StatementFinalizerTest.java
new file mode 100644 (file)
index 0000000..e8b2d45
--- /dev/null
@@ -0,0 +1,25 @@
+package org.apache.tomcat.jdbc.test;
+
+import java.sql.Connection;
+import java.sql.Statement;
+
+import org.apache.tomcat.jdbc.pool.DataSourceProxy;
+import org.apache.tomcat.jdbc.pool.interceptor.StatementFinalizer;
+
+public class StatementFinalizerTest extends DefaultTestCase {
+
+    public StatementFinalizerTest(String name) {
+        super(name);
+    }
+    
+    public void testStatementFinalization() throws Exception {
+        DataSourceProxy d1 = this.createDefaultDataSource();
+        d1.setJdbcInterceptors(StatementFinalizer.class.getName());
+        Connection con = d1.getConnection();
+        Statement st = con.createStatement();
+        assertFalse("Statement should not be closed.",st.isClosed());
+        con.close();
+        assertTrue("Statement should be closed.",st.isClosed());
+    }
+
+}