diff options
Diffstat (limited to 'server')
13 files changed, 373 insertions, 160 deletions
diff --git a/server/src/com/vaadin/data/util/sqlcontainer/SQLContainer.java b/server/src/com/vaadin/data/util/sqlcontainer/SQLContainer.java index f7f3e73a7f..64c16b2798 100644 --- a/server/src/com/vaadin/data/util/sqlcontainer/SQLContainer.java +++ b/server/src/com/vaadin/data/util/sqlcontainer/SQLContainer.java @@ -1116,7 +1116,7 @@ public class SQLContainer implements Container, Container.Filterable, delegate.setOrderBy(sorters); } catch (UnsupportedOperationException e) { getLogger().log(Level.FINE, - "The query delegate doesn't support filtering", e); + "The query delegate doesn't support sorting", e); } int newSize = delegate.getCount(); sizeUpdated = new Date(); @@ -1127,7 +1127,7 @@ public class SQLContainer implements Container, Container.Filterable, refresh(false); } getLogger().log(Level.FINER, - "Updated row count. New count is: " + size); + "Updated row count. New count is: {0}", size); } catch (SQLException e) { throw new RuntimeException("Failed to update item set size.", e); } @@ -1249,7 +1249,8 @@ public class SQLContainer implements Container, Container.Filterable, "The query delegate doesn't support sorting", e); } delegate.beginTransaction(); - rs = delegate.getResults(currentOffset, pageLength * CACHE_RATIO); + int fetchedRows = pageLength * CACHE_RATIO; + rs = delegate.getResults(currentOffset, fetchedRows); rsmd = rs.getMetaData(); List<String> pKeys = delegate.getPrimaryKeyColumns(); // } @@ -1330,10 +1331,8 @@ public class SQLContainer implements Container, Container.Filterable, rs.getStatement().close(); rs.close(); delegate.commit(); - getLogger().log( - Level.FINER, - "Fetched " + pageLength * CACHE_RATIO - + " rows starting from " + currentOffset); + getLogger().log(Level.FINER, "Fetched {0} rows starting from {1}", + new Object[] { fetchedRows, currentOffset }); } catch (SQLException e) { getLogger().log(Level.WARNING, "Failed to fetch rows, rolling back", e); 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 2b539ecf99..299183f5e6 100644 --- a/server/src/com/vaadin/data/util/sqlcontainer/query/FreeformQuery.java +++ b/server/src/com/vaadin/data/util/sqlcontainer/query/FreeformQuery.java @@ -117,20 +117,23 @@ public class FreeformQuery implements QueryDelegate { int count = countByDelegate(); if (count < 0) { // Couldn't use the delegate, use the bad way. + Statement statement = null; + ResultSet rs = null; Connection conn = getConnection(); - Statement statement = conn.createStatement( - ResultSet.TYPE_SCROLL_INSENSITIVE, - ResultSet.CONCUR_READ_ONLY); + try { + statement = conn.createStatement( + ResultSet.TYPE_SCROLL_INSENSITIVE, + ResultSet.CONCUR_READ_ONLY); - ResultSet rs = statement.executeQuery(queryString); - if (rs.last()) { - count = rs.getRow(); - } else { - count = 0; + rs = statement.executeQuery(queryString); + if (rs.last()) { + count = rs.getRow(); + } else { + count = 0; + } + } finally { + releaseConnection(conn, statement, rs); } - rs.close(); - statement.close(); - releaseConnection(conn); } return count; } @@ -146,17 +149,18 @@ public class FreeformQuery implements QueryDelegate { try { StatementHelper sh = ((FreeformStatementDelegate) delegate) .getCountStatement(); + PreparedStatement pstmt = null; + ResultSet rs = null; Connection c = getConnection(); - PreparedStatement pstmt = c.prepareStatement(sh - .getQueryString()); - sh.setParameterValuesToStatement(pstmt); - ResultSet rs = pstmt.executeQuery(); - rs.next(); - count = rs.getInt(1); - rs.close(); - pstmt.clearParameters(); - pstmt.close(); - releaseConnection(c); + try { + pstmt = c.prepareStatement(sh.getQueryString()); + sh.setParameterValuesToStatement(pstmt); + rs = pstmt.executeQuery(); + rs.next(); + count = rs.getInt(1); + } finally { + releaseConnection(c, pstmt, rs); + } return count; } catch (UnsupportedOperationException e) { // Count statement generation not supported @@ -166,15 +170,18 @@ public class FreeformQuery implements QueryDelegate { try { String countQuery = delegate.getCountQuery(); if (countQuery != null) { + Statement statement = null; + ResultSet rs = null; Connection conn = getConnection(); - Statement statement = conn.createStatement(); - ResultSet rs = statement.executeQuery(countQuery); - rs.next(); - count = rs.getInt(1); - rs.close(); - statement.close(); - releaseConnection(conn); - return count; + try { + statement = conn.createStatement(); + rs = statement.executeQuery(countQuery); + rs.next(); + count = rs.getInt(1); + return count; + } finally { + releaseConnection(conn, statement, rs); + } } } catch (UnsupportedOperationException e) { // Count query generation not supported @@ -201,7 +208,7 @@ public class FreeformQuery implements QueryDelegate { * @see FreeformQueryDelegate#getQueryString(int, int) */ @Override - @SuppressWarnings("deprecation") + @SuppressWarnings({ "deprecation", "finally" }) public ResultSet getResults(int offset, int pagelength) throws SQLException { if (activeConnection == null) { throw new SQLException("No active transaction!"); @@ -228,7 +235,18 @@ public class FreeformQuery implements QueryDelegate { } } Statement statement = activeConnection.createStatement(); - ResultSet rs = statement.executeQuery(query); + ResultSet rs; + try { + rs = statement.executeQuery(query); + } catch (SQLException e) { + try { + statement.close(); + } finally { + // throw the original exception even if closing the statement + // fails + throw e; + } + } return rs; } @@ -436,17 +454,19 @@ public class FreeformQuery implements QueryDelegate { try { StatementHelper sh = ((FreeformStatementDelegate) delegate) .getContainsRowQueryStatement(keys); + + PreparedStatement pstmt = null; + ResultSet rs = null; Connection c = getConnection(); - PreparedStatement pstmt = c.prepareStatement(sh - .getQueryString()); - sh.setParameterValuesToStatement(pstmt); - ResultSet rs = pstmt.executeQuery(); - contains = rs.next(); - rs.close(); - pstmt.clearParameters(); - pstmt.close(); - releaseConnection(c); - return contains; + try { + pstmt = c.prepareStatement(sh.getQueryString()); + sh.setParameterValuesToStatement(pstmt); + rs = pstmt.executeQuery(); + contains = rs.next(); + return contains; + } finally { + releaseConnection(c, pstmt, rs); + } } catch (UnsupportedOperationException e) { // Statement generation not supported, continue... } @@ -459,15 +479,15 @@ public class FreeformQuery implements QueryDelegate { } else { query = modifyWhereClause(keys); } + Statement statement = null; + ResultSet rs = null; Connection conn = getConnection(); try { - Statement statement = conn.createStatement(); - ResultSet rs = statement.executeQuery(query); + statement = conn.createStatement(); + rs = statement.executeQuery(query); contains = rs.next(); - rs.close(); - statement.close(); } finally { - releaseConnection(conn); + releaseConnection(conn, statement, rs); } return contains; } @@ -484,6 +504,54 @@ public class FreeformQuery implements QueryDelegate { } } + /** + * 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 246384ee57..4d60a8cc17 100644 --- a/server/src/com/vaadin/data/util/sqlcontainer/query/TableQuery.java +++ b/server/src/com/vaadin/data/util/sqlcontainer/query/TableQuery.java @@ -159,7 +159,9 @@ public class TableQuery implements QueryDelegate, */ if (orderBys == null || orderBys.isEmpty()) { List<OrderBy> ob = new ArrayList<OrderBy>(); - ob.add(new OrderBy(primaryKeyColumns.get(0), true)); + for (int i = 0; i < primaryKeyColumns.size(); i++) { + ob.add(new OrderBy(primaryKeyColumns.get(i), true)); + } sh = sqlGenerator.generateSelectQuery(tableName, filters, ob, offset, pagelength, null); } else { @@ -241,7 +243,7 @@ public class TableQuery implements QueryDelegate, PreparedStatement pstmt = activeConnection.prepareStatement( sh.getQueryString(), primaryKeyColumns.toArray(new String[0])); sh.setParameterValuesToStatement(pstmt); - getLogger().log(Level.FINE, "DB -> " + sh.getQueryString()); + getLogger().log(Level.FINE, "DB -> {0}", sh.getQueryString()); int result = pstmt.executeUpdate(); if (result > 0) { /* @@ -408,7 +410,7 @@ public class TableQuery implements QueryDelegate, } PreparedStatement pstmt = c.prepareStatement(sh.getQueryString()); sh.setParameterValuesToStatement(pstmt); - getLogger().log(Level.FINE, "DB -> " + sh.getQueryString()); + getLogger().log(Level.FINE, "DB -> {0}", sh.getQueryString()); return pstmt.executeQuery(); } @@ -434,7 +436,7 @@ public class TableQuery implements QueryDelegate, } pstmt = c.prepareStatement(sh.getQueryString()); sh.setParameterValuesToStatement(pstmt); - getLogger().log(Level.FINE, "DB -> " + sh.getQueryString()); + getLogger().log(Level.FINE, "DB -> {0}", sh.getQueryString()); int retval = pstmt.executeUpdate(); return retval; } finally { @@ -477,7 +479,7 @@ public class TableQuery implements QueryDelegate, pstmt = c.prepareStatement(sh.getQueryString(), primaryKeyColumns.toArray(new String[0])); sh.setParameterValuesToStatement(pstmt); - getLogger().log(Level.FINE, "DB -> " + sh.getQueryString()); + getLogger().log(Level.FINE, "DB -> {0}", sh.getQueryString()); int result = pstmt.executeUpdate(); genKeys = pstmt.getGeneratedKeys(); RowId newId = getNewRowId(row, genKeys); @@ -590,8 +592,10 @@ public class TableQuery implements QueryDelegate, } return new RowId(newRowId.toArray()); } catch (Exception e) { - getLogger().log(Level.FINE, - "Failed to fetch key values on insert: " + e.getMessage()); + getLogger() + .log(Level.FINE, + "Failed to fetch key values on insert: {0}", + e.getMessage()); return null; } } @@ -606,8 +610,8 @@ public class TableQuery implements QueryDelegate, @Override public boolean removeRow(RowItem row) throws UnsupportedOperationException, SQLException { - getLogger().log(Level.FINE, - "Removing row with id: " + row.getId().getId()[0].toString()); + getLogger().log(Level.FINE, "Removing row with id: {0}", + row.getId().getId()[0].toString()); if (executeUpdate(sqlGenerator.generateDeleteQuery(getTableName(), primaryKeyColumns, versionColumn, row)) == 1) { return true; diff --git a/server/src/com/vaadin/event/ListenerMethod.java b/server/src/com/vaadin/event/ListenerMethod.java index 16a8121901..a0ecdc4769 100644 --- a/server/src/com/vaadin/event/ListenerMethod.java +++ b/server/src/com/vaadin/event/ListenerMethod.java @@ -91,10 +91,10 @@ public class ListenerMethod implements EventListener, Serializable { out.writeObject(name); out.writeObject(paramTypes); } catch (NotSerializableException e) { - getLogger().warning( - "Error in serialization of the application: Class " - + target.getClass().getName() - + " must implement serialization."); + getLogger() + .log(Level.WARNING, + "Error in serialization of the application: Class {0} must implement serialization.", + target.getClass().getName()); throw e; } diff --git a/server/src/com/vaadin/server/AbstractCommunicationManager.java b/server/src/com/vaadin/server/AbstractCommunicationManager.java index c676cb2ce3..c1c18901b4 100644 --- a/server/src/com/vaadin/server/AbstractCommunicationManager.java +++ b/server/src/com/vaadin/server/AbstractCommunicationManager.java @@ -186,7 +186,7 @@ public abstract class AbstractCommunicationManager implements Serializable { private static final String CRLF = "\r\n"; - private static final String UTF8 = "UTF8"; + private static final String UTF8 = "UTF-8"; private static String readLine(InputStream stream) throws IOException { ByteArrayOutputStream bout = new ByteArrayOutputStream(); @@ -234,14 +234,14 @@ public abstract class AbstractCommunicationManager implements Serializable { */ while (!atStart) { String readLine = readLine(inputStream); - contentLength -= (readLine.length() + 2); + contentLength -= (readLine.getBytes(UTF8).length + CRLF.length()); if (readLine.startsWith("Content-Disposition:") && readLine.indexOf("filename=") > 0) { rawfilename = readLine.replaceAll(".*filename=", ""); - String parenthesis = rawfilename.substring(0, 1); + char quote = rawfilename.charAt(0); rawfilename = rawfilename.substring(1); rawfilename = rawfilename.substring(0, - rawfilename.indexOf(parenthesis)); + rawfilename.indexOf(quote)); firstFileFieldFound = true; } else if (firstFileFieldFound && readLine.equals("")) { atStart = true; @@ -251,7 +251,7 @@ public abstract class AbstractCommunicationManager implements Serializable { } contentLength -= (boundary.length() + CRLF.length() + 2 - * DASHDASH.length() + 2); // 2 == CRLF + * DASHDASH.length() + CRLF.length()); /* * Reads bytes from the underlying stream. Compares the read bytes to diff --git a/server/src/com/vaadin/server/VaadinPortletService.java b/server/src/com/vaadin/server/VaadinPortletService.java index e59ea7fd5e..8c1e7af0fa 100644 --- a/server/src/com/vaadin/server/VaadinPortletService.java +++ b/server/src/com/vaadin/server/VaadinPortletService.java @@ -46,7 +46,12 @@ public class VaadinPortletService extends VaadinService { } } - protected VaadinPortlet getPortlet() { + /** + * Retrieves a reference to the portlet associated with this service. + * + * @return A reference to the VaadinPortlet this service is using + */ + public VaadinPortlet getPortlet() { return portlet; } diff --git a/server/src/com/vaadin/server/VaadinServletService.java b/server/src/com/vaadin/server/VaadinServletService.java index 71f47ea217..7120e3a5c5 100644 --- a/server/src/com/vaadin/server/VaadinServletService.java +++ b/server/src/com/vaadin/server/VaadinServletService.java @@ -44,7 +44,12 @@ public class VaadinServletService extends VaadinService { } } - protected VaadinServlet getServlet() { + /** + * Retrieves a reference to the servlet associated with this service. + * + * @return A reference to the VaadinServlet this service is using + */ + public VaadinServlet getServlet() { return servlet; } diff --git a/server/src/com/vaadin/server/WebBrowser.java b/server/src/com/vaadin/server/WebBrowser.java index ca0e4cd6ce..4122f053ae 100644 --- a/server/src/com/vaadin/server/WebBrowser.java +++ b/server/src/com/vaadin/server/WebBrowser.java @@ -293,19 +293,19 @@ public class WebBrowser implements Serializable { } /** - * Gets the difference in minutes between the browser's GMT TimeZone and + * Returns the offset in milliseconds between the browser's GMT TimeZone and * DST. * - * @return the amount of minutes that the TimeZone shifts when DST is in - * effect + * @return the number of milliseconds that the TimeZone shifts when DST is + * in effect */ public int getDSTSavings() { return dstSavings; } /** - * Determines whether daylight savings time (DST) is currently in effect in - * the region of the browser or not. + * Returns whether daylight saving time (DST) is currently in effect in the + * region of the browser or not. * * @return true if the browser resides at a location that currently is in * DST diff --git a/server/src/com/vaadin/ui/AbstractField.java b/server/src/com/vaadin/ui/AbstractField.java index 422e0a1796..619d717d97 100644 --- a/server/src/com/vaadin/ui/AbstractField.java +++ b/server/src/com/vaadin/ui/AbstractField.java @@ -373,30 +373,6 @@ public abstract class AbstractField<T> extends AbstractComponent implements /* Property interface implementation */ /** - * Returns the (field) value converted to a String using toString(). - * - * @see java.lang.Object#toString() - * @deprecated As of 7.0, use {@link #getValue()} to get the value of the - * field, {@link #getConvertedValue()} to get the field value - * converted to the data model type or - * {@link #getPropertyDataSource()} .getValue() to get the value - * of the data source. - */ - @Deprecated - @Override - public String toString() { - logger.warning("You are using AbstractField.toString() to get the value for a " - + getClass().getSimpleName() - + ". This will not be supported starting from Vaadin 7.1 " - + "(your debugger might call toString() and cause this message to appear)."); - final Object value = getFieldValue(); - if (value == null) { - return null; - } - return value.toString(); - } - - /** * Gets the current value of the field. * * <p> diff --git a/server/src/com/vaadin/ui/Label.java b/server/src/com/vaadin/ui/Label.java index f49a1403cf..f413ea47f2 100644 --- a/server/src/com/vaadin/ui/Label.java +++ b/server/src/com/vaadin/ui/Label.java @@ -203,23 +203,6 @@ public class Label extends AbstractComponent implements Property<String>, } /** - * Returns the value displayed by this label. - * - * @see java.lang.Object#toString() - * @deprecated As of 7.0, use {@link #getValue()} to get the value of the - * label or {@link #getPropertyDataSource()} .getValue() to get - * the value of the data source. - */ - @Deprecated - @Override - public String toString() { - logger.warning("You are using Label.toString() to get the value for a " - + getClass().getSimpleName() - + ". This will not be supported starting from Vaadin 7.1 (your debugger might call toString() and cause this message to appear)."); - return getValue(); - } - - /** * Gets the type of the Property. * * @see com.vaadin.data.Property#getType() diff --git a/server/src/com/vaadin/ui/Table.java b/server/src/com/vaadin/ui/Table.java index e73c6d7188..a9632da038 100644 --- a/server/src/com/vaadin/ui/Table.java +++ b/server/src/com/vaadin/ui/Table.java @@ -557,6 +557,8 @@ public class Table extends AbstractSelect implements Action.Container, */ private boolean keyMapperReset; + private List<Throwable> exceptionsDuringCachePopulation = new ArrayList<Throwable>(); + /* Table constructors */ /** @@ -1646,6 +1648,66 @@ public class Table extends AbstractSelect implements Action.Container, setRowCacheInvalidated(true); markAsDirty(); + maybeThrowCacheUpdateExceptions(); + + } + + private void maybeThrowCacheUpdateExceptions() { + if (!exceptionsDuringCachePopulation.isEmpty()) { + Throwable[] causes = new Throwable[exceptionsDuringCachePopulation + .size()]; + exceptionsDuringCachePopulation.toArray(causes); + + exceptionsDuringCachePopulation.clear(); + throw new CacheUpdateException(this, + "Error during Table cache update.", causes); + } + + } + + /** + * Exception thrown when one or more exceptions occurred during updating of + * the Table cache. + * <p> + * Contains all exceptions which occurred during the cache update. The first + * occurred exception is set as the cause of this exception. All occurred + * exceptions can be accessed using {@link #getCauses()}. + * </p> + * + */ + public static class CacheUpdateException extends RuntimeException { + private Throwable[] causes; + private Table table; + + public CacheUpdateException(Table table, String message, + Throwable[] causes) { + super(maybeSupplementMessage(message, causes.length), causes[0]); + this.table = table; + this.causes = causes; + } + + private static String maybeSupplementMessage(String message, + int causeCount) { + if (causeCount > 1) { + return message + " Additional causes not shown."; + } else { + return message; + } + } + + /** + * Returns the cause(s) for this exception + * + * @return the exception(s) which caused this exception + */ + public Throwable[] getCauses() { + return causes; + } + + public Table getTable() { + return table; + } + } /** @@ -1789,9 +1851,10 @@ public class Table extends AbstractSelect implements Action.Container, * @return */ private Object[][] getVisibleCellsInsertIntoCache(int firstIndex, int rows) { - getLogger().finest( - "Insert " + rows + " rows at index " + firstIndex - + " to existing page buffer requested"); + getLogger() + .log(Level.FINEST, + "Insert {0} rows at index {1} to existing page buffer requested", + new Object[] { rows, firstIndex }); // Page buffer must not become larger than pageLength*cacheRate before // or after the current page @@ -1894,14 +1957,16 @@ public class Table extends AbstractSelect implements Action.Container, } } pageBuffer = newPageBuffer; - getLogger().finest( - "Page Buffer now contains " - + pageBuffer[CELL_ITEMID].length - + " rows (" - + pageBufferFirstIndex - + "-" - + (pageBufferFirstIndex - + pageBuffer[CELL_ITEMID].length - 1) + ")"); + if (getLogger().isLoggable(Level.FINEST)) { + getLogger().log( + Level.FINEST, + "Page Buffer now contains {0} rows ({1}-{2})", + new Object[] { + pageBuffer[CELL_ITEMID].length, + pageBufferFirstIndex, + (pageBufferFirstIndex + + pageBuffer[CELL_ITEMID].length - 1) }); + } return cells; } @@ -1918,9 +1983,11 @@ public class Table extends AbstractSelect implements Action.Container, */ private Object[][] getVisibleCellsNoCache(int firstIndex, int rows, boolean replaceListeners) { - getLogger().finest( - "Render visible cells for rows " + firstIndex + "-" - + (firstIndex + rows - 1)); + if (getLogger().isLoggable(Level.FINEST)) { + getLogger().log(Level.FINEST, + "Render visible cells for rows {0}-{1}", + new Object[] { firstIndex, (firstIndex + rows - 1) }); + } final Object[] colids = getVisibleColumns(); final int cols = colids.length; @@ -2036,9 +2103,19 @@ public class Table extends AbstractSelect implements Action.Container, cells[CELL_HEADER][i] = String.valueOf(i + firstIndex + 1); break; default: - cells[CELL_HEADER][i] = getItemCaption(id); + try { + cells[CELL_HEADER][i] = getItemCaption(id); + } catch (Exception e) { + exceptionsDuringCachePopulation.add(e); + cells[CELL_HEADER][i] = ""; + } + } + try { + cells[CELL_ICON][i] = getItemIcon(id); + } catch (Exception e) { + exceptionsDuringCachePopulation.add(e); + cells[CELL_ICON][i] = null; } - cells[CELL_ICON][i] = getItemIcon(id); } GeneratedRow generatedRow = rowGenerator != null ? rowGenerator @@ -2056,7 +2133,12 @@ public class Table extends AbstractSelect implements Action.Container, boolean isGenerated = isGeneratedRow || isGeneratedColumn; if (!isGenerated) { - p = getContainerProperty(id, colids[j]); + try { + p = getContainerProperty(id, colids[j]); + } catch (Exception e) { + exceptionsDuringCachePopulation.add(e); + value = null; + } } if (isGeneratedRow) { @@ -2089,7 +2171,12 @@ public class Table extends AbstractSelect implements Action.Container, if (isGeneratedColumn) { ColumnGenerator cg = columnGenerators .get(colids[j]); - value = cg.generateCell(this, id, colids[j]); + try { + value = cg.generateCell(this, id, colids[j]); + } catch (Exception e) { + exceptionsDuringCachePopulation.add(e); + value = null; + } if (value != null && !(value instanceof Component) && !(value instanceof String)) { // Avoid errors if a generator returns @@ -2098,10 +2185,20 @@ public class Table extends AbstractSelect implements Action.Container, value = value.toString(); } } else if (iscomponent[j]) { - value = p.getValue(); + try { + value = p.getValue(); + } catch (Exception e) { + exceptionsDuringCachePopulation.add(e); + value = null; + } listenProperty(p, oldListenedProperties); } else if (p != null) { - value = getPropertyValue(id, colids[j], p); + try { + value = getPropertyValue(id, colids[j], p); + } catch (Exception e) { + exceptionsDuringCachePopulation.add(e); + value = null; + } /* * If returned value is Component (via fieldfactory * or overridden getPropertyValue) we expect it to @@ -2114,7 +2211,12 @@ public class Table extends AbstractSelect implements Action.Container, listenProperty(p, oldListenedProperties); } } else { - value = getPropertyValue(id, colids[j], null); + try { + value = getPropertyValue(id, colids[j], null); + } catch (Exception e) { + exceptionsDuringCachePopulation.add(e); + value = null; + } } } } @@ -2128,9 +2230,11 @@ public class Table extends AbstractSelect implements Action.Container, } protected void registerComponent(Component component) { - getLogger().finest( - "Registered " + component.getClass().getSimpleName() + ": " - + component.getCaption()); + getLogger().log( + Level.FINEST, + "Registered {0}: {1}", + new Object[] { component.getClass().getSimpleName(), + component.getCaption() }); if (component.getParent() != this) { component.setParent(this); } @@ -2161,9 +2265,11 @@ public class Table extends AbstractSelect implements Action.Container, * @param count */ private void unregisterComponentsAndPropertiesInRows(int firstIx, int count) { - getLogger().finest( - "Unregistering components in rows " + firstIx + "-" - + (firstIx + count - 1)); + if (getLogger().isLoggable(Level.FINEST)) { + getLogger().log(Level.FINEST, + "Unregistering components in rows {0}-{1}", + new Object[] { firstIx, (firstIx + count - 1) }); + } Object[] colids = getVisibleColumns(); if (pageBuffer != null && pageBuffer[CELL_ITEMID].length > 0) { int bufSize = pageBuffer[CELL_ITEMID].length; @@ -2243,9 +2349,11 @@ public class Table extends AbstractSelect implements Action.Container, * a set of components that should be unregistered. */ protected void unregisterComponent(Component component) { - getLogger().finest( - "Unregistered " + component.getClass().getSimpleName() + ": " - + component.getCaption()); + getLogger().log( + Level.FINEST, + "Unregistered {0}: {1}", + new Object[] { component.getClass().getSimpleName(), + component.getCaption() }); component.setParent(null); /* * Also remove property data sources to unregister listeners keeping the @@ -2679,9 +2787,13 @@ public class Table extends AbstractSelect implements Action.Container, } } } - getLogger().finest( - "Client wants rows " + reqFirstRowToPaint + "-" - + (reqFirstRowToPaint + reqRowsToPaint - 1)); + if (getLogger().isLoggable(Level.FINEST)) { + getLogger().log( + Level.FINEST, + "Client wants rows {0}-{1}", + new Object[] { reqFirstRowToPaint, + (reqFirstRowToPaint + reqRowsToPaint - 1) }); + } clientNeedsContentRefresh = true; } @@ -3049,6 +3161,7 @@ public class Table extends AbstractSelect implements Action.Container, indexInRowbuffer, itemId); } target.endTag("urows"); + maybeThrowCacheUpdateExceptions(); } private void paintPartialRowAdditions(PaintTarget target, @@ -3061,9 +3174,9 @@ public class Table extends AbstractSelect implements Action.Container, target.startTag("prows"); if (!shouldHideAddedRows()) { - getLogger().finest( - "Paint rows for add. Index: " + firstIx + ", count: " - + count + "."); + getLogger().log(Level.FINEST, + "Paint rows for add. Index: {0}, count: {1}.", + new Object[] { firstIx, count }); // Partial row additions bypass the normal caching mechanism. Object[][] cells = getVisibleCellsInsertIntoCache(firstIx, count); @@ -3086,9 +3199,9 @@ public class Table extends AbstractSelect implements Action.Container, indexInRowbuffer, itemId); } } else { - getLogger().finest( - "Paint rows for remove. Index: " + firstIx + ", count: " - + count + "."); + getLogger().log(Level.FINEST, + "Paint rows for remove. Index: {0}, count: {1}.", + new Object[] { firstIx, count }); removeRowsFromCacheAndFillBottom(firstIx, count); target.addAttribute("hide", true); } @@ -3096,6 +3209,7 @@ public class Table extends AbstractSelect implements Action.Container, target.addAttribute("firstprowix", firstIx); target.addAttribute("numprows", count); target.endTag("prows"); + maybeThrowCacheUpdateExceptions(); } /** diff --git a/server/src/com/vaadin/ui/TreeTable.java b/server/src/com/vaadin/ui/TreeTable.java index b5c026c9df..e150db9423 100644 --- a/server/src/com/vaadin/ui/TreeTable.java +++ b/server/src/com/vaadin/ui/TreeTable.java @@ -23,6 +23,7 @@ import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.logging.Level; import java.util.logging.Logger; import com.vaadin.data.Collapsible; @@ -252,9 +253,11 @@ public class TreeTable extends Table implements Hierarchical { boolean removed = openItems.remove(itemId); if (!removed) { openItems.add(itemId); - getLogger().finest("Item " + itemId + " is now expanded"); + getLogger().log(Level.FINEST, "Item {0} is now expanded", + itemId); } else { - getLogger().finest("Item " + itemId + " is now collapsed"); + getLogger().log(Level.FINEST, "Item {0} is now collapsed", + itemId); } clearPreorderCache(); } diff --git a/server/tests/src/com/vaadin/tests/server/component/table/CacheUpdateExceptionCauses.java b/server/tests/src/com/vaadin/tests/server/component/table/CacheUpdateExceptionCauses.java new file mode 100644 index 0000000000..7a7b488bc0 --- /dev/null +++ b/server/tests/src/com/vaadin/tests/server/component/table/CacheUpdateExceptionCauses.java @@ -0,0 +1,56 @@ +/* + * Copyright 2012 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.tests.server.component.table; + +import junit.framework.Assert; + +import org.junit.Test; + +import com.vaadin.ui.Table; +import com.vaadin.ui.Table.CacheUpdateException; + +public class CacheUpdateExceptionCauses { + @Test + public void testSingleCauseException() { + Table table = new Table(); + Throwable[] causes = new Throwable[] { new RuntimeException( + "Broken in one way.") }; + + CacheUpdateException exception = new CacheUpdateException(table, + "Error during Table cache update.", causes); + + Assert.assertSame(causes[0], exception.getCause()); + Assert.assertEquals("Error during Table cache update.", + exception.getMessage()); + } + + @Test + public void testMultipleCauseException() { + Table table = new Table(); + Throwable[] causes = new Throwable[] { + new RuntimeException("Broken in the first way."), + new RuntimeException("Broken in the second way.") }; + + CacheUpdateException exception = new CacheUpdateException(table, + "Error during Table cache update.", causes); + + Assert.assertSame(causes[0], exception.getCause()); + Assert.assertEquals( + "Error during Table cache update. Additional causes not shown.", + exception.getMessage()); + } +} |