Browse Source

Merge of (#10312) to Vaadin 7.

Cache update exception handling to Table.

Change-Id: I882e78c3a2eb1ceaab484be748b6890ee321c290
tags/7.0.1
Anna Koskinen 11 years ago
parent
commit
7c5aec1e34

+ 95
- 7
server/src/com/vaadin/ui/Table.java View File

@@ -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,55 @@ 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.
* </p>
*
*/
public static class CacheUpdateException extends RuntimeException {
private Throwable[] causes;
private Table table;

public CacheUpdateException(Table table, String message,
Throwable[] causes) {
super(message);
this.table = table;
this.causes = causes;
}

/**
* 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;
}

}

/**
@@ -2036,9 +2087,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 +2117,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 +2155,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 +2169,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 +2195,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;
}
}
}
}
@@ -3049,6 +3135,7 @@ public class Table extends AbstractSelect implements Action.Container,
indexInRowbuffer, itemId);
}
target.endTag("urows");
maybeThrowCacheUpdateExceptions();
}

private void paintPartialRowAdditions(PaintTarget target,
@@ -3096,6 +3183,7 @@ public class Table extends AbstractSelect implements Action.Container,
target.addAttribute("firstprowix", firstIx);
target.addAttribute("numprows", count);
target.endTag("prows");
maybeThrowCacheUpdateExceptions();
}

/**

+ 178
- 0
uitest/src/com/vaadin/tests/components/table/TableWithBrokenGeneratorAndContainer.html View File

@@ -0,0 +1,178 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head profile="http://selenium-ide.openqa.org/profiles/test-case">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<link rel="selenium.base" href="http://localhost:9999/" />
<title>TableWithBrokenGeneratorAndContainer</title>
</head>
<body>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">TableWithBrokenGeneratorAndContainer</td></tr>
</thead><tbody>
<tr>
<td>open</td>
<td>/run/com.vaadin.tests.components.table.TableWithBrokenGeneratorAndContainer?restartApplication</td>
<td></td>
</tr>
<tr>
<td>assertText</td>
<td>vaadin=runcomvaadintestscomponentstableTableWithBrokenGeneratorAndContainer::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[4]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]/domChild[0]/domChild[0]</td>
<td>item1/prop1</td>
</tr>
<tr>
<td>assertText</td>
<td>vaadin=runcomvaadintestscomponentstableTableWithBrokenGeneratorAndContainer::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[4]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]</td>
<td>item2/prop1</td>
</tr>
<tr>
<td>assertText</td>
<td>vaadin=runcomvaadintestscomponentstableTableWithBrokenGeneratorAndContainer::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[4]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[2]/domChild[0]/domChild[0]</td>
<td>item3/prop1</td>
</tr>
<tr>
<td>assertText</td>
<td>vaadin=runcomvaadintestscomponentstableTableWithBrokenGeneratorAndContainer::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[4]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]/domChild[4]/domChild[0]</td>
<td>Generated item1/Gen</td>
</tr>
<tr>
<td>assertText</td>
<td>vaadin=runcomvaadintestscomponentstableTableWithBrokenGeneratorAndContainer::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[4]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[1]/domChild[4]/domChild[0]</td>
<td>Generated item2/Gen</td>
</tr>
<tr>
<td>assertText</td>
<td>vaadin=runcomvaadintestscomponentstableTableWithBrokenGeneratorAndContainer::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[4]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[2]/domChild[4]/domChild[0]</td>
<td>Generated item3/Gen</td>
</tr>
<tr>
<td>mouseClick</td>
<td>vaadin=runcomvaadintestscomponentstableTableWithBrokenGeneratorAndContainer::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VCheckBox[0]/domChild[0]</td>
<td>12,6</td>
</tr>
<tr>
<td>click</td>
<td>vaadin=runcomvaadintestscomponentstableTableWithBrokenGeneratorAndContainer::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VButton[0]/domChild[0]/domChild[0]</td>
<td></td>
</tr>
<!--error indicator should be present-->
<tr>
<td>assertCSSClass</td>
<td>vaadin=runcomvaadintestscomponentstableTableWithBrokenGeneratorAndContainer::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VButton[0]/domChild[0]/domChild[0]</td>
<td>v-errorindicator</td>
</tr>
<!--error notification should not be present-->
<tr>
<td>assertElementNotPresent</td>
<td>vaadin=runcomvaadintestscomponentstableTableWithBrokenGeneratorAndContainer::Root/VNotification[0]</td>
<td></td>
</tr>
<tr>
<td>assertText</td>
<td>vaadin=runcomvaadintestscomponentstableTableWithBrokenGeneratorAndContainer::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[4]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]/domChild[0]/domChild[0]</td>
<td></td>
</tr>
<tr>
<td>assertText</td>
<td>vaadin=runcomvaadintestscomponentstableTableWithBrokenGeneratorAndContainer::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[4]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]</td>
<td>item2/prop1</td>
</tr>
<tr>
<td>assertText</td>
<td>vaadin=runcomvaadintestscomponentstableTableWithBrokenGeneratorAndContainer::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[4]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[2]/domChild[0]/domChild[0]</td>
<td>item3/prop1</td>
</tr>
<tr>
<td>assertText</td>
<td>vaadin=runcomvaadintestscomponentstableTableWithBrokenGeneratorAndContainer::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[4]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]/domChild[4]/domChild[0]</td>
<td>Generated item1/Gen</td>
</tr>
<tr>
<td>assertText</td>
<td>vaadin=runcomvaadintestscomponentstableTableWithBrokenGeneratorAndContainer::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[4]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[1]/domChild[4]/domChild[0]</td>
<td>Generated item2/Gen</td>
</tr>
<tr>
<td>assertText</td>
<td>vaadin=runcomvaadintestscomponentstableTableWithBrokenGeneratorAndContainer::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[4]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[2]/domChild[4]/domChild[0]</td>
<td>Generated item3/Gen</td>
</tr>
<tr>
<td>mouseClick</td>
<td>vaadin=runcomvaadintestscomponentstableTableWithBrokenGeneratorAndContainer::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[2]/VCheckBox[0]/domChild[0]</td>
<td>9,6</td>
</tr>
<tr>
<td>click</td>
<td>vaadin=runcomvaadintestscomponentstableTableWithBrokenGeneratorAndContainer::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VButton[0]/domChild[0]/domChild[1]</td>
<td></td>
</tr>
<!--error indicator should be present-->
<tr>
<td>assertCSSClass</td>
<td>vaadin=runcomvaadintestscomponentstableTableWithBrokenGeneratorAndContainer::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VButton[0]/domChild[0]/domChild[0]</td>
<td>v-errorindicator</td>
</tr>
<!--error notification should not be present-->
<tr>
<td>assertElementNotPresent</td>
<td>vaadin=runcomvaadintestscomponentstableTableWithBrokenGeneratorAndContainer::Root/VNotification[0]</td>
<td></td>
</tr>
<tr>
<td>assertText</td>
<td>vaadin=runcomvaadintestscomponentstableTableWithBrokenGeneratorAndContainer::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[4]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]/domChild[0]/domChild[0]</td>
<td></td>
</tr>
<tr>
<td>assertText</td>
<td>vaadin=runcomvaadintestscomponentstableTableWithBrokenGeneratorAndContainer::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[4]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]</td>
<td>item2/prop1</td>
</tr>
<tr>
<td>assertText</td>
<td>vaadin=runcomvaadintestscomponentstableTableWithBrokenGeneratorAndContainer::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[4]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[2]/domChild[0]/domChild[0]</td>
<td>item3/prop1</td>
</tr>
<tr>
<td>assertText</td>
<td>vaadin=runcomvaadintestscomponentstableTableWithBrokenGeneratorAndContainer::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[4]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]/domChild[4]/domChild[0]</td>
<td></td>
</tr>
<tr>
<td>assertText</td>
<td>vaadin=runcomvaadintestscomponentstableTableWithBrokenGeneratorAndContainer::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[4]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[1]/domChild[4]/domChild[0]</td>
<td>Generated item2/Gen</td>
</tr>
<tr>
<td>assertText</td>
<td>vaadin=runcomvaadintestscomponentstableTableWithBrokenGeneratorAndContainer::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[4]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[2]/domChild[4]/domChild[0]</td>
<td>Generated item3/Gen</td>
</tr>
<tr>
<td>mouseClick</td>
<td>vaadin=runcomvaadintestscomponentstableTableWithBrokenGeneratorAndContainer::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[3]/VCheckBox[0]/domChild[0]</td>
<td>9,8</td>
</tr>
<tr>
<td>click</td>
<td>vaadin=runcomvaadintestscomponentstableTableWithBrokenGeneratorAndContainer::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VButton[0]/domChild[0]/domChild[1]</td>
<td></td>
</tr>
<!--error notification-->
<tr>
<td>assertText</td>
<td>vaadin=runcomvaadintestscomponentstableTableWithBrokenGeneratorAndContainer::Root/VNotification[0]/HTML[0]/domChild[0]</td>
<td>Problem updating table. Please try again later</td>
</tr>
<!--table should be empty-->
<tr>
<td>assertElementNotPresent</td>
<td>vaadin=runcomvaadintestscomponentstableTableWithBrokenGeneratorAndContainer::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[4]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]/domChild[0]/domChild[0]</td>
<td></td>
</tr>

</tbody></table>
</body>
</html>

+ 181
- 0
uitest/src/com/vaadin/tests/components/table/TableWithBrokenGeneratorAndContainer.java View File

@@ -0,0 +1,181 @@
/*
* 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.tests.components.table;

import java.lang.reflect.InvocationTargetException;

import com.vaadin.data.Item;
import com.vaadin.data.Property;
import com.vaadin.data.Property.ValueChangeEvent;
import com.vaadin.data.Property.ValueChangeListener;
import com.vaadin.data.util.IndexedContainer;
import com.vaadin.event.ListenerMethod.MethodException;
import com.vaadin.server.ErrorEvent;
import com.vaadin.server.ErrorHandler;
import com.vaadin.server.ServerRpcManager.RpcInvocationException;
import com.vaadin.server.VaadinSession;
import com.vaadin.tests.components.TestBase;
import com.vaadin.ui.Button;
import com.vaadin.ui.Button.ClickEvent;
import com.vaadin.ui.CheckBox;
import com.vaadin.ui.Notification;
import com.vaadin.ui.Table;
import com.vaadin.ui.Table.CacheUpdateException;
import com.vaadin.ui.Table.ColumnGenerator;

public class TableWithBrokenGeneratorAndContainer extends TestBase {

private CheckBox brokenContainer = new CheckBox("Broken container");
private CheckBox brokenGenerator = new CheckBox("Broken generator");
private CheckBox clearTableOnError = new CheckBox("Clear Table on Error");

/**
* Container which throws an exception on every fifth call to
* {@link #getContainerProperty(Object, Object)}.
*
* @author Vaadin Ltd
* @version @VERSION@
* @since 7.0
*
*/
public class BrokenContainer extends IndexedContainer {
private int counter = 0;

public BrokenContainer() {
super();
}

@Override
public Property getContainerProperty(Object itemId, Object propertyId) {
if (counter++ % 5 == 0
&& Boolean.TRUE.equals(brokenContainer.getValue())) {
throw new RuntimeException(getClass().getSimpleName()
+ " cannot fetch the property for " + itemId + "/"
+ propertyId + " right now");
}
return super.getContainerProperty(itemId, propertyId);
}
}

public class BrokenColumnGenerator implements ColumnGenerator {
private int brokenInterval;
private int counter = 0;

public BrokenColumnGenerator(int brokenInterval) {
this.brokenInterval = brokenInterval;
}

public Object generateCell(Table source, Object itemId, Object columnId) {
if (counter++ % brokenInterval == 0
&& Boolean.TRUE.equals(brokenGenerator.getValue())) {
throw new IllegalArgumentException("Broken generator for "
+ itemId + "/" + columnId);
} else {
return "Generated " + itemId + "/" + columnId;
}
}

}

@Override
protected void setup() {
brokenContainer.setImmediate(true);
brokenGenerator.setImmediate(true);
clearTableOnError.setImmediate(true);
clearTableOnError.addValueChangeListener(new ValueChangeListener() {

public void valueChange(ValueChangeEvent event) {
Boolean value = clearTableOnError.getValue();
setErrorHandler(value != null ? value : false);
}
});
final Table table = new Table("Semi-broken table");
table.setContainerDataSource(createBrokenContainer(10, 4));
table.addGeneratedColumn("Gen", new BrokenColumnGenerator(4));
table.setPageLength(20);

Button refreshTableCache = new Button("Refresh table cache",
new Button.ClickListener() {

public void buttonClick(ClickEvent event) {
table.markAsDirty();
table.refreshRowCache();
}
});
addComponent(refreshTableCache);
addComponent(brokenContainer);
addComponent(brokenGenerator);
addComponent(clearTableOnError);
addComponent(table);
}

protected void setErrorHandler(boolean enabled) {
if (enabled) {
VaadinSession.getCurrent().setErrorHandler(new ErrorHandler() {

@Override
public void error(ErrorEvent event) {
Throwable t = event.getThrowable();
if (t instanceof RpcInvocationException) {
t = t.getCause();
if (t instanceof InvocationTargetException) {
t = t.getCause();
if (t instanceof MethodException) {
t = t.getCause();
if (t instanceof CacheUpdateException) {
Table table = ((CacheUpdateException) t)
.getTable();
table.removeAllItems();
Notification
.show("Problem updating table. Please try again later",
Notification.Type.ERROR_MESSAGE);
}
}
}
}
}
});
} else {
VaadinSession.getCurrent().setErrorHandler(this);
}
}

private BrokenContainer createBrokenContainer(int rows, int cols) {
BrokenContainer container = new BrokenContainer();
for (int j = 1; j <= cols; j++) {
container.addContainerProperty("prop" + j, String.class, null);
}
for (int i = 1; i <= rows; i++) {
Item item = container.addItem("item" + i);
for (int j = 1; j <= cols; j++) {
item.getItemProperty("prop" + j).setValue(
"item" + i + "/prop" + j);
}
}
return container;
}

@Override
protected Integer getTicketNumber() {
return 10312;
}

@Override
protected String getDescription() {
return "A Table should not show 'Internal Error' just because a column generator or container throws an exception during filling of the cache";
}

}

Loading…
Cancel
Save