diff options
author | Artur Signell <artur@vaadin.com> | 2013-03-21 08:59:51 +0200 |
---|---|---|
committer | Artur Signell <artur@vaadin.com> | 2013-03-21 08:59:51 +0200 |
commit | bd3bb24a36a0ad02ffb9cee2e46afc445a354191 (patch) | |
tree | 00d9248c84f8b7b60768552c822279c9cf151f45 /server/src/com/vaadin | |
parent | 320b4e3776976e5dad822f01542f338cf76140bb (diff) | |
parent | e4c9eda51082a443822b66864df2fe14be7dc6d7 (diff) | |
download | vaadin-framework-bd3bb24a36a0ad02ffb9cee2e46afc445a354191.tar.gz vaadin-framework-bd3bb24a36a0ad02ffb9cee2e46afc445a354191.zip |
Merge commit 'e4c9eda51082a443822b66864df2fe14be7dc6d7'
Conflicts:
uitest/test.xml
Change-Id: I2c82fa7117b21bddad313abdd2f3f43143317c12
Diffstat (limited to 'server/src/com/vaadin')
7 files changed, 381 insertions, 252 deletions
diff --git a/server/src/com/vaadin/data/util/sqlcontainer/query/AbstractTransactionalQuery.java b/server/src/com/vaadin/data/util/sqlcontainer/query/AbstractTransactionalQuery.java new file mode 100644 index 0000000000..3264118732 --- /dev/null +++ b/server/src/com/vaadin/data/util/sqlcontainer/query/AbstractTransactionalQuery.java @@ -0,0 +1,185 @@ +/* + * Copyright 2000-2013 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.io.Serializable; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; + +import com.vaadin.data.util.sqlcontainer.connection.JDBCConnectionPool; + +/** + * Common base class for database query classes that handle connections and + * transactions. + * + * @author Vaadin Ltd + * @since 6.8.9 + */ +abstract class AbstractTransactionalQuery implements Serializable { + + private JDBCConnectionPool connectionPool; + private transient Connection activeConnection; + + AbstractTransactionalQuery() { + } + + AbstractTransactionalQuery(JDBCConnectionPool connectionPool) { + this.connectionPool = connectionPool; + } + + /** + * Reserves a connection with auto-commit off if no transaction is in + * progress. + * + * @throws IllegalStateException + * if a transaction is already open + * @throws SQLException + * if a connection could not be obtained or configured + */ + public void beginTransaction() throws UnsupportedOperationException, + SQLException { + if (isInTransaction()) { + throw new IllegalStateException("A transaction is already active!"); + } + activeConnection = connectionPool.reserveConnection(); + activeConnection.setAutoCommit(false); + } + + /** + * Commits (if not in auto-commit mode) and releases the active connection. + * + * @throws SQLException + * if not in a transaction managed by this query + */ + public void commit() throws UnsupportedOperationException, SQLException { + if (!isInTransaction()) { + throw new SQLException("No active transaction"); + } + if (!activeConnection.getAutoCommit()) { + activeConnection.commit(); + } + connectionPool.releaseConnection(activeConnection); + activeConnection = null; + } + + /** + * Rolls back and releases the active connection. + * + * @throws SQLException + * if not in a transaction managed by this query + */ + public void rollback() throws UnsupportedOperationException, SQLException { + if (!isInTransaction()) { + throw new SQLException("No active transaction"); + } + activeConnection.rollback(); + connectionPool.releaseConnection(activeConnection); + activeConnection = null; + } + + /** + * Check that a transaction is active. + * + * @throws SQLException + * if no active transaction + */ + protected void ensureTransaction() throws SQLException { + if (!isInTransaction()) { + throw new SQLException("No active transaction!"); + } + } + + /** + * Closes a statement and a resultset, then releases the connection if it is + * not part of an active transaction. A failure in closing one of the + * parameters does not prevent closing the rest. + * + * If the statement is a {@link PreparedStatement}, its parameters are + * cleared prior to closing the statement. + * + * Although JDBC specification does state that closing a statement closes + * its result set and closing a connection closes statements and result + * sets, this method does try to close the result set and statement + * explicitly whenever not null. This can guard against bugs in certain JDBC + * drivers and reduce leaks in case e.g. closing the result set succeeds but + * closing the statement or connection fails. + * + * @param conn + * the connection to release + * @param statement + * the statement to close, may be null to skip closing + * @param rs + * the result set to close, may be null to skip closing + * @throws SQLException + * if closing the result set or the statement fails + */ + protected void releaseConnection(Connection conn, Statement statement, + ResultSet rs) throws SQLException { + try { + try { + if (null != rs) { + rs.close(); + } + } finally { + if (null != statement) { + if (statement instanceof PreparedStatement) { + try { + ((PreparedStatement) statement).clearParameters(); + } catch (Exception e) { + // will be closed below anyway + } + } + statement.close(); + } + } + } finally { + releaseConnection(conn); + } + } + + /** + * Returns the currently active connection, reserves and returns a new + * connection if no active connection. + * + * @return previously active or newly reserved connection + * @throws SQLException + */ + protected Connection getConnection() throws SQLException { + if (activeConnection != null) { + return activeConnection; + } + return connectionPool.reserveConnection(); + } + + protected boolean isInTransaction() { + return activeConnection != null; + } + + /** + * Releases the connection if it is not part of an active transaction. + * + * @param conn + * the connection to release + */ + private void releaseConnection(Connection conn) { + if (conn != activeConnection && conn != null) { + connectionPool.releaseConnection(conn); + } + } +} diff --git a/server/src/com/vaadin/data/util/sqlcontainer/query/FreeformQuery.java b/server/src/com/vaadin/data/util/sqlcontainer/query/FreeformQuery.java index 299183f5e6..6895e02147 100644 --- a/server/src/com/vaadin/data/util/sqlcontainer/query/FreeformQuery.java +++ b/server/src/com/vaadin/data/util/sqlcontainer/query/FreeformQuery.java @@ -34,13 +34,12 @@ import com.vaadin.data.util.sqlcontainer.query.generator.StatementHelper; import com.vaadin.data.util.sqlcontainer.query.generator.filter.QueryBuilder; @SuppressWarnings("serial") -public class FreeformQuery implements QueryDelegate { +public class FreeformQuery extends AbstractTransactionalQuery implements + QueryDelegate { FreeformQueryDelegate delegate = null; private String queryString; private List<String> primaryKeyColumns; - private JDBCConnectionPool connectionPool; - private transient Connection activeConnection = null; /** * Prevent no-parameters instantiation of FreeformQuery @@ -67,6 +66,7 @@ public class FreeformQuery implements QueryDelegate { @Deprecated public FreeformQuery(String queryString, List<String> primaryKeyColumns, JDBCConnectionPool connectionPool) { + super(connectionPool); if (primaryKeyColumns == null) { primaryKeyColumns = new ArrayList<String>(); } @@ -83,7 +83,6 @@ public class FreeformQuery implements QueryDelegate { this.queryString = queryString; this.primaryKeyColumns = Collections .unmodifiableList(primaryKeyColumns); - this.connectionPool = connectionPool; } /** @@ -189,13 +188,6 @@ public class FreeformQuery implements QueryDelegate { return count; } - private Connection getConnection() throws SQLException { - if (activeConnection != null) { - return activeConnection; - } - return connectionPool.reserveConnection(); - } - /** * Fetches the results for the query. This implementation always fetches the * entire record set, ignoring the offset and page length parameters. In @@ -210,9 +202,7 @@ public class FreeformQuery implements QueryDelegate { @Override @SuppressWarnings({ "deprecation", "finally" }) public ResultSet getResults(int offset, int pagelength) throws SQLException { - if (activeConnection == null) { - throw new SQLException("No active transaction!"); - } + ensureTransaction(); String query = queryString; if (delegate != null) { /* First try using prepared statement */ @@ -220,8 +210,8 @@ public class FreeformQuery implements QueryDelegate { try { StatementHelper sh = ((FreeformStatementDelegate) delegate) .getQueryStatement(offset, pagelength); - PreparedStatement pstmt = activeConnection - .prepareStatement(sh.getQueryString()); + PreparedStatement pstmt = getConnection().prepareStatement( + sh.getQueryString()); sh.setParameterValuesToStatement(pstmt); return pstmt.executeQuery(); } catch (UnsupportedOperationException e) { @@ -234,7 +224,7 @@ public class FreeformQuery implements QueryDelegate { // This is fine, we'll just use the default queryString. } } - Statement statement = activeConnection.createStatement(); + Statement statement = getConnection().createStatement(); ResultSet rs; try { rs = statement.executeQuery(query); @@ -322,14 +312,14 @@ public class FreeformQuery implements QueryDelegate { */ @Override public int storeRow(RowItem row) throws SQLException { - if (activeConnection == null) { + if (!isInTransaction()) { throw new IllegalStateException("No transaction is active!"); } else if (primaryKeyColumns.isEmpty()) { throw new UnsupportedOperationException( "Cannot store items fetched with a read-only freeform query!"); } if (delegate != null) { - return delegate.storeRow(activeConnection, row); + return delegate.storeRow(getConnection(), row); } else { throw new UnsupportedOperationException( "FreeFormQueryDelegate not set!"); @@ -345,68 +335,36 @@ public class FreeformQuery implements QueryDelegate { */ @Override public boolean removeRow(RowItem row) throws SQLException { - if (activeConnection == null) { + if (!isInTransaction()) { throw new IllegalStateException("No transaction is active!"); } else if (primaryKeyColumns.isEmpty()) { throw new UnsupportedOperationException( "Cannot remove items fetched with a read-only freeform query!"); } if (delegate != null) { - return delegate.removeRow(activeConnection, row); + return delegate.removeRow(getConnection(), row); } else { throw new UnsupportedOperationException( "FreeFormQueryDelegate not set!"); } } - /* - * (non-Javadoc) - * - * @see - * com.vaadin.data.util.sqlcontainer.query.QueryDelegate#beginTransaction() - */ @Override public synchronized void beginTransaction() throws UnsupportedOperationException, SQLException { - if (activeConnection != null) { - throw new IllegalStateException("A transaction is already active!"); - } - activeConnection = connectionPool.reserveConnection(); - activeConnection.setAutoCommit(false); + super.beginTransaction(); } - /* - * (non-Javadoc) - * - * @see com.vaadin.data.util.sqlcontainer.query.QueryDelegate#commit() - */ @Override public synchronized void commit() throws UnsupportedOperationException, SQLException { - if (activeConnection == null) { - throw new SQLException("No active transaction"); - } - if (!activeConnection.getAutoCommit()) { - activeConnection.commit(); - } - connectionPool.releaseConnection(activeConnection); - activeConnection = null; + super.commit(); } - /* - * (non-Javadoc) - * - * @see com.vaadin.data.util.sqlcontainer.query.QueryDelegate#rollback() - */ @Override public synchronized void rollback() throws UnsupportedOperationException, SQLException { - if (activeConnection == null) { - throw new SQLException("No active transaction"); - } - activeConnection.rollback(); - connectionPool.releaseConnection(activeConnection); - activeConnection = null; + super.rollback(); } /* @@ -492,66 +450,6 @@ public class FreeformQuery implements QueryDelegate { return contains; } - /** - * Releases the connection if it is not part of an active transaction. - * - * @param conn - * the connection to release - */ - private void releaseConnection(Connection conn) { - if (conn != activeConnection) { - connectionPool.releaseConnection(conn); - } - } - - /** - * Closes a statement and a resultset, then releases the connection if it is - * not part of an active transaction. A failure in closing one of the - * parameters does not prevent closing the rest. - * - * If the statement is a {@link PreparedStatement}, its parameters are - * cleared prior to closing the statement. - * - * Although JDBC specification does state that closing a statement closes - * its result set and closing a connection closes statements and result - * sets, this method does try to close the result set and statement - * explicitly whenever not null. This can guard against bugs in certain JDBC - * drivers and reduce leaks in case e.g. closing the result set succeeds but - * closing the statement or connection fails. - * - * @param conn - * the connection to release - * @param statement - * the statement to close, may be null to skip closing - * @param rs - * the result set to close, may be null to skip closing - * @throws SQLException - * if closing the result set or the statement fails - */ - private void releaseConnection(Connection conn, Statement statement, - ResultSet rs) throws SQLException { - try { - try { - if (null != rs) { - rs.close(); - } - } finally { - if (null != statement) { - if (statement instanceof PreparedStatement) { - try { - ((PreparedStatement) statement).clearParameters(); - } catch (Exception e) { - // will be closed below anyway - } - } - statement.close(); - } - } - } finally { - releaseConnection(conn); - } - } - private String modifyWhereClause(Object... keys) { // Build the where rules for the provided keys StringBuffer where = new StringBuffer(); 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 63e4b3362c..caed5526e3 100644 --- a/server/src/com/vaadin/data/util/sqlcontainer/query/TableQuery.java +++ b/server/src/com/vaadin/data/util/sqlcontainer/query/TableQuery.java @@ -47,8 +47,8 @@ import com.vaadin.data.util.sqlcontainer.query.generator.SQLGenerator; import com.vaadin.data.util.sqlcontainer.query.generator.StatementHelper; @SuppressWarnings("serial") -public class TableQuery implements QueryDelegate, - QueryDelegate.RowIdChangeNotifier { +public class TableQuery extends AbstractTransactionalQuery implements + QueryDelegate, QueryDelegate.RowIdChangeNotifier { /** Table name, primary key column name(s) and version column name */ private String tableName; @@ -62,18 +62,13 @@ public class TableQuery implements QueryDelegate, /** SQLGenerator instance to use for generating queries */ private SQLGenerator sqlGenerator; - /** Fields related to Connection and Transaction handling */ - private JDBCConnectionPool connectionPool; - private transient Connection activeConnection; - private boolean transactionOpen; - /** Row ID change listeners */ private LinkedList<RowIdChangeListener> rowIdChangeListeners; /** Row ID change events, stored until commit() is called */ private final List<RowIdChangeEvent> bufferedEvents = new ArrayList<RowIdChangeEvent>(); /** Set to true to output generated SQL Queries to System.out */ - private boolean debug = false; + private final boolean debug = false; /** Prevent no-parameters instantiation of TableQuery */ @SuppressWarnings("unused") @@ -93,6 +88,7 @@ public class TableQuery implements QueryDelegate, */ public TableQuery(String tableName, JDBCConnectionPool connectionPool, SQLGenerator sqlGenerator) { + super(connectionPool); if (tableName == null || tableName.trim().length() < 1 || connectionPool == null || sqlGenerator == null) { throw new IllegalArgumentException( @@ -100,7 +96,6 @@ public class TableQuery implements QueryDelegate, } this.tableName = tableName; this.sqlGenerator = sqlGenerator; - this.connectionPool = connectionPool; fetchMetaData(); } @@ -129,17 +124,27 @@ public class TableQuery implements QueryDelegate, StatementHelper sh = sqlGenerator.generateSelectQuery(tableName, filters, null, 0, 0, "COUNT(*)"); boolean shouldCloseTransaction = false; - if (!transactionOpen) { + if (!isInTransaction()) { shouldCloseTransaction = true; beginTransaction(); } - ResultSet r = executeQuery(sh); - r.next(); - int count = r.getInt(1); - r.getStatement().close(); - r.close(); - if (shouldCloseTransaction) { - commit(); + ResultSet r = null; + int count = -1; + try { + r = executeQuery(sh); + r.next(); + count = r.getInt(1); + } finally { + try { + if (r != null) { + releaseConnection(r.getStatement().getConnection(), + r.getStatement(), r); + } + } finally { + if (shouldCloseTransaction) { + commit(); + } + } } return count; } @@ -240,28 +245,30 @@ public class TableQuery implements QueryDelegate, setVersionColumnFlagInProperty(row); /* Generate query */ StatementHelper sh = sqlGenerator.generateInsertQuery(tableName, row); - PreparedStatement pstmt = activeConnection.prepareStatement( - sh.getQueryString(), primaryKeyColumns.toArray(new String[0])); - sh.setParameterValuesToStatement(pstmt); - getLogger().log(Level.FINE, "DB -> {0}", sh.getQueryString()); - int result = pstmt.executeUpdate(); - if (result > 0) { - /* - * If affected rows exist, we'll get the new RowId, commit the - * transaction and return the new RowId. - */ - ResultSet generatedKeys = pstmt.getGeneratedKeys(); - RowId newId = getNewRowId(row, generatedKeys); - generatedKeys.close(); - pstmt.clearParameters(); - pstmt.close(); + Connection connection = null; + PreparedStatement pstmt = null; + ResultSet generatedKeys = null; + connection = getConnection(); + try { + pstmt = connection.prepareStatement(sh.getQueryString(), + primaryKeyColumns.toArray(new String[0])); + sh.setParameterValuesToStatement(pstmt); + getLogger().log(Level.FINE, "DB -> {0}", sh.getQueryString()); + int result = pstmt.executeUpdate(); + RowId newId = null; + if (result > 0) { + /* + * If affected rows exist, we'll get the new RowId, commit the + * transaction and return the new RowId. + */ + generatedKeys = pstmt.getGeneratedKeys(); + newId = getNewRowId(row, generatedKeys); + } + // transaction has to be closed in any case commit(); return newId; - } else { - pstmt.clearParameters(); - pstmt.close(); - /* On failure return null */ - return null; + } finally { + releaseConnection(connection, pstmt, generatedKeys); } } @@ -307,14 +314,8 @@ public class TableQuery implements QueryDelegate, @Override public void beginTransaction() throws UnsupportedOperationException, SQLException { - if (transactionOpen && activeConnection != null) { - throw new IllegalStateException(); - } - getLogger().log(Level.FINE, "DB -> begin transaction"); - activeConnection = connectionPool.reserveConnection(); - activeConnection.setAutoCommit(false); - transactionOpen = true; + super.beginTransaction(); } /* @@ -324,14 +325,8 @@ public class TableQuery implements QueryDelegate, */ @Override public void commit() throws UnsupportedOperationException, SQLException { - if (transactionOpen && activeConnection != null) { - getLogger().log(Level.FINE, "DB -> commit"); - activeConnection.commit(); - connectionPool.releaseConnection(activeConnection); - } else { - throw new SQLException("No active transaction"); - } - transactionOpen = false; + getLogger().log(Level.FINE, "DB -> commit"); + super.commit(); /* Handle firing row ID change events */ RowIdChangeEvent[] unFiredEvents = bufferedEvents @@ -353,14 +348,8 @@ public class TableQuery implements QueryDelegate, */ @Override public void rollback() throws UnsupportedOperationException, SQLException { - if (transactionOpen && activeConnection != null) { - getLogger().log(Level.FINE, "DB -> rollback"); - activeConnection.rollback(); - connectionPool.releaseConnection(activeConnection); - } else { - throw new SQLException("No active transaction"); - } - transactionOpen = false; + getLogger().log(Level.FINE, "DB -> rollback"); + super.rollback(); } /* @@ -402,16 +391,18 @@ public class TableQuery implements QueryDelegate, * @throws SQLException */ private ResultSet executeQuery(StatementHelper sh) throws SQLException { - Connection c = null; - if (transactionOpen && activeConnection != null) { - c = activeConnection; - } else { - throw new SQLException("No active transaction!"); + ensureTransaction(); + Connection connection = getConnection(); + PreparedStatement pstmt = null; + try { + pstmt = connection.prepareStatement(sh.getQueryString()); + sh.setParameterValuesToStatement(pstmt); + getLogger().log(Level.FINE, "DB -> {0}", sh.getQueryString()); + return pstmt.executeQuery(); + } catch (SQLException e) { + releaseConnection(null, pstmt, null); + throw e; } - PreparedStatement pstmt = c.prepareStatement(sh.getQueryString()); - sh.setParameterValuesToStatement(pstmt); - getLogger().log(Level.FINE, "DB -> {0}", sh.getQueryString()); - return pstmt.executeQuery(); } /** @@ -426,27 +417,17 @@ public class TableQuery implements QueryDelegate, * @throws SQLException */ private int executeUpdate(StatementHelper sh) throws SQLException { - Connection c = null; PreparedStatement pstmt = null; + Connection connection = null; try { - if (transactionOpen && activeConnection != null) { - c = activeConnection; - } else { - c = connectionPool.reserveConnection(); - } - pstmt = c.prepareStatement(sh.getQueryString()); + connection = getConnection(); + pstmt = connection.prepareStatement(sh.getQueryString()); sh.setParameterValuesToStatement(pstmt); getLogger().log(Level.FINE, "DB -> {0}", sh.getQueryString()); int retval = pstmt.executeUpdate(); return retval; } finally { - if (pstmt != null) { - pstmt.clearParameters(); - pstmt.close(); - } - if (!transactionOpen) { - connectionPool.releaseConnection(c); - } + releaseConnection(connection, pstmt, null); } } @@ -467,16 +448,12 @@ public class TableQuery implements QueryDelegate, */ private int executeUpdateReturnKeys(StatementHelper sh, RowItem row) throws SQLException { - Connection c = null; PreparedStatement pstmt = null; ResultSet genKeys = null; + Connection connection = null; try { - if (transactionOpen && activeConnection != null) { - c = activeConnection; - } else { - c = connectionPool.reserveConnection(); - } - pstmt = c.prepareStatement(sh.getQueryString(), + connection = getConnection(); + pstmt = connection.prepareStatement(sh.getQueryString(), primaryKeyColumns.toArray(new String[0])); sh.setParameterValuesToStatement(pstmt); getLogger().log(Level.FINE, "DB -> {0}", sh.getQueryString()); @@ -486,16 +463,7 @@ public class TableQuery implements QueryDelegate, bufferedEvents.add(new RowIdChangeEvent(row.getId(), newId)); return result; } finally { - if (genKeys != null) { - genKeys.close(); - } - if (pstmt != null) { - pstmt.clearParameters(); - pstmt.close(); - } - if (!transactionOpen) { - connectionPool.releaseConnection(c); - } + releaseConnection(connection, pstmt, genKeys); } } @@ -505,13 +473,15 @@ public class TableQuery implements QueryDelegate, * Also tries to get the escape string to be used in search strings. */ private void fetchMetaData() { - Connection c = null; + Connection connection = null; + ResultSet rs = null; + ResultSet tables = null; try { - c = connectionPool.reserveConnection(); - DatabaseMetaData dbmd = c.getMetaData(); + connection = getConnection(); + DatabaseMetaData dbmd = connection.getMetaData(); if (dbmd != null) { tableName = SQLUtil.escapeSQL(tableName); - ResultSet tables = dbmd.getTables(null, null, tableName, null); + tables = dbmd.getTables(null, null, tableName, null); if (!tables.next()) { tables = dbmd.getTables(null, null, tableName.toUpperCase(), null); @@ -525,7 +495,7 @@ public class TableQuery implements QueryDelegate, } } tables.close(); - ResultSet rs = dbmd.getPrimaryKeys(null, null, tableName); + rs = dbmd.getPrimaryKeys(null, null, tableName); List<String> names = new ArrayList<String>(); while (rs.next()) { names.add(rs.getString("COLUMN_NAME")); @@ -554,7 +524,15 @@ public class TableQuery implements QueryDelegate, } catch (SQLException e) { throw new RuntimeException(e); } finally { - connectionPool.releaseConnection(c); + try { + releaseConnection(connection, null, rs); + } catch (SQLException ignore) { + } finally { + try { + tables.close(); + } catch (SQLException ignore) { + } + } } } @@ -648,7 +626,7 @@ public class TableQuery implements QueryDelegate, filtersAndKeys, orderBys, 0, 0, "*"); boolean shouldCloseTransaction = false; - if (!transactionOpen) { + if (!isInTransaction()) { shouldCloseTransaction = true; beginTransaction(); } @@ -658,14 +636,15 @@ public class TableQuery implements QueryDelegate, boolean contains = rs.next(); return contains; } finally { - if (rs != null) { - if (rs.getStatement() != null) { - rs.getStatement().close(); + try { + if (rs != null) { + releaseConnection(rs.getStatement().getConnection(), + rs.getStatement(), rs); + } + } finally { + if (shouldCloseTransaction) { + commit(); } - rs.close(); - } - if (shouldCloseTransaction) { - commit(); } } } diff --git a/server/src/com/vaadin/ui/AbstractComponentContainer.java b/server/src/com/vaadin/ui/AbstractComponentContainer.java index ca83286311..4aacad680f 100644 --- a/server/src/com/vaadin/ui/AbstractComponentContainer.java +++ b/server/src/com/vaadin/ui/AbstractComponentContainer.java @@ -339,6 +339,12 @@ public abstract class AbstractComponentContainer extends AbstractComponent true); } + /** + * {@inheritDoc} + * + * @deprecated As of 7.0, use {@link #iterator()} instead. + */ + @Deprecated @Override public Iterator<Component> getComponentIterator() { return iterator(); diff --git a/server/src/com/vaadin/ui/CheckBox.java b/server/src/com/vaadin/ui/CheckBox.java index 0ace0a4f26..ac33f5e410 100644 --- a/server/src/com/vaadin/ui/CheckBox.java +++ b/server/src/com/vaadin/ui/CheckBox.java @@ -16,6 +16,8 @@ package com.vaadin.ui; +import org.json.JSONException; + import com.vaadin.data.Property; import com.vaadin.event.FieldEvents.BlurEvent; import com.vaadin.event.FieldEvents.BlurListener; @@ -37,6 +39,21 @@ public class CheckBox extends AbstractField<Boolean> { return; } + /* + * Client side updates the state before sending the event so we need + * to make sure the cached state is updated to match the client. If + * we do not do this, a reverting setValue() call in a listener will + * not cause the new state to be sent to the client. + * + * See #11028, #10030. + */ + try { + getUI().getConnectorTracker().getDiffState(CheckBox.this) + .put("checked", checked); + } catch (JSONException e) { + throw new RuntimeException(e); + } + final Boolean oldValue = getValue(); final Boolean newValue = checked; diff --git a/server/src/com/vaadin/ui/Table.java b/server/src/com/vaadin/ui/Table.java index 641c0ff1f6..3d7cb42050 100644 --- a/server/src/com/vaadin/ui/Table.java +++ b/server/src/com/vaadin/ui/Table.java @@ -396,10 +396,14 @@ public class Table extends AbstractSelect implements Action.Container, private HashMap<Object, Align> columnAlignments = new HashMap<Object, Align>(); /** - * Holds column widths in pixels (Integer) or expand ratios (Float) for - * visible columns (by propertyId). + * Holds column widths in pixels for visible columns (by propertyId). */ - private final HashMap<Object, Object> columnWidths = new HashMap<Object, Object>(); + private final HashMap<Object, Integer> columnWidths = new HashMap<Object, Integer>(); + + /** + * Holds column expand rations for visible columns (by propertyId). + */ + private final HashMap<Object, Float> columnExpandRatios = new HashMap<Object, Float>(); /** * Holds column generators @@ -886,10 +890,14 @@ public class Table extends AbstractSelect implements Action.Container, // id to store the width of the row header. propertyId = ROW_HEADER_FAKE_PROPERTY_ID; } + + // Setting column width should remove any expand ratios as well + columnExpandRatios.remove(propertyId); + if (width < 0) { columnWidths.remove(propertyId); } else { - columnWidths.put(propertyId, Integer.valueOf(width)); + columnWidths.put(propertyId, width); } markAsDirty(); } @@ -930,21 +938,39 @@ public class Table extends AbstractSelect implements Action.Container, * the expandRatio used to divide excess space for this column */ public void setColumnExpandRatio(Object propertyId, float expandRatio) { + if (propertyId == null) { + // Since propertyId is null, this is the row header. Use the magic + // id to store the width of the row header. + propertyId = ROW_HEADER_FAKE_PROPERTY_ID; + } + + // Setting the column expand ratio should remove and defined column + // width + columnWidths.remove(propertyId); + if (expandRatio < 0) { - columnWidths.remove(propertyId); + columnExpandRatios.remove(propertyId); } else { - columnWidths.put(propertyId, new Float(expandRatio)); + columnExpandRatios.put(propertyId, expandRatio); } + + requestRepaint(); } + /** + * Gets the column expand ratio for a columnd. See + * {@link #setColumnExpandRatio(Object, float)} + * + * @param propertyId + * columns property id + * @return the expandRatio used to divide excess space for this column + */ public float getColumnExpandRatio(Object propertyId) { - final Object width = columnWidths.get(propertyId); - if (width == null || !(width instanceof Float)) { + final Float width = columnExpandRatios.get(propertyId); + if (width == null) { return -1; } - final Float value = (Float) width; - return value.floatValue(); - + return width.floatValue(); } /** @@ -959,12 +985,11 @@ public class Table extends AbstractSelect implements Action.Container, // id to retrieve the width of the row header. propertyId = ROW_HEADER_FAKE_PROPERTY_ID; } - final Object width = columnWidths.get(propertyId); - if (width == null || !(width instanceof Integer)) { + final Integer width = columnWidths.get(propertyId); + if (width == null) { return -1; } - final Integer value = (Integer) width; - return value.intValue(); + return width.intValue(); } /** @@ -3434,6 +3459,7 @@ public class Table extends AbstractSelect implements Action.Container, target.startTag("column"); target.addAttribute("cid", ROW_HEADER_COLUMN_KEY); paintColumnWidth(target, ROW_HEADER_FAKE_PROPERTY_ID); + paintColumnExpandRatio(target, ROW_HEADER_FAKE_PROPERTY_ID); target.endTag("column"); } final Collection<?> sortables = getSortableContainerPropertyIds(); @@ -3461,6 +3487,7 @@ public class Table extends AbstractSelect implements Action.Container, .toString()); } paintColumnWidth(target, colId); + paintColumnExpandRatio(target, colId); target.endTag("column"); } } @@ -3706,12 +3733,14 @@ public class Table extends AbstractSelect implements Action.Container, private void paintColumnWidth(PaintTarget target, final Object columnId) throws PaintException { if (columnWidths.containsKey(columnId)) { - if (getColumnWidth(columnId) > -1) { - target.addAttribute("width", - String.valueOf(getColumnWidth(columnId))); - } else { - target.addAttribute("er", getColumnExpandRatio(columnId)); - } + target.addAttribute("width", getColumnWidth(columnId)); + } + } + + private void paintColumnExpandRatio(PaintTarget target, + final Object columnId) throws PaintException { + if (columnExpandRatios.containsKey(columnId)) { + target.addAttribute("er", getColumnExpandRatio(columnId)); } } diff --git a/server/src/com/vaadin/ui/UI.java b/server/src/com/vaadin/ui/UI.java index d12c8d89c9..796d1f08ea 100644 --- a/server/src/com/vaadin/ui/UI.java +++ b/server/src/com/vaadin/ui/UI.java @@ -78,7 +78,7 @@ import com.vaadin.util.CurrentInstance; * @since 7.0 */ public abstract class UI extends AbstractSingleComponentContainer implements - Action.Container, Action.Notifier, LegacyComponent { + Action.Container, Action.Notifier, LegacyComponent, Focusable { /** * The application to which this UI belongs @@ -184,6 +184,11 @@ public abstract class UI extends AbstractSingleComponentContainer implements } @Override + protected UIState getState(boolean markAsDirty) { + return (UIState) super.getState(markAsDirty); + } + + @Override public Class<? extends UIState> getStateType() { // This is a workaround for a problem with creating the correct state // object during build @@ -1039,4 +1044,14 @@ public abstract class UI extends AbstractSingleComponentContainer implements } super.setContent(content); } + + @Override + public void setTabIndex(int tabIndex) { + getState().tabIndex = tabIndex; + } + + @Override + public int getTabIndex() { + return getState(false).tabIndex; + } } |