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/23 19:23:39 UTC

svn commit: r1150170 - in /myfaces/core/branches/1.2.x/api/src/main/java/javax/faces: component/UIData.java model/DataModel.java

Author: lu4242
Date: Sat Jul 23 17:23:38 2011
New Revision: 1150170

URL: http://svn.apache.org/viewvc?rev=1150170&view=rev
Log:
MYFACES-3236 UIData performance improvements (backport to 1.2.x)

Modified:
    myfaces/core/branches/1.2.x/api/src/main/java/javax/faces/component/UIData.java
    myfaces/core/branches/1.2.x/api/src/main/java/javax/faces/model/DataModel.java

Modified: myfaces/core/branches/1.2.x/api/src/main/java/javax/faces/component/UIData.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/1.2.x/api/src/main/java/javax/faces/component/UIData.java?rev=1150170&r1=1150169&r2=1150170&view=diff
==============================================================================
--- myfaces/core/branches/1.2.x/api/src/main/java/javax/faces/component/UIData.java (original)
+++ myfaces/core/branches/1.2.x/api/src/main/java/javax/faces/component/UIData.java Sat Jul 23 17:23:38 2011
@@ -114,6 +114,8 @@ public class UIData extends UIComponentB
     private static final int PROCESS_VALIDATORS = 2;
     private static final int PROCESS_UPDATES = 3;
 
+    private static final Object[] LEAF_NO_STATE = new Object[]{null,null};
+
     private int _rowIndex = -1;
     private String _var;
 
@@ -464,6 +466,7 @@ public class UIData extends UIComponentB
      * <p>
      * Param rowIndex can be -1, meaning "no row".
      * <p>
+     * 
      * @param rowIndex
      */
     public void setRowIndex(int rowIndex)
@@ -488,19 +491,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(getClientId(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(getClientId(facesContext), savedRowState);
+                }
+            }
         }
 
         _rowIndex = rowIndex;
@@ -537,8 +547,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
         {
@@ -548,8 +565,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
             {
@@ -557,122 +581,345 @@ 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);
             }
         }
     }
 
     /**
-     * Overwrite the state of the child components of this component
-     * with data previously saved by method saveDescendantComponentStates.
+     * Overwrite the state of the child components of this component with data previously saved by method
+     * saveDescendantComponentStates.
      * <p>
-     * The saved state info only covers those fields that are expected to
-     * vary between rows of a table. Other fields are not modified.
+     * The saved state info only covers those fields that are expected to vary between rows of a table. Other fields are
+     * not modified.
      */
-    private void restoreDescendantComponentStates(Iterator childIterator,
-            Object state, boolean restoreChildFacets)
+    @SuppressWarnings("unchecked")
+    private void restoreDescendantComponentStates(UIComponent parent, boolean iterateFacets, Object state,
+                                                  boolean restoreChildFacets)
     {
-        Iterator 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) state).iterator();
-            }
-            UIComponent component = (UIComponent) 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 = (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 (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 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);
             }
         }
     }
 
     /**
-     * Walk the tree of child components of this UIData, saving the parts of
-     * their state that can vary between rows.
+     * Walk the tree of child components of this UIData, saving the parts of their state that can vary between rows.
      * <p>
-     * This is very similar to the process that occurs for normal components
-     * when the view is serialized. Transient components are skipped (no
-     * state is saved for them).
+     * This is very similar to the process that occurs for normal components when the view is serialized. Transient
+     * components are skipped (no state is saved for them).
      * <p>
-     * If there are no children then null is returned. If there are one or
-     * more children, and all children are transient then an empty collection
-     * is returned; this will happen whenever a table contains only read-only
-     * components.
+     * If there are no children then null is returned. If there are one or more children, and all children are transient
+     * then an empty collection is returned; this will happen whenever a table contains only read-only components.
      * <p>
-     * 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.
+     * 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 Object saveDescendantComponentStates(Iterator childIterator,
-            boolean saveChildFacets)
+    private Collection<Object[]> saveDescendantComponentStates(UIComponent parent, boolean iterateFacets,
+                                                               boolean saveChildFacets)
     {
-        Collection childStates = null;
-        while (childIterator.hasNext())
+        Collection<Object[]> childStates = null;
+        // Index to indicate how many components has been passed without state to save.
+        int childEmptyIndex = 0;
+        int totalChildCount = 0;
+                
+        if (iterateFacets && parent.getFacetCount() > 0)
         {
-            if (childStates == null)
-            {
-                childStates = new ArrayList();
-            }
-            UIComponent child = (UIComponent) childIterator.next();
-            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.
+            Iterator<UIComponent> childIterator = parent.getFacets().values().iterator();
 
-                Iterator childsIterator;
-                if (saveChildFacets)
-                {
-                    childsIterator = child.getFacetsAndChildren();
-                }
-                else
+            while (childIterator.hasNext())
+            {
+                UIComponent child = childIterator.next();
+                if (!child.isTransient())
                 {
-                    childsIterator = child.getChildren().iterator();
+                    // 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);
+                        }
+                    }
                 }
-                Object descendantState = saveDescendantComponentStates(
-                        childsIterator, true);
-                Object state = null;
-                if (child instanceof EditableValueHolder)
+                totalChildCount++;
+            }
+        }
+        
+        if (parent.getChildCount() > 0)
+        {
+            for (int i = 0; i < parent.getChildCount(); i++)
+            {
+                UIComponent child = parent.getChildren().get(i);
+                if (!child.isTransient())
                 {
-                    state = new EditableValueHolderState(
-                            (EditableValueHolder) child);
+                    // 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);
+                        }
+                    }
                 }
-                childStates.add(new Object[] { state, descendantState });
+                totalChildCount++;
             }
         }
+        
         return childStates;
     }
-
+    
     @Override
     public void setValueExpression(String name, ValueExpression binding) {
         if (name == null)

Modified: myfaces/core/branches/1.2.x/api/src/main/java/javax/faces/model/DataModel.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/1.2.x/api/src/main/java/javax/faces/model/DataModel.java?rev=1150170&r1=1150169&r2=1150170&view=diff
==============================================================================
--- myfaces/core/branches/1.2.x/api/src/main/java/javax/faces/model/DataModel.java (original)
+++ myfaces/core/branches/1.2.x/api/src/main/java/javax/faces/model/DataModel.java Sat Jul 23 17:23:38 2011
@@ -49,8 +49,11 @@ import java.util.List;
 */
 public abstract class DataModel
 {
+    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)
@@ -61,15 +64,20 @@ public abstract class DataModel
             _listeners = new ArrayList<DataModelListener>();
         }
         _listeners.add(listener);
+        _cachedListenersArray = null;
     }
 
     public DataModelListener[] getDataModelListeners()
     {
         if (_listeners == null)
         {
-            return new DataModelListener[0];
+            return EMPTY_DATA_MODEL_LISTENER;
         }
-        return _listeners.toArray(new DataModelListener[_listeners.size()]);
+        if (_cachedListenersArray == null)
+        {
+            _cachedListenersArray = _listeners.toArray(new DataModelListener[_listeners.size()]);
+        }
+        return _cachedListenersArray;
     }
 
     /**