You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by lu...@apache.org on 2011/07/22 23:01:50 UTC
svn commit: r1149735 - in /myfaces/core/trunk/api/src:
main/java/javax/faces/component/UIData.java
main/java/javax/faces/model/DataModel.java
test/java/javax/faces/component/UIDataRowStateTest.java
Author: lu4242
Date: Fri Jul 22 21:01:49 2011
New Revision: 1149735
URL: http://svn.apache.org/viewvc?rev=1149735&view=rev
Log:
MYFACES-3236 UIData performance improvements
Added:
myfaces/core/trunk/api/src/test/java/javax/faces/component/UIDataRowStateTest.java
Modified:
myfaces/core/trunk/api/src/main/java/javax/faces/component/UIData.java
myfaces/core/trunk/api/src/main/java/javax/faces/model/DataModel.java
Modified: myfaces/core/trunk/api/src/main/java/javax/faces/component/UIData.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/api/src/main/java/javax/faces/component/UIData.java?rev=1149735&r1=1149734&r2=1149735&view=diff
==============================================================================
--- myfaces/core/trunk/api/src/main/java/javax/faces/component/UIData.java (original)
+++ myfaces/core/trunk/api/src/main/java/javax/faces/component/UIData.java Fri Jul 22 21:01:49 2011
@@ -130,6 +130,8 @@ public class UIData extends UIComponentB
private static final int PROCESS_UPDATES = 3;
//private static final String SKIP_ITERATION_HINT = "javax.faces.visit.SKIP_ITERATION";
+ private static final Object[] LEAF_NO_STATE = new Object[]{null,null};
+
private int _rowIndex = -1;
// Holds for each row the states of the child components of this UIData.
@@ -523,16 +525,26 @@ public class UIData extends UIComponentB
// that we haven't visited before, ie a "saved state" that can
// be pushed to the "restoreState" method of all the child
// components to set them up to represent a clean row.
- _initialDescendantComponentState = saveDescendantComponentStates(getChildren().iterator(), false);
+ _initialDescendantComponentState = saveDescendantComponentStates(this, false, false);
}
}
else
{
- // We are currently positioned on some row, and are about to
- // move off it, so save the (partial) state of the components
- // representing the current row. Later if this row is revisited
- // then we can restore this state.
- _rowStates.put(getContainerClientId(facesContext), saveDescendantComponentStates(getChildren().iterator(), false));
+ // If no initial component state, there are no EditableValueHolder instances,
+ // and that means there is no state to be saved for the current row, so we can
+ // skip row state saving code safely.
+ if (_initialDescendantComponentState != null)
+ {
+ // We are currently positioned on some row, and are about to
+ // move off it, so save the (partial) state of the components
+ // representing the current row. Later if this row is revisited
+ // then we can restore this state.
+ Collection<Object[]> savedRowState = saveDescendantComponentStates(this, false, false);
+ if (savedRowState != null)
+ {
+ _rowStates.put(getContainerClientId(facesContext), savedRowState);
+ }
+ }
}
_rowIndex = rowIndex;
@@ -567,7 +579,15 @@ public class UIData extends UIComponentB
if (_rowIndex == -1)
{
// reset components to initial state
- restoreDescendantComponentStates(getChildren().iterator(), _initialDescendantComponentState, false);
+ // If no initial state, skip row restore state code
+ if (_initialDescendantComponentState != null)
+ {
+ restoreDescendantComponentStates(this, false, _initialDescendantComponentState, false);
+ }
+ else
+ {
+ restoreDescendantComponentWithoutRestoreState(this, false, false);
+ }
}
else
{
@@ -577,7 +597,15 @@ public class UIData extends UIComponentB
// We haven't been positioned on this row before, so just
// configure the child components of this component with
// the standard "initial" state
- restoreDescendantComponentStates(getChildren().iterator(), _initialDescendantComponentState, false);
+ // If no initial state, skip row restore state code
+ if (_initialDescendantComponentState != null)
+ {
+ restoreDescendantComponentStates(this, false, _initialDescendantComponentState, false);
+ }
+ else
+ {
+ restoreDescendantComponentWithoutRestoreState(this, false, false);
+ }
}
else
{
@@ -585,7 +613,7 @@ public class UIData extends UIComponentB
// the child components of this component with the (partial)
// state that was previously saved. Fields not in the
// partial saved state are left with their original values.
- restoreDescendantComponentStates(getChildren().iterator(), rowState, false);
+ restoreDescendantComponentStates(this, false, rowState, false);
}
}
}
@@ -689,44 +717,141 @@ public class UIData extends UIComponentB
* not modified.
*/
@SuppressWarnings("unchecked")
- private void restoreDescendantComponentStates(Iterator<UIComponent> childIterator, Object state,
+ private void restoreDescendantComponentStates(UIComponent parent, boolean iterateFacets, Object state,
boolean restoreChildFacets)
{
- Iterator<? extends Object[]> descendantStateIterator = null;
- while (childIterator.hasNext())
+ int descendantStateIndex = -1;
+ List<? extends Object[]> stateCollection = null;
+
+ if (iterateFacets && parent.getFacetCount() > 0)
{
- if (descendantStateIterator == null && state != null)
+ Iterator<UIComponent> childIterator = parent.getFacets().values().iterator();
+
+ while (childIterator.hasNext())
{
- descendantStateIterator = ((Collection<? extends Object[]>) state).iterator();
- }
- UIComponent component = childIterator.next();
+ UIComponent component = childIterator.next();
- // reset the client id (see spec 3.1.6)
- component.setId(component.getId());
- if (!component.isTransient())
- {
- Object childState = null;
- Object descendantState = null;
- if (descendantStateIterator != null && descendantStateIterator.hasNext())
+ // reset the client id (see spec 3.1.6)
+ component.setId(component.getId());
+ if (!component.isTransient())
{
- Object[] object = descendantStateIterator.next();
- childState = object[0];
- descendantState = object[1];
+ if (descendantStateIndex == -1)
+ {
+ stateCollection = ((List<? extends Object[]>) state);
+ descendantStateIndex = stateCollection.isEmpty() ? -1 : 0;
+ }
+
+ if (descendantStateIndex != -1 && descendantStateIndex < stateCollection.size())
+ {
+ Object[] object = stateCollection.get(descendantStateIndex);
+ if (object[0] != null && component instanceof EditableValueHolder)
+ {
+ ((EditableValueHolderState) object[0]).restoreState((EditableValueHolder) component);
+ }
+ // If there is descendant state to restore, call it recursively, otherwise
+ // it is safe to skip iteration.
+ if (object[1] != null)
+ {
+ restoreDescendantComponentStates(component, restoreChildFacets, object[1], true);
+ }
+ else
+ {
+ restoreDescendantComponentWithoutRestoreState(component, restoreChildFacets, true);
+ }
+ }
+ else
+ {
+ restoreDescendantComponentWithoutRestoreState(component, restoreChildFacets, true);
+ }
+ descendantStateIndex++;
}
- if (childState != null && component instanceof EditableValueHolder)
+ }
+ }
+
+ if (parent.getChildCount() > 0)
+ {
+ for (int i = 0; i < parent.getChildCount(); i++)
+ {
+ UIComponent component = parent.getChildren().get(i);
+
+ // reset the client id (see spec 3.1.6)
+ component.setId(component.getId());
+ if (!component.isTransient())
{
- ((EditableValueHolderState) childState).restoreState((EditableValueHolder) component);
+ if (descendantStateIndex == -1)
+ {
+ stateCollection = ((List<? extends Object[]>) state);
+ descendantStateIndex = stateCollection.isEmpty() ? -1 : 0;
+ }
+
+ if (descendantStateIndex != -1 && descendantStateIndex < stateCollection.size())
+ {
+ Object[] object = stateCollection.get(descendantStateIndex);
+ if (object[0] != null && component instanceof EditableValueHolder)
+ {
+ ((EditableValueHolderState) object[0]).restoreState((EditableValueHolder) component);
+ }
+ // If there is descendant state to restore, call it recursively, otherwise
+ // it is safe to skip iteration.
+ if (object[1] != null)
+ {
+ restoreDescendantComponentStates(component, restoreChildFacets, object[1], true);
+ }
+ else
+ {
+ restoreDescendantComponentWithoutRestoreState(component, restoreChildFacets, true);
+ }
+ }
+ else
+ {
+ restoreDescendantComponentWithoutRestoreState(component, restoreChildFacets, true);
+ }
+ descendantStateIndex++;
}
- Iterator<UIComponent> childsIterator;
- if (restoreChildFacets)
+ }
+ }
+ }
+
+ /**
+ * Just call component.setId(component.getId()) to reset all client ids and
+ * ensure they will be calculated for the current row, but do not waste time
+ * dealing with row state code.
+ *
+ * @param parent
+ * @param iterateFacets
+ * @param restoreChildFacets
+ */
+ private void restoreDescendantComponentWithoutRestoreState(UIComponent parent, boolean iterateFacets, boolean restoreChildFacets)
+ {
+ if (iterateFacets && parent.getFacetCount() > 0)
+ {
+ Iterator<UIComponent> childIterator = parent.getFacets().values().iterator();
+
+ while (childIterator.hasNext())
+ {
+ UIComponent component = childIterator.next();
+
+ // reset the client id (see spec 3.1.6)
+ component.setId(component.getId());
+ if (!component.isTransient())
{
- childsIterator = component.getFacetsAndChildren();
+ restoreDescendantComponentWithoutRestoreState(component, restoreChildFacets, true);
}
- else
+ }
+ }
+
+ if (parent.getChildCount() > 0)
+ {
+ for (int i = 0; i < parent.getChildCount(); i++)
+ {
+ UIComponent component = parent.getChildren().get(i);
+
+ // reset the client id (see spec 3.1.6)
+ component.setId(component.getId());
+ if (!component.isTransient())
{
- childsIterator = component.getChildren().iterator();
+ restoreDescendantComponentWithoutRestoreState(component, restoreChildFacets, true);
}
- restoreDescendantComponentStates(childsIterator, descendantState, true);
}
}
}
@@ -743,52 +868,176 @@ public class UIData extends UIComponentB
* Otherwise a collection is returned which contains an object for every non-transient child component; that object
* may itself contain a collection of the state of that child's child components.
*/
- private Collection<Object[]> saveDescendantComponentStates(Iterator<UIComponent> childIterator,
+ private Collection<Object[]> saveDescendantComponentStates(UIComponent parent, boolean iterateFacets,
boolean saveChildFacets)
{
Collection<Object[]> childStates = null;
- boolean hasChildren = childIterator.hasNext();
-
- while (childIterator.hasNext())
+ // Index to indicate how many components has been passed without state to save.
+ int childEmptyIndex = 0;
+ int totalChildCount = 0;
+
+ if (iterateFacets && parent.getFacetCount() > 0)
{
-
- UIComponent child = childIterator.next();
- if (!child.isTransient())
+ Iterator<UIComponent> childIterator = parent.getFacets().values().iterator();
+
+ while (childIterator.hasNext())
{
- // Add an entry to the collection, being an array of two
- // elements. The first element is the state of the children
- // of this component; the second is the state of the current
- // child itself.
- Object descendantState = null;
- if (child.getChildCount() > 0)
+ UIComponent child = childIterator.next();
+ if (!child.isTransient())
{
- Iterator<UIComponent> childsIterator;
- if (saveChildFacets)
+ // Add an entry to the collection, being an array of two
+ // elements. The first element is the state of the children
+ // of this component; the second is the state of the current
+ // child itself.
+
+ if (child instanceof EditableValueHolder)
+ {
+ if (childStates == null)
+ {
+ childStates = new ArrayList<Object[]>(
+ parent.getFacetCount()
+ + parent.getChildCount()
+ - totalChildCount
+ + childEmptyIndex);
+ for (int ci = 0; ci < childEmptyIndex; ci++)
+ {
+ childStates.add(LEAF_NO_STATE);
+ }
+ }
+
+ childStates.add(child.getChildCount() > 0 ?
+ new Object[]{new EditableValueHolderState((EditableValueHolder) child),
+ saveDescendantComponentStates(child, saveChildFacets, true)} :
+ new Object[]{new EditableValueHolderState((EditableValueHolder) child),
+ null});
+ }
+ else if (child.getChildCount() > 0)
{
- childsIterator = child.getFacetsAndChildren();
+ Object descendantSavedState = saveDescendantComponentStates(child, saveChildFacets, true);
+
+ if (descendantSavedState == null)
+ {
+ if (childStates == null)
+ {
+ childEmptyIndex++;
+ }
+ else
+ {
+ childStates.add(LEAF_NO_STATE);
+ }
+ }
+ else
+ {
+ if (childStates == null)
+ {
+ childStates = new ArrayList<Object[]>(
+ parent.getFacetCount()
+ + parent.getChildCount()
+ - totalChildCount
+ + childEmptyIndex);
+ for (int ci = 0; ci < childEmptyIndex; ci++)
+ {
+ childStates.add(LEAF_NO_STATE);
+ }
+ }
+ childStates.add(new Object[]{null, descendantSavedState});
+ }
}
else
{
- childsIterator = child.getChildren().iterator();
+ if (childStates == null)
+ {
+ childEmptyIndex++;
+ }
+ else
+ {
+ childStates.add(LEAF_NO_STATE);
+ }
}
-
- descendantState = saveDescendantComponentStates(childsIterator, true);
- }
- Object state = null;
- if (child instanceof EditableValueHolder)
- {
- state = new EditableValueHolderState((EditableValueHolder) child);
- }
- if (childStates == null)
- {
- childStates = new ArrayList<Object[]>();
}
- childStates.add(new Object[] { state, descendantState });
+ totalChildCount++;
}
}
- if (hasChildren == true && childStates == null) {
- childStates = Collections.emptyList();
+ if (parent.getChildCount() > 0)
+ {
+ for (int i = 0; i < parent.getChildCount(); i++)
+ {
+ UIComponent child = parent.getChildren().get(i);
+ if (!child.isTransient())
+ {
+ // Add an entry to the collection, being an array of two
+ // elements. The first element is the state of the children
+ // of this component; the second is the state of the current
+ // child itself.
+
+ if (child instanceof EditableValueHolder)
+ {
+ if (childStates == null)
+ {
+ childStates = new ArrayList<Object[]>(
+ parent.getFacetCount()
+ + parent.getChildCount()
+ - totalChildCount
+ + childEmptyIndex);
+ for (int ci = 0; ci < childEmptyIndex; ci++)
+ {
+ childStates.add(LEAF_NO_STATE);
+ }
+ }
+
+ childStates.add(child.getChildCount() > 0 ?
+ new Object[]{new EditableValueHolderState((EditableValueHolder) child),
+ saveDescendantComponentStates(child, saveChildFacets, true)} :
+ new Object[]{new EditableValueHolderState((EditableValueHolder) child),
+ null});
+ }
+ else if (child.getChildCount() > 0)
+ {
+ Object descendantSavedState = saveDescendantComponentStates(child, saveChildFacets, true);
+
+ if (descendantSavedState == null)
+ {
+ if (childStates == null)
+ {
+ childEmptyIndex++;
+ }
+ else
+ {
+ childStates.add(LEAF_NO_STATE);
+ }
+ }
+ else
+ {
+ if (childStates == null)
+ {
+ childStates = new ArrayList<Object[]>(
+ parent.getFacetCount()
+ + parent.getChildCount()
+ - totalChildCount
+ + childEmptyIndex);
+ for (int ci = 0; ci < childEmptyIndex; ci++)
+ {
+ childStates.add(LEAF_NO_STATE);
+ }
+ }
+ childStates.add(new Object[]{null, descendantSavedState});
+ }
+ }
+ else
+ {
+ if (childStates == null)
+ {
+ childEmptyIndex++;
+ }
+ else
+ {
+ childStates.add(LEAF_NO_STATE);
+ }
+ }
+ }
+ totalChildCount++;
+ }
}
return childStates;
Modified: myfaces/core/trunk/api/src/main/java/javax/faces/model/DataModel.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/api/src/main/java/javax/faces/model/DataModel.java?rev=1149735&r1=1149734&r2=1149735&view=diff
==============================================================================
--- myfaces/core/trunk/api/src/main/java/javax/faces/model/DataModel.java (original)
+++ myfaces/core/trunk/api/src/main/java/javax/faces/model/DataModel.java Fri Jul 22 21:01:49 2011
@@ -51,8 +51,11 @@ import java.util.NoSuchElementException;
*/
public abstract class DataModel<E> implements Iterable<E>
{
+ private final static DataModelListener[] EMPTY_DATA_MODEL_LISTENER = new DataModelListener[]{};
// FIELDS
private List<DataModelListener> _listeners;
+
+ private DataModelListener[] _cachedListenersArray = null;
// METHODS
public void addDataModelListener(DataModelListener listener)
@@ -63,15 +66,20 @@ public abstract class DataModel<E> imple
_listeners = new ArrayList<DataModelListener>();
}
_listeners.add(listener);
+ _cachedListenersArray = null;
}
public DataModelListener[] getDataModelListeners()
{
if (_listeners == null)
{
- return new DataModelListener[0];
+ return EMPTY_DATA_MODEL_LISTENER;
+ }
+ if (_cachedListenersArray == null)
+ {
+ _cachedListenersArray = _listeners.toArray(new DataModelListener[_listeners.size()]);
}
- return _listeners.toArray(new DataModelListener[_listeners.size()]);
+ return _cachedListenersArray;
}
/**
@@ -141,6 +149,7 @@ public abstract class DataModel<E> imple
{
_listeners.remove(listener);
}
+ _cachedListenersArray = null;
}
/**
Added: myfaces/core/trunk/api/src/test/java/javax/faces/component/UIDataRowStateTest.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/api/src/test/java/javax/faces/component/UIDataRowStateTest.java?rev=1149735&view=auto
==============================================================================
--- myfaces/core/trunk/api/src/test/java/javax/faces/component/UIDataRowStateTest.java (added)
+++ myfaces/core/trunk/api/src/test/java/javax/faces/component/UIDataRowStateTest.java Fri Jul 22 21:01:49 2011
@@ -0,0 +1,282 @@
+/*
+ * Copyright 2011 The Apache Software Foundation.
+ *
+ * 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 javax.faces.component;
+
+import java.util.ArrayList;
+import java.util.List;
+import javax.faces.component.html.HtmlColumn;
+import javax.faces.component.html.HtmlDataTable;
+import javax.faces.component.html.HtmlInputText;
+import javax.faces.component.html.HtmlOutputText;
+import javax.faces.model.ListDataModel;
+import javax.faces.render.Renderer;
+import junit.framework.Assert;
+import org.apache.myfaces.test.base.junit4.AbstractJsfTestCase;
+import org.junit.Test;
+
+/**
+ *
+ * @author Leonardo Uribe
+ */
+public class UIDataRowStateTest extends AbstractJsfTestCase
+{
+
+ public static class Item
+ {
+
+ private Integer id;
+ private String name;
+ private String lastName;
+
+ public Item(Integer id, String name, String lastName)
+ {
+ this.id = id;
+ this.name = name;
+ this.lastName = lastName;
+ }
+ /**
+ * @return the id
+ */
+ public Integer getId() {
+ return id;
+ }
+
+ /**
+ * @param id the id to set
+ */
+ public void setId(Integer id) {
+ this.id = id;
+ }
+
+ /**
+ * @return the name
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * @param name the name to set
+ */
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ /**
+ * @return the lastName
+ */
+ public String getLastName() {
+ return lastName;
+ }
+
+ /**
+ * @param lastName the lastName to set
+ */
+ public void setLastName(String lastName) {
+ this.lastName = lastName;
+ }
+ }
+
+ @Override
+ protected void setUpRenderKit() throws Exception {
+ super.setUpRenderKit();
+ renderKit.addRenderer(HtmlDataTable.COMPONENT_FAMILY, new HtmlDataTable().getRendererType(), new Renderer(){});
+ renderKit.addRenderer(HtmlOutputText.COMPONENT_FAMILY, new HtmlOutputText().getRendererType(), new Renderer(){});
+ renderKit.addRenderer(HtmlInputText.COMPONENT_FAMILY, new HtmlInputText().getRendererType(), new Renderer(){});
+ }
+
+ /**
+ *
+ */
+ @Test
+ public void testChangeIdsAfterSetRowIndex()
+ {
+ List<Item> list = new ArrayList<Item>();
+ int rowCount = 10;
+ for (int i = 0; i < rowCount; i++)
+ {
+ list.add(new Item(i, "name"+i, "lastName"+i));
+ }
+
+ facesContext.getExternalContext().getRequestMap().put("items", list);
+
+ UIViewRoot root = facesContext.getViewRoot();
+ UIData data = new HtmlDataTable();
+ data.setId("table");
+ root.getChildren().add(data);
+ data.setValue(new ListDataModel(list));
+ data.setVar("item");
+ data.setRows(rowCount);
+
+ UIColumn col = new HtmlColumn();
+ data.getChildren().add(col);
+
+ UIOutput text = new HtmlOutputText();
+ text.setId("text");
+ text.setValue(facesContext.getApplication().
+ getExpressionFactory().createValueExpression(
+ facesContext.getELContext(), "#{item.name}", String.class));
+ col.getChildren().add(text);
+
+ for (int i = 0; i < rowCount ; i++)
+ {
+ data.setRowIndex(i);
+ Assert.assertEquals(data.getId()+":"+i+":"+text.getId(), text.getClientId());
+ }
+ data.setRowIndex(-1);
+ Assert.assertEquals(data.getId()+":"+text.getId(), text.getClientId());
+ }
+
+ @Test
+ public void testChangeIdsAfterSetRowIndex2()
+ {
+ List<Item> list = new ArrayList<Item>();
+ int rowCount = 10;
+ for (int i = 0; i < rowCount; i++)
+ {
+ list.add(new Item(i, "name"+i, "lastName"+i));
+ }
+
+ facesContext.getExternalContext().getRequestMap().put("items", list);
+
+ UIViewRoot root = facesContext.getViewRoot();
+ UIData data = new HtmlDataTable();
+ data.setId("table");
+ root.getChildren().add(data);
+ data.setValue(new ListDataModel(list));
+ data.setVar("item");
+ data.setRows(rowCount);
+
+ UIColumn col = new HtmlColumn();
+ data.getChildren().add(col);
+
+ UIOutput text = new HtmlOutputText();
+ text.setId("text");
+ text.setValue(facesContext.getApplication().
+ getExpressionFactory().createValueExpression(
+ facesContext.getELContext(), "#{item.name}", String.class));
+ col.getChildren().add(text);
+
+ UIInput inputText = new HtmlInputText();
+ inputText.setId("text");
+ inputText.setValue(facesContext.getApplication().
+ getExpressionFactory().createValueExpression(
+ facesContext.getELContext(), "#{item.lastName}", String.class));
+ col.getChildren().add(inputText);
+
+ for (int i = 0; i < rowCount ; i++)
+ {
+ data.setRowIndex(i);
+ Assert.assertEquals(data.getId()+":"+i+":"+text.getId(), text.getClientId());
+ Assert.assertEquals(data.getId()+":"+i+":"+inputText.getId(), inputText.getClientId());
+ }
+ data.setRowIndex(-1);
+ Assert.assertEquals(data.getId()+":"+text.getId(), text.getClientId());
+ Assert.assertEquals(data.getId()+":"+inputText.getId(), inputText.getClientId());
+ }
+
+ @Test
+ public void testAddRowAfterSetRowIndex()
+ {
+ List<Item> list = new ArrayList<Item>();
+ int rowCount = 10;
+
+ facesContext.getExternalContext().getRequestMap().put("items", list);
+
+ UIViewRoot root = facesContext.getViewRoot();
+ UIData data = new HtmlDataTable();
+ data.setId("table");
+ root.getChildren().add(data);
+ data.setValue(new ListDataModel(list));
+ data.setVar("item");
+ data.setRows(rowCount);
+
+ UIColumn col = new HtmlColumn();
+ data.getChildren().add(col);
+
+ UIOutput text = new HtmlOutputText();
+ text.setId("text");
+ text.setValue(facesContext.getApplication().
+ getExpressionFactory().createValueExpression(
+ facesContext.getELContext(), "#{item.name}", String.class));
+ col.getChildren().add(text);
+
+ data.setRowIndex(-1);
+
+ data.processDecodes(facesContext);
+
+ for (int i = 0; i < rowCount; i++)
+ {
+ list.add(new Item(i, "name"+i, "lastName"+i));
+ }
+
+ data.processDecodes(facesContext);
+ }
+
+ /**
+ * Check if EditableValueHolder is being saved and restored.
+ */
+ @Test
+ public void testEditableValueHolderState()
+ {
+ List<Item> list = new ArrayList<Item>();
+ int rowCount = 10;
+ for (int i = 0; i < rowCount; i++)
+ {
+ list.add(new Item(i, "name"+i, "lastName"+i));
+ }
+
+ facesContext.getExternalContext().getRequestMap().put("items", list);
+
+ UIViewRoot root = facesContext.getViewRoot();
+ UIData data = new HtmlDataTable();
+ data.setId("table");
+ root.getChildren().add(data);
+ data.setValue(new ListDataModel(list));
+ data.setVar("item");
+ data.setRows(rowCount);
+
+ UIColumn col = new HtmlColumn();
+ data.getChildren().add(col);
+
+ UIOutput text = new HtmlOutputText();
+ text.setId("text");
+ text.setValue(facesContext.getApplication().
+ getExpressionFactory().createValueExpression(
+ facesContext.getELContext(), "#{item.name}", String.class));
+ col.getChildren().add(text);
+
+ UIInput inputText = new HtmlInputText();
+ inputText.setId("text");
+ inputText.setValue(facesContext.getApplication().
+ getExpressionFactory().createValueExpression(
+ facesContext.getELContext(), "#{item.lastName}", String.class));
+ col.getChildren().add(inputText);
+
+ for (int i = 0; i < rowCount ; i++)
+ {
+ data.setRowIndex(i);
+ inputText.setSubmittedValue("someString"+i);
+ }
+ data.setRowIndex(-1);
+
+ for (int i = 0; i < rowCount ; i++)
+ {
+ data.setRowIndex(i);
+ Assert.assertEquals("someString"+i, inputText.getSubmittedValue());
+ }
+ }
+}