You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by ar...@apache.org on 2009/11/30 23:28:48 UTC

svn commit: r885598 - in /myfaces/trinidad/branches/ar_clientBehaviors/trinidad-api/src/main/java/org/apache/myfaces/trinidad: bean/FacesBeanImpl.java bean/util/FlaggedPropertyMap.java bean/util/PropertyHashMap.java component/UIXComponentBase.java

Author: arobinson74
Date: Mon Nov 30 22:28:47 2009
New Revision: 885598

URL: http://svn.apache.org/viewvc?rev=885598&view=rev
Log:
Checkpoint

Modified:
    myfaces/trinidad/branches/ar_clientBehaviors/trinidad-api/src/main/java/org/apache/myfaces/trinidad/bean/FacesBeanImpl.java
    myfaces/trinidad/branches/ar_clientBehaviors/trinidad-api/src/main/java/org/apache/myfaces/trinidad/bean/util/FlaggedPropertyMap.java
    myfaces/trinidad/branches/ar_clientBehaviors/trinidad-api/src/main/java/org/apache/myfaces/trinidad/bean/util/PropertyHashMap.java
    myfaces/trinidad/branches/ar_clientBehaviors/trinidad-api/src/main/java/org/apache/myfaces/trinidad/component/UIXComponentBase.java

Modified: myfaces/trinidad/branches/ar_clientBehaviors/trinidad-api/src/main/java/org/apache/myfaces/trinidad/bean/FacesBeanImpl.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/branches/ar_clientBehaviors/trinidad-api/src/main/java/org/apache/myfaces/trinidad/bean/FacesBeanImpl.java?rev=885598&r1=885597&r2=885598&view=diff
==============================================================================
--- myfaces/trinidad/branches/ar_clientBehaviors/trinidad-api/src/main/java/org/apache/myfaces/trinidad/bean/FacesBeanImpl.java (original)
+++ myfaces/trinidad/branches/ar_clientBehaviors/trinidad-api/src/main/java/org/apache/myfaces/trinidad/bean/FacesBeanImpl.java Mon Nov 30 22:28:47 2009
@@ -6,9 +6,9 @@
  *  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
@@ -31,11 +31,10 @@
 import javax.faces.context.FacesContext;
 import javax.faces.el.ValueBinding;
 
-
-
 import org.apache.myfaces.trinidad.bean.util.FlaggedPropertyMap;
 import org.apache.myfaces.trinidad.logging.TrinidadLogger;
 
+
 /**
  * Base implementation of FacesBean.
  *
@@ -72,8 +71,6 @@
     return null;
   }
 
-
-  
   /**
    * {@inheritDoc}
    */
@@ -87,7 +84,6 @@
     return key.getSupportsBinding() ? getValueExpression(key) : null;
   }
 
-
   // TODO Need *good* way of hooking property-sets;  it's
   // currently not called from state restoring, so really, it shouldn't
   // be used as a hook, but EditableValueBase currently
@@ -113,7 +109,7 @@
     if (map == null)
       return null;
 
-    return (ValueExpression) map.get(key);    
+    return (ValueExpression) map.get(key);
   }
 
   final public void setValueExpression(PropertyKey key,
@@ -139,7 +135,7 @@
     }
 
   }
-  
+
   @SuppressWarnings("deprecation")
   final public ValueBinding getValueBinding(PropertyKey key)
   {
@@ -160,7 +156,7 @@
   final public void setValueBinding(PropertyKey key, ValueBinding binding)
   {
     ValueExpression ve;
-    
+
     if (binding == null)
     {
       ve = null;
@@ -173,7 +169,6 @@
     setValueExpression(key, ve);
   }
 
-
   @SuppressWarnings("unchecked")
   final public void addEntry(PropertyKey listKey, Object value)
   {
@@ -318,7 +313,6 @@
     return _expressions.keySet();
   }
 
-
   public void markInitialState()
   {
     _initialStateMarked = true;
@@ -330,7 +324,6 @@
       _expressions.markInitialState();
   }
 
-
   public void clearInitialState()
   {
     _initialStateMarked = false;
@@ -482,7 +475,6 @@
     return (fromKey.isList() == toKey.isList());
   }
 
-
   private PropertyMap _getPropertyMap()
   {
     if (_properties == null)
@@ -504,7 +496,6 @@
     return _expressions;
   }
 
-
   static private void _checkListKey(PropertyKey listKey)
     throws IllegalArgumentException
   {
@@ -525,6 +516,6 @@
   private PropertyMap  _expressions;
   private transient boolean  _initialStateMarked;
 
-  static private final TrinidadLogger _LOG = TrinidadLogger.createTrinidadLogger(FacesBeanImpl.class);
-
+  static private final TrinidadLogger _LOG = TrinidadLogger.createTrinidadLogger(
+                                               FacesBeanImpl.class);
 }

Modified: myfaces/trinidad/branches/ar_clientBehaviors/trinidad-api/src/main/java/org/apache/myfaces/trinidad/bean/util/FlaggedPropertyMap.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/branches/ar_clientBehaviors/trinidad-api/src/main/java/org/apache/myfaces/trinidad/bean/util/FlaggedPropertyMap.java?rev=885598&r1=885597&r2=885598&view=diff
==============================================================================
--- myfaces/trinidad/branches/ar_clientBehaviors/trinidad-api/src/main/java/org/apache/myfaces/trinidad/bean/util/FlaggedPropertyMap.java (original)
+++ myfaces/trinidad/branches/ar_clientBehaviors/trinidad-api/src/main/java/org/apache/myfaces/trinidad/bean/util/FlaggedPropertyMap.java Mon Nov 30 22:28:47 2009
@@ -6,9 +6,9 @@
  *  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
@@ -23,7 +23,6 @@
 import java.util.Collections;
 import java.util.Iterator;
 import java.util.Map;
-
 import java.util.Set;
 
 import javax.faces.context.FacesContext;
@@ -32,6 +31,7 @@
 import org.apache.myfaces.trinidad.bean.PropertyKey;
 import org.apache.myfaces.trinidad.bean.PropertyMap;
 
+
 public class FlaggedPropertyMap extends AbstractMap<PropertyKey,Object>
                                 implements PropertyMap
 {
@@ -176,7 +176,6 @@
       map.markInitialState();
   }
 
-
   public void clearInitialState()
   {
     PropertyMap map = getPropertyMap(false);
@@ -187,10 +186,10 @@
   public boolean initialStateMarked()
   {
     PropertyMap map = getPropertyMap(false);
-    
+
     if (map != null)
       return map.initialStateMarked();
-    
+
     // TODO gcrawford - do something better?
     return false;
   }
@@ -213,7 +212,6 @@
     StateUtils.restoreState(this, context, type, state, getUseStateHolder());
   }
 
-
   public boolean getUseStateHolder()
   {
     return _useStateHolder;

Modified: myfaces/trinidad/branches/ar_clientBehaviors/trinidad-api/src/main/java/org/apache/myfaces/trinidad/bean/util/PropertyHashMap.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/branches/ar_clientBehaviors/trinidad-api/src/main/java/org/apache/myfaces/trinidad/bean/util/PropertyHashMap.java?rev=885598&r1=885597&r2=885598&view=diff
==============================================================================
--- myfaces/trinidad/branches/ar_clientBehaviors/trinidad-api/src/main/java/org/apache/myfaces/trinidad/bean/util/PropertyHashMap.java (original)
+++ myfaces/trinidad/branches/ar_clientBehaviors/trinidad-api/src/main/java/org/apache/myfaces/trinidad/bean/util/PropertyHashMap.java Mon Nov 30 22:28:47 2009
@@ -6,9 +6,9 @@
  *  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
@@ -21,11 +21,12 @@
 import java.util.HashMap;
 import java.util.Map;
 
+import javax.faces.context.FacesContext;
+
 import org.apache.myfaces.trinidad.bean.FacesBean;
 import org.apache.myfaces.trinidad.bean.PropertyKey;
 import org.apache.myfaces.trinidad.bean.PropertyMap;
 
-import javax.faces.context.FacesContext;
 
 public class PropertyHashMap extends HashMap<PropertyKey,Object>
                              implements PropertyMap
@@ -77,7 +78,7 @@
     {
       if (!super.containsKey(key))
         return null;
-      
+
       // If this key is contained, it certainly must be a PropertyKey!
       assert(key instanceof PropertyKey);
       _deltas.put((PropertyKey) key, null);
@@ -118,7 +119,6 @@
     StateUtils.restoreState(this, context, type, state, getUseStateHolder());
   }
 
-
   protected PropertyMap createDeltaPropertyMap()
   {
     PropertyHashMap map = new PropertyHashMap(2);
@@ -126,7 +126,6 @@
     return map;
   }
 
-
   public boolean getUseStateHolder()
   {
     return _useStateHolder;
@@ -137,7 +136,6 @@
     _useStateHolder = useStateHolder;
   }
 
-
   // =-=AEW CLEAR?
 
   public void markInitialState()
@@ -167,7 +165,7 @@
 
       return true;
     }
-    
+
     return false;
   }
 

Modified: myfaces/trinidad/branches/ar_clientBehaviors/trinidad-api/src/main/java/org/apache/myfaces/trinidad/component/UIXComponentBase.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/branches/ar_clientBehaviors/trinidad-api/src/main/java/org/apache/myfaces/trinidad/component/UIXComponentBase.java?rev=885598&r1=885597&r2=885598&view=diff
==============================================================================
--- myfaces/trinidad/branches/ar_clientBehaviors/trinidad-api/src/main/java/org/apache/myfaces/trinidad/component/UIXComponentBase.java (original)
+++ myfaces/trinidad/branches/ar_clientBehaviors/trinidad-api/src/main/java/org/apache/myfaces/trinidad/component/UIXComponentBase.java Mon Nov 30 22:28:47 2009
@@ -19,11 +19,16 @@
 package org.apache.myfaces.trinidad.component;
 
 import java.io.ByteArrayOutputStream;
-import java.io.InputStream;
 import java.io.IOException;
+import java.io.InputStream;
 import java.io.ObjectOutputStream;
 
 import java.net.URL;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
@@ -38,7 +43,11 @@
 import javax.faces.FacesException;
 import javax.faces.component.ContextCallback;
 import javax.faces.component.NamingContainer;
+import javax.faces.component.PartialStateHolder;
+import javax.faces.component.StateHolder;
 import javax.faces.component.UIComponent;
+import javax.faces.component.behavior.ClientBehavior;
+import javax.faces.component.behavior.ClientBehaviorHolder;
 import javax.faces.context.FacesContext;
 import javax.faces.el.EvaluationException;
 import javax.faces.el.MethodBinding;
@@ -63,6 +72,7 @@
 import org.apache.myfaces.trinidad.render.LifecycleRenderer;
 import org.apache.myfaces.trinidad.util.ThreadLocalUtils;
 
+
 /**
  * Base implementation of components for all of Trinidad.  UIXComponentBase
  * offers a number of features not supplied by the standard UIComponentBase
@@ -398,7 +408,6 @@
     return _parent;
   }
 
-
   /**
    * <p>Set the parent <code>UIComponent</code> of this
    * <code>UIComponent</code>.</p>
@@ -412,14 +421,12 @@
     _parent = parent;
   }
 
-
   @Override
   public boolean isRendered()
   {
     return getBooleanProperty(RENDERED_KEY, true);
   }
 
-
   @Override
   public void setRendered(boolean rendered)
   {
@@ -468,7 +475,6 @@
     setProperty(RENDERER_TYPE_KEY, rendererType);
   }
 
-
   @Override
   public boolean getRendersChildren()
   {
@@ -479,13 +485,8 @@
     return renderer.getRendersChildren();
   }
 
-
-
-
   // ------------------------------------------------ Tree Management Methods
 
-
-
   @Override
   public UIComponent findComponent(String id)
   {
@@ -556,8 +557,6 @@
     }
   }
 
-
-
   /**
    * <p>Create (if necessary) and return a List of the children associated
    * with this component.</p>
@@ -579,7 +578,6 @@
     return getChildren().size();
   }
 
-
   /**
    * <p>Create (if necessary) and return a Map of the facets associated
    * with this component.</p>
@@ -594,7 +592,6 @@
     return _facets;
   }
 
-
   @Override
   public UIComponent getFacet(String facetName)
   {
@@ -605,7 +602,6 @@
     return getFacets().get(facetName);
   }
 
-
   /**
    * Returns an Iterator over the names of all facets.
    * Unlike getFacets().keySet().iterator(), this does
@@ -678,10 +674,8 @@
     }
   }
 
-
   // ------------------------------------------- Lifecycle Processing Methods
 
-
   @Override
   public void decode(FacesContext context)
   {
@@ -918,12 +912,20 @@
     // FIXME: Set to true, but never read
     //_initialStateMarked = true;
     getFacesBean().markInitialState();
+    if (_behaviors != null)
+    {
+      _behaviors.markInitialState();
+    }
   }
 
   @Override
   public void clearInitialState()
   {
     getFacesBean().clearInitialState();
+    if (_behaviors != null)
+    {
+      _behaviors.clearInitialState();
+    }
   }
 
   @Override
@@ -932,17 +934,31 @@
     return getFacesBean().initialStateMarked();
   }
 
-  public Object saveState(FacesContext context)
+  public Object saveState(FacesContext facesContext)
   {
-    return getFacesBean().saveState(context);
+    return new Object[]
+      {
+        getFacesBean().saveState(facesContext),
+        _behaviors == null ? null : _behaviors.saveState(facesContext)
+      };
   }
 
-  public void restoreState(FacesContext context, Object stateObj)
+  public void restoreState(
+    FacesContext facesContext,
+    Object       stateObj)
   {
-    getFacesBean().restoreState(context, stateObj);
+    Object[] state = (Object[])stateObj;
+    getFacesBean().restoreState(facesContext, state[0]);
+    if (state[1] != null)
+    {
+      if (_behaviors == null)
+      {
+        _behaviors = new BehaviorMap();
+      }
+      _behaviors.restoreState(facesContext, state[1]);
+    }
   }
 
-
   @Override
   public String toString()
   {
@@ -966,7 +982,6 @@
     return FacesContext.getCurrentInstance();
   }
 
-
   /**
    * Delegates to LifecycleRenderer, if present,
    * otherwise calls decodeChildrenImpl.
@@ -1001,7 +1016,6 @@
     }
   }
 
-
   /**
    * Delegates to LifecycleRenderer, if present,
    * otherwise calls validateChildrenImpl.
@@ -1037,7 +1051,6 @@
     }
   }
 
-
   /**
    * Delegates to LifecycleRenderer, if present,
    * otherwise calls upateChildrenImpl.
@@ -1223,7 +1236,6 @@
     return n.intValue();
   }
 
-
   /**
    * Return the number of facets.  This is more efficient than
    * calling getFacets().size();
@@ -1237,7 +1249,6 @@
     return _facets.size();
   }
 
-
   /**
    * Broadcast an event to a MethodBinding.
    * This can be used to support MethodBindings such as the "actionListener"
@@ -1390,7 +1401,6 @@
     }
   }
 
-
   /**
    * Override to calls the hooks for setting up and tearing down the
    * context before the children are visited.
@@ -1434,7 +1444,115 @@
     }
   }
 
+  // ------------------------- Client behavior holder methods -------------------------
 
+  /**
+   * Utility method to assist sub-classes in the implementation of the
+   * {@link javax.faces.component.behavior.ClientBehaviorHolder} interface.
+   * <p>This method must only
+   * be called by classes that implement the interface, doing otherwise will result in an exception.
+   * </p>
+   * @param eventName The event name
+   * @param behavior The behavior to add
+   * @see javax.faces.component.behavior.ClientBehaviorHolder#addClientBehavior(String, ClientBehavior)
+   */
+  protected void addClientBehavior(
+    String         eventName,
+    ClientBehavior behavior)
+  {
+    // This will throw a class cast exception when illegally called by a class that does not
+    // implement ClientBehaviorHolder
+    Collection<String> events = ((ClientBehaviorHolder)this).getEventNames();
+
+    // This will throw a null pointer exception if the component author did not correctly implement
+    // the ClientBehaviorHolder contract which requires a non-empty collection to be returned from
+    // getEventNames
+    if (!events.contains(eventName))
+    {
+      return;
+    }
+
+    if (_behaviors != null)
+    {
+      if (_behaviors.initialStateMarked())
+      {
+        // Resest the state of the behaviors so that their full state is saved when the
+        // behaviors of this component have been changed
+        _behaviors.clearInitialState();
+      }
+    }
+    else
+    {
+      _behaviors = new BehaviorMap();
+      _behaviorsReadOnly = null;
+    }
+
+    List<ClientBehavior> list = _behaviors.get(eventName);
+    if (list == null)
+    {
+      // Use a small number here as it will not be likely to have many behaviors for a component
+      // per event (probably 1)
+      list = new ArrayList<ClientBehavior>(5);
+      _behaviors.put(eventName, list);
+    }
+    list.add(behavior);
+  }
+
+  // Note, we do not need to provide a default implementation for the event names, as client
+  // behavior holder components must provide a non-empty list of event names. UIComponentBase
+  // decided to return a non-valid null in their code, but that is only confusing to the user, it
+  // is better to not implement the method and force the users to write the method upon interface
+  // implementation.
+  //protected Collection<String> getEventNames() {}
+
+  /**
+   * Utility method to assist sub-classes in the implementation of the
+   * {@link javax.faces.component.behavior.ClientBehaviorHolder} interface.
+   * <p>This method must only
+   * be called by classes that implement the interface, doing otherwise will result in an exception.
+   * </p>
+   * @see javax.faces.component.behavior.ClientBehaviorHolder#getClientBehaviors()
+   * @return Read-only map of the client behaviors for this component
+   */
+  protected Map<String, List<ClientBehavior>> getClientBehaviors()
+  {
+    if (_behaviors == null)
+    {
+      // never return null, per the spec.
+      return Collections.emptyMap();
+    }
+
+    if (_behaviorsReadOnly == null)
+    {
+      _behaviorsReadOnly = Collections.unmodifiableMap(_behaviors);
+    }
+    return _behaviorsReadOnly;
+  }
+
+  /**
+   * Utility method to assist sub-classes in the implementation of the
+   * {@link javax.faces.component.behavior.ClientBehaviorHolder} interface.
+   * <p>This method must only
+   * be called by classes that implement the interface, doing otherwise will result in an exception.
+   * </p>
+   * @return null
+   * @see javax.faces.component.behavior.ClientBehaviorHolder#getDefaultEventName()
+   */
+  protected String getDefaultEventName()
+  {
+    _ensureClientBehaviorHolder();
+    return null;
+  }
+
+  private void _ensureClientBehaviorHolder()
+  {
+    if (!(this instanceof ClientBehaviorHolder))
+    {
+      throw new IllegalStateException("Component must implement ClientBehaviorHolder in order " +
+        "to make use of this method.");
+    }
+  }
+  // ------------------------- End of the client behavior holder methods -------------------------
 
   /**
    * <p>
@@ -1514,7 +1632,6 @@
     }
   }
 
-
   static private UIComponent _findInsideOf(
     UIComponent from,
     String id)
@@ -1599,6 +1716,9 @@
   private Map<String, Object>      _attributes;
   private Map<String, UIComponent> _facets;
   private UIComponent              _parent;
+  private BehaviorMap              _behaviors;
+
+  private transient Map<String, List<ClientBehavior>> _behaviorsReadOnly;
 
   // Cached instance of the Renderer for this component.
   // The instance will be re-retrieved in encodeBegin()
@@ -1617,7 +1737,6 @@
   private static final Iterator<UIComponent> _EMPTY_UICOMPONENT_ITERATOR =
     new EmptyIterator<UIComponent>();
 
-
   static private final ThreadLocal<StringBuilder> _STRING_BUILDER =
                                                           ThreadLocalUtils.newRequestThreadLocal();
 
@@ -1688,6 +1807,165 @@
 
   }
 
+  private static class BehaviorMap
+    extends HashMap<String, List<ClientBehavior>>
+    implements PartialStateHolder
+  {
+    BehaviorMap()
+    {
+      // We do not expect many event types to be present on the component and we will assume 5
+      // to avoid the overhead of actually checking the number by calling the component method
+      this(5);
+    }
+
+    BehaviorMap(int initialCapacity)
+    {
+      super(initialCapacity, 1.0f);
+    }
+
+    public void markInitialState()
+    {
+      for (Map.Entry<String, List<ClientBehavior>> e : this.entrySet())
+      {
+        for (ClientBehavior behavior : e.getValue())
+        {
+          if (behavior instanceof PartialStateHolder)
+          {
+            ((PartialStateHolder)behavior).markInitialState();
+          }
+        }
+      }
+      _initialStateMarked = true;
+    }
+
+    public void clearInitialState()
+    {
+      _initialStateMarked = false;
+      for (Map.Entry<String, List<ClientBehavior>> e : this.entrySet())
+      {
+        for (ClientBehavior behavior : e.getValue())
+        {
+          if (behavior instanceof PartialStateHolder)
+          {
+            ((PartialStateHolder)behavior).clearInitialState();
+          }
+        }
+      }
+    }
+
+    public boolean initialStateMarked()
+    {
+      return _initialStateMarked;
+    }
+
+    public Object saveState(
+      FacesContext facesContext)
+    {
+      Map<String, Object[]> state = new HashMap<String, Object[]>(this.size());
+      for (Map.Entry<String, List<ClientBehavior>> e : this.entrySet())
+      {
+        List<ClientBehavior> l = e.getValue();
+        Object[] entryState = new Object[l.size()];
+        boolean stateWasSaved = false;
+        for (int i = 0, size = entryState.length; i < size; ++i)
+        {
+          ClientBehavior behavior = l.get(i);
+          if (_initialStateMarked)
+          {
+            // JSF 2 state saving, only save the behavior's state if it is a state holder,
+            // otherwise the re-application of the template will handle the re-creation of the
+            // client behavior in the correct state
+            if (behavior instanceof StateHolder)
+            {
+              entryState[i] = ((StateHolder)behavior).saveState(facesContext);
+            }
+          }
+          else
+          {
+            // Use JSF <= 1.2 state saving method as the initial state was not marked
+            entryState[i] = StateUtils.saveStateHolder(facesContext, behavior);
+          }
+
+          stateWasSaved &= (entryState[i] != null);
+        }
+
+        if (stateWasSaved)
+        {
+          state.put(e.getKey(), entryState);
+        }
+      }
+      return state.isEmpty() ? null : state;
+    }
+
+    public void restoreState(
+      FacesContext facesContext,
+      Object       state)
+    {
+      @SuppressWarnings("unchecked")
+      Map<String, Object[]> savedState = (Map<String, Object[]>) state;
+
+      if (_initialStateMarked)
+      {
+        // In JSF 2 state saving, we only need to super impose the state onto the existing
+        // client behavior list of the current map as the behaviors will already be restored in
+        // the same order that they were in the previous request (if not there is an application
+        // bug).
+        for (Map.Entry<String, Object[]> e : savedState.entrySet())
+        {
+          // Assume that the behaviors were correctly re-attached to the component and we only
+          // need to restore the state onto the objects. The order must be maintained.
+          List<ClientBehavior> behaviors = get(e.getKey());
+          Object[] entryState = e.getValue();
+          for (int i = 0, size = entryState.length; i < size; ++i)
+          {
+            if (entryState[i] != null)
+            {
+              ClientBehavior behavior = behaviors.get(i);
+              if (behavior instanceof StateHolder)
+              {
+                ((StateHolder)behavior).restoreState(facesContext, entryState[i]);
+              }
+            }
+          }
+        }
+      }
+      else
+      {
+        // For JSF <= 1.2 style state saving, we should ensure that we are empty and then
+        // re-hydrate the behaviors directly from the state
+        this.clear();
+
+        for (Map.Entry<String, Object[]> e : savedState.entrySet())
+        {
+          Object[] entryState = e.getValue();
+          // Assume the list is not going to grow in this request, so only allocate the size
+          // of the list from the previous request
+          List<ClientBehavior> list = new ArrayList<ClientBehavior>(entryState.length);
+          for (int i = 0, size = entryState.length; i < size; ++i)
+          {
+            list.add((ClientBehavior)StateUtils.restoreStateHolder(facesContext, entryState[i]));
+          }
+
+          this.put(e.getKey(), list);
+        }
+      }
+    }
+
+    public boolean isTransient()
+    {
+      return _transient;
+    }
+
+    public void setTransient(
+      boolean newTransientValue)
+    {
+      _transient = newTransientValue;
+    }
+
+    private boolean _transient;
+    private boolean _initialStateMarked;
+  }
+
   static private final LifecycleRenderer _UNDEFINED_LIFECYCLE_RENDERER =
                                                 new ExtendedRendererImpl();
   static private final Renderer _UNDEFINED_RENDERER = new RendererImpl();