If you only want to handle refresh, have a look at the redirect
option in navigation rules.
<navigation-rule>
<display-name>navBack</display-name>
<from-view-id>/navBack.jsp</from-view-id>
<navigation-case>
<from-outcome>navTo</from-outcome>
<to-view-id>/navTo.jsp</to-view-id>
<redirect />
</navigation-case>
</navigation-rule>
If you want to handle back-button and multiple window cases too, read on.
You could detect this using a hidden field and a row-level artifact. Basically, you check the id emitted to the client against the id received when the form is submitted.
public class SafeRow {
private final String rowId;
private String rowIdClient;
private String name;
private boolean delete;
public SafeRow(String name) {
this();
this.name = name;
}
public SafeRow() {
rowId = UUID.randomUUID().toString();
}
public String getRowId() { return rowId; }
public void setRowId(String rowIdClient) { this.rowIdClient = rowIdClient; }
public boolean isStateConsistent() {
return rowId.equals(rowIdClient);
}
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public boolean isDelete() { return delete; }
public void setDelete(boolean delete) { this.delete = delete; }
}
The table data:
public class SafeUpdateBean {
private final List<SafeRow> data = new ArrayList<SafeRow>();
public SafeUpdateBean() {
data.add(new SafeRow("Bill"));
data.add(new SafeRow("Ben"));
data.add(new SafeRow("Sue"));
}
public List<SafeRow> getData() { return data; }
public String deleteSelected() {
Iterator<SafeRow> all = data.iterator();
while (all.hasNext()) {
SafeRow row = all.next();
if (!row.isStateConsistent()) {
System.err.println("Caught inconsistency on " + row.getRowId());
} else if (row.isDelete()) {
all.remove();
}
}
return null;
}
}
The view:
<h:form>
<h:dataTable value="#{safeUpdateBean.data}" var="row">
<h:column>
<h:inputHidden value="#{row.rowId}" />
<h:selectBooleanCheckbox value="#{row.delete}" />
<h:outputText value="#{row.name}" />
</h:column>
</h:dataTable>
<h:commandButton value="delete selected"
action="#{safeUpdateBean.deleteSelected}" />
</h:form>
This demo code uses a simple session bean, but hopefully it is clear how you could adapt it to something more sensible. This isn't the only thing you could do - you could perform a more general duplicate form submission, for example. 3rd party frameworks like Seam also add handling for this sort of thing.