--- org/apache/tomcat/jdbc/pool/interceptor/StatementFinalizer.java (revision 1583445) +++ org/apache/tomcat/jdbc/pool/interceptor/StatementFinalizer.java (working copy) @@ -20,10 +20,12 @@ import java.lang.reflect.Method; import java.sql.Statement; import java.util.ArrayList; +import java.util.Map; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; import org.apache.tomcat.jdbc.pool.ConnectionPool; +import org.apache.tomcat.jdbc.pool.PoolProperties; import org.apache.tomcat.jdbc.pool.PooledConnection; /** * Keeps track of statements associated with a connection and invokes close upon {@link java.sql.Connection#close()} @@ -34,15 +36,14 @@ public class StatementFinalizer extends AbstractCreateStatementInterceptor { private static final Log log = LogFactory.getLog(StatementFinalizer.class); - protected ArrayList> statements = new ArrayList>(); + private boolean logCreationStack = false; + protected ArrayList> statements = new ArrayList>(); + @Override public Object createStatement(Object proxy, Method method, Object[] args, Object statement, long time) { - try { - if (statement instanceof Statement) - statements.add(new WeakReference((Statement)statement)); - }catch (ClassCastException x) { - //ignore this one + if (statement instanceof Statement) { + statements.add(new WeakReference(new StatementEntry((Statement) statement))); } return statement; } @@ -50,11 +51,17 @@ @Override public void closeInvoked() { while (statements.size()>0) { - WeakReference ws = statements.remove(0); - Statement st = ws.get(); - if (st!=null) { + WeakReference ws = statements.remove(0); + StatementEntry se = ws.get(); + if (se!=null) { + Statement st = se.getStatement(); try { - st.close(); + if (!st.isClosed()) { + if (logCreationStack) { + log.warn("Statement created, but was not closed ", se.getAllocationStack()); + } + st.close(); + } } catch (Exception ignore) { if (log.isDebugEnabled()) { log.debug("Unable to closed statement upon connection close.",ignore); @@ -65,6 +72,16 @@ } @Override + public void setProperties(Map properties) { + super.setProperties(properties); + + PoolProperties.InterceptorProperty logProperty = properties.get("logCreationStack"); + if (null != logProperty) { + logCreationStack = logProperty.getValueAsBoolean(logCreationStack); + } + } + + @Override public void reset(ConnectionPool parent, PooledConnection con) { statements.clear(); super.reset(parent, con); @@ -71,4 +88,23 @@ } + protected class StatementEntry { + private Statement statement; + private Throwable allocationStack; + + public StatementEntry(Statement statement) { + this.statement = statement; + if (logCreationStack) { + this.allocationStack = new Throwable(); + } + } + + public Statement getStatement() { + return statement; + } + + public Throwable getAllocationStack() { + return allocationStack; + } + } }