Index: src/main/java/org/apache/tomcat/jdbc/pool/ConnectionPool.java =================================================================== --- src/main/java/org/apache/tomcat/jdbc/pool/ConnectionPool.java (revision 1180904) +++ src/main/java/org/apache/tomcat/jdbc/pool/ConnectionPool.java (working copy) @@ -307,7 +307,7 @@ getProxyConstructor(con.getXAConnection() != null); //create the proxy //TODO possible optimization, keep track if this connection was returned properly, and don't generate a new facade - Connection connection = (Connection)proxyClassConstructor.newInstance(new Object[] { handler }); + Connection connection = (Connection)proxyClassConstructor.newInstance(new Object[] { new ProxyCutOffConnection(handler) }); //return the connection return connection; }catch (Exception x) { Index: src/main/java/org/apache/tomcat/jdbc/pool/ProxyCutOffConnection.java =================================================================== --- src/main/java/org/apache/tomcat/jdbc/pool/ProxyCutOffConnection.java (revision 0) +++ src/main/java/org/apache/tomcat/jdbc/pool/ProxyCutOffConnection.java (working copy) @@ -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; + +import java.lang.reflect.Method; +import java.sql.SQLException; + +/** + * A ProxyCutOffConnection object is the top most interceptor that wraps an object of type + * {@link PooledConnection}. The ProxyCutOffConnection intercepts two methods: + * + * By default method comparisons is done on a String reference level, unless the {@link PoolConfiguration#setUseEquals(boolean)} has been called + * with a true argument. + * @author Filip Hanik + */ +public class ProxyCutOffConnection extends JdbcInterceptor { + protected ProxyCutOffConnection(JdbcInterceptor interceptor) throws SQLException { + setUseEquals(interceptor.isUseEquals()); + setNext(interceptor); + } + + @Override + public void reset(ConnectionPool parent, PooledConnection con) { + } + + @Override + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + if (compare(ISCLOSED_VAL, method) && getNext() == null) { + return Boolean.TRUE; + } + + try { + return super.invoke(proxy, method, args); + } catch (NullPointerException e) { + if (getNext() == null) { + if (compare(TOSTRING_VAL, method)) { + return "ProxyConnection[null]"; + } + throw new SQLException("Connection has already been closed."); + } + + throw e; + } finally { + if (compare(CLOSE_VAL, method)) { + setNext(null); + } + } + } +} Index: src/test/java/org/apache/tomcat/jdbc/test/MultipleCloseTest.java =================================================================== --- src/test/java/org/apache/tomcat/jdbc/test/MultipleCloseTest.java (revision 0) +++ src/test/java/org/apache/tomcat/jdbc/test/MultipleCloseTest.java (working copy) @@ -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.test; + +import java.sql.Connection; +import org.apache.tomcat.jdbc.test.driver.Driver; + +public class MultipleCloseTest extends DefaultTestCase { + + public MultipleCloseTest(String name) { + super(name); + } + + @Override + public org.apache.tomcat.jdbc.pool.DataSource createDefaultDataSource() { + org.apache.tomcat.jdbc.pool.DataSource ds = super.createDefaultDataSource(); + ds.getPoolProperties().setDriverClassName(Driver.class.getName()); + ds.getPoolProperties().setUrl(Driver.url); + ds.getPoolProperties().setInitialSize(0); + ds.getPoolProperties().setMaxIdle(1); + ds.getPoolProperties().setMinIdle(1); + ds.getPoolProperties().setMaxActive(1); + return ds; + } + + @Override + protected void tearDown() throws Exception { + Driver.reset(); + super.tearDown(); + } + + public void testClosedConnectionsNotReused() throws Exception { + this.init(); + + Connection con1 = datasource.getConnection(); + + // A new connection is open + assertFalse(con1.isClosed()); + + con1.close(); + + // Confirm that a closed connection is closed + assertTrue(con1.isClosed()); + + // Open a new connection (This will re-use the previous pooled connection) + datasource.getConnection(); + + // A connection, once closed, should stay closed + assertTrue(con1.isClosed()); + } +}