Fix connection state, make it smarter and faster.
authorfhanik <fhanik@13f79535-47bb-0310-9956-ffa450edef68>
Thu, 13 Nov 2008 18:02:35 +0000 (18:02 +0000)
committerfhanik <fhanik@13f79535-47bb-0310-9956-ffa450edef68>
Thu, 13 Nov 2008 18:02:35 +0000 (18:02 +0000)
git-svn-id: https://svn.apache.org/repos/asf/tomcat/trunk@713763 13f79535-47bb-0310-9956-ffa450edef68

modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/ConnectionPool.java
modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/DataSourceProxy.java
modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/JdbcInterceptor.java
modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/ProxyConnection.java
modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/interceptor/ConnectionState.java
modules/jdbc-pool/test/org/apache/tomcat/jdbc/test/TestConnectionState.java [new file with mode: 0644]

index 2a78ffd..60d8d91 100644 (file)
@@ -129,6 +129,7 @@ public class ConnectionPool {
                         (JdbcInterceptor) Class.forName(proxies[i], true, //should this be the class loader?
                                 Thread.currentThread().getContextClassLoader()).newInstance();
                     interceptor.setNext(handler);
+                    interceptor.reset(this, con); //initialize
                     handler = interceptor;
                 }catch(Exception x) {
                     SQLException sx = new SQLException("Unable to instantiate interceptor chain.");
index 4301686..78b2663 100644 (file)
@@ -172,13 +172,16 @@ public class DataSourceProxy  {
         return driver.getPool(getPoolProperties().getPoolName()).getSize();
     }
 
-   public String toString() {
+    public String toString() {
         return super.toString()+"{"+getPoolProperties()+"}";
     }
 
 /*-----------------------------------------------------------------------*/
 //      PROPERTIES WHEN NOT USED WITH FACTORY
 /*------------------------------------------------------------------------*/
+   
+   
+   
     public void setPoolProperties(PoolProperties poolProperties) {
         this.poolProperties = poolProperties;
     }
@@ -200,7 +203,7 @@ public class DataSourceProxy  {
     }
 
     public void setMaxActive(int maxActive) {
-        this.poolProperties.setMaxIdle(maxActive);
+        this.poolProperties.setMaxActive(maxActive);
     }
 
     public void setMaxIdle(int maxIdle) {
@@ -212,12 +215,11 @@ public class DataSourceProxy  {
     }
 
     public void setMinEvictableIdleTimeMillis(int minEvictableIdleTimeMillis) {
-        this.poolProperties.setMinEvictableIdleTimeMillis(
-            minEvictableIdleTimeMillis);
+        this.poolProperties.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
     }
 
     public void setMinIdle(int minIdle) {
-        this.setMinIdle(minIdle);
+        this.poolProperties.setMinIdle(minIdle);
     }
 
     public void setNumTestsPerEvictionRun(int numTestsPerEvictionRun) {
@@ -253,10 +255,8 @@ public class DataSourceProxy  {
         this.poolProperties.setTestWhileIdle(testWhileIdle);
     }
 
-    public void setTimeBetweenEvictionRunsMillis(int
-                                                 timeBetweenEvictionRunsMillis) {
-        this.poolProperties.setTimeBetweenEvictionRunsMillis(
-            timeBetweenEvictionRunsMillis);
+    public void setTimeBetweenEvictionRunsMillis(int timeBetweenEvictionRunsMillis) {
+        this.poolProperties.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
     }
 
     public void setUrl(String url) {
@@ -283,26 +283,38 @@ public class DataSourceProxy  {
     public void setJmxEnabled(boolean enabled) {
         this.getPoolProperties().setJmxEnabled(enabled);
     }
-    
+
     public void setFairQueue(boolean fairQueue) {
         this.getPoolProperties().setFairQueue(fairQueue);
     }
     
+    public void setDefaultCatalog(String catalog) {
+        this.getPoolProperties().setDefaultCatalog(catalog);
+    }
+    
+    public void setDefaultAutoCommit(Boolean autocommit) {
+        this.getPoolProperties().setDefaultAutoCommit(autocommit);
+    }
+    
+    public void setDefaultTransactionIsolation(int defaultTransactionIsolation) {
+        this.getPoolProperties().setDefaultTransactionIsolation(defaultTransactionIsolation);
+    }
+
     public void setConnectionProperties(String properties) {
         try {
-            java.util.Properties prop = DataSourceFactory.getProperties(properties);
+            java.util.Properties prop = DataSourceFactory
+                    .getProperties(properties);
             Iterator i = prop.keySet().iterator();
             while (i.hasNext()) {
-                String key = (String)i.next();
+                String key = (String) i.next();
                 String value = prop.getProperty(key);
                 getPoolProperties().getDbProperties().setProperty(key, value);
             }
-            
-        }catch (Exception x) {
+
+        } catch (Exception x) {
             log.error("Unable to parse connection properties.", x);
             throw new RuntimeException(x);
         }
     }
 
-
 }
index 21e26b8..171d003 100644 (file)
@@ -26,6 +26,7 @@ import java.lang.reflect.Method;
 public abstract class JdbcInterceptor implements InvocationHandler {
     public  static final String CLOSE_VAL = "close";
     public  static final String TOSTRING_VAL = "toString";
+    public  static final String ISCLOSED_VAL = "isClosed"; 
 
     private JdbcInterceptor next = null;
 
@@ -47,6 +48,11 @@ public abstract class JdbcInterceptor implements InvocationHandler {
     public void setNext(JdbcInterceptor next) {
         this.next = next;
     }
-
+    
+    /**
+     * Gets called each time the connection is borrowed from the pool
+     * @param parent - the connection pool owning the connection
+     * @param con - the pooled connection
+     */
     public abstract void reset(ConnectionPool parent, PooledConnection con);
 }
index 5aa2cf2..871a56e 100644 (file)
@@ -68,6 +68,9 @@ public class ProxyConnection extends JdbcInterceptor {
     }
 
     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+        if (ISCLOSED_VAL==method.getName()) {
+            return isClosed();
+        }
         if (isClosed()) throw new SQLException("Connection has already been closed.");
         if (CLOSE_VAL==method.getName()) {
             PooledConnection poolc = this.connection;
index b30ae01..a3f5609 100644 (file)
 package org.apache.tomcat.jdbc.pool.interceptor;\r
 \r
 import java.lang.reflect.Method;\r
+import java.sql.SQLException;\r
 \r
+import org.apache.juli.logging.Log;\r
+import org.apache.juli.logging.LogFactory;\r
 import org.apache.tomcat.jdbc.pool.ConnectionPool;\r
 import org.apache.tomcat.jdbc.pool.DataSourceFactory;\r
 import org.apache.tomcat.jdbc.pool.JdbcInterceptor;\r
+import org.apache.tomcat.jdbc.pool.PoolProperties;\r
 import org.apache.tomcat.jdbc.pool.PooledConnection;\r
 \r
 /**\r
@@ -30,18 +34,63 @@ import org.apache.tomcat.jdbc.pool.PooledConnection;
  */\r
 \r
 public class ConnectionState extends JdbcInterceptor  {\r
-\r
-    protected final String[] readState = {"getAutoCommit","getTransactionIsolation","isReadOnly"};\r
-    protected final String[] writeState = {"setAutoCommit","setTransactionIsolation","setReadOnly"};\r
+    protected static Log log = LogFactory.getLog(ConnectionState.class);\r
+    \r
+    protected final String[] readState = {"getAutoCommit","getTransactionIsolation","isReadOnly","getCatalog"};\r
+    protected final String[] writeState = {"setAutoCommit","setTransactionIsolation","setReadOnly","setCatalog"};\r
 \r
     protected Boolean autoCommit = null;\r
     protected Integer transactionIsolation = null;\r
     protected Boolean readOnly = null;\r
-\r
+    protected String catalog = null;\r
+    \r
+    \r
     public void reset(ConnectionPool parent, PooledConnection con) {\r
-        autoCommit = null;\r
-        transactionIsolation = null;\r
-        readOnly = null;\r
+        PoolProperties poolProperties = parent.getPoolProperties();\r
+        if (poolProperties.getDefaultReadOnly()!=null) {\r
+            try {\r
+                if (readOnly==null || readOnly.booleanValue()!=poolProperties.getDefaultReadOnly().booleanValue()) {\r
+                    con.getConnection().setReadOnly(poolProperties.getDefaultReadOnly().booleanValue());\r
+                    readOnly = poolProperties.getDefaultReadOnly();\r
+                }\r
+            }catch (SQLException x) {\r
+                readOnly = null;\r
+                log.error("Unable to reset readonly state to connection.",x);\r
+            }\r
+        }\r
+        if (poolProperties.getDefaultAutoCommit()!=null) {\r
+            try {\r
+                if (autoCommit==null || autoCommit.booleanValue()!=poolProperties.getDefaultAutoCommit().booleanValue()) {\r
+                    con.getConnection().setAutoCommit(poolProperties.getDefaultAutoCommit().booleanValue());\r
+                    autoCommit = poolProperties.getDefaultAutoCommit();\r
+                }\r
+            }catch (SQLException x) {\r
+                autoCommit = null;\r
+                log.error("Unable to reset autocommit state to connection.",x);\r
+            }\r
+        }\r
+        if (poolProperties.getDefaultCatalog()!=null) {\r
+            try {\r
+                if (catalog==null || (!catalog.equals(poolProperties.getDefaultCatalog()))) {\r
+                    con.getConnection().setCatalog(poolProperties.getDefaultCatalog());\r
+                    catalog = poolProperties.getDefaultCatalog();\r
+                }\r
+            }catch (SQLException x) {\r
+                catalog = null;\r
+                log.error("Unable to reset default catalog state to connection.",x);\r
+            }\r
+        }\r
+        if (poolProperties.getDefaultTransactionIsolation()!=DataSourceFactory.UNKNOWN_TRANSACTIONISOLATION) {\r
+            try {\r
+                if (transactionIsolation==null || transactionIsolation.intValue()!=poolProperties.getDefaultTransactionIsolation()) {\r
+                    con.getConnection().setTransactionIsolation(poolProperties.getDefaultTransactionIsolation());\r
+                    transactionIsolation = poolProperties.getDefaultTransactionIsolation();\r
+                }\r
+            }catch (SQLException x) {\r
+                transactionIsolation = null;\r
+                log.error("Unable to reset transaction isolation state to connection.",x);\r
+            }\r
+        }\r
     }\r
 \r
     @Override\r
@@ -64,6 +113,7 @@ public class ConnectionState extends JdbcInterceptor  {
                 case 0:{result = autoCommit; break;}\r
                 case 1:{result = transactionIsolation; break;}\r
                 case 2:{result = readOnly; break;}\r
+                case 3:{result = catalog; break;}\r
                 default: result = null;\r
             }\r
             //return cached result, if we have it\r
@@ -76,6 +126,7 @@ public class ConnectionState extends JdbcInterceptor  {
                 case 0:{autoCommit = (Boolean) (read?result:args[0]); break;}\r
                 case 1:{transactionIsolation = (Integer)(read?result:args[0]); break;}\r
                 case 2:{readOnly = (Boolean)(read?result:args[0]); break;}\r
+                case 3:{catalog = (String)(read?result:args[0]); break;}\r
             }\r
         }\r
         return result;\r
diff --git a/modules/jdbc-pool/test/org/apache/tomcat/jdbc/test/TestConnectionState.java b/modules/jdbc-pool/test/org/apache/tomcat/jdbc/test/TestConnectionState.java
new file mode 100644 (file)
index 0000000..f7ed28d
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * 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.test;
+
+import java.sql.Connection;
+
+import org.apache.tomcat.jdbc.pool.DataSourceProxy;
+import org.apache.tomcat.jdbc.pool.interceptor.ConnectionState;
+
+public class TestConnectionState extends DefaultTestCase {
+
+    public TestConnectionState(String name) {
+        super(name);
+    }
+
+    public void testAutoCommitFalse() throws Exception {
+        DataSourceProxy d1 = this.createDefaultDataSource();
+        d1.setMaxActive(1);
+        d1.setMinIdle(1);
+        d1.setMaxIdle(1);
+        d1.setJdbcInterceptors(ConnectionState.class.getName());
+        d1.setDefaultAutoCommit(Boolean.FALSE);
+        Connection c1 = d1.getConnection();
+        assertFalse("Auto commit should be false",c1.getAutoCommit());
+        c1.setAutoCommit(true);
+        assertTrue("Auto commit should be true",c1.getAutoCommit());
+        c1.close();
+        c1 = d1.getConnection();
+        assertFalse("Auto commit should be false for a reused connection",c1.getAutoCommit());
+        d1.close(true);
+        assertTrue("Connection should be closed",c1.isClosed());
+    }
+    
+    public void testAutoCommitTrue() throws Exception {
+        DataSourceProxy d1 = this.createDefaultDataSource();
+        d1.setMaxActive(1);
+        d1.setJdbcInterceptors(ConnectionState.class.getName());
+        d1.setDefaultAutoCommit(Boolean.TRUE);
+        d1.setMinIdle(1);
+        Connection c1 = d1.getConnection();
+        assertTrue("Auto commit should be true",c1.getAutoCommit());
+        c1.setAutoCommit(false);
+        assertFalse("Auto commit should be false",c1.getAutoCommit());
+        c1.close();
+        c1 = d1.getConnection();
+        assertTrue("Auto commit should be true for a reused connection",c1.getAutoCommit());
+    }
+    
+    public void testDefaultCatalog() throws Exception {
+        DataSourceProxy d1 = this.createDefaultDataSource();
+        d1.setMaxActive(1);
+        d1.setJdbcInterceptors(ConnectionState.class.getName());
+        d1.setDefaultCatalog("information_schema");
+        d1.setMinIdle(1);
+        Connection c1 = d1.getConnection();
+        assertEquals("Catalog should be information_schema",c1.getCatalog(),"information_schema");
+        c1.close();
+        c1 = d1.getConnection();
+        assertEquals("Catalog should be information_schema",c1.getCatalog(),"information_schema");
+        c1.setCatalog("mysql");
+        assertEquals("Catalog should be information_schema",c1.getCatalog(),"mysql");
+        c1.close();
+        c1 = d1.getConnection();
+        assertEquals("Catalog should be information_schema",c1.getCatalog(),"information_schema");
+    }
+    
+    
+
+
+}