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 2009/06/23 03:36:37 UTC

svn commit: r787511 - in /myfaces/core/branches/2_0_0/api/src: main/java/javax/faces/component/ test/java/javax/faces/component/

Author: lu4242
Date: Tue Jun 23 01:36:37 2009
New Revision: 787511

URL: http://svn.apache.org/viewvc?rev=787511&view=rev
Log:
MYFACES-2250 implement getStateHelper 

Added:
    myfaces/core/branches/2_0_0/api/src/main/java/javax/faces/component/_AttachedDeltaWrapper.java   (with props)
    myfaces/core/branches/2_0_0/api/src/test/java/javax/faces/component/_Delta2StateHelperTest.java   (with props)
Modified:
    myfaces/core/branches/2_0_0/api/src/main/java/javax/faces/component/UIComponentBase.java
    myfaces/core/branches/2_0_0/api/src/main/java/javax/faces/component/_DeltaStateHelper.java
    myfaces/core/branches/2_0_0/api/src/test/java/javax/faces/component/_DeltaStateHelperTest.java

Modified: myfaces/core/branches/2_0_0/api/src/main/java/javax/faces/component/UIComponentBase.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2_0_0/api/src/main/java/javax/faces/component/UIComponentBase.java?rev=787511&r1=787510&r2=787511&view=diff
==============================================================================
--- myfaces/core/branches/2_0_0/api/src/main/java/javax/faces/component/UIComponentBase.java (original)
+++ myfaces/core/branches/2_0_0/api/src/main/java/javax/faces/component/UIComponentBase.java Tue Jun 23 01:36:37 2009
@@ -85,6 +85,7 @@
     private String _id = null;
     private UIComponent _parent = null;
     private boolean _transient = false;
+    private boolean _initialStateMarked = false;
 
     public UIComponentBase()
     {
@@ -349,7 +350,7 @@
     
     public void clearInitialState()
     {
-        // TODO: IMPLEMENT HERE
+        _initialStateMarked = false;
     }
 
     /**
@@ -876,7 +877,7 @@
     {
         // TODO: IMPLEMENT HERE
         // FIXME: Nofity EG, this method should be in the specification
-        return false;
+        return _initialStateMarked;
     }
 
     /**
@@ -907,7 +908,7 @@
     
     public void markInitialState()
     {
-        // TODO: IMPLEMENT HERE
+        _initialStateMarked = true;
     }
 
     @Override
@@ -1348,17 +1349,9 @@
     {
         if (attachedObject == null)
             return null;
-        if (attachedObject instanceof List)
-        {
-            List<Object> lst = new ArrayList<Object>(((List<?>) attachedObject).size());
-            for (Object item : (List<?>) attachedObject)
-            {
-                lst.add(saveAttachedState(context, item));
-            }
-
-            return new _AttachedListStateWrapper(lst);
-        }
-        else if (attachedObject instanceof StateHolder)
+        // StateHolder interface should take precedence over
+        // List children
+        if (attachedObject instanceof StateHolder)
         {
             StateHolder holder = (StateHolder) attachedObject;
             if (holder.isTransient())
@@ -1367,6 +1360,16 @@
             }
 
             return new _AttachedStateWrapper(attachedObject.getClass(), holder.saveState(context));
+        }        
+        else if (attachedObject instanceof List)
+        {
+            List<Object> lst = new ArrayList<Object>(((List<?>) attachedObject).size());
+            for (Object item : (List<?>) attachedObject)
+            {
+                lst.add(saveAttachedState(context, item));
+            }
+
+            return new _AttachedListStateWrapper(lst);
         }
         else if (attachedObject instanceof Serializable)
         {
@@ -1434,7 +1437,7 @@
      */
     public Object saveState(FacesContext context)
     {
-        Object values[] = new Object[7];
+        Object values[] = new Object[8];
         values[0] = _id;
         values[1] = _rendered;
         values[2] = _rendererType;
@@ -1442,6 +1445,11 @@
         values[4] = saveAttributesMap();
         values[5] = saveAttachedState(context, _facesListeners);
         values[6] = saveBindings(context);
+        StateHelper stateHelper = getStateHelper(false);
+        if (stateHelper != null)
+        {
+            values[7] = stateHelper.saveState(context);
+        }
         return values;
     }
 
@@ -1464,6 +1472,7 @@
         restoreAttributesMap(values[4]);
         _facesListeners = (List<FacesListener>) restoreAttachedState(context, values[5]);
         restoreValueExpressionMap(context, values[6]);
+        getStateHelper().restoreState(context, values[7]);
     }
 
     private Object saveAttributesMap()

Added: myfaces/core/branches/2_0_0/api/src/main/java/javax/faces/component/_AttachedDeltaWrapper.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2_0_0/api/src/main/java/javax/faces/component/_AttachedDeltaWrapper.java?rev=787511&view=auto
==============================================================================
--- myfaces/core/branches/2_0_0/api/src/main/java/javax/faces/component/_AttachedDeltaWrapper.java (added)
+++ myfaces/core/branches/2_0_0/api/src/main/java/javax/faces/component/_AttachedDeltaWrapper.java Tue Jun 23 01:36:37 2009
@@ -0,0 +1,58 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.io.Serializable;
+
+/**
+ * @author Leonardo Uribe (latest modification by $Author$)
+ * @version $Revision$ $Date$
+ */
+class _AttachedDeltaWrapper implements Serializable
+{
+    private static final long serialVersionUID = 4732389964367986402L;
+    private Class<?> _class;
+    private Object _wrappedStateObject;
+
+    /**
+     * @param clazz
+     *            null means wrappedStateObject is a List of state objects
+     * @param wrappedStateObject
+     */
+    public _AttachedDeltaWrapper(Class<?> clazz, Object wrappedStateObject)
+    {
+        if (wrappedStateObject != null && !(wrappedStateObject instanceof Serializable))
+        {
+            throw new IllegalArgumentException("Attached state for Object of type " + clazz + " (Class "
+                    + wrappedStateObject.getClass().getName() + ") is not serializable");
+        }
+        _class = clazz;
+        _wrappedStateObject = wrappedStateObject;
+    }
+
+    public Class<?> getClazz()
+    {
+        return _class;
+    }
+
+    public Object getWrappedStateObject()
+    {
+        return _wrappedStateObject;
+    }
+}

Propchange: myfaces/core/branches/2_0_0/api/src/main/java/javax/faces/component/_AttachedDeltaWrapper.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: myfaces/core/branches/2_0_0/api/src/main/java/javax/faces/component/_AttachedDeltaWrapper.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Modified: myfaces/core/branches/2_0_0/api/src/main/java/javax/faces/component/_DeltaStateHelper.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2_0_0/api/src/main/java/javax/faces/component/_DeltaStateHelper.java?rev=787511&r1=787510&r2=787511&view=diff
==============================================================================
--- myfaces/core/branches/2_0_0/api/src/main/java/javax/faces/component/_DeltaStateHelper.java (original)
+++ myfaces/core/branches/2_0_0/api/src/main/java/javax/faces/component/_DeltaStateHelper.java Tue Jun 23 01:36:37 2009
@@ -22,136 +22,233 @@
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashMap;
-import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
-import java.util.Set;
+
 import javax.el.ValueExpression;
 import javax.faces.context.FacesContext;
 
 /**
- * A delta enabled state holder implementing the StateHolder Interface
- *
- * components implementing the PartalStateHolder interface have an initial state
+ * A delta enabled state holder implementing the StateHolder Interface. 
+ * <p>
+ * Components implementing the PartalStateHolder interface have an initial state
  * and delta states, the initial state is the one holding all root values
  * and deltas store differences to the initial states
- *
- * for components not implementing partial state saving only the initial states are
+ * </p>
+ * <p>
+ * For components not implementing partial state saving only the initial states are
  * of importance, everything is stored and restored continously there
- *
- * The state helper seems to have three internal storage mechanisms
- * one being a list which stores plain values
+ * </p> 
+ * <p>
+ * The state helper seems to have three internal storage mechanisms:
+ * one being a list which stores plain values,
  * one being a key value pair which stores key values in maps
  * add serves the plain list type while put serves the 
- * key value type
- *
+ * key value type, 
  * the third is the value which has to be stored plainly as is!
+ * </p>
+ * In other words, this map can be seen as a composite map. It has two maps: 
+ * initial state map and delta map.
+ * <p> 
+ * If delta map is used (method component.initialStateMarked() ), 
+ * base or initial state map cannot be changed, since all changes 
+ * should be tracked on delta map.
+ * </p>
+ * <p> 
+ * The intention of this class is just hold property values
+ * and do a clean separation between initial state and delta.
+ * </p>
+ * <p>
+ * The code from this class comes from a refactor of 
+ * org.apache.myfaces.trinidad.bean.util.PropertyHashMap
+ * </p>
+ * <p>
+ * The context from this class comes and that should be taken into account
+ * is this:
+ * </p>
+ * <p> 
+ * First request:
+ * </p>
+ * <ul>
+ *   <li> A new template is created (using 
+ *   javax.faces.view.ViewDeclarationLanguage.buildView method)
+ *   and component.markInitialState is called from its related TagHandler classes 
+ *  (see javax.faces.view.facelets.ComponentHandler ).
+ *   When this method is executed, the component tree was populated from the values
+ *   set in the facelet abstract syntax tree (or in other words composition of 
+ *   facelets templates). </li>
+ *   <li> From this point all updates on the variables are considered "delta". </li>
+ *   <li> SaveState, if initialStateMarked is true, only delta is saved. </li>
+ * </ul>
+ * <p>
+ * Second request (and next ones)
+ * </p>
+ * <ul>
+ *   <li> A new template is created and component.markInitialState is called from
+ *   its related TagHandler classes again. In this way, components like c:forEach 
+ *   or c:if, that add or remove components could notify about this and handle 
+ *   them properly (see javax.faces.view.StateManagementStrategy). Note that a 
+ *   component restored using this method is no different as the same component 
+ *   at the first request at the same time. </li>
+ *   <li> A call for restoreState is done, passing the delta as object value. If no 
+ *   delta, the state is complete and no call is triggered. </li>
+ *   <li> Lifecycle occur, changing the necessary stuff. </li>
+ *   <li> SaveState, if initialStateMarked is true, only delta is saved. </li>
+ * </ul>
+ * <p>
+ * From the previous analysis, the following conclusions arise:
+ * <ul>
+ *   <li>This class only needs to keep track of delta changes, so when 
+ *   restoreState/saveState is called, the right objects are passed.</li>
+ *   <li>UIComponent.clearInitialState is used to reset the partial
+ *   state holder to a non delta state, so the state to be saved by
+ *   saveState is no longer a delta instead is a full state. If a call
+ *   to clearInitialState occur it is not expected a call for 
+ *   UIComponent.markInitialState occur on the current request.</li>
+ *   <li>The state is handled in the same way on UIData, so components
+ *   inside UIData share its state on all rows. There is no way to save 
+ *   delta per row.</li>
+ * </ul>
+ * </p>
+ * <p>
+ * NOTE: The current implementation of StateHelper on RI does not handle
+ * stateHolder values internally. To prevent problems when developers create
+ * custom components we should do this too. But anyway, the code that 
+ * handle this case should be let here as comment, if some day this feature
+ * is provided. Note than stateHolder aware properties like converter,
+ * validator or listeners should deal with StateHolder or PartialStateHolder
+ * on component classes. 
+ * 
+ * </p>
  *
- *
- * The flow probably goes following
- * restore -> restore initial state done from the outside
- * switch component to -> initialState = true
- * store the deltas as well!
- *
- * the main save and restore works only on the deltas
- * as far as it seems!
- *
- * we are keeping two states the full state and the delta state
- * the full state must access all values, full + delta
- * and the delta state should keep the states only if initialState is set
- *
- * @author Werner Punz (latest modification by $Author$)
+ * @author Werner Punz
+ * @author Leonardo Uribe (latest modification by $Author$)
  * @version $Rev$ $Date$
  */
 public class _DeltaStateHelper implements StateHelper
 {
 
-    UIComponent _component = null;
-    Map<Serializable, Object> _fullState = null;
-    Map<Serializable, Object> _deltas = null;
-    Set<Object> _deleted = null;
-    boolean _transient = false;
-    static final String INTERNAL_MAP_KEY = "_MYFACES._IMAP";
-    static final String INTERNAL_LIST_KEY = "_MYFACES._ILIST";
-    static final String INTERNAL_DELETED_KEY = "_MYFACES._DELETED";
+    /**
+     * We need to hold a component instance because:
+     * 
+     * - The component is the one who knows if we are on initial or delta mode
+     * - eval assume calls to component.ValueExpression
+     */
+    private UIComponent _component;
+
+    /**
+     * This map holds the full current state
+     */
+    private Map<Serializable, Object> _fullState;
+
+    /**
+     * This map only keep track of delta changes to be saved
+     */
+    private Map<Serializable, Object> _deltas;
+    
+    /**
+     * This map keep track of StateHolder keys, to be saved when
+     * saveState is called. 
+     */
+    //private Set<Serializable> _stateHolderKeys;  
+
+    private boolean _transient = false;
 
     public _DeltaStateHelper(UIComponent component)
     {
+        super();
         this._component = component;
         _fullState = new HashMap<Serializable, Object>();
-        //we only can store the deltas if the component is instance of partial state holder
-        //but as it seems the latest specs already have enforced PartialStateHolder on UIComponent
-        //initialStateMarked is responsible for determination if we have partial saving
-
-        _deltas = new HashMap<Serializable, Object>();
-        _transient = (component != null) ? component.isTransient() : true;
+        _deltas = null;
+        //_stateHolderKeys = new HashSet<Serializable>();
     }
 
+    /**
+     * Used to create delta map on demand
+     * 
+     * @return
+     */
+    private boolean _createDeltas()
+    {
+        if (isInitalStateMarked())
+        {
+            if (_deltas == null)
+            {
+                _deltas = new HashMap<Serializable, Object>(2);
+            }
+            return true;
+        }
+
+        return false;
+    }
+    
     protected boolean isInitalStateMarked()
     {
         return _component.initialStateMarked();
     }
 
-    /**
-     * stores the object in an internal list if not present in the detal map
-     */
     @Override
     public void add(Serializable key, Object value)
     {
-        if (_deleted != null)
-        {
-            _deleted.remove(key);
-        }
-        if (isInitalStateMarked())
+        if (_createDeltas())
         {
-
-            List<Object> deltaStorageList = (List) _deltas.get(key);
-            if (deltaStorageList == null)
+            //Track delta case
+            Map<Object, Boolean> deltaListMapValues = (Map<Object, Boolean>) _deltas
+                    .get(key);
+            if (deltaListMapValues == null)
             {
-                deltaStorageList = new InternalList(3);
+                deltaListMapValues = new InternalDeltaListMap<Object, Boolean>(
+                        3);
+                _deltas.put(key, deltaListMapValues);
             }
-            deltaStorageList.add(value);
-            _deltas.put(key, deltaStorageList);
-
+            deltaListMapValues.put(value, Boolean.TRUE);
         }
-        List<Object> fullStorageList = (List) _fullState.get(key);
-        if (fullStorageList == null)
+
+        //Handle change on full map
+        List<Object> fullListValues = (List<Object>) _fullState.get(key);
+        if (fullListValues == null)
         {
-            fullStorageList = new InternalList(3);
+            fullListValues = new InternalList<Object>(3);
+            _fullState.put(key, fullListValues);
         }
-        fullStorageList.add(value);
-        _fullState.put(key, fullStorageList);
+        fullListValues.add(value);
     }
 
     @Override
     public Object eval(Serializable key)
     {
-        return eval(key, null);
+        Object returnValue = _fullState.get(key);
+        if (returnValue != null)
+        {
+            return returnValue;
+        }
+        ValueExpression expression = _component.getValueExpression(key
+                .toString());
+        if (expression != null)
+        {
+            return expression.getValue(_component.getFacesContext()
+                    .getELContext());
+        }
+        return null;
     }
 
     @Override
-    /**
-     * returns a given value or the result of a value expression
-     * @param key  the key or value expression to be evaluated
-     * @return the result of the eval or the default value if
-     *          the value is not present in our states
-     */
     public Object eval(Serializable key, Object defaultValue)
     {
-        Object retVal = get(key);
-        if (retVal != null)
+        Object returnValue = _fullState.get(key);
+        if (returnValue != null)
         {
-            return retVal;
+            return returnValue;
         }
-        //not found lets do the eval of a possible value expression
-        ValueExpression expr = _component.getValueExpression(key.toString());
-        if (expr == null)
+        ValueExpression expression = _component.getValueExpression(key
+                .toString());
+        if (expression != null)
         {
-            return defaultValue;
+            return expression.getValue(_component.getFacesContext()
+                    .getELContext());
         }
-        retVal = expr.getValue(_component.getFacesContext().getELContext());
-        return (retVal == null) ? defaultValue : retVal;
+        return defaultValue;
     }
 
     @Override
@@ -161,110 +258,224 @@
     }
 
     @Override
-    /**
-     * puts an object into the data structures with a given key
-     *
-     * @param key the key for the mapping
-     * @param value the value to be stored
-     * @returns the old value if present
-     */
     public Object put(Serializable key, Object value)
     {
-        if (_deleted != null)
+        Object returnValue = null;
+        if (_createDeltas())
         {
-            _deleted.remove(key);
+            if (_deltas.containsKey(key))
+            {
+                returnValue = _deltas.put(key, value);
+                _fullState.put(key, value);
+            }
+            else
+            {
+                _deltas.put(key, value);
+                returnValue = _fullState.put(key, value);
+            }
         }
-        if (isInitalStateMarked())
+        else
         {
-            //delta tracking is on
-            Object oldValue = _deltas.put(key, value);
-            if (oldValue == null)
+            /*
+            if (value instanceof StateHolder)
             {
-                oldValue = _fullState.put(key, value);
+                _stateHolderKeys.add(key);
             }
-            return oldValue;
+            */
+            returnValue = _fullState.put(key, value);
         }
-
-        return _fullState.put(key, value);
+        return returnValue;
     }
 
-    /**
-     * puts a value into the internal data structures and the value has to be map
-     * mapped via mapkey,
-     * @param key the key for the mapping
-     * @param mapKey the internal map key for the mapping
-     * @returns the old value of key->mapKey if present!
-     */
     @Override
     public Object put(Serializable key, String mapKey, Object value)
     {
-        Object oldValue = null;
-        if (_deleted != null)
-        {
-            _deleted.remove(key);
-        }
-        if (isInitalStateMarked())
-        {
-            oldValue = _putMap(_deltas, key, mapKey, value);
-            if (oldValue == null)
+        boolean returnSet = false;
+        Object returnValue = null;
+        if (_createDeltas())
+        {
+            //Track delta case
+            Map<String, Object> mapValues = (Map<String, Object>) _deltas
+                    .get(key);
+            if (mapValues == null)
             {
-                oldValue = _putMap(_fullState, key, mapKey, value);
-
+                mapValues = new InternalMap<String, Object>();
+                _deltas.put(key, mapValues);
+            }
+            if (mapValues.containsKey(mapKey))
+            {
+                returnValue = mapValues.put(mapKey, value);
+                returnSet = true;
+            }
+            else
+            {
+                mapValues.put(mapKey, value);
             }
-            return oldValue;
         }
 
-        //either no initial state or no delta state saving
-        return _putMap(_fullState, key, mapKey, value);
+        //Handle change on full map
+        Map<String, Object> mapValues = (Map<String, Object>) _fullState
+                .get(key);
+        if (mapValues == null)
+        {
+            mapValues = new InternalMap<String, Object>();
+            _fullState.put(key, mapValues);
+        }
+        if (returnSet)
+        {
+            mapValues.put(mapKey, value);
+        }
+        else
+        {
+            returnValue = mapValues.put(mapKey, value);
+        }
+        return returnValue;
     }
 
     @Override
     public Object remove(Serializable key)
     {
-        Object deltaRetVal = _deltas.remove(key);
-        Object initRetVal = _fullState.remove(key);
-        //delta if given is always newer than init!
-        if (_deleted == null)
+        Object returnValue = null;
+        if (_createDeltas())
         {
-            _deleted = new HashSet<Object>();
+            if (_deltas.containsKey(key))
+            {
+                // Keep track of the removed values using key/null pair on the delta map
+                returnValue = _deltas.put(key, null);
+                _fullState.remove(key);
+            }
+            else
+            {
+                // Keep track of the removed values using key/null pair on the delta map
+                _deltas.put(key, null);
+                returnValue = _fullState.remove(key);
+            }
+        }
+        else
+        {
+            returnValue = _fullState.remove(key);
         }
-        _deleted.add(key);
-        return (deltaRetVal != null) ? deltaRetVal : initRetVal;
+        return returnValue;
     }
 
     @Override
     public Object remove(Serializable key, Object valueOrKey)
     {
-        Object deltaDS = _deltas.get(key);
-        Object initDS = _fullState.get(key);
-
-        Object deltaRetVal = null;
-        Object initRetVal = null;
+        // Comment by lu4242 : The spec javadoc says if it is a Collection 
+        // or Map deal with it. But the intention of this method is work 
+        // with add(?,?) and put(?,?,?), this ones return instances of 
+        // InternalMap and InternalList to prevent mixing, so to be 
+        // consistent we'll cast to those classes here.
+        
+        Object collectionOrMap = _fullState.get(key);
+        Object returnValue = null;
+        if (collectionOrMap instanceof InternalMap)
+        {
+            if (_createDeltas())
+            {
+                returnValue = _removeValueOrKeyFromMap(_deltas, key,
+                        valueOrKey, true);
+                _removeValueOrKeyFromMap(_fullState, key, valueOrKey, false);
+            }
+            else
+            {
+                returnValue = _removeValueOrKeyFromMap(_fullState, key,
+                        valueOrKey, false);
+            }
+        }
+        else if (collectionOrMap instanceof InternalList)
+        {
+            if (_createDeltas())
+            {
+                returnValue = _removeValueOrKeyFromCollectionDelta(_deltas,
+                        key, valueOrKey);
+                _removeValueOrKeyFromCollection(_fullState, key, valueOrKey);
+            }
+            else
+            {
+                returnValue = _removeValueOrKeyFromCollection(_fullState, key,
+                        valueOrKey);
+            }
+        }
+        return returnValue;
+    }
 
-        if (deltaDS != null)
+    private static Object _removeValueOrKeyFromCollectionDelta(
+            Map<Serializable, Object> stateMap, Serializable key,
+            Object valueOrKey)
+    {
+        Object returnValue = null;
+        Map<Object, Boolean> c = (Map<Object, Boolean>) stateMap.get(key);
+        if (c != null)
         {
-            deltaRetVal = _removeFromCollection(_deltas, key, deltaDS,
-                    valueOrKey);
+            if (c.containsKey(valueOrKey))
+            {
+                returnValue = valueOrKey;
+            }
+            c.put(valueOrKey, Boolean.FALSE);
         }
-        if (initDS != null)
+        return returnValue;
+    }
+
+    private static Object _removeValueOrKeyFromCollection(
+            Map<Serializable, Object> stateMap, Serializable key,
+            Object valueOrKey)
+    {
+        Object returnValue = null;
+        Collection c = (Collection) stateMap.get(key);
+        if (c != null)
         {
-            initRetVal = _removeFromCollection(_fullState, key, initDS,
-                    valueOrKey);
+            if (c.remove(valueOrKey))
+            {
+                returnValue = valueOrKey;
+            }
+            if (c.isEmpty())
+            {
+                stateMap.remove(key);
+            }
         }
+        return returnValue;
+    }
 
-        if (_deleted == null)
+    private static Object _removeValueOrKeyFromMap(
+            Map<Serializable, Object> stateMap, Serializable key,
+            Object valueOrKey, boolean delta)
+    {
+        if (valueOrKey == null)
         {
-            _deleted = new HashSet<Object>();
+            return null;
         }
 
-        if (!_deltas.containsKey(key))
+        Object returnValue = null;
+        Map<String, Object> map = (Map<String, Object>) stateMap.get(key);
+        if (map != null)
         {
-            _deleted.add(key);
+            if (delta)
+            {
+                // Keep track of the removed values using key/null pair on the delta map
+                returnValue = map.put((String) valueOrKey, null);
+            }
+            else
+            {
+                returnValue = map.remove(valueOrKey);
+            }
+
+            if (map.isEmpty())
+            {
+                //stateMap.remove(key);
+                stateMap.put(key, null);
+            }
         }
-        return (deltaRetVal != null) ? deltaRetVal : initRetVal;
+        return returnValue;
     }
 
-    /*
+    @Override
+    public boolean isTransient()
+    {
+        return _transient;
+    }
+
+    /**
      * Serializing cod
      * the serialized data structure consists of key value pairs unless the value itself is an internal array
      * or a map in case of an internal array or map the value itself is another array with its initial value
@@ -280,12 +491,30 @@
     public Object saveState(FacesContext context)
     {
         Map serializableMap = (isInitalStateMarked()) ? _deltas : _fullState;
-        Set<Object> deltaDeleted = (isInitalStateMarked()) ? _deleted : null;
 
+        if (serializableMap == null || serializableMap.size() == 0)
+        {
+            return null;
+        }
+        
+        /*
+        int stateHolderKeyCount = 0;
+        if (isInitalStateMarked())
+        {
+            for (Iterator<Serializable> it = _stateHolderKeys.iterator(); it.hasNext();)
+            {
+                Serializable key = it.next();
+                if (!_deltas.containsKey(key))
+                {
+                    stateHolderKeyCount++;
+                }
+            }
+        }*/
+        
         Map.Entry<Serializable, Object> entry;
         //entry == key, value, key, value
-        Object[] retArr = new Object[serializableMap.entrySet().size() * 2
-                + ((_deleted != null && _deleted.size() > 0) ? 2 : 0)];
+        Object[] retArr = new Object[serializableMap.entrySet().size() * 2];
+        //Object[] retArr = new Object[serializableMap.entrySet().size() * 2 + stateHolderKeyCount]; 
 
         Iterator<Map.Entry<Serializable, Object>> it = serializableMap
                 .entrySet().iterator();
@@ -294,216 +523,293 @@
         {
             entry = it.next();
             retArr[cnt] = entry.getKey();
-            if (entry instanceof InternalList)
-            {
-                //TODO add list serialisation code
-                retArr[cnt + 1] = serializeOneDimDS((InternalList) entry);
-            }
-            else if (entry instanceof InternalMap)
-            {
-                //TODO add map serialisation code here
-                retArr[cnt + 1] = serializeInternalMap((InternalMap) entry);
+
+            Object value = entry.getValue();
+            
+            // The condition in which the call to saveAttachedState
+            // is to handle List, StateHolder or non Serializable instances.
+            // we check it here, to prevent unnecessary calls.
+            if (value instanceof StateHolder ||
+                value instanceof List ||
+                !(value instanceof Serializable))
+            {
+                Object savedValue = UIComponentBase.saveAttachedState(context,
+                    value);
+                retArr[cnt + 1] = savedValue;
             }
             else
             {
-
-                retArr[cnt + 1] = (Serializable) entry.getValue();
+                retArr[cnt + 1] = value;
             }
             cnt += 2;
-
         }
-
-        //we now store the deleted deltas as well, we cannot handle deleted in our map alone!
-        if (deltaDeleted != null && deltaDeleted.size() > 0)
+        
+        /*
+        if (isInitalStateMarked())
         {
-            Object[] serializedDeletes = serializeOneDimDS(_deleted);
-            retArr[cnt] = INTERNAL_DELETED_KEY;
-            retArr[cnt + 1] = serializedDeletes;
+            for (Iterator<Serializable> it2 = _stateHolderKeys.iterator(); it.hasNext();)
+            {
+                Serializable key = it2.next();
+                if (!_deltas.containsKey(key))
+                {
+                    retArr[cnt] = key;
+                    Object value = _fullState.get(key);
+                    if (value instanceof PartialStateHolder)
+                    {
+                        //Could contain delta, save it as _AttachedDeltaState
+                        PartialStateHolder holder = (PartialStateHolder) value;
+                        if (holder.isTransient())
+                        {
+                            retArr[cnt + 1] = null;
+                        }
+                        else
+                        {
+                            retArr[cnt + 1] = new _AttachedDeltaWrapper(value.getClass(), holder.saveState(context));
+                        }
+                    }
+                    else
+                    {
+                        //Save everything
+                        retArr[cnt + 1] = UIComponentBase.saveAttachedState(context, _fullState.get(key));
+                    }
+                    cnt += 2;
+                }
+            }
         }
+        */       
         return retArr;
     }
 
-    /**
-     * serializes a one dimensional data structure (array, list, set)
-     *
-     * @param entry the one dimensional collection to be serialized
-     * @return an array representation of the collection with two entries
-     * the first entry an identifier key and the second entry an array
-     * of elements which represent our collection
-     */
-    private Object[] serializeOneDimDS(Collection<Object> entry)
-    {
-        Object[] retVal = new Object[2]; //array with two elements one the marker second the array
-        retVal[0] = _DeltaStateHelper.INTERNAL_LIST_KEY;
-        retVal[1] = entry.toArray(new Object[entry.size()]);
-
-        return retVal;
-    }
-
-    private void deserializeOneDimDS(Object param, Collection target)
-    {
-        Object[] saveState = (Object[]) param;
-        //first element list marker, already processed!
-        Object[] listAsArr = (Object[]) saveState[1];
-
-        //since all other options would mean dual iteration we have to do it the hard way
-        for (Object elem : listAsArr)
-        {
-            target.add(elem);
-        }
-
-    }
-
-    private InternalMap deserializeInternalMap(Object param)
-    {
-        Object[] saveState = (Object[]) param;
-        Object[] listAsMap = (Object[]) saveState[1];
-
-        InternalMap retVal = new InternalMap(listAsMap.length / 2);
-        for (int cnt = 0; cnt < listAsMap.length; cnt += 2)
-        {
-            retVal.put((String) listAsMap[cnt], listAsMap[cnt + 1]);
-        }
-        return retVal;
-    }
-
-    private Object[] serializeInternalMap(Map<String, Object> map)
-    {
-        Object[] retVal = new Object[2];
-        retVal[0] = _DeltaStateHelper.INTERNAL_MAP_KEY;
-
-        int cnt = 0;
-        Object[] mapArr = new Object[map.size()];
-        retVal[1] = mapArr;
-        for (Map.Entry<String, Object> entry : map.entrySet())
-        {
-            mapArr[cnt] = entry.getKey();
-            mapArr[cnt + 1] = entry.getValue();
-            cnt += 2;
-        }
-        return retVal;
-    }
-
     @Override
     public void restoreState(FacesContext context, Object state)
     {
+        if (state == null)
+            return;
+
         Object[] serializedState = (Object[]) state;
 
         for (int cnt = 0; cnt < serializedState.length; cnt += 2)
         {
             Serializable key = (Serializable) serializedState[cnt];
-            Object value = serializedState[cnt + 1];
+            Object savedValue = UIComponentBase.restoreAttachedState(context,
+                    serializedState[cnt + 1]);
 
-            if (key instanceof String
-                    && ((String) key).equals(INTERNAL_DELETED_KEY))
+            if (isInitalStateMarked())
             {
-                _deleted = new HashSet<Object>();
-                deserializeOneDimDS(value, _deleted);
-            }
-            else if (value instanceof String
-                    && ((String) value).equals(INTERNAL_LIST_KEY))
-            {
-                Object[] valArr = (Object[]) ((Object[]) value)[1];
-                InternalList target = new InternalList(valArr.length * 2);
-                deserializeOneDimDS(value, target);
-                put(key, target);
+                if (savedValue instanceof InternalDeltaListMap)
+                {
+                    for (Map.Entry<Object, Boolean> mapEntry : ((Map<Object, Boolean>) savedValue)
+                            .entrySet())
+                    {
+                        boolean addOrRemove = mapEntry.getValue();
+                        if (addOrRemove)
+                        {
+                            //add
+                            this.add(key, mapEntry.getKey());
+                        }
+                        else
+                        {
+                            //remove
+                            this.remove(key, mapEntry.getKey());
+                        }
+                    }
+                }
+                else if (savedValue instanceof InternalMap)
+                {
+                    for (Map.Entry<String, Object> mapEntry : ((Map<String, Object>) savedValue)
+                            .entrySet())
+                    {
+                        this.put(key, mapEntry.getKey(), mapEntry.getValue());
+                    }
+                }
+                /*
+                else if (savedValue instanceof _AttachedDeltaWrapper)
+                {
+                    _AttachedStateWrapper wrapper = (_AttachedStateWrapper) savedValue;
+                    //Restore delta state
+                    ((PartialStateHolder)_fullState.get(key)).restoreState(context, wrapper.getWrappedStateObject());
+                    //Add this key as StateHolder key 
+                    _stateHolderKeys.add(key);
+                }
+                */
+                else
+                {
+                    put(key, savedValue);
+                }
             }
-            else if (value instanceof String
-                    && ((String) value).equals(INTERNAL_MAP_KEY))
+            else
             {
-                value = deserializeInternalMap(value);
-                put(key, value);
+                put(key, savedValue);
             }
         }
     }
 
     @Override
-    public boolean isTransient()
+    public void setTransient(boolean transientValue)
     {
-        return _transient;
+        _transient = transientValue;
     }
 
-    @Override
-    public void setTransient(boolean newTransientValue)
+    //We use our own data structures just to make sure
+    //nothing gets mixed up internally
+    static class InternalMap<K, V> extends HashMap<K, V> implements StateHolder
     {
-        _transient = newTransientValue;
-    }
+        public InternalMap()
+        {
+            super();
+        }
 
-    private Object _putMap(Map rootMap, Serializable key, String mapKey,
-            Object value)
-    {
-        Object oldValue = rootMap.get(key);
-        //if no delta is found we add it to both DS
-        if (oldValue == null)
+        public InternalMap(int initialCapacity, float loadFactor)
         {
-            Map storageMap = new InternalMap(3);
-            storageMap.put(mapKey, value);
-            return rootMap.put(key, storageMap);
+            super(initialCapacity, loadFactor);
         }
-        else
+
+        public InternalMap(Map<? extends K, ? extends V> m)
         {
-            return ((Map) oldValue).put(mapKey, value);
+            super(m);
         }
-    }
 
-    private Object _removeFromCollection(Map initialMap, Serializable key,
-            Object dataStructure, Object valueOrKey)
-    {
-        Object retVal = null;
-        if (dataStructure != null)
+        public InternalMap(int initialSize)
         {
-            if (dataStructure instanceof InternalList)
-            {
-                retVal = ((InternalList) dataStructure).remove(valueOrKey);
-                if (((Collection) dataStructure).isEmpty())
-                {
-                    initialMap.remove(key);
-                    if (_deleted == null)
-                    {
-                        _deleted = new HashSet<Object>();
-                    }
-                    _deleted.add(key);
+            super(initialSize);
+        }
 
-                }
+        @Override
+        public boolean isTransient()
+        {
+            return false;
+        }
+
+        @Override
+        public void setTransient(boolean newTransientValue)
+        {
+            // No op
+        }
+
+        @Override
+        public void restoreState(FacesContext context, Object state)
+        {
+            Object[] listAsMap = (Object[]) state;
+            for (int cnt = 0; cnt < listAsMap.length; cnt += 2)
+            {
+                this.put((K) listAsMap[cnt], (V) UIComponentBase
+                        .restoreAttachedState(context, listAsMap[cnt + 1]));
             }
-            else if (dataStructure instanceof InternalMap)
+        }
+
+        @Override
+        public Object saveState(FacesContext context)
+        {
+            int cnt = 0;
+            Object[] mapArr = new Object[this.size() * 2];
+            for (Map.Entry<K, V> entry : this.entrySet())
             {
-                retVal = ((InternalMap) dataStructure).remove(valueOrKey);
-                if (((InternalMap) dataStructure).isEmpty())
+                mapArr[cnt] = entry.getKey();
+                Object value = entry.getValue();
+                
+                if (value instanceof StateHolder ||
+                    value instanceof List ||
+                    !(value instanceof Serializable))
                 {
-                    initialMap.remove(key);
-                    if (_deleted == null)
-                    {
-                        _deleted = new HashSet<Object>();
-                    }
-                    _deleted.add(key);
+                    mapArr[cnt + 1] = UIComponentBase.saveAttachedState(context, value);
                 }
+                else
+                {
+                    mapArr[cnt + 1] = value;
+                }
+                cnt += 2;
             }
-            else
-            {
-                retVal = dataStructure;
-            }
+            return mapArr;
         }
-        return retVal;
     }
 
-    //We use our own data structures just to make sure
-    //nothing gets mixed up internally
-    class InternalMap extends HashMap
+    /**
+     * Map used to keep track of list changes 
+     */
+    static class InternalDeltaListMap<K, V> extends InternalMap<K, V>
     {
 
-        public InternalMap(int initialSize)
+        public InternalDeltaListMap()
+        {
+            super();
+        }
+
+        public InternalDeltaListMap(int initialCapacity, float loadFactor)
+        {
+            super(initialCapacity, loadFactor);
+        }
+
+        public InternalDeltaListMap(int initialSize)
         {
             super(initialSize);
         }
+
+        public InternalDeltaListMap(Map<? extends K, ? extends V> m)
+        {
+            super(m);
+        }
     }
 
-    class InternalList extends ArrayList
+    static class InternalList<T> extends ArrayList<T> implements StateHolder
     {
+        public InternalList()
+        {
+            super();
+        }
+
+        public InternalList(Collection<? extends T> c)
+        {
+            super(c);
+        }
 
         public InternalList(int initialSize)
         {
             super(initialSize);
         }
+
+        @Override
+        public boolean isTransient()
+        {
+            return false;
+        }
+
+        @Override
+        public void setTransient(boolean newTransientValue)
+        {
+        }
+
+        @Override
+        public void restoreState(FacesContext context, Object state)
+        {
+            Object[] listAsArr = (Object[]) state;
+            //since all other options would mean dual iteration 
+            //we have to do it the hard way
+            for (Object elem : listAsArr)
+            {
+                add((T) UIComponentBase.restoreAttachedState(context, elem));
+            }
+        }
+
+        @Override
+        public Object saveState(FacesContext context)
+        {
+            Object[] values = new Object[size()];
+            for (int i = 0; i < size(); i++)
+            {
+                Object value = get(i);
+                
+                if (value instanceof StateHolder ||
+                    value instanceof List ||
+                    !(value instanceof Serializable))
+                {
+                    values[i] = UIComponentBase.saveAttachedState(context, value);
+                }
+                else
+                {
+                    values[i] = value;
+                }                
+            }
+            return values;
+        }
     }
 }

Added: myfaces/core/branches/2_0_0/api/src/test/java/javax/faces/component/_Delta2StateHelperTest.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2_0_0/api/src/test/java/javax/faces/component/_Delta2StateHelperTest.java?rev=787511&view=auto
==============================================================================
--- myfaces/core/branches/2_0_0/api/src/test/java/javax/faces/component/_Delta2StateHelperTest.java (added)
+++ myfaces/core/branches/2_0_0/api/src/test/java/javax/faces/component/_Delta2StateHelperTest.java Tue Jun 23 01:36:37 2009
@@ -0,0 +1,484 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.List;
+import java.util.Map;
+
+import javax.faces.context.FacesContext;
+
+
+public class _Delta2StateHelperTest extends AbstractComponentTest
+{
+
+    public _Delta2StateHelperTest(String name)
+    {
+        super(name);
+    }
+    
+    public static class UITestComponent extends UIComponentBase
+    {
+        public UITestComponent()
+        {
+            super();
+        }
+
+        @Override
+        public String getFamily()
+        {
+            return "javax.faces.Test";
+        }
+
+        private enum PropertyKeys
+        {
+            testProperty1,
+            testProperty2
+        }
+        
+        public String getTestProperty1()
+        {
+            return (String) getStateHelper().eval(PropertyKeys.testProperty1);
+        }
+
+        public void setTestProperty1(String testProperty1)
+        {
+            getStateHelper().put(PropertyKeys.testProperty1, testProperty1);
+        }
+        
+        public String getTestProperty2()
+        {
+            return (String) getStateHelper().eval(PropertyKeys.testProperty2);
+        }
+
+        public void setTestProperty2(String testProperty2)
+        {
+            getStateHelper().put(PropertyKeys.testProperty2, testProperty2);
+        }
+
+        /*
+        private StateHelper _stateHelper = null;
+        
+        public StateHelper getStateHelper(boolean create) {
+
+            if (create && _stateHelper == null) 
+            {
+                _stateHelper = new _DeltaStateHelper(this);
+            }
+            return _stateHelper;
+        }
+        */
+        
+        public StateHelper getStateHelper()
+        {
+            return super.getStateHelper();
+        }
+
+        @Override
+        public void restoreState(FacesContext context, Object state)
+        {
+            Object[] values = (Object[]) state;
+            super.restoreState(context, values[0]);
+            //getStateHelper().restoreState(context, values[1]);
+        }
+
+        @Override
+        public Object saveState(FacesContext context)
+        {
+            Object[] values = new Object[2];
+            values[0] = super.saveState(context);
+            //values[1] = _stateHelper == null ? null : _stateHelper.saveState(context);
+            return values;
+        }
+    }
+
+    @Override
+    protected void setUp() throws Exception
+    {
+        super.setUp();
+    }
+
+    @Override
+    protected void tearDown() throws Exception
+    {
+        super.tearDown();
+    }
+    
+    public void testSimpleGetterSetter() throws Exception
+    {
+        UITestComponent a = new UITestComponent();
+        assertNull(a.getTestProperty1());
+        a.setTestProperty1("testProperty1");
+        assertEquals("testProperty1", a.getTestProperty1());
+        a.setTestProperty1(null);
+        assertNull(a.getTestProperty1());
+    }
+    
+    public void testEmptySaveRestore() throws Exception
+    {
+        UITestComponent a = new UITestComponent();
+        UITestComponent b = new UITestComponent();
+        
+        Object state1 = (Object) a.saveState(facesContext);
+
+        b.restoreState(facesContext, state1);
+
+        Object state2 = b.saveState(facesContext);
+
+        assertEquals(a.getTestProperty1(), b.getTestProperty1());
+        assertEquals(a.getTestProperty2(), b.getTestProperty2());        
+    }
+    
+    public void testSimpleSaveRestore() throws Exception
+    {
+        UITestComponent a = new UITestComponent();
+        UITestComponent b = new UITestComponent();
+        
+        a.setTestProperty1("testProperty1");
+        a.setTestProperty2(null);
+        Object state1 = (Object) a.saveState(facesContext);
+
+        b.restoreState(facesContext, state1);
+
+        Object state2 = b.saveState(facesContext);
+
+        assertEquals(a.getTestProperty1(), b.getTestProperty1());
+        assertEquals(a.getTestProperty2(), b.getTestProperty2());
+    }
+    
+    public void testDeltaStateSaveRestore()
+    {
+        UITestComponent a = new UITestComponent();
+        UITestComponent b = new UITestComponent();
+        
+        a.setTestProperty1("testProperty1");
+        a.setTestProperty2(null);
+        
+        //Replicate the stuff to reach template status
+        b.setTestProperty1("testProperty1");
+        b.setTestProperty2(null);
+        
+        a.markInitialState();
+        b.markInitialState();
+        
+        a.setTestProperty2("testProperty2");
+        a.setTestProperty1(null);
+        
+        Object state1 = (Object) a.saveState(facesContext);
+
+        b.restoreState(facesContext, state1);
+
+        Object state2 = b.saveState(facesContext);
+
+        assertNull(a.getTestProperty1());
+        assertNull(b.getTestProperty1());        
+        assertEquals("testProperty2", a.getTestProperty2());
+        assertEquals("testProperty2", b.getTestProperty2());
+    }
+    
+    public void testPutPropertyStateHelper1()
+    {
+        UITestComponent a = new UITestComponent();
+        
+        StateHelper helper = a.getStateHelper();
+        
+        Object retValue = helper.put("someProperty", "someValue");
+        //No value previously set
+        assertNull(retValue);
+        
+        a.markInitialState();
+        
+        retValue = helper.put("someProperty", "someOtherValue");
+        
+        assertEquals("someValue",retValue);
+        
+        retValue = helper.put("someProperty", "someOtherOtherValue");
+        
+        assertEquals("someOtherValue",retValue);
+        
+        a.clearInitialState();
+        
+        retValue = helper.put("someProperty", "someOtherOtherOtherValue");
+        
+        assertEquals("someOtherOtherValue",retValue);
+    }
+    
+    public void testPutPropertyStateHelper2()
+    {
+        UITestComponent a = new UITestComponent();
+        
+        StateHelper helper = a.getStateHelper();
+        
+        Object retValue = helper.put("someProperty", "someValue");
+        //No value previously set
+        assertNull(retValue);
+        
+        a.markInitialState();
+        
+        retValue = helper.put("someProperty", null);
+        
+        assertEquals("someValue",retValue);
+        
+        retValue = helper.put("someProperty", "someOtherOtherValue");
+        
+        assertNull(retValue);
+        
+        a.clearInitialState();
+        
+        retValue = helper.put("someProperty", null);
+        
+        assertEquals("someOtherOtherValue",retValue);
+    }
+    
+    public void testRemovePropertyStateHelper1()
+    {
+        UITestComponent a = new UITestComponent();
+        
+        StateHelper helper = a.getStateHelper();
+        
+        Object retValue = helper.put("someProperty", "someValue");
+        //No value previously set
+        assertNull(retValue);
+        
+        a.markInitialState();
+        
+        retValue = helper.remove("someProperty");
+        
+        assertEquals("someValue",retValue);
+        
+        retValue = helper.put("someProperty", "someOtherOtherValue");
+        
+        assertNull(retValue);
+        
+        a.clearInitialState();
+        
+        retValue = helper.remove("someProperty");
+        
+        assertEquals("someOtherOtherValue",retValue);
+    }
+    
+    
+    public void testAddItemOnList1()
+    {
+        UITestComponent a = new UITestComponent();
+        UITestComponent b = new UITestComponent();
+        
+        StateHelper helperA = a.getStateHelper();
+        StateHelper helperB = b.getStateHelper();
+        
+        helperA.add("somePropertyList", "someValue1");
+        helperB.add("somePropertyList", "someValue1");
+        a.markInitialState();
+        b.markInitialState();
+
+        helperA.add("somePropertyList", "someValue2");
+        helperA.add("somePropertyList", "someValue3");
+        
+        b.restoreState(facesContext, a.saveState(facesContext));
+        
+        List listA = (List) helperA.get("somePropertyList");
+        
+        assertEquals("someValue1",listA.get(0));
+        assertEquals("someValue2",listA.get(1));
+        assertEquals("someValue3",listA.get(2));
+        
+        List listB = (List) helperB.get("somePropertyList");
+        
+        assertEquals("someValue1",listB.get(0));
+        assertEquals("someValue2",listB.get(1));
+        assertEquals("someValue3",listB.get(2));
+    }
+    
+    public void testAddItemOnList2()
+    {
+        UITestComponent a = new UITestComponent();
+        UITestComponent b = new UITestComponent();
+        
+        StateHelper helperA = a.getStateHelper();
+        StateHelper helperB = b.getStateHelper();
+        
+        helperA.add("somePropertyList", "someValue1");
+        helperB.add("somePropertyList", "someValue1");
+        a.markInitialState();
+        b.markInitialState();
+
+        helperA.add("somePropertyList", "someValue2");
+        //helperA.add("somePropertyList", "someValue3");
+        
+        helperA.remove("somePropertyList","someValue1");
+        helperA.remove("somePropertyList","someValue2");
+        
+        b.restoreState(facesContext, a.saveState(facesContext));
+        
+        List listA = (List) helperA.get("somePropertyList");
+        
+        if (listA != null)
+        {
+            assertFalse("The list should not contain [someValue1]", listA.contains("someValue1"));
+            assertFalse("The list should not contain [someValue2]", listA.contains("someValue2"));
+        }
+        
+        List listB = (List) helperB.get("somePropertyList");
+
+        if (listB != null)
+        {
+            assertFalse("The list should not contain [someValue2]", listB.contains("someValue2"));            
+            assertFalse("The list should not contain [someValue1]", listB.contains("someValue1"));
+        }
+    }
+    
+    public void testAddItemOnList3()
+    {
+        UITestComponent a = new UITestComponent();
+        UITestComponent b = new UITestComponent();
+        
+        StateHelper helperA = a.getStateHelper();
+        StateHelper helperB = b.getStateHelper();
+        
+        helperA.add("somePropertyList", "someValue1");
+        helperB.add("somePropertyList", "someValue1");
+        a.markInitialState();
+        b.markInitialState();
+
+        helperA.add("somePropertyList", "someValue2");
+        helperA.add("somePropertyList", "someValue3");
+        
+        helperA.remove("somePropertyList","someValue1");
+        helperA.remove("somePropertyList","someValue2");
+        
+        b.restoreState(facesContext, a.saveState(facesContext));
+        
+        List listA = (List) helperA.get("somePropertyList");
+        
+        assertTrue("The list should contain [someValue3]", listA.contains("someValue3"));
+        assertFalse("The list should not contain [someValue1]", listA.contains("someValue1"));
+        assertFalse("The list should not contain [someValue2]", listA.contains("someValue2"));
+        
+        List listB = (List) helperB.get("somePropertyList");
+
+        assertTrue("The list should contain [someValue3]", listB.contains("someValue3"));
+        assertFalse("The list should not contain [someValue2]", listB.contains("someValue2"));            
+        assertFalse("The list should not contain [someValue1]", listB.contains("someValue1"));
+    }    
+    
+    public void testPutItemOnMap1()
+    {
+        UITestComponent a = new UITestComponent();
+        UITestComponent b = new UITestComponent();
+        
+        StateHelper helperA = a.getStateHelper();
+        StateHelper helperB = b.getStateHelper();
+        
+        helperA.put("somePropertyMap","key1", "someValue1");
+        helperB.put("somePropertyMap","key1", "someValue1");
+        a.markInitialState();
+        b.markInitialState();
+        
+        helperA.put("somePropertyMap","key2", "someValue2");
+        helperA.put("somePropertyMap","key3", "someValue3");
+        
+        b.restoreState(facesContext, a.saveState(facesContext));
+        
+        Map mapA = (Map) helperA.get("somePropertyMap");
+        
+        assertEquals("someValue1",mapA.get("key1"));
+        assertEquals("someValue2",mapA.get("key2"));
+        assertEquals("someValue3",mapA.get("key3"));        
+
+        Map mapB = (Map) helperB.get("somePropertyMap");
+        
+        assertEquals("someValue1",mapB.get("key1"));
+        assertEquals("someValue2",mapB.get("key2"));
+        assertEquals("someValue3",mapB.get("key3"));        
+    }
+    
+    public void testPutRemoveItemOnMap2()
+    {
+        UITestComponent a = new UITestComponent();
+        UITestComponent b = new UITestComponent();
+        
+        StateHelper helperA = a.getStateHelper();
+        StateHelper helperB = b.getStateHelper();
+        
+        helperA.put("somePropertyMap","key1", "someValue1");
+        helperB.put("somePropertyMap","key1", "someValue1");
+        a.markInitialState();
+        b.markInitialState();
+        
+        helperA.put("somePropertyMap","key2", "someValue2");
+        
+        helperA.remove("somePropertyMap","key1");
+        helperA.remove("somePropertyMap","key2");
+        
+        b.restoreState(facesContext, a.saveState(facesContext));
+        
+        Map mapA = (Map) helperA.get("somePropertyMap");
+        
+        if (mapA != null)
+        {
+            assertNull(mapA.get("key2"));
+            assertNull(mapA.get("key1"));
+        }
+
+        Map mapB = (Map) helperB.get("somePropertyMap");
+        
+        if (mapB != null)
+        {
+            assertNull(mapB.get("key2"));
+            assertNull(mapB.get("key1"));
+        }
+    }
+    
+    public void testPutRemoveItemOnMap3()
+    {
+        UITestComponent a = new UITestComponent();
+        UITestComponent b = new UITestComponent();
+        
+        StateHelper helperA = a.getStateHelper();
+        StateHelper helperB = b.getStateHelper();
+        
+        helperA.put("somePropertyMap","key1", "someValue1");
+        helperB.put("somePropertyMap","key1", "someValue1");
+        a.markInitialState();
+        b.markInitialState();
+        
+        helperA.put("somePropertyMap","key2", "someValue2");
+        helperA.put("somePropertyMap","key3", "someValue3");
+        
+        helperA.remove("somePropertyMap","key1");
+        helperA.remove("somePropertyMap","key2");
+        
+        b.restoreState(facesContext, a.saveState(facesContext));
+        
+        Map mapA = (Map) helperA.get("somePropertyMap");
+        
+        if (mapA != null)
+        {
+            assertNull(mapA.get("key2"));
+            assertNull(mapA.get("key1"));
+        }
+
+        Map mapB = (Map) helperB.get("somePropertyMap");
+        
+        if (mapB != null)
+        {
+            assertNull(mapB.get("key2"));
+            assertNull(mapB.get("key1"));
+        }
+    }    
+}

Propchange: myfaces/core/branches/2_0_0/api/src/test/java/javax/faces/component/_Delta2StateHelperTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: myfaces/core/branches/2_0_0/api/src/test/java/javax/faces/component/_Delta2StateHelperTest.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Modified: myfaces/core/branches/2_0_0/api/src/test/java/javax/faces/component/_DeltaStateHelperTest.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2_0_0/api/src/test/java/javax/faces/component/_DeltaStateHelperTest.java?rev=787511&r1=787510&r2=787511&view=diff
==============================================================================
--- myfaces/core/branches/2_0_0/api/src/test/java/javax/faces/component/_DeltaStateHelperTest.java (original)
+++ myfaces/core/branches/2_0_0/api/src/test/java/javax/faces/component/_DeltaStateHelperTest.java Tue Jun 23 01:36:37 2009
@@ -21,15 +21,13 @@
 import java.util.List;
 import java.util.Map;
 
-import junit.framework.TestCase;
-
 /**
  * A generic framework less testcase for our _DeltaStateHelper class!
  *
  * @author Werner Punz (latest modification by $Author$)
  * @version $Rev$ $Date$
  */
-public class _DeltaStateHelperTest extends TestCase
+public class _DeltaStateHelperTest extends AbstractComponentTest
 {
 
     private static final String KEY3 = "key3";
@@ -260,19 +258,19 @@
         _setupGetTests();
         _instance.setInitialStateMarked(false);
         Object serializedState = _instance.saveState(null);
-        _instance.restoreState(null, serializedState);
+        _instance.restoreState(facesContext, serializedState);
         assertStructure();
 
         _setupGetTests();
         _instance.setInitialStateMarked(true);
         serializedState = _instance.saveState(null);
-        _instance.restoreState(null, serializedState);
+        _instance.restoreState(facesContext, serializedState);
         assertStructure();
 
         _instance.setInitialStateMarked(true);
         _setupGetTests();
         serializedState = _instance.saveState(null);
-        _instance.restoreState(null, serializedState);
+        _instance.restoreState(facesContext, serializedState);
         assertStructure();
     }