You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by ps...@apache.org on 2011/04/24 01:04:44 UTC

svn commit: r1096257 - in /commons/proper/dbcp/trunk/src: changes/ java/org/apache/commons/dbcp/ site/xdoc/ test/org/apache/commons/dbcp/

Author: psteitz
Date: Sat Apr 23 23:04:43 2011
New Revision: 1096257

URL: http://svn.apache.org/viewvc?rev=1096257&view=rev
Log:
Modified execute methods of Statement objects to ensure that whenever
a statement is used, the lastUsed property of its parent connection is updated.
JIRA: DBCP-343

Modified:
    commons/proper/dbcp/trunk/src/changes/changes.xml
    commons/proper/dbcp/trunk/src/java/org/apache/commons/dbcp/AbandonedConfig.java
    commons/proper/dbcp/trunk/src/java/org/apache/commons/dbcp/BasicDataSource.java
    commons/proper/dbcp/trunk/src/java/org/apache/commons/dbcp/DelegatingPreparedStatement.java
    commons/proper/dbcp/trunk/src/java/org/apache/commons/dbcp/DelegatingStatement.java
    commons/proper/dbcp/trunk/src/site/xdoc/configuration.xml
    commons/proper/dbcp/trunk/src/test/org/apache/commons/dbcp/TestAbandonedBasicDataSource.java
    commons/proper/dbcp/trunk/src/test/org/apache/commons/dbcp/TesterPreparedStatement.java

Modified: commons/proper/dbcp/trunk/src/changes/changes.xml
URL: http://svn.apache.org/viewvc/commons/proper/dbcp/trunk/src/changes/changes.xml?rev=1096257&r1=1096256&r2=1096257&view=diff
==============================================================================
--- commons/proper/dbcp/trunk/src/changes/changes.xml (original)
+++ commons/proper/dbcp/trunk/src/changes/changes.xml Sat Apr 23 23:04:43 2011
@@ -41,6 +41,11 @@ The <action> type attribute can be add,u
     <release version="2.0" date="TBD" description="TBD">
     </release>
     <release version="1.4.1" date="TBD" description="TBD">
+      <action dev="psteitz" issue="DBCP-343" type="fix">
+        Modified execute methods of Statement objects to ensure that whenever
+        a statement is used, the lastUsed property of its parent connection is
+        updated.
+      </action>
       <action dev="psteitz" issue="DBCP-346" type="update" due-to="Ken Tatsushita">
         LIFO configuration option has been added to BasicDataSource.  When set
         to true (the default), the pool acts as a LIFO queue; setting to false

Modified: commons/proper/dbcp/trunk/src/java/org/apache/commons/dbcp/AbandonedConfig.java
URL: http://svn.apache.org/viewvc/commons/proper/dbcp/trunk/src/java/org/apache/commons/dbcp/AbandonedConfig.java?rev=1096257&r1=1096256&r2=1096257&view=diff
==============================================================================
--- commons/proper/dbcp/trunk/src/java/org/apache/commons/dbcp/AbandonedConfig.java (original)
+++ commons/proper/dbcp/trunk/src/java/org/apache/commons/dbcp/AbandonedConfig.java Sat Apr 23 23:04:43 2011
@@ -34,14 +34,14 @@ public class AbandonedConfig {
     private boolean removeAbandoned = false;
 
     /**
-     * Flag to remove abandoned connections if they exceed the
-     * removeAbandonedTimeout.
+     * <p>Flag to remove abandoned connections if they exceed the
+     * removeAbandonedTimeout.</p>
      *
-     * Set to true or false, default false.
-     * If set to true a connection is considered abandoned and eligible
-     * for removal if it has been idle longer than the removeAbandonedTimeout.
-     * Setting this to true can recover db connections from poorly written    
-     * applications which fail to close a connection.
+     * <p>The default value is false.</p>
+     * 
+     * <p>If set to true a connection is considered abandoned and eligible
+     * for removal if it has been idle longer than the
+     * {@link #getRemoveAbandoned() removeAbandonedTimeout}.</p>
      *
      * @return true if abandoned connections are to be removed
      */
@@ -50,17 +50,16 @@ public class AbandonedConfig {
     }
 
     /**
-     * Flag to remove abandoned connections if they exceed the
-     * removeAbandonedTimeout.
+     * <p>Flag to remove abandoned connections if they exceed the
+     * removeAbandonedTimeout.</p>
      *
-     * Set to true or false, default false.
-     * If set to true a connection is considered abandoned and eligible   
-     * for removal if it has been idle longer than the removeAbandonedTimeout.
-     * Setting this to true can recover db connections from poorly written
-     * applications which fail to close a connection.
+     * <p>If set to true a connection is considered abandoned and eligible   
+     * for removal if it has been idle longer than the
+     * {@link #getRemoveAbandoned() removeAbandonedTimeout}.</p>
      *
      * @param removeAbandoned true means abandoned connections will be
      *   removed
+     * @see #getRemoveAbandoned()
      */
     public void setRemoveAbandoned(boolean removeAbandoned) {
         this.removeAbandoned = removeAbandoned;
@@ -71,23 +70,36 @@ public class AbandonedConfig {
      */
     private int removeAbandonedTimeout = 300;
 
-    /**
-     * Timeout in seconds before an abandoned connection can be removed.
-     *
-     * Defaults to 300 seconds.
-     *
-     * @return abandoned timeout in seconds
+    /** 
+     * <p>Timeout in seconds before an abandoned connection can be removed.</p>
+     * 
+     * <p>Creating a Statement, PreparedStatement or CallableStatement or using
+     * one of these to execute a query (using one of the execute methods)
+     * resets the lastUsed property of the parent connection.</p>
+     * 
+     * <p>Abandoned connection cleanup happens when
+     * <code><ul>
+     * <li><code>{@link #getRemoveAbandoned() removeAbandoned} == true</li>
+     * <li>{@link #getNumIdle() numIdle &lt; 2</li>
+     * <li>{@link #getNumActive() numActive} &gt; {@link #getMaxActive() maxActive} - 3</li>
+     * </ul></code></p>
+     * 
+     * <p>The default value is 300 seconds.</p>
      */
     public int getRemoveAbandonedTimeout() {
         return (this.removeAbandonedTimeout);
     }
 
     /**
-     * Timeout in seconds before an abandoned connection can be removed.
-     *
-     * Defaults to 300 seconds.
+     * <p>Sets the timeout in seconds before an abandoned connection can be
+     * removed.</p>
+     * 
+     * <p>Setting this property has no effect if 
+     * {@link #getRemoveAbandoned() removeAbandoned} is false.</p>
      *
-     * @param removeAbandonedTimeout abandoned timeout in seconds
+     * @param removeAbandonedTimeout new abandoned timeout in seconds
+     * @see #getRemoveAbandonedTimeout()
+     * @see #getRemoveAbandoned()
      */
     public void setRemoveAbandonedTimeout(int removeAbandonedTimeout) {
         this.removeAbandonedTimeout = removeAbandonedTimeout;

Modified: commons/proper/dbcp/trunk/src/java/org/apache/commons/dbcp/BasicDataSource.java
URL: http://svn.apache.org/viewvc/commons/proper/dbcp/trunk/src/java/org/apache/commons/dbcp/BasicDataSource.java?rev=1096257&r1=1096256&r2=1096257&view=diff
==============================================================================
--- commons/proper/dbcp/trunk/src/java/org/apache/commons/dbcp/BasicDataSource.java (original)
+++ commons/proper/dbcp/trunk/src/java/org/apache/commons/dbcp/BasicDataSource.java Sat Apr 23 23:04:43 2011
@@ -1180,20 +1180,22 @@ public class BasicDataSource implements 
     private AbandonedConfig abandonedConfig;
 
     /**                       
-     * Flag to remove abandoned connections if they exceed the
-     * removeAbandonedTimout.
+     * <p>Flag to remove abandoned connections if they exceed the
+     * removeAbandonedTimout.</p>
      *
-     * Set to true or false, default false.
-     * If set to true a connection is considered abandoned and eligible
-     * for removal if it has been idle longer than the removeAbandonedTimeout.
-     * Setting this to true can recover db connections from poorly written    
-     * applications which fail to close a connection.
-     * <p>
-     * Abandonded connections are identified and removed when 
+     * <p>The default value is false.<p>
+     * 
+     * <p>If set to true a connection is considered abandoned and eligible
+     * for removal if it has not been used for more than
+     * {@link #getRemoveAbandonedTimeout() removeAbandonedTimeout} seconds.</p>
+     * 
+     * <p>Abandoned connections are identified and removed when 
      * {@link #getConnection()} is invoked and the following conditions hold
      * <ul><li>{@link #getRemoveAbandoned()} = true </li>
      *     <li>{@link #getNumActive()} > {@link #getMaxActive()} - 3 </li>
      *     <li>{@link #getNumIdle()} < 2 </li></ul></p>
+     *
+     * @see #getRemoveAbandonedTimeout()
      */                                                                   
     public boolean getRemoveAbandoned() {   
         if (abandonedConfig != null) {
@@ -1203,7 +1205,18 @@ public class BasicDataSource implements 
     }                                    
                                  
     /**
-     * @param removeAbandoned new removeAbandoned property value
+     * <p>Flag to remove abandoned connections if they exceed the
+     * removeAbandonedTimeout.</p>
+     *
+     * <p>If set to true a connection is considered abandoned and eligible   
+     * for removal if it has been idle longer than the
+     * {@link #getRemoveAbandoned() removeAbandonedTimeout}.</p>
+     * 
+     * <p>Setting this to true can recover db connections from poorly written
+     * applications which fail to close a connection.</p>
+     *
+     * @param removeAbandoned true means abandoned connections will be
+     *   removed
      * @see #getRemoveAbandoned()
      */
     public void setRemoveAbandoned(boolean removeAbandoned) {
@@ -1214,12 +1227,22 @@ public class BasicDataSource implements 
         this.restartNeeded = true;
     }                                                        
                                                
-    /**
-     * Timeout in seconds before an abandoned connection can be removed.
-     *
-     * Defaults to 300 seconds. 
-     * @return abandoned connection timeout        
-     */                                                                 
+    /** 
+     * <p>Timeout in seconds before an abandoned connection can be removed.</p>
+     * 
+     * <p>Creating a Statement, PreparedStatement or CallableStatement or using
+     * one of these to execute a query (using one of the execute methods)
+     * resets the lastUsed property of the parent connection.</p>
+     * 
+     * <p>Abandoned connection cleanup happens when
+     * <code><ul>
+     * <li><code>{@link #getRemoveAbandoned() removeAbandoned} == true</li>
+     * <li>{@link #getNumIdle() numIdle &lt; 2</li>
+     * <li>{@link #getNumActive() numActive} &gt; {@link #getMaxActive() maxActive} - 3</li>
+     * </ul></code></p>
+     * 
+     * <p>The default value is 300 seconds.</p>
+     */                                                  
     public int getRemoveAbandonedTimeout() { 
         if (abandonedConfig != null) {
             return abandonedConfig.getRemoveAbandonedTimeout();
@@ -1228,7 +1251,15 @@ public class BasicDataSource implements 
     }                                        
 
     /**
-     * @param removeAbandonedTimeout new removeAbandonedTimeout value
+     * <p>Sets the timeout in seconds before an abandoned connection can be
+     * removed.</p>
+     * 
+     * <p>Setting this property has no effect if 
+     * {@link #getRemoveAbandoned() removeAbandoned} is false.</p>
+     *
+     * @param removeAbandonedTimeout new abandoned timeout in seconds
+     * @see #getRemoveAbandonedTimeout()
+     * @see #getRemoveAbandoned()
      */               
     public void setRemoveAbandonedTimeout(int removeAbandonedTimeout) {
         if (abandonedConfig == null) {

Modified: commons/proper/dbcp/trunk/src/java/org/apache/commons/dbcp/DelegatingPreparedStatement.java
URL: http://svn.apache.org/viewvc/commons/proper/dbcp/trunk/src/java/org/apache/commons/dbcp/DelegatingPreparedStatement.java?rev=1096257&r1=1096256&r2=1096257&view=diff
==============================================================================
--- commons/proper/dbcp/trunk/src/java/org/apache/commons/dbcp/DelegatingPreparedStatement.java (original)
+++ commons/proper/dbcp/trunk/src/java/org/apache/commons/dbcp/DelegatingPreparedStatement.java Sat Apr 23 23:04:43 2011
@@ -92,6 +92,9 @@ public class DelegatingPreparedStatement
 
     public ResultSet executeQuery() throws SQLException {
         checkOpen();
+        if (_conn != null) {
+            _conn.setLastUsed();
+        }
         try {
             return DelegatingResultSet.wrapResultSet(this,((PreparedStatement)_stmt).executeQuery());
         }
@@ -101,8 +104,18 @@ public class DelegatingPreparedStatement
         }
     }
 
-    public int executeUpdate() throws SQLException
-    { checkOpen(); try { return ((PreparedStatement)_stmt).executeUpdate(); } catch (SQLException e) { handleException(e); return 0; } }
+    public int executeUpdate() throws SQLException {
+        checkOpen();
+        if (_conn != null) {
+            _conn.setLastUsed();
+        }
+        try {
+            return ((PreparedStatement) _stmt).executeUpdate();
+        } catch (SQLException e) {
+            handleException(e);
+            return 0;
+        }
+    }
 
     public void setNull(int parameterIndex, int sqlType) throws SQLException
     { checkOpen(); try { ((PreparedStatement)_stmt).setNull(parameterIndex,sqlType); } catch (SQLException e) { handleException(e); } }
@@ -168,8 +181,18 @@ public class DelegatingPreparedStatement
     public void setObject(int parameterIndex, Object x) throws SQLException
     { checkOpen(); try { ((PreparedStatement)_stmt).setObject(parameterIndex, x); } catch (SQLException e) { handleException(e); } }
 
-    public boolean execute() throws SQLException
-    { checkOpen(); try { return ((PreparedStatement)_stmt).execute(); } catch (SQLException e) { handleException(e); return false; } }
+    public boolean execute() throws SQLException {
+        checkOpen();
+        if (_conn != null) {
+            _conn.setLastUsed();
+        }
+        try {
+            return ((PreparedStatement) _stmt).execute();
+        } catch (SQLException e) {
+            handleException(e);
+            return false;
+        }
+    }
 
     public void addBatch() throws SQLException
     { checkOpen(); try { ((PreparedStatement)_stmt).addBatch(); } catch (SQLException e) { handleException(e); } }

Modified: commons/proper/dbcp/trunk/src/java/org/apache/commons/dbcp/DelegatingStatement.java
URL: http://svn.apache.org/viewvc/commons/proper/dbcp/trunk/src/java/org/apache/commons/dbcp/DelegatingStatement.java?rev=1096257&r1=1096256&r2=1096257&view=diff
==============================================================================
--- commons/proper/dbcp/trunk/src/java/org/apache/commons/dbcp/DelegatingStatement.java (original)
+++ commons/proper/dbcp/trunk/src/java/org/apache/commons/dbcp/DelegatingStatement.java Sat Apr 23 23:04:43 2011
@@ -204,6 +204,9 @@ public class DelegatingStatement extends
 
     public ResultSet executeQuery(String sql) throws SQLException {
         checkOpen();
+        if (_conn != null) {
+            _conn.setLastUsed();
+        }
         try {
             return DelegatingResultSet.wrapResultSet(this,_stmt.executeQuery(sql));
         }
@@ -224,8 +227,17 @@ public class DelegatingStatement extends
         }
     }
 
-    public int executeUpdate(String sql) throws SQLException
-    { checkOpen(); try { return _stmt.executeUpdate(sql); } catch (SQLException e) { handleException(e); return 0; } }
+    public int executeUpdate(String sql) throws SQLException {
+        checkOpen();
+        if (_conn != null) {
+            _conn.setLastUsed();
+        }
+        try {
+            return _stmt.executeUpdate(sql);
+        } catch (SQLException e) {
+            handleException(e); return 0;
+        }
+    }
 
     public int getMaxFieldSize() throws SQLException
     { checkOpen(); try { return _stmt.getMaxFieldSize(); } catch (SQLException e) { handleException(e); return 0; } }
@@ -260,8 +272,18 @@ public class DelegatingStatement extends
     public void setCursorName(String name) throws SQLException
     { checkOpen(); try { _stmt.setCursorName(name); } catch (SQLException e) { handleException(e); } }
 
-    public boolean execute(String sql) throws SQLException
-    { checkOpen(); try { return _stmt.execute(sql); } catch (SQLException e) { handleException(e); return false; } }
+    public boolean execute(String sql) throws SQLException {
+        checkOpen();
+        if (_conn != null) {
+            _conn.setLastUsed();
+        }
+        try {
+            return _stmt.execute(sql);
+        } catch (SQLException e) {
+            handleException(e);
+            return false;
+        }
+    }
 
     public int getUpdateCount() throws SQLException
     { checkOpen(); try { return _stmt.getUpdateCount(); } catch (SQLException e) { handleException(e); return 0; } }
@@ -293,8 +315,18 @@ public class DelegatingStatement extends
     public void clearBatch() throws SQLException
     { checkOpen(); try { _stmt.clearBatch(); } catch (SQLException e) { handleException(e); } }
 
-    public int[] executeBatch() throws SQLException
-    { checkOpen(); try { return _stmt.executeBatch(); } catch (SQLException e) { handleException(e); throw new AssertionError(); } }
+    public int[] executeBatch() throws SQLException {
+        checkOpen();
+        if (_conn != null) {
+            _conn.setLastUsed();
+        }
+        try {
+            return _stmt.executeBatch();
+        } catch (SQLException e) {
+            handleException(e);
+            throw new AssertionError();
+        }
+    }
 
     /**
      * Returns a String representation of this object.
@@ -319,23 +351,83 @@ public class DelegatingStatement extends
         }
     }
 
-    public int executeUpdate(String sql, int autoGeneratedKeys) throws SQLException
-    { checkOpen(); try { return _stmt.executeUpdate(sql, autoGeneratedKeys); } catch (SQLException e) { handleException(e); return 0; } }
+    public int executeUpdate(String sql, int autoGeneratedKeys) throws SQLException {
+        checkOpen();
+        if (_conn != null) {
+            _conn.setLastUsed();
+        }
+        try {
+            return _stmt.executeUpdate(sql, autoGeneratedKeys);
+        } catch (SQLException e) {
+            handleException(e);
+            return 0;
+        }
+    }
 
-    public int executeUpdate(String sql, int columnIndexes[]) throws SQLException
-    { checkOpen(); try { return _stmt.executeUpdate(sql, columnIndexes); } catch (SQLException e) { handleException(e); return 0; } }
+    public int executeUpdate(String sql, int columnIndexes[]) throws SQLException {
+        checkOpen();
+        if (_conn != null) {
+            _conn.setLastUsed();
+        }
+        try {
+            return _stmt.executeUpdate(sql, columnIndexes);
+        } catch (SQLException e) {
+            handleException(e);
+            return 0;
+        }
+    }
 
-    public int executeUpdate(String sql, String columnNames[]) throws SQLException
-    { checkOpen(); try { return _stmt.executeUpdate(sql, columnNames); } catch (SQLException e) { handleException(e); return 0; } }
+    public int executeUpdate(String sql, String columnNames[]) throws SQLException {
+        checkOpen();
+        if (_conn != null) {
+            _conn.setLastUsed();
+        }
+        try {
+            return _stmt.executeUpdate(sql, columnNames);
+        } catch (SQLException e) {
+            handleException(e);
+            return 0;
+        }
+    }
 
-    public boolean execute(String sql, int autoGeneratedKeys) throws SQLException
-    { checkOpen(); try { return _stmt.execute(sql, autoGeneratedKeys); } catch (SQLException e) { handleException(e); return false; } }
+    public boolean execute(String sql, int autoGeneratedKeys) throws SQLException {
+        checkOpen();
+        if (_conn != null) {
+            _conn.setLastUsed();
+        }
+        try {
+            return _stmt.execute(sql, autoGeneratedKeys);
+        } catch (SQLException e) {
+            handleException(e);
+            return false;
+        }
+    }
 
-    public boolean execute(String sql, int columnIndexes[]) throws SQLException
-    { checkOpen(); try { return _stmt.execute(sql, columnIndexes); } catch (SQLException e) { handleException(e); return false; } }
+    public boolean execute(String sql, int columnIndexes[]) throws SQLException {
+        checkOpen();
+        if (_conn != null) {
+            _conn.setLastUsed();
+        }
+        try {
+            return _stmt.execute(sql, columnIndexes);
+        } catch (SQLException e) {
+            handleException(e);
+            return false;
+        }
+    }
 
-    public boolean execute(String sql, String columnNames[]) throws SQLException
-    { checkOpen(); try { return _stmt.execute(sql, columnNames); } catch (SQLException e) { handleException(e); return false; } }
+    public boolean execute(String sql, String columnNames[]) throws SQLException {
+        checkOpen();
+        if (_conn != null) {
+            _conn.setLastUsed();
+        }
+        try {
+            return _stmt.execute(sql, columnNames);
+        } catch (SQLException e) {
+            handleException(e);
+            return false;
+        }
+    }
 
     public int getResultSetHoldability() throws SQLException
     { checkOpen(); try { return _stmt.getResultSetHoldability(); } catch (SQLException e) { handleException(e); return 0; } }

Modified: commons/proper/dbcp/trunk/src/site/xdoc/configuration.xml
URL: http://svn.apache.org/viewvc/commons/proper/dbcp/trunk/src/site/xdoc/configuration.xml?rev=1096257&r1=1096256&r2=1096257&view=diff
==============================================================================
--- commons/proper/dbcp/trunk/src/site/xdoc/configuration.xml (original)
+++ commons/proper/dbcp/trunk/src/site/xdoc/configuration.xml Sat Apr 23 23:04:43 2011
@@ -331,7 +331,10 @@ Be carefull and only use when you need d
       Flag to remove abandoned connections if they exceed the
       removeAbandonedTimout.<br/>
       If set to true a connection is considered abandoned and eligible
-      for removal if it has been idle longer than the removeAbandonedTimeout.
+      for removal if it has not been used for longer than the removeAbandonedTimeout.<br/>
+      Creating a Statement, PreparedStatement or CallableStatement or using
+      one of these to execute a query (using one of the execute methods)
+      resets the lastUsed property of the parent connection.<br/>
       Setting this to true can recover db connections from poorly written
       applications which fail to close a connection.
    </td>
@@ -355,14 +358,17 @@ Be carefull and only use when you need d
 </table>
 <p>
 <img src="images/icon_info_sml.gif"/>
-If you have enabled "removeAbandoned" then it is possible that a connection is reclaimed by the pool because it is considered to be abandoned.
-This mechanism is triggered when (getNumIdle() &lt; 2) and (getNumActive() &gt; getMaxActive() - 3)
+If you have enabled "removeAbandoned" then it is possible that a connection is reclaimed by the pool because
+it is considered to be abandoned. This mechanism is triggered when (getNumIdle() &lt; 2) and
+(getNumActive() &gt; getMaxActive() - 3)
 </p>
 <p>
 <img src="images/icon_info_sml.gif"/>
-For example maxActive=20 and 18 active connections and 1 idle connection would trigger the "removeAbandoned".
+For example, maxActive=20 and 18 active connections and 1 idle connection would trigger the "removeAbandoned".
 But only the active connections that aren't used for more then "removeAbandonedTimeout" seconds are removed,
-default (300 sec). Traversing a resultset doesn't count as being used. 
+default (300 sec). Traversing a resultset doesn't count as being used. Creating a Statement, PreparedStatement
+or CallableStatement or using one of these to execute a query (using one of the execute methods) resets
+the lastUsed property of the parent connection.
 </p>
 
 </section>

Modified: commons/proper/dbcp/trunk/src/test/org/apache/commons/dbcp/TestAbandonedBasicDataSource.java
URL: http://svn.apache.org/viewvc/commons/proper/dbcp/trunk/src/test/org/apache/commons/dbcp/TestAbandonedBasicDataSource.java?rev=1096257&r1=1096256&r2=1096257&view=diff
==============================================================================
--- commons/proper/dbcp/trunk/src/test/org/apache/commons/dbcp/TestAbandonedBasicDataSource.java (original)
+++ commons/proper/dbcp/trunk/src/test/org/apache/commons/dbcp/TestAbandonedBasicDataSource.java Sat Apr 23 23:04:43 2011
@@ -19,7 +19,10 @@ package org.apache.commons.dbcp;
 
 import java.io.IOException;
 import java.sql.Connection;
+import java.sql.CallableStatement;
+import java.sql.PreparedStatement;
 import java.sql.SQLException;
+import java.sql.Statement;
 
 import junit.framework.Test;
 import junit.framework.TestSuite;
@@ -160,4 +163,87 @@ public class TestAbandonedBasicDataSourc
         ds.getConnection(); // trigger abandoned cleanup again
         conn1.createStatement();         
     }
+    
+    /**
+     * DBCP-343 - verify that using a DelegatingStatement updates
+     * the lastUsed on the parent connection
+     */
+    public void testLastUsedPreparedStatementUse() throws Exception {
+        ds.setRemoveAbandonedTimeout(1);
+        ds.setMaxActive(2);
+        Connection conn1 = ds.getConnection();
+        Statement st = conn1.createStatement(); 
+        String querySQL = "SELECT 1 FROM DUAL";
+        Thread.sleep(500);
+        st.executeQuery(querySQL); // Should reset lastUsed
+        Thread.sleep(800);
+        Connection conn2 = ds.getConnection(); // triggers abandoned cleanup
+        st.executeQuery(querySQL); // Should still be OK
+        conn2.close();
+        Thread.sleep(500);
+        st.executeUpdate(""); // Should also reset
+        Thread.sleep(800);
+        ds.getConnection(); // trigger abandoned cleanup again
+        conn1.createStatement();  // Connection should still be good  
+    }
+    
+    /**
+     * DBCP-343 - verify additional operations reset lastUsed on
+     * the parent connection
+     */
+    public void testLastUsedUpdate() throws Exception {
+        DelegatingConnection conn = (DelegatingConnection) ds.getConnection();
+        PreparedStatement ps = conn.prepareStatement("");
+        CallableStatement cs = conn.prepareCall("");
+        Statement st = conn.prepareStatement("");
+        checkLastUsedStatement(ps, conn);
+        checkLastUsedPreparedStatement(ps, conn);
+        checkLastUsedStatement(cs, conn);
+        checkLastUsedPreparedStatement(cs, conn);
+        checkLastUsedStatement(st, conn);    
+    }
+    
+    /**
+     * Verifies that Statement executeXxx methods update lastUsed on the parent connection
+     */
+    private void checkLastUsedStatement(Statement st, DelegatingConnection conn) throws Exception {
+        st.execute("");
+        assertAndReset(conn);
+        st.execute("", new int[] {});
+        assertAndReset(conn);
+        st.execute("", 0);
+        assertAndReset(conn);
+        st.executeBatch();
+        assertAndReset(conn);
+        st.executeQuery("");
+        assertAndReset(conn);
+        st.executeUpdate("");
+        assertAndReset(conn);
+        st.executeUpdate("", new int[] {});
+        assertAndReset(conn);
+        st.executeUpdate("", 0);
+        assertAndReset(conn);
+        st.executeUpdate("", new String[] {});
+        assertAndReset(conn);
+    }
+    
+    /**
+     * Verifies that PreparedStatement executeXxx methods update lastUsed on the parent connection
+     */
+    private void checkLastUsedPreparedStatement(PreparedStatement ps, DelegatingConnection conn) throws Exception {
+        ps.execute();
+        assertAndReset(conn);
+        ps.executeQuery();
+        assertAndReset(conn);
+        ps.executeUpdate();
+        assertAndReset(conn);
+    }
+      
+    /**
+     * Verifies that con.lastUsed has been updated and then resets it to 0
+     */
+    private void assertAndReset(DelegatingConnection con) {
+        assertTrue(con.getLastUsed() > 0);
+        con.setLastUsed(0); 
+    }
 }

Modified: commons/proper/dbcp/trunk/src/test/org/apache/commons/dbcp/TesterPreparedStatement.java
URL: http://svn.apache.org/viewvc/commons/proper/dbcp/trunk/src/test/org/apache/commons/dbcp/TesterPreparedStatement.java?rev=1096257&r1=1096256&r2=1096257&view=diff
==============================================================================
--- commons/proper/dbcp/trunk/src/test/org/apache/commons/dbcp/TesterPreparedStatement.java (original)
+++ commons/proper/dbcp/trunk/src/test/org/apache/commons/dbcp/TesterPreparedStatement.java Sat Apr 23 23:04:43 2011
@@ -249,32 +249,32 @@ public class TesterPreparedStatement ext
 
     public int executeUpdate(String sql, int autoGeneratedKeys)
         throws SQLException {
-        throw new SQLException("Not implemented.");
+        checkOpen(); return 0;
     }
 
     public int executeUpdate(String sql, int columnIndexes[])
         throws SQLException {
-        throw new SQLException("Not implemented.");
+        checkOpen(); return 0;
     }
 
     public int executeUpdate(String sql, String columnNames[])
         throws SQLException {
-        throw new SQLException("Not implemented.");
+        checkOpen(); return 0;
     }
 
     public boolean execute(String sql, int autoGeneratedKeys)
         throws SQLException {
-        throw new SQLException("Not implemented.");
+        checkOpen(); return true;
     }
 
     public boolean execute(String sl, int columnIndexes[])
         throws SQLException {
-        throw new SQLException("Not implemented.");
+        checkOpen(); return true;
     }
 
     public boolean execute(String sql, String columnNames[])
         throws SQLException {
-        throw new SQLException("Not implemented.");
+        checkOpen(); return true;
     }
 
     public int getResultSetHoldability() throws SQLException {