diff options
author | Artur Signell <artur@vaadin.com> | 2015-05-15 17:50:51 +0300 |
---|---|---|
committer | Mika Murtojarvi <mika@vaadin.com> | 2015-05-25 13:44:21 +0300 |
commit | aef530fc3a09f520cde52cca0ece1f4065764e4d (patch) | |
tree | 1f5ae2838b3aa2423ab7c529d256f3464148ac5e /server | |
parent | c8703cc12fe3f918fa4caaa39b419067b76024b1 (diff) | |
download | vaadin-framework-aef530fc3a09f520cde52cca0ece1f4065764e4d.tar.gz vaadin-framework-aef530fc3a09f520cde52cca0ece1f4065764e4d.zip |
Make TableQuery only release connections reserved through its pool
(#12370)
Updated all SQLContainer tests to track that connection are correctly
reserved and released
Change-Id: I2ac355cf9a72b7eef1dd306b19c8e7a8b478f075
Diffstat (limited to 'server')
9 files changed, 198 insertions, 66 deletions
diff --git a/server/src/com/vaadin/data/util/sqlcontainer/query/TableQuery.java b/server/src/com/vaadin/data/util/sqlcontainer/query/TableQuery.java index bb000bd8f5..9a41766a31 100644 --- a/server/src/com/vaadin/data/util/sqlcontainer/query/TableQuery.java +++ b/server/src/com/vaadin/data/util/sqlcontainer/query/TableQuery.java @@ -213,8 +213,8 @@ public class TableQuery extends AbstractTransactionalQuery implements } finally { try { if (r != null) { - releaseConnection(r.getStatement().getConnection(), - r.getStatement(), r); + // Do not release connection, it is done in commit() + releaseConnection(null, r.getStatement(), r); } } finally { if (shouldCloseTransaction) { @@ -774,8 +774,8 @@ public class TableQuery extends AbstractTransactionalQuery implements } finally { try { if (rs != null) { - releaseConnection(rs.getStatement().getConnection(), - rs.getStatement(), rs); + // Do not release connection, it is done in commit() + releaseConnection(null, rs.getStatement(), rs); } } finally { if (shouldCloseTransaction) { diff --git a/server/tests/src/com/vaadin/data/util/sqlcontainer/SQLContainerTableQueryTest.java b/server/tests/src/com/vaadin/data/util/sqlcontainer/SQLContainerTableQueryTest.java index c70462012e..92d0c49205 100644 --- a/server/tests/src/com/vaadin/data/util/sqlcontainer/SQLContainerTableQueryTest.java +++ b/server/tests/src/com/vaadin/data/util/sqlcontainer/SQLContainerTableQueryTest.java @@ -29,9 +29,9 @@ import com.vaadin.data.Item; import com.vaadin.data.util.filter.Like; import com.vaadin.data.util.sqlcontainer.SQLTestsConstants.DB; import com.vaadin.data.util.sqlcontainer.connection.JDBCConnectionPool; -import com.vaadin.data.util.sqlcontainer.connection.SimpleJDBCConnectionPool; import com.vaadin.data.util.sqlcontainer.query.OrderBy; import com.vaadin.data.util.sqlcontainer.query.TableQuery; +import com.vaadin.data.util.sqlcontainer.query.ValidatingSimpleJDBCConnectionPool; public class SQLContainerTableQueryTest { @@ -51,7 +51,7 @@ public class SQLContainerTableQueryTest { public void setUp() throws SQLException { try { - connectionPool = new SimpleJDBCConnectionPool( + connectionPool = new ValidatingSimpleJDBCConnectionPool( SQLTestsConstants.dbDriver, SQLTestsConstants.dbURL, SQLTestsConstants.dbUser, SQLTestsConstants.dbPwd, 2, 2); } catch (SQLException e) { @@ -99,14 +99,23 @@ public class SQLContainerTableQueryTest { assertTrue(container.removeItem(container.lastItemId())); } - @Test(expected = IllegalArgumentException.class) + @Test public void itemWithNonExistingVersionColumnCannotBeRemoved() throws SQLException { query.setVersionColumn("version"); container.removeItem(container.lastItemId()); - container.commit(); + // FIXME Remove try-catch when https://dev.vaadin.com/ticket/17858 is + // fixed + try { + container.commit(); + Assert.fail("Commit should not succeed when version column does not exist"); + } catch (IllegalArgumentException e) { + // This should not be here at all as commit() should not leave the + // transaction open! + container.getQueryDelegate().rollback(); + } } @Test diff --git a/server/tests/src/com/vaadin/data/util/sqlcontainer/SQLContainerTest.java b/server/tests/src/com/vaadin/data/util/sqlcontainer/SQLContainerTest.java index 4c132eba30..a332d9d9ee 100644 --- a/server/tests/src/com/vaadin/data/util/sqlcontainer/SQLContainerTest.java +++ b/server/tests/src/com/vaadin/data/util/sqlcontainer/SQLContainerTest.java @@ -26,11 +26,11 @@ import com.vaadin.data.util.filter.Compare.Equal; import com.vaadin.data.util.filter.Like; import com.vaadin.data.util.sqlcontainer.SQLTestsConstants.DB; import com.vaadin.data.util.sqlcontainer.connection.JDBCConnectionPool; -import com.vaadin.data.util.sqlcontainer.connection.SimpleJDBCConnectionPool; import com.vaadin.data.util.sqlcontainer.query.FreeformQuery; import com.vaadin.data.util.sqlcontainer.query.FreeformQueryDelegate; import com.vaadin.data.util.sqlcontainer.query.FreeformStatementDelegate; import com.vaadin.data.util.sqlcontainer.query.OrderBy; +import com.vaadin.data.util.sqlcontainer.query.ValidatingSimpleJDBCConnectionPool; import com.vaadin.data.util.sqlcontainer.query.generator.MSSQLGenerator; import com.vaadin.data.util.sqlcontainer.query.generator.OracleGenerator; import com.vaadin.data.util.sqlcontainer.query.generator.SQLGenerator; @@ -45,7 +45,7 @@ public class SQLContainerTest { public void setUp() throws SQLException { try { - connectionPool = new SimpleJDBCConnectionPool( + connectionPool = new ValidatingSimpleJDBCConnectionPool( SQLTestsConstants.dbDriver, SQLTestsConstants.dbURL, SQLTestsConstants.dbUser, SQLTestsConstants.dbPwd, 2, 2); } catch (SQLException e) { diff --git a/server/tests/src/com/vaadin/data/util/sqlcontainer/TicketTests.java b/server/tests/src/com/vaadin/data/util/sqlcontainer/TicketTests.java index 110225e206..e180e3f3e7 100644 --- a/server/tests/src/com/vaadin/data/util/sqlcontainer/TicketTests.java +++ b/server/tests/src/com/vaadin/data/util/sqlcontainer/TicketTests.java @@ -16,10 +16,11 @@ import com.vaadin.data.Container.Filter; import com.vaadin.data.Item; import com.vaadin.data.util.filter.Compare.Equal; import com.vaadin.data.util.sqlcontainer.SQLTestsConstants.DB; -import com.vaadin.data.util.sqlcontainer.connection.SimpleJDBCConnectionPool; +import com.vaadin.data.util.sqlcontainer.connection.JDBCConnectionPool; import com.vaadin.data.util.sqlcontainer.query.FreeformQuery; import com.vaadin.data.util.sqlcontainer.query.FreeformStatementDelegate; import com.vaadin.data.util.sqlcontainer.query.TableQuery; +import com.vaadin.data.util.sqlcontainer.query.ValidatingSimpleJDBCConnectionPool; import com.vaadin.data.util.sqlcontainer.query.generator.StatementHelper; import com.vaadin.data.util.sqlcontainer.query.generator.filter.QueryBuilder; import com.vaadin.ui.Table; @@ -27,11 +28,11 @@ import com.vaadin.ui.Window; public class TicketTests { - private SimpleJDBCConnectionPool connectionPool; + private JDBCConnectionPool connectionPool; @Before public void setUp() throws SQLException { - connectionPool = new SimpleJDBCConnectionPool( + connectionPool = new ValidatingSimpleJDBCConnectionPool( SQLTestsConstants.dbDriver, SQLTestsConstants.dbURL, SQLTestsConstants.dbUser, SQLTestsConstants.dbPwd, 2, 2); DataGenerator.addPeopleToDatabase(connectionPool); diff --git a/server/tests/src/com/vaadin/data/util/sqlcontainer/connection/SimpleJDBCConnectionPoolTest.java b/server/tests/src/com/vaadin/data/util/sqlcontainer/connection/SimpleJDBCConnectionPoolTest.java index 99ad420229..b786f5b2de 100644 --- a/server/tests/src/com/vaadin/data/util/sqlcontainer/connection/SimpleJDBCConnectionPoolTest.java +++ b/server/tests/src/com/vaadin/data/util/sqlcontainer/connection/SimpleJDBCConnectionPoolTest.java @@ -9,13 +9,14 @@ import org.junit.Before; import org.junit.Test; import com.vaadin.data.util.sqlcontainer.SQLTestsConstants; +import com.vaadin.data.util.sqlcontainer.query.ValidatingSimpleJDBCConnectionPool; public class SimpleJDBCConnectionPoolTest { private JDBCConnectionPool connectionPool; @Before public void setUp() throws SQLException { - connectionPool = new SimpleJDBCConnectionPool( + connectionPool = new ValidatingSimpleJDBCConnectionPool( SQLTestsConstants.dbDriver, SQLTestsConstants.dbURL, SQLTestsConstants.dbUser, SQLTestsConstants.dbPwd, 2, 2); } @@ -145,8 +146,11 @@ public class SimpleJDBCConnectionPoolTest { EasyMock.expectLastCall().atLeastOnce(); EasyMock.replay(c); // make sure the connection pool is initialized - connectionPool.reserveConnection(); - connectionPool.releaseConnection(c); + // Bypass validation + JDBCConnectionPool realPool = ((ValidatingSimpleJDBCConnectionPool) connectionPool) + .getRealPool(); + realPool.reserveConnection(); + realPool.releaseConnection(c); EasyMock.verify(c); } @@ -154,7 +158,13 @@ public class SimpleJDBCConnectionPoolTest { public void destroy_shouldCloseAllConnections() throws SQLException { Connection c1 = connectionPool.reserveConnection(); Connection c2 = connectionPool.reserveConnection(); - connectionPool.destroy(); + try { + connectionPool.destroy(); + } catch (RuntimeException e) { + // The test connection pool throws an exception when the pool was + // not empty but only after cleanup of the real pool has been done + } + Assert.assertTrue(c1.isClosed()); Assert.assertTrue(c2.isClosed()); } diff --git a/server/tests/src/com/vaadin/data/util/sqlcontainer/generator/SQLGeneratorsTest.java b/server/tests/src/com/vaadin/data/util/sqlcontainer/generator/SQLGeneratorsTest.java index 59e879a8e0..c2dbf0f12a 100644 --- a/server/tests/src/com/vaadin/data/util/sqlcontainer/generator/SQLGeneratorsTest.java +++ b/server/tests/src/com/vaadin/data/util/sqlcontainer/generator/SQLGeneratorsTest.java @@ -18,9 +18,9 @@ import com.vaadin.data.util.sqlcontainer.RowItem; import com.vaadin.data.util.sqlcontainer.SQLContainer; import com.vaadin.data.util.sqlcontainer.SQLTestsConstants; import com.vaadin.data.util.sqlcontainer.connection.JDBCConnectionPool; -import com.vaadin.data.util.sqlcontainer.connection.SimpleJDBCConnectionPool; import com.vaadin.data.util.sqlcontainer.query.OrderBy; import com.vaadin.data.util.sqlcontainer.query.TableQuery; +import com.vaadin.data.util.sqlcontainer.query.ValidatingSimpleJDBCConnectionPool; import com.vaadin.data.util.sqlcontainer.query.generator.DefaultSQLGenerator; import com.vaadin.data.util.sqlcontainer.query.generator.MSSQLGenerator; import com.vaadin.data.util.sqlcontainer.query.generator.OracleGenerator; @@ -34,7 +34,7 @@ public class SQLGeneratorsTest { public void setUp() throws SQLException { try { - connectionPool = new SimpleJDBCConnectionPool( + connectionPool = new ValidatingSimpleJDBCConnectionPool( SQLTestsConstants.dbDriver, SQLTestsConstants.dbURL, SQLTestsConstants.dbUser, SQLTestsConstants.dbPwd, 2, 2); } catch (SQLException e) { diff --git a/server/tests/src/com/vaadin/data/util/sqlcontainer/query/FreeformQueryTest.java b/server/tests/src/com/vaadin/data/util/sqlcontainer/query/FreeformQueryTest.java index 195911475e..e193b79df3 100644 --- a/server/tests/src/com/vaadin/data/util/sqlcontainer/query/FreeformQueryTest.java +++ b/server/tests/src/com/vaadin/data/util/sqlcontainer/query/FreeformQueryTest.java @@ -23,7 +23,6 @@ import com.vaadin.data.util.sqlcontainer.SQLContainer; import com.vaadin.data.util.sqlcontainer.SQLTestsConstants; import com.vaadin.data.util.sqlcontainer.SQLTestsConstants.DB; import com.vaadin.data.util.sqlcontainer.connection.JDBCConnectionPool; -import com.vaadin.data.util.sqlcontainer.connection.SimpleJDBCConnectionPool; public class FreeformQueryTest { @@ -34,7 +33,7 @@ public class FreeformQueryTest { public void setUp() throws SQLException { try { - connectionPool = new SimpleJDBCConnectionPool( + connectionPool = new ValidatingSimpleJDBCConnectionPool( SQLTestsConstants.dbDriver, SQLTestsConstants.dbURL, SQLTestsConstants.dbUser, SQLTestsConstants.dbPwd, 2, 2); } catch (SQLException e) { @@ -148,7 +147,10 @@ public class FreeformQueryTest { connectionPool, "ID"); query.getCount(); query.getCount(); - Assert.assertNotNull(connectionPool.reserveConnection()); + Connection c = connectionPool.reserveConnection(); + Assert.assertNotNull(c); + // Cleanup to make test connection pool happy + connectionPool.releaseConnection(c); } @Test @@ -276,37 +278,38 @@ public class FreeformQueryTest { new Object[] { 1 }), null)); } - @Test(expected = UnsupportedOperationException.class) + @Test public void storeRow_noDelegate_shouldFail() throws SQLException { FreeformQuery query = new FreeformQuery("SELECT * FROM people", Arrays.asList("ID"), connectionPool); SQLContainer container = EasyMock.createNiceMock(SQLContainer.class); EasyMock.replay(container); query.beginTransaction(); - query.storeRow(new RowItem(container, new RowId(new Object[] { 1 }), - null)); - query.commit(); - EasyMock.verify(container); + try { + query.storeRow(new RowItem(container, + new RowId(new Object[] { 1 }), null)); + Assert.fail("storeRow should fail when there is no delegate"); + } catch (UnsupportedOperationException e) { + // Cleanup to make test connection pool happy + query.rollback(); + } } - @Test(expected = UnsupportedOperationException.class) + @Test public void removeRow_noDelegate_shouldFail() throws SQLException { FreeformQuery query = new FreeformQuery("SELECT * FROM people", Arrays.asList("ID"), connectionPool); SQLContainer container = EasyMock.createNiceMock(SQLContainer.class); EasyMock.replay(container); query.beginTransaction(); - query.removeRow(new RowItem(container, new RowId(new Object[] { 1 }), - null)); - query.commit(); - EasyMock.verify(container); - } - - @Test - public void beginTransaction_readOnly_shouldSucceed() throws SQLException { - FreeformQuery query = new FreeformQuery("SELECT * FROM people", - Arrays.asList("ID"), connectionPool); - query.beginTransaction(); + try { + query.removeRow(new RowItem(container, + new RowId(new Object[] { 1 }), null)); + Assert.fail("removeRow should fail when there is no delgate"); + } catch (UnsupportedOperationException e) { + // Cleanup to make test connection pool happy + query.rollback(); + } } @Test @@ -628,7 +631,7 @@ public class FreeformQueryTest { EasyMock.verify(delegate, container); } - @Test(expected = UnsupportedOperationException.class) + @Test public void storeRow_delegateDoesNotImplementStoreRow_shouldFail() throws SQLException { FreeformQuery query = new FreeformQuery("SELECT * FROM people", @@ -646,10 +649,13 @@ public class FreeformQueryTest { query.beginTransaction(); RowItem row = new RowItem(container, new RowId(new Object[] { 1 }), null); - query.storeRow(row); - query.commit(); - - EasyMock.verify(delegate, container); + try { + query.storeRow(row); + Assert.fail("storeRow should fail when delgate does not implement storeRow"); + } catch (UnsupportedOperationException e) { + // Cleanup to make test connection pool happy + query.rollback(); + } } @Test @@ -675,7 +681,7 @@ public class FreeformQueryTest { EasyMock.verify(delegate, container); } - @Test(expected = UnsupportedOperationException.class) + @Test public void removeRow_delegateDoesNotImplementRemoveRow_shouldFail() throws SQLException { FreeformQuery query = new FreeformQuery("SELECT * FROM people", @@ -693,10 +699,13 @@ public class FreeformQueryTest { query.beginTransaction(); RowItem row = new RowItem(container, new RowId(new Object[] { 1 }), null); - query.removeRow(row); - query.commit(); - - EasyMock.verify(delegate, container); + try { + query.removeRow(row); + Assert.fail("removeRow should fail when delegate does not implement removeRow"); + } catch (UnsupportedOperationException e) { + // Cleanup to make test connection pool happy + query.rollback(); + } } @Test @@ -710,16 +719,24 @@ public class FreeformQueryTest { query.setDelegate(delegate); query.beginTransaction(); + // Cleanup to make test connection pool happy + query.rollback(); } - @Test(expected = IllegalStateException.class) + @Test public void beginTransaction_transactionAlreadyActive_shouldFail() throws SQLException { FreeformQuery query = new FreeformQuery("SELECT * FROM people", Arrays.asList("ID"), connectionPool); query.beginTransaction(); - query.beginTransaction(); + try { + query.beginTransaction(); + Assert.fail("Should throw exception when starting a transaction while already in a transaction"); + } catch (IllegalStateException e) { + // Cleanup to make test connection pool happy + query.rollback(); + } } @Test(expected = SQLException.class) diff --git a/server/tests/src/com/vaadin/data/util/sqlcontainer/query/TableQueryTest.java b/server/tests/src/com/vaadin/data/util/sqlcontainer/query/TableQueryTest.java index f009fc505e..1cb3d722c6 100644 --- a/server/tests/src/com/vaadin/data/util/sqlcontainer/query/TableQueryTest.java +++ b/server/tests/src/com/vaadin/data/util/sqlcontainer/query/TableQueryTest.java @@ -24,7 +24,6 @@ import com.vaadin.data.util.sqlcontainer.SQLContainer; import com.vaadin.data.util.sqlcontainer.SQLTestsConstants; import com.vaadin.data.util.sqlcontainer.SQLTestsConstants.DB; import com.vaadin.data.util.sqlcontainer.connection.JDBCConnectionPool; -import com.vaadin.data.util.sqlcontainer.connection.SimpleJDBCConnectionPool; import com.vaadin.data.util.sqlcontainer.query.generator.DefaultSQLGenerator; public class TableQueryTest { @@ -33,16 +32,14 @@ public class TableQueryTest { @Before public void setUp() throws SQLException { - try { - connectionPool = new SimpleJDBCConnectionPool( + connectionPool = new ValidatingSimpleJDBCConnectionPool( SQLTestsConstants.dbDriver, SQLTestsConstants.dbURL, SQLTestsConstants.dbUser, SQLTestsConstants.dbPwd, 2, 2); } catch (SQLException e) { e.printStackTrace(); Assert.fail(e.getMessage()); } - DataGenerator.addPeopleToDatabase(connectionPool); } @@ -139,7 +136,9 @@ public class TableQueryTest { SQLTestsConstants.sqlGen); tQuery.getCount(); tQuery.getCount(); - Assert.assertNotNull(connectionPool.reserveConnection()); + Connection c = connectionPool.reserveConnection(); + Assert.assertNotNull(c); + connectionPool.releaseConnection(c); } /********************************************************************** @@ -193,20 +192,19 @@ public class TableQueryTest { * TableQuery transaction management tests **********************************************************************/ @Test - public void beginTransaction_readOnly_shouldSucceed() throws SQLException { - TableQuery tQuery = new TableQuery("people", connectionPool, - SQLTestsConstants.sqlGen); - tQuery.beginTransaction(); - } - - @Test(expected = IllegalStateException.class) public void beginTransaction_transactionAlreadyActive_shouldFail() throws SQLException { TableQuery tQuery = new TableQuery("people", connectionPool, SQLTestsConstants.sqlGen); tQuery.beginTransaction(); - tQuery.beginTransaction(); + try { + tQuery.beginTransaction(); + Assert.fail("Should throw exception when starting a transaction while already in a transaction"); + } catch (IllegalStateException e) { + // Cleanup to make test connection pool happy + tQuery.rollback(); + } } @Test @@ -284,8 +282,13 @@ public class TableQueryTest { .fail("null should throw an IllegalArgumentException from StatementHelper"); } catch (IllegalArgumentException e) { // We should now be able to reserve two connections - connectionPool.reserveConnection(); - connectionPool.reserveConnection(); + Connection c1 = connectionPool.reserveConnection(); + Connection c2 = connectionPool.reserveConnection(); + + // Cleanup to make test connection pool happy + connectionPool.releaseConnection(c1); + connectionPool.releaseConnection(c2); + } } @@ -693,6 +696,9 @@ public class TableQueryTest { // cleanup - might not be an in-memory DB statement.execute(SQLTestsConstants.dropSchema); } + + // Cleanup to make test connection pool happy + connectionPool.releaseConnection(conn); } @Test diff --git a/server/tests/src/com/vaadin/data/util/sqlcontainer/query/ValidatingSimpleJDBCConnectionPool.java b/server/tests/src/com/vaadin/data/util/sqlcontainer/query/ValidatingSimpleJDBCConnectionPool.java new file mode 100644 index 0000000000..464f3c8562 --- /dev/null +++ b/server/tests/src/com/vaadin/data/util/sqlcontainer/query/ValidatingSimpleJDBCConnectionPool.java @@ -0,0 +1,89 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed 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 com.vaadin.data.util.sqlcontainer.query; + +import java.sql.Connection; +import java.sql.SQLException; +import java.util.HashSet; +import java.util.Set; +import java.util.logging.Logger; + +import com.vaadin.data.util.sqlcontainer.connection.JDBCConnectionPool; +import com.vaadin.data.util.sqlcontainer.connection.SimpleJDBCConnectionPool; + +/** + * Connection pool for testing SQLContainer. Ensures that only reserved + * connections are released and that all connections are released before the + * pool is destroyed. + * + * @author Vaadin Ltd + */ +public class ValidatingSimpleJDBCConnectionPool implements JDBCConnectionPool { + + private JDBCConnectionPool realPool; + private Set<Connection> reserved = new HashSet<Connection>(); + private Set<Connection> alreadyReleased = new HashSet<Connection>(); + + public ValidatingSimpleJDBCConnectionPool(String driverName, + String connectionUri, String userName, String password, + int initialConnections, int maxConnections) throws SQLException { + realPool = new SimpleJDBCConnectionPool(driverName, connectionUri, + userName, password, initialConnections, maxConnections); + } + + @Deprecated + public JDBCConnectionPool getRealPool() { + return realPool; + } + + @Override + public Connection reserveConnection() throws SQLException { + Connection c = realPool.reserveConnection(); + reserved.add(c); + return c; + } + + @Override + public void releaseConnection(Connection conn) { + if (conn != null && !reserved.remove(conn)) { + if (alreadyReleased.contains(conn)) { + getLogger().severe( + "Tried to release connection (" + conn + + ") which has already been released"); + } else { + throw new RuntimeException("Tried to release connection (" + + conn + ") not reserved using reserveConnection"); + } + } + realPool.releaseConnection(conn); + alreadyReleased.add(conn); + + } + + @Override + public void destroy() { + realPool.destroy(); + if (!reserved.isEmpty()) { + throw new RuntimeException(reserved.size() + + " connections never released"); + } + } + + public static Logger getLogger() { + return Logger.getLogger(ValidatingSimpleJDBCConnectionPool.class + .getName()); + } +}
\ No newline at end of file |