Author: psteitz Date: Sun Jan 18 18:59:59 2015 New Revision: 1652830 URL: http://svn.apache.org/r1652830 Log: Made Datasources implement AutoCloseable. JIRA: DBCP-423.
Modified: commons/proper/dbcp/trunk/src/changes/changes.xml commons/proper/dbcp/trunk/src/main/java/org/apache/commons/dbcp2/BasicDataSource.java commons/proper/dbcp/trunk/src/main/java/org/apache/commons/dbcp2/PoolingDataSource.java commons/proper/dbcp/trunk/src/main/java/org/apache/commons/dbcp2/datasources/InstanceKeyDataSource.java commons/proper/dbcp/trunk/src/main/resources/org/apache/commons/dbcp2/LocalStrings.properties commons/proper/dbcp/trunk/src/test/java/org/apache/commons/dbcp2/TestBasicDataSource.java commons/proper/dbcp/trunk/src/test/java/org/apache/commons/dbcp2/TestPStmtPooling.java commons/proper/dbcp/trunk/src/test/java/org/apache/commons/dbcp2/TestPoolingDataSource.java commons/proper/dbcp/trunk/src/test/java/org/apache/commons/dbcp2/datasources/TestCPDSConnectionFactory.java commons/proper/dbcp/trunk/src/test/java/org/apache/commons/dbcp2/datasources/TestInstanceKeyDataSource.java commons/proper/dbcp/trunk/src/test/java/org/apache/commons/dbcp2/datasources/TestKeyedCPDSConnectionFactory.java commons/proper/dbcp/trunk/src/test/java/org/apache/commons/dbcp2/datasources/TestSharedPoolDataSource.java commons/proper/dbcp/trunk/src/test/java/org/apache/commons/dbcp2/managed/TestTransactionContext.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=1652830&r1=1652829&r2=1652830&view=diff ============================================================================== --- commons/proper/dbcp/trunk/src/changes/changes.xml (original) +++ commons/proper/dbcp/trunk/src/changes/changes.xml Sun Jan 18 18:59:59 2015 @@ -60,7 +60,12 @@ The <action> type attribute can be add,u --> <body> - <release version="2.1" date="TBD" description="This is minor release, including bug fixes and enhancements."> + <release version="2.1" date="TBD" description= + "This is minor release, including bug fixes and enhancements. Note that + one of the enhancements (DBCP-423) is to implement AutoCloseable in + BasicDataSource, PoolingDataSource and the InstanceKeyDataSource + implementations. + "> <action issue="DBCP-420" dev="sebb" type="fix"> InstanceKeyDataSource discards native SQLException when given password does not match password used to create the connection. @@ -86,6 +91,9 @@ The <action> type attribute can be add,u Made expired connection logging configurable in BasicDataSource. Setting logExpiredConnections to false suppresses expired connection log messages. </action> + <action issue="DBCP-423" dev="psteitz" type="update"> + Made Datasources implement AutoCloseable. + </action> </release> <release version="2.0.1" date="24 May 2014" description="This is a bug fix release."> <action dev="markt" type="fix"> Modified: commons/proper/dbcp/trunk/src/main/java/org/apache/commons/dbcp2/BasicDataSource.java URL: http://svn.apache.org/viewvc/commons/proper/dbcp/trunk/src/main/java/org/apache/commons/dbcp2/BasicDataSource.java?rev=1652830&r1=1652829&r2=1652830&view=diff ============================================================================== --- commons/proper/dbcp/trunk/src/main/java/org/apache/commons/dbcp2/BasicDataSource.java (original) +++ commons/proper/dbcp/trunk/src/main/java/org/apache/commons/dbcp2/BasicDataSource.java Sun Jan 18 18:59:59 2015 @@ -66,7 +66,7 @@ import org.apache.commons.pool2.impl.Gen * @version $Id$ * @since 2.0 */ -public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBeanRegistration { +public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBeanRegistration, AutoCloseable { private static final Log log = LogFactory.getLog(BasicDataSource.class); @@ -1861,7 +1861,7 @@ public class BasicDataSource implements } catch(RuntimeException e) { throw e; } catch(Exception e) { - throw new SQLException("Cannot close connection pool", e); + throw new SQLException(Utils.getMessage("pool.close.fail"), e); } } Modified: commons/proper/dbcp/trunk/src/main/java/org/apache/commons/dbcp2/PoolingDataSource.java URL: http://svn.apache.org/viewvc/commons/proper/dbcp/trunk/src/main/java/org/apache/commons/dbcp2/PoolingDataSource.java?rev=1652830&r1=1652829&r2=1652830&view=diff ============================================================================== --- commons/proper/dbcp/trunk/src/main/java/org/apache/commons/dbcp2/PoolingDataSource.java (original) +++ commons/proper/dbcp/trunk/src/main/java/org/apache/commons/dbcp2/PoolingDataSource.java Sun Jan 18 18:59:59 2015 @@ -43,7 +43,7 @@ import org.apache.commons.pool2.impl.Gen * @version $Id$ * @since 2.0 */ -public class PoolingDataSource<C extends Connection> implements DataSource { +public class PoolingDataSource<C extends Connection> implements DataSource, AutoCloseable { private static final Log log = LogFactory.getLog(PoolingDataSource.class); @@ -70,6 +70,21 @@ public class PoolingDataSource<C extends } } + /** + * Close and free all {@link Connections}s from the pool. + * @since 2.1 + */ + @Override + public void close() throws Exception { + try { + _pool.close(); + } catch(RuntimeException rte) { + throw new RuntimeException(Utils.getMessage("pool.close.fail"), rte); + } catch(Exception e) { + throw new SQLException(Utils.getMessage("pool.close.fail"), e); + } + } + /** * Returns the value of the accessToUnderlyingConnectionAllowed property. * Modified: commons/proper/dbcp/trunk/src/main/java/org/apache/commons/dbcp2/datasources/InstanceKeyDataSource.java URL: http://svn.apache.org/viewvc/commons/proper/dbcp/trunk/src/main/java/org/apache/commons/dbcp2/datasources/InstanceKeyDataSource.java?rev=1652830&r1=1652829&r2=1652830&view=diff ============================================================================== --- commons/proper/dbcp/trunk/src/main/java/org/apache/commons/dbcp2/datasources/InstanceKeyDataSource.java (original) +++ commons/proper/dbcp/trunk/src/main/java/org/apache/commons/dbcp2/datasources/InstanceKeyDataSource.java Sun Jan 18 18:59:59 2015 @@ -85,7 +85,7 @@ import org.apache.commons.pool2.impl.Gen * @since 2.0 */ public abstract class InstanceKeyDataSource - implements DataSource, Referenceable, Serializable { + implements DataSource, Referenceable, Serializable, AutoCloseable { private static final long serialVersionUID = -6819270431752240878L; Modified: commons/proper/dbcp/trunk/src/main/resources/org/apache/commons/dbcp2/LocalStrings.properties URL: http://svn.apache.org/viewvc/commons/proper/dbcp/trunk/src/main/resources/org/apache/commons/dbcp2/LocalStrings.properties?rev=1652830&r1=1652829&r2=1652830&view=diff ============================================================================== --- commons/proper/dbcp/trunk/src/main/resources/org/apache/commons/dbcp2/LocalStrings.properties (original) +++ commons/proper/dbcp/trunk/src/main/resources/org/apache/commons/dbcp2/LocalStrings.properties Sun Jan 18 18:59:59 2015 @@ -21,3 +21,4 @@ swallowedExceptionLogger.onSwallowedExce poolingDataSource.factoryConfig=PoolableConnectionFactory not linked to pool. Calling setPool() to fix the configuration. +pool.close.fail=Cannot close connection pool. Modified: commons/proper/dbcp/trunk/src/test/java/org/apache/commons/dbcp2/TestBasicDataSource.java URL: http://svn.apache.org/viewvc/commons/proper/dbcp/trunk/src/test/java/org/apache/commons/dbcp2/TestBasicDataSource.java?rev=1652830&r1=1652829&r2=1652830&view=diff ============================================================================== --- commons/proper/dbcp/trunk/src/test/java/org/apache/commons/dbcp2/TestBasicDataSource.java (original) +++ commons/proper/dbcp/trunk/src/test/java/org/apache/commons/dbcp2/TestBasicDataSource.java Sun Jan 18 18:59:59 2015 @@ -428,6 +428,61 @@ public class TestBasicDataSource extends assertEquals(0, ds.getNumActive()); } + + /** + * Verifies correct handling of exceptions generated by the underlying pool as it closes + * connections in response to BDS#close. Exceptions have to be either swallowed by the + * underlying pool and logged, or propagated and wrapped. + */ + @Test + public void testPoolCloseCheckedException() throws Exception { + ds.setAccessToUnderlyingConnectionAllowed(true); // Allow dirty tricks + + // Get an idle connection into the pool + Connection conn = ds.getConnection(); + TesterConnection tc = (TesterConnection) ((DelegatingConnection<?>) conn).getInnermostDelegate(); + conn.close(); + + // After returning the connection to the pool, bork it. + // Don't try this at home - bad violation of pool contract! + tc.setFailure(new SQLException("bang")); + + // Now close Datasource, which will cause tc to be closed, triggering SQLE + // Pool 2.x swallows and logs exceptions on pool close. Below verifies that + // Either exceptions get logged or wrapped appropriately. + try { + StackMessageLog.lock(); + StackMessageLog.clear(); + ds.close(); + // Exception must have been swallowed by the pool - verify it is logged + assertTrue(StackMessageLog.popMessage().indexOf("bang") > 0); + } catch (SQLException ex) { + assertTrue(ex.getMessage().indexOf("Cannot close") > 0); + assertTrue(ex.getCause().getMessage().indexOf("bang") > 0); + } finally { + StackMessageLog.unLock(); + } + } + + @Test + public void testPoolCloseRTE() throws Exception { + // RTE version of testPoolCloseCheckedException - see comments there. + ds.setAccessToUnderlyingConnectionAllowed(true); + Connection conn = ds.getConnection(); + TesterConnection tc = (TesterConnection) ((DelegatingConnection<?>) conn).getInnermostDelegate(); + conn.close(); + tc.setFailure(new IllegalStateException("boom")); + try { + StackMessageLog.lock(); + StackMessageLog.clear(); + ds.close(); + assertTrue(StackMessageLog.popMessage().indexOf("boom") > 0); + } catch (IllegalStateException ex) { + assertTrue(ex.getMessage().indexOf("boom") > 0); // RTE is not wrapped by BDS#close + } finally { + StackMessageLog.unLock(); + } + } /** * Bugzilla Bug 29054: @@ -613,6 +668,7 @@ public class TestBasicDataSource extends public void testMaxConnLifetimeExceededMutedLog() throws Exception { try { StackMessageLog.lock(); + StackMessageLog.clear(); ds.setMaxConnLifetimeMillis(100); ds.setLogExpiredConnections(false); Connection conn = ds.getConnection(); Modified: commons/proper/dbcp/trunk/src/test/java/org/apache/commons/dbcp2/TestPStmtPooling.java URL: http://svn.apache.org/viewvc/commons/proper/dbcp/trunk/src/test/java/org/apache/commons/dbcp2/TestPStmtPooling.java?rev=1652830&r1=1652829&r2=1652830&view=diff ============================================================================== --- commons/proper/dbcp/trunk/src/test/java/org/apache/commons/dbcp2/TestPStmtPooling.java (original) +++ commons/proper/dbcp/trunk/src/test/java/org/apache/commons/dbcp2/TestPStmtPooling.java Sun Jan 18 18:59:59 2015 @@ -141,7 +141,7 @@ public class TestPStmtPooling { new GenericObjectPool<>(pcf, config); pcf.setPool(connPool); - DataSource ds = new PoolingDataSource<>(connPool); + PoolingDataSource<?> ds = new PoolingDataSource<>(connPool); try (Connection conn = ds.getConnection()) { Statement stmt1 = conn.prepareStatement("select 1 from dual"); @@ -165,6 +165,7 @@ public class TestPStmtPooling { assertNotSame(ustmt1, ustmt3); assertNotSame(ustmt3, ucstmt1); } + ds.close(); } @Test @@ -182,7 +183,7 @@ public class TestPStmtPooling { ObjectPool<PoolableConnection> connPool = new GenericObjectPool<>(pcf); pcf.setPool(connPool); - DataSource ds = new PoolingDataSource<>(connPool); + PoolingDataSource<?> ds = new PoolingDataSource<>(connPool); ((PoolingDataSource<?>) ds).setAccessToUnderlyingConnectionAllowed(true); Connection conn = ds.getConnection(); @@ -197,6 +198,7 @@ public class TestPStmtPooling { } catch (SQLException ex) { assertTrue(ex.getMessage().endsWith("invalid PoolingConnection.")); } + ds.close(); } @Test @@ -213,7 +215,7 @@ public class TestPStmtPooling { ObjectPool<PoolableConnection> connPool = new GenericObjectPool<>(pcf); pcf.setPool(connPool); - DataSource ds = new PoolingDataSource<>(connPool); + PoolingDataSource<?> ds = new PoolingDataSource<>(connPool); Connection conn = ds.getConnection(); PreparedStatement ps = conn.prepareStatement("select 1 from dual"); @@ -223,5 +225,6 @@ public class TestPStmtPooling { ps.close(); conn.close(); Assert.assertFalse(inner.isClosed()); + ds.close(); } } Modified: commons/proper/dbcp/trunk/src/test/java/org/apache/commons/dbcp2/TestPoolingDataSource.java URL: http://svn.apache.org/viewvc/commons/proper/dbcp/trunk/src/test/java/org/apache/commons/dbcp2/TestPoolingDataSource.java?rev=1652830&r1=1652829&r2=1652830&view=diff ============================================================================== --- commons/proper/dbcp/trunk/src/test/java/org/apache/commons/dbcp2/TestPoolingDataSource.java (original) +++ commons/proper/dbcp/trunk/src/test/java/org/apache/commons/dbcp2/TestPoolingDataSource.java Sun Jan 18 18:59:59 2015 @@ -17,7 +17,9 @@ package org.apache.commons.dbcp2; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import java.sql.Connection; @@ -67,7 +69,7 @@ public class TestPoolingDataSource exten @After public void tearDown() throws Exception { - pool.close(); + ds.close(); super.tearDown(); } @@ -169,4 +171,34 @@ public class TestPoolingDataSource exten assertTrue(f.getPool().equals(p)); ds.getConnection(); } + + @Test + public void testClose() throws Exception { + + Properties props = new Properties(); + props.setProperty("user", "username"); + props.setProperty("password", "password"); + PoolableConnectionFactory f = + new PoolableConnectionFactory( + new DriverConnectionFactory(new TesterDriver(), + "jdbc:apache:commons:testdriver", props), + null); + f.setValidationQuery("SELECT DUMMY FROM DUAL"); + f.setDefaultReadOnly(Boolean.TRUE); + f.setDefaultAutoCommit(Boolean.TRUE); + GenericObjectPool<PoolableConnection> p = new GenericObjectPool<>(f); + p.setMaxTotal(getMaxTotal()); + p.setMaxWaitMillis(getMaxWaitMillis()); + + try ( PoolingDataSource<PoolableConnection> dataSource = + new PoolingDataSource<PoolableConnection>(p) ) { + Connection connection = dataSource.getConnection(); + assertNotNull(connection); + connection.close(); + } + + assertTrue(p.isClosed()); + assertEquals(0, p.getNumIdle()); + assertEquals(0, p.getNumActive()); + } } Modified: commons/proper/dbcp/trunk/src/test/java/org/apache/commons/dbcp2/datasources/TestCPDSConnectionFactory.java URL: http://svn.apache.org/viewvc/commons/proper/dbcp/trunk/src/test/java/org/apache/commons/dbcp2/datasources/TestCPDSConnectionFactory.java?rev=1652830&r1=1652829&r2=1652830&view=diff ============================================================================== --- commons/proper/dbcp/trunk/src/test/java/org/apache/commons/dbcp2/datasources/TestCPDSConnectionFactory.java (original) +++ commons/proper/dbcp/trunk/src/test/java/org/apache/commons/dbcp2/datasources/TestCPDSConnectionFactory.java Sun Jan 18 18:59:59 2015 @@ -72,6 +72,7 @@ public class TestCPDSConnectionFactory { assertEquals(2, ds.getNumIdle("username")); conn3.close(); // Return to pool will trigger destroy -> close sequence assertEquals(2, ds.getNumIdle("username")); + ds.close(); } /** Modified: commons/proper/dbcp/trunk/src/test/java/org/apache/commons/dbcp2/datasources/TestInstanceKeyDataSource.java URL: http://svn.apache.org/viewvc/commons/proper/dbcp/trunk/src/test/java/org/apache/commons/dbcp2/datasources/TestInstanceKeyDataSource.java?rev=1652830&r1=1652829&r2=1652830&view=diff ============================================================================== --- commons/proper/dbcp/trunk/src/test/java/org/apache/commons/dbcp2/datasources/TestInstanceKeyDataSource.java (original) +++ commons/proper/dbcp/trunk/src/test/java/org/apache/commons/dbcp2/datasources/TestInstanceKeyDataSource.java Sun Jan 18 18:59:59 2015 @@ -54,7 +54,8 @@ public class TestInstanceKeyDataSource { } catch (SQLException ex) { //Expected } - assertEquals(numConnections,tds.getNumActive()); + assertEquals(numConnections,tds.getNumActive()); + tds.close(); } private static class ThrowOnSetupDefaultsDataSource Modified: commons/proper/dbcp/trunk/src/test/java/org/apache/commons/dbcp2/datasources/TestKeyedCPDSConnectionFactory.java URL: http://svn.apache.org/viewvc/commons/proper/dbcp/trunk/src/test/java/org/apache/commons/dbcp2/datasources/TestKeyedCPDSConnectionFactory.java?rev=1652830&r1=1652829&r2=1652830&view=diff ============================================================================== --- commons/proper/dbcp/trunk/src/test/java/org/apache/commons/dbcp2/datasources/TestKeyedCPDSConnectionFactory.java (original) +++ commons/proper/dbcp/trunk/src/test/java/org/apache/commons/dbcp2/datasources/TestKeyedCPDSConnectionFactory.java Sun Jan 18 18:59:59 2015 @@ -73,6 +73,7 @@ public class TestKeyedCPDSConnectionFact assertEquals(2, ds.getNumIdle()); conn3.close(); // Return to pool will trigger destroy -> close sequence assertEquals(2, ds.getNumIdle()); + ds.close(); } /** Modified: commons/proper/dbcp/trunk/src/test/java/org/apache/commons/dbcp2/datasources/TestSharedPoolDataSource.java URL: http://svn.apache.org/viewvc/commons/proper/dbcp/trunk/src/test/java/org/apache/commons/dbcp2/datasources/TestSharedPoolDataSource.java?rev=1652830&r1=1652829&r2=1652830&view=diff ============================================================================== --- commons/proper/dbcp/trunk/src/test/java/org/apache/commons/dbcp2/datasources/TestSharedPoolDataSource.java (original) +++ commons/proper/dbcp/trunk/src/test/java/org/apache/commons/dbcp2/datasources/TestSharedPoolDataSource.java Sun Jan 18 18:59:59 2015 @@ -538,6 +538,7 @@ public class TestSharedPoolDataSource ex assertTrue(l3HashCode == l4HashCode); conn.close(); conn = null; + tds.close(); } @Test Modified: commons/proper/dbcp/trunk/src/test/java/org/apache/commons/dbcp2/managed/TestTransactionContext.java URL: http://svn.apache.org/viewvc/commons/proper/dbcp/trunk/src/test/java/org/apache/commons/dbcp2/managed/TestTransactionContext.java?rev=1652830&r1=1652829&r2=1652830&view=diff ============================================================================== --- commons/proper/dbcp/trunk/src/test/java/org/apache/commons/dbcp2/managed/TestTransactionContext.java (original) +++ commons/proper/dbcp/trunk/src/test/java/org/apache/commons/dbcp2/managed/TestTransactionContext.java Sun Jan 18 18:59:59 2015 @@ -46,6 +46,7 @@ public class TestTransactionContext { final TransactionContext transactionContext = new TransactionContext(basicManagedDataSource.getTransactionRegistry(), transaction); transactionContext.setSharedConnection(conn); + basicManagedDataSource.close(); } /**