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 2010/11/10 03:11:47 UTC

svn commit: r1033329 [1/2] - in /myfaces/commons/branches/jsf_20: myfaces-commons-converters/src/main/java/org/apache/myfaces/commons/converter/ myfaces-commons-converters/src/main/resources/META-INF/ myfaces-commons-validators/src/main/java/org/apache...

Author: lu4242
Date: Wed Nov 10 02:11:46 2010
New Revision: 1033329

URL: http://svn.apache.org/viewvc?rev=1033329&view=rev
Log:
MFCOMMONS-19 Create branch for JSF 2.0

Added:
    myfaces/commons/branches/jsf_20/myfaces-commons-converters/src/main/java/org/apache/myfaces/commons/converter/_DeltaStateHelper.java
    myfaces/commons/branches/jsf_20/myfaces-commons-validators/src/main/java/org/apache/myfaces/commons/validator/_DeltaStateHelper.java
Modified:
    myfaces/commons/branches/jsf_20/myfaces-commons-converters/src/main/java/org/apache/myfaces/commons/converter/ConverterBase.java
    myfaces/commons/branches/jsf_20/myfaces-commons-converters/src/main/java/org/apache/myfaces/commons/converter/EnumConverter.java
    myfaces/commons/branches/jsf_20/myfaces-commons-converters/src/main/resources/META-INF/converterClass12.vm
    myfaces/commons/branches/jsf_20/myfaces-commons-validators/src/main/java/org/apache/myfaces/commons/validator/ValidatorBase.java
    myfaces/commons/branches/jsf_20/myfaces-commons-validators/src/main/resources/META-INF/validatorClass12.vm

Modified: myfaces/commons/branches/jsf_20/myfaces-commons-converters/src/main/java/org/apache/myfaces/commons/converter/ConverterBase.java
URL: http://svn.apache.org/viewvc/myfaces/commons/branches/jsf_20/myfaces-commons-converters/src/main/java/org/apache/myfaces/commons/converter/ConverterBase.java?rev=1033329&r1=1033328&r2=1033329&view=diff
==============================================================================
--- myfaces/commons/branches/jsf_20/myfaces-commons-converters/src/main/java/org/apache/myfaces/commons/converter/ConverterBase.java (original)
+++ myfaces/commons/branches/jsf_20/myfaces-commons-converters/src/main/java/org/apache/myfaces/commons/converter/ConverterBase.java Wed Nov 10 02:11:46 2010
@@ -20,14 +20,14 @@ package org.apache.myfaces.commons.conve
 
 import java.io.Serializable;
 import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Iterator;
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
 
 import javax.el.ValueExpression;
 import javax.faces.application.FacesMessage;
+import javax.faces.component.PartialStateHolder;
+import javax.faces.component.StateHelper;
 import javax.faces.component.StateHolder;
 import javax.faces.context.FacesContext;
 import javax.faces.convert.Converter;
@@ -45,11 +45,13 @@ import org.apache.myfaces.commons.util.M
    evaluateELOnExecution = true,
    tagClass = "org.apache.myfaces.commons.converter.ConverterBaseTag",
    tagHandler = "org.apache.myfaces.commons.converter.ConverterBaseTagHandler")
-public abstract class ConverterBase implements StateHolder, Converter {
+public abstract class ConverterBase implements PartialStateHolder, Converter {
 
-    private String _summaryMessage = null;
-    private String _detailMessage = null;
     private boolean _transient = false;
+    
+    private transient FacesContext _facesContext;
+    private StateHelper _stateHelper = null;
+    private boolean _initialStateMarked = false;
 
     /**
      * alternate conversion error summary message format string
@@ -59,9 +61,7 @@ public abstract class ConverterBase impl
     @JSFProperty
     public String getSummaryMessage()
     {
-        if (_summaryMessage != null) return _summaryMessage;
-        ValueExpression expression = getValueExpression("summaryMessage");
-        return expression != null ? getStringValue(getFacesContext(), expression) : null;
+        return (String) getStateHelper().eval(PropertyKeys.summaryMessage);
     }
 
     /**
@@ -69,7 +69,7 @@ public abstract class ConverterBase impl
      * @param message   The summary message to be displayed.
      */
     public void setSummaryMessage(String message) {
-        _summaryMessage = message;
+        getStateHelper().put(PropertyKeys.summaryMessage, message);
     }
 
     /**
@@ -80,9 +80,7 @@ public abstract class ConverterBase impl
      */
     @JSFProperty
     public String getDetailMessage() {
-        if (_detailMessage != null) return _detailMessage;
-        ValueExpression vb = getValueExpression("detailMessage");
-        return vb != null ? getStringValue(getFacesContext(), vb) : null;
+        return (String) getStateHelper().eval(PropertyKeys.detailMessage);
     }
 
     /**
@@ -90,26 +88,34 @@ public abstract class ConverterBase impl
      * @param message  The detail message to be displayed.
      */
     public void setDetailMessage(String message) {
-        _detailMessage = message;
+        getStateHelper().put(PropertyKeys.detailMessage, message);
     }
 
 
     /**
      * @param context
      */
-    public Object saveState(FacesContext context) {
-        Object[] state = new Object[3];
-        state[0] = _summaryMessage;
-        state[1] = _detailMessage;
-        state[2] = saveValueExpressionMap(context);
-        return state;
+    public Object saveState(FacesContext context)
+    {
+        if (context == null)
+        {
+            throw new NullPointerException ("context");
+        }
+        
+        StateHelper stateHelper = getStateHelper(false);
+        if (stateHelper != null)
+        {
+            return stateHelper.saveState(context);
+        }
+        else
+        {
+            return null;
+        }
     }
 
-    public void restoreState(FacesContext context, Object state) {
-        Object[] values = (Object[]) state;
-        _summaryMessage = (String) values[0];
-        _detailMessage = (String) values[1];
-        restoreValueExpressionMap(context, values[2]);
+    public void restoreState(FacesContext context, Object state)
+    {
+        getStateHelper().restoreState(context, state);
     }
 
     public boolean isTransient() {
@@ -144,69 +150,33 @@ public abstract class ConverterBase impl
 
     // --------------------- borrowed from UIComponentBase ------------
 
-    private Map _valueExpressionMap = null;
-
+    @SuppressWarnings("unchecked")
     public ValueExpression getValueExpression(String name)
     {
         if (name == null) throw new NullPointerException("name");
-        if (_valueExpressionMap == null)
+        StateHelper helper = getStateHelper(false);
+        if (helper == null)
         {
             return null;
         }
-        else
+        Map<String,Object> bindings = (Map<String,Object>) helper.get(PropertyKeys.bindings); 
+        if (bindings == null)
         {
-            return (ValueExpression)_valueExpressionMap.get(name);
-        }
-    }
-
-    public void setValueExpression(String name,
-                                ValueExpression binding)
-    {
-        if (name == null) throw new NullPointerException("name");
-        if (_valueExpressionMap == null)
-        {
-            _valueExpressionMap = new HashMap();
-        }
-        _valueExpressionMap.put(name, binding);
-    }
-
-    private Object saveValueExpressionMap(FacesContext context)
-    {
-        if (_valueExpressionMap != null)
-        {
-            int initCapacity = (_valueExpressionMap.size() * 4 + 3) / 3;
-            HashMap stateMap = new HashMap(initCapacity);
-            for (Iterator it = _valueExpressionMap.entrySet().iterator(); it.hasNext(); )
-            {
-                Map.Entry entry = (Map.Entry)it.next();
-                stateMap.put(entry.getKey(),
-                             saveAttachedState(context, entry.getValue()));
-            }
-            return stateMap;
+            return null;
         }
         else
         {
-            return null;
+            return (ValueExpression) bindings.get(name);
         }
     }
-
-    private void restoreValueExpressionMap(FacesContext context, Object stateObj)
+    
+    public void setValueExpression(String name, ValueExpression expression)
     {
-        if (stateObj != null)
-        {
-            Map stateMap = (Map)stateObj;
-            int initCapacity = (stateMap.size() * 4 + 3) / 3;
-            _valueExpressionMap = new HashMap(initCapacity);
-            for (Iterator it = stateMap.entrySet().iterator(); it.hasNext(); )
-            {
-                Map.Entry entry = (Map.Entry)it.next();
-                _valueExpressionMap.put(entry.getKey(),
-                                     restoreAttachedState(context, entry.getValue()));
-            }
-        }
-        else
-        {
-            _valueExpressionMap = null;
+        if (name == null) throw new NullPointerException("name");
+        if (expression == null) {
+            getStateHelper().remove(PropertyKeys.bindings, name);
+        } else {
+            getStateHelper().put(PropertyKeys.bindings, name, expression);
         }
     }
 
@@ -235,30 +205,39 @@ public abstract class ConverterBase impl
      * of the provided object. When deserialized, a default instance of that
      * type will be recreated.
      */
-    public static Object saveAttachedState(FacesContext context,
-                                           Object attachedObject)
+    public static Object saveAttachedState(FacesContext context, Object attachedObject)
     {
-        if (attachedObject == null) return null;
-        if (attachedObject instanceof List)
+        if (context == null)
         {
-            List lst = new ArrayList(((List)attachedObject).size());
-            for (Iterator it = ((List)attachedObject).iterator(); it.hasNext(); )
-            {
-                lst.add(saveAttachedState(context, it.next()));
-            }
-            return new _AttachedListStateWrapper(lst);
+            throw new NullPointerException ("context");
         }
-        else if (attachedObject instanceof StateHolder)
+        
+        if (attachedObject == null)
+            return null;
+        // StateHolder interface should take precedence over
+        // List children
+        if (attachedObject instanceof StateHolder)
         {
-            if (((StateHolder)attachedObject).isTransient())
+            StateHolder holder = (StateHolder) attachedObject;
+            if (holder.isTransient())
             {
                 return null;
             }
-            else
+
+            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)
             {
-                return new _AttachedStateWrapper(attachedObject.getClass(),
-                                                 ((StateHolder)attachedObject).saveState(context));
+                if (item != null)
+                {
+                    lst.add(saveAttachedState(context, item));
+                }
             }
+
+            return new _AttachedListStateWrapper(lst);
         }
         else if (attachedObject instanceof Serializable)
         {
@@ -270,25 +249,26 @@ public abstract class ConverterBase impl
         }
     }
 
-    public static Object restoreAttachedState(FacesContext context,
-                                              Object stateObj)
-            throws IllegalStateException
+    @SuppressWarnings("unchecked")
+    public static Object restoreAttachedState(FacesContext context, Object stateObj) throws IllegalStateException
     {
-        if (context == null) throw new NullPointerException("context");
-        if (stateObj == null) return null;
+        if (context == null)
+            throw new NullPointerException("context");
+        if (stateObj == null)
+            return null;
         if (stateObj instanceof _AttachedListStateWrapper)
         {
-            List lst = ((_AttachedListStateWrapper)stateObj).getWrappedStateList();
-            List restoredList = new ArrayList(lst.size());
-            for (Iterator it = lst.iterator(); it.hasNext(); )
+            List<Object> lst = ((_AttachedListStateWrapper) stateObj).getWrappedStateList();
+            List<Object> restoredList = new ArrayList<Object>(lst.size());
+            for (Object item : lst)
             {
-                restoredList.add(restoreAttachedState(context, it.next()));
+                restoredList.add(restoreAttachedState(context, item));
             }
             return restoredList;
         }
         else if (stateObj instanceof _AttachedStateWrapper)
         {
-            Class clazz = ((_AttachedStateWrapper)stateObj).getClazz();
+            Class<?> clazz = ((_AttachedStateWrapper) stateObj).getClazz();
             Object restoredObject;
             try
             {
@@ -296,7 +276,8 @@ public abstract class ConverterBase impl
             }
             catch (InstantiationException e)
             {
-                throw new RuntimeException("Could not restore StateHolder of type " + clazz.getName() + " (missing no-args constructor?)", e);
+                throw new RuntimeException("Could not restore StateHolder of type " + clazz.getName()
+                        + " (missing no-args constructor?)", e);
             }
             catch (IllegalAccessException e)
             {
@@ -304,8 +285,11 @@ public abstract class ConverterBase impl
             }
             if (restoredObject instanceof StateHolder)
             {
-                Object wrappedState = ((_AttachedStateWrapper)stateObj).getWrappedStateObject();
-                ((StateHolder)restoredObject).restoreState(context, wrappedState);
+                _AttachedStateWrapper wrapper = (_AttachedStateWrapper) stateObj;
+                Object wrappedState = wrapper.getWrappedStateObject();
+
+                StateHolder holder = (StateHolder) restoredObject;
+                holder.restoreState(context, wrappedState);
             }
             return restoredObject;
         }
@@ -315,11 +299,63 @@ public abstract class ConverterBase impl
         }
     }
 
-
     protected FacesContext getFacesContext()
     {
-        return FacesContext.getCurrentInstance();
+        if (_facesContext == null)
+        {
+            return FacesContext.getCurrentInstance();
+        }
+        else
+        {
+            return _facesContext;
+        }
+    }
+    
+    boolean isCachedFacesContext()
+    {
+        return _facesContext != null;
+    }
+    
+    void setCachedFacesContext(FacesContext facesContext)
+    {
+        _facesContext = facesContext;
     }
+    
+    protected StateHelper getStateHelper() {
+        return getStateHelper(true);
+    }
+
+    /**
+     * returns a delta state saving enabled state helper
+     * for the current component
+     * @param create if true a state helper is created if not already existing
+     * @return an implementation of the StateHelper interface or null if none exists and create is set to false
+     */
+    protected StateHelper getStateHelper(boolean create) {
+        if(_stateHelper != null) {
+            return _stateHelper;
+        }
+        if(create) {
+            _stateHelper = new _DeltaStateHelper(this);
+        }
+        return _stateHelper;
+    }
+    
+    public void clearInitialState()
+    {
+        _initialStateMarked = false;
+    }
+
+    public boolean initialStateMarked()
+    {
+        return _initialStateMarked;
+    }
+
+    public void markInitialState()
+    {
+        _initialStateMarked = true;
+    }
+
     protected String getStringValue(FacesContext context, ValueExpression vb)
     {
         Object value = vb.getValue(context.getELContext());
@@ -329,4 +365,11 @@ public abstract class ConverterBase impl
         }
         return null;
     }
+    
+    enum PropertyKeys
+    {
+        bindings,
+        summaryMessage,
+        detailMessage
+    }
 }

Modified: myfaces/commons/branches/jsf_20/myfaces-commons-converters/src/main/java/org/apache/myfaces/commons/converter/EnumConverter.java
URL: http://svn.apache.org/viewvc/myfaces/commons/branches/jsf_20/myfaces-commons-converters/src/main/java/org/apache/myfaces/commons/converter/EnumConverter.java?rev=1033329&r1=1033328&r2=1033329&view=diff
==============================================================================
--- myfaces/commons/branches/jsf_20/myfaces-commons-converters/src/main/java/org/apache/myfaces/commons/converter/EnumConverter.java (original)
+++ myfaces/commons/branches/jsf_20/myfaces-commons-converters/src/main/java/org/apache/myfaces/commons/converter/EnumConverter.java Wed Nov 10 02:11:46 2010
@@ -19,7 +19,7 @@
 package org.apache.myfaces.commons.converter;
 
 import javax.faces.application.FacesMessage;
-import javax.faces.component.StateHolder;
+import javax.faces.component.PartialStateHolder;
 import javax.faces.component.UIComponent;
 import javax.faces.context.FacesContext;
 import javax.faces.convert.Converter;
@@ -41,7 +41,7 @@ import org.apache.myfaces.commons.util.M
    name = "mcc:convertEnum",
    tagClass = "org.apache.myfaces.commons.converter.ConvertEnumTag", 
    serialuidtag = "3864584277821896141L")
-public class EnumConverter implements Converter, StateHolder {
+public class EnumConverter implements Converter, PartialStateHolder {
     
     public static final String CONVERTER_ID = "org.apache.myfaces.commons.converter.Enum";
     public static final String ENUM_ID = "org.apache.myfaces.commons.converter.EnumConverter.ENUM";
@@ -168,11 +168,18 @@ public class EnumConverter implements Co
     }
 
     public void restoreState(FacesContext context, Object state) {
-        targetClass = (Class)state;
+        if (state != null)
+        {
+            targetClass = (Class)state;
+        }
     }
 
     public Object saveState(FacesContext context) {
-        return targetClass;
+        if (!initialStateMarked())
+        {
+            return targetClass;
+        }
+        return null;
     }
 
     public void setTransient(boolean newTransientValue) {
@@ -197,4 +204,21 @@ public class EnumConverter implements Co
     {
         this.targetClass = targetClass;
     }
+    
+    private boolean _initialStateMarked = false;
+
+    public void clearInitialState()
+    {
+        _initialStateMarked = false;
+    }
+
+    public boolean initialStateMarked()
+    {
+        return _initialStateMarked;
+    }
+
+    public void markInitialState()
+    {
+        _initialStateMarked = true;
+    }
 }

Added: myfaces/commons/branches/jsf_20/myfaces-commons-converters/src/main/java/org/apache/myfaces/commons/converter/_DeltaStateHelper.java
URL: http://svn.apache.org/viewvc/myfaces/commons/branches/jsf_20/myfaces-commons-converters/src/main/java/org/apache/myfaces/commons/converter/_DeltaStateHelper.java?rev=1033329&view=auto
==============================================================================
--- myfaces/commons/branches/jsf_20/myfaces-commons-converters/src/main/java/org/apache/myfaces/commons/converter/_DeltaStateHelper.java (added)
+++ myfaces/commons/branches/jsf_20/myfaces-commons-converters/src/main/java/org/apache/myfaces/commons/converter/_DeltaStateHelper.java Wed Nov 10 02:11:46 2010
@@ -0,0 +1,827 @@
+/*
+ * 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 org.apache.myfaces.commons.converter;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import javax.el.ValueExpression;
+import javax.faces.component.StateHelper;
+import javax.faces.component.StateHolder;
+import javax.faces.component.UIComponent;
+import javax.faces.component.UIComponentBase;
+import javax.faces.context.FacesContext;
+
+/**
+ * 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
+ * </p>
+ * <p>
+ * For components not implementing partial state saving only the initial states are
+ * of importance, everything is stored and restored continously there
+ * </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, 
+ * 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>
+ *   <li>The map backed by method put(Serializable,String,Object) is
+ *   a replacement of UIComponentBase.attributesMap and UIComponent.bindings map.
+ *   Note that on jsf 1.2, instances saved on attributesMap should not be
+ *   StateHolder, but on jsf 2.0 it is possible to have it. PartialStateHolder
+ *   instances are not handled in this map, or in other words delta state is not
+ *   handled in this classes (markInitialState and clearInitialState is not propagated).</li>
+ *   <li>The list backed by method add(Serializable,Object) should be (is not) a 
+ *   replacement of UIComponentBase.facesListeners, but note that StateHelper
+ *   does not implement PartialStateHolder, and facesListener could have instances
+ *   of that class that needs to be notified when UIComponent.markInitialState or
+ *   UIComponent.clearInitialState is called, or in other words facesListeners
+ *   should deal with PartialStateHolder instances.</li>
+ *   <li>The list backed by method add(Serializable,Object) is 
+ *   a replacement of UIViewRoot.phaseListeners list. Note that instances of
+ *   PhaseListener are not expected to implement StateHolder or PartialStateHolder.</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>
+ *
+ * @author Werner Punz
+ * @author Leonardo Uribe (latest modification by $Author: lu4242 $)
+ * @version $Rev: 980927 $ $Date: 2010-07-30 14:05:55 -0500 (Vie, 30 Jul 2010) $
+ */
+class _DeltaStateHelper implements StateHelper
+{
+
+    /**
+     * 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 ConverterBase _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(ConverterBase component)
+    {
+        super();
+        this._component = component;
+        _fullState = new HashMap<Serializable, Object>();
+        _deltas = null;
+        //_stateHolderKeys = new HashSet<Serializable>();
+    }
+
+    /**
+     * Used to create delta map on demand
+     * 
+     * @return
+     */
+    private boolean _createDeltas()
+    {
+        if (isInitialStateMarked())
+        {
+            if (_deltas == null)
+            {
+                _deltas = new HashMap<Serializable, Object>(2);
+            }
+            return true;
+        }
+
+        return false;
+    }
+    
+    protected boolean isInitialStateMarked()
+    {
+        return _component.initialStateMarked();
+    }
+
+    public void add(Serializable key, Object value)
+    {
+        if (_createDeltas())
+        {
+            //Track delta case
+            Map<Object, Boolean> deltaListMapValues = (Map<Object, Boolean>) _deltas
+                    .get(key);
+            if (deltaListMapValues == null)
+            {
+                deltaListMapValues = new InternalDeltaListMap<Object, Boolean>(
+                        3);
+                _deltas.put(key, deltaListMapValues);
+            }
+            deltaListMapValues.put(value, Boolean.TRUE);
+        }
+
+        //Handle change on full map
+        List<Object> fullListValues = (List<Object>) _fullState.get(key);
+        if (fullListValues == null)
+        {
+            fullListValues = new InternalList<Object>(3);
+            _fullState.put(key, fullListValues);
+        }
+        fullListValues.add(value);
+    }
+
+    public Object eval(Serializable key)
+    {
+        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;
+    }
+
+    public Object eval(Serializable key, Object defaultValue)
+    {
+        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 defaultValue;
+    }
+
+    public Object get(Serializable key)
+    {
+        return _fullState.get(key);
+    }
+
+    public Object put(Serializable key, Object value)
+    {
+        Object returnValue = null;
+        if (_createDeltas())
+        {
+            if (_deltas.containsKey(key))
+            {
+                returnValue = _deltas.put(key, value);
+                _fullState.put(key, value);
+            }
+            else if (value == null && !_fullState.containsKey(key))
+            {
+                returnValue = null;
+            }
+            else
+            {
+                _deltas.put(key, value);
+                returnValue = _fullState.put(key, value);
+            }
+        }
+        else
+        {
+            /*
+            if (value instanceof StateHolder)
+            {
+                _stateHolderKeys.add(key);
+            }
+            */
+            returnValue = _fullState.put(key, value);
+        }
+        return returnValue;
+    }
+
+    public Object put(Serializable key, String mapKey, Object value)
+    {
+        boolean returnSet = false;
+        Object returnValue = null;
+        if (_createDeltas())
+        {
+            //Track delta case
+            Map<String, Object> mapValues = (Map<String, Object>) _deltas
+                    .get(key);
+            if (mapValues == null)
+            {
+                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);
+            }
+        }
+
+        //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;
+    }
+
+    public Object remove(Serializable key)
+    {
+        Object returnValue = null;
+        if (_createDeltas())
+        {
+            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);
+        }
+        return returnValue;
+    }
+
+    public Object remove(Serializable key, Object valueOrKey)
+    {
+        // 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;
+    }
+
+    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)
+        {
+            if (c.containsKey(valueOrKey))
+            {
+                returnValue = valueOrKey;
+            }
+            c.put(valueOrKey, Boolean.FALSE);
+        }
+        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)
+        {
+            if (c.remove(valueOrKey))
+            {
+                returnValue = valueOrKey;
+            }
+            if (c.isEmpty())
+            {
+                stateMap.remove(key);
+            }
+        }
+        return returnValue;
+    }
+
+    private static Object _removeValueOrKeyFromMap(
+            Map<Serializable, Object> stateMap, Serializable key,
+            Object valueOrKey, boolean delta)
+    {
+        if (valueOrKey == null)
+        {
+            return null;
+        }
+
+        Object returnValue = null;
+        Map<String, Object> map = (Map<String, Object>) stateMap.get(key);
+        if (map != null)
+        {
+            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 returnValue;
+    }
+
+    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
+     * myfaces.InternalArray, myfaces.internalMap
+     *
+     * the internal Array is then mapped to another array
+     *
+     * the internal Map again is then mapped to a map with key value pairs
+     *
+     *
+     */
+    public Object saveState(FacesContext context)
+    {
+        Map serializableMap = (isInitialStateMarked()) ? _deltas : _fullState;
+
+        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];
+        //Object[] retArr = new Object[serializableMap.entrySet().size() * 2 + stateHolderKeyCount]; 
+
+        Iterator<Map.Entry<Serializable, Object>> it = serializableMap
+                .entrySet().iterator();
+        int cnt = 0;
+        while (it.hasNext())
+        {
+            entry = it.next();
+            retArr[cnt] = entry.getKey();
+
+            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] = value;
+            }
+            cnt += 2;
+        }
+        
+        /*
+        if (isInitalStateMarked())
+        {
+            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;
+    }
+
+    public void restoreState(FacesContext context, Object state)
+    {
+        if (state == null)
+            return;
+
+        Object[] serializedState = (Object[]) state;
+        
+        if (!isInitialStateMarked() && !_fullState.isEmpty())
+        {
+            _fullState.clear();
+            if(_deltas != null)
+            {
+                _deltas.clear();
+            }
+        }
+
+        for (int cnt = 0; cnt < serializedState.length; cnt += 2)
+        {
+            Serializable key = (Serializable) serializedState[cnt];
+            Object savedValue = UIComponentBase.restoreAttachedState(context,
+                    serializedState[cnt + 1]);
+
+            if (isInitialStateMarked())
+            {
+                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
+            {
+                put(key, savedValue);
+            }
+        }
+    }
+
+    public void setTransient(boolean transientValue)
+    {
+        _transient = transientValue;
+    }
+
+    //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
+    {
+        public InternalMap()
+        {
+            super();
+        }
+
+        public InternalMap(int initialCapacity, float loadFactor)
+        {
+            super(initialCapacity, loadFactor);
+        }
+
+        public InternalMap(Map<? extends K, ? extends V> m)
+        {
+            super(m);
+        }
+
+        public InternalMap(int initialSize)
+        {
+            super(initialSize);
+        }
+
+        public boolean isTransient()
+        {
+            return false;
+        }
+
+        public void setTransient(boolean newTransientValue)
+        {
+            // No op
+        }
+
+        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]));
+            }
+        }
+
+        public Object saveState(FacesContext context)
+        {
+            int cnt = 0;
+            Object[] mapArr = new Object[this.size() * 2];
+            for (Map.Entry<K, V> entry : this.entrySet())
+            {
+                mapArr[cnt] = entry.getKey();
+                Object value = entry.getValue();
+                
+                if (value instanceof StateHolder ||
+                    value instanceof List ||
+                    !(value instanceof Serializable))
+                {
+                    mapArr[cnt + 1] = UIComponentBase.saveAttachedState(context, value);
+                }
+                else
+                {
+                    mapArr[cnt + 1] = value;
+                }
+                cnt += 2;
+            }
+            return mapArr;
+        }
+    }
+
+    /**
+     * Map used to keep track of list changes 
+     */
+    static class InternalDeltaListMap<K, V> extends InternalMap<K, V>
+    {
+
+        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);
+        }
+    }
+
+    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);
+        }
+
+        public boolean isTransient()
+        {
+            return false;
+        }
+
+        public void setTransient(boolean newTransientValue)
+        {
+        }
+
+        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));
+            }
+        }
+
+        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;
+        }
+    }
+}

Modified: myfaces/commons/branches/jsf_20/myfaces-commons-converters/src/main/resources/META-INF/converterClass12.vm
URL: http://svn.apache.org/viewvc/myfaces/commons/branches/jsf_20/myfaces-commons-converters/src/main/resources/META-INF/converterClass12.vm?rev=1033329&r1=1033328&r2=1033329&view=diff
==============================================================================
--- myfaces/commons/branches/jsf_20/myfaces-commons-converters/src/main/resources/META-INF/converterClass12.vm (original)
+++ myfaces/commons/branches/jsf_20/myfaces-commons-converters/src/main/resources/META-INF/converterClass12.vm Wed Nov 10 02:11:46 2010
@@ -51,7 +51,7 @@ public class ${utils.getClassFromFullCla
 {
 
 #if ($converter.converterId)
-    static public final String VALIDATOR_ID = 
+    static public final String CONVERTER_ID = 
         "$converter.converterId";
 #end
 
@@ -176,6 +176,167 @@ public class ${utils.getClassFromFullCla
 
 #end
 ##
+## -------------------------------
+## writePropertySetStateHelperDeclaration
+## -------------------------------
+##
+#macro (writePropertySetStateHelperDeclaration $property $type $field $defaultValue )
+#if($utils.isPrimitiveClass($type) && !$property.isTagExcluded() && $property.isSetMethod())
+    private boolean ${field}Set;
+    
+#end
+#end
+##
+## -------------------------------
+## writePropertyStateHelperDeclaration
+## -------------------------------
+##
+#macro( writePropertyStateHelperDeclaration $property $type $field $defaultValue )
+#if ($property.isPartialStateHolder())
+#if ($property.isLiteralOnly() || $property.isTagExcluded())
+    private $type $field #if($defaultValue) = $defaultValue;#{else};#{end}
+
+#else
+    private $type $field;
+    
+#end
+#end
+#writePropertySetStateHelperDeclaration ($property $type $field $defaultValue)
+#end
+##
+## -------------------------------
+## writeLocalPropertyStateHelperGetter
+## -------------------------------
+##
+#macro (writeLocalPropertyStateHelperGetter $property $type $field $defaultValue )
+#if($utils.isPrimitiveClass($type) && !$property.isTagExcluded() && $property.isSetMethod())
+    $property.setMethodScope boolean $utils.getPrefixedPropertyName("isSet", $property.name)()
+    {
+        return ${field}Set;
+    }
+
+#end
+#if($property.isLocalMethod())
+#if("boolean" == $type)
+#set ($methodName = $utils.getPrefixedPropertyName("isLocal", $property.name))
+#else
+#set ($methodName = $utils.getPrefixedPropertyName("getLocal", $property.name))
+#end
+    final $property.localMethodScope $type ${methodName}()
+    {
+#if ($property.isPartialStateHolder())
+        return $field;
+#else
+        return $utils.castIfNecessary($type) getStateHelper().get(PropertyKeys.$field);
+#end
+    }
+
+#end
+#end
+##
+## -------------------------------
+## writePropertyStateHelperGetter
+## -------------------------------
+##
+#macro (writePropertyStateHelperGetter $property $type $field $defaultValue )
+#if ($property.isPartialStateHolder())
+    public $type $utils.getMethodReaderFromProperty($property.name, $type)()
+    {
+#if ($property.isTagExcluded() || $property.isLiteralOnly() || !($converter.isEvaluateELOnExecution()))
+        return $field;
+#else
+#if ($utils.isPrimitiveClass($type))
+        if (${field}Set)
+#else
+        if ($field != null)
+#end
+        {
+            return $field;
+        }
+        ValueExpression vb = getValueExpression("$property.name");
+        if (vb != null)
+        {
+#if ($utils.isPrimitiveClass($type))
+            return ($utils.castIfNecessary($type) vb.getValue(getFacesContext().getELContext())).${type}Value();
+#else
+#set ($pritype = $utils.getPrimitiveType($property.className))
+#if ($utils.isPrimitiveClass($pritype))
+            Object value = vb == null ? null : vb.getValue(getFacesContext().getELContext());
+            if (!(value instanceof $type)){
+                value = ${type}.valueOf(value.toString());
+            }            
+            return $utils.castIfNecessary($type) value;
+#else
+            return $utils.castIfNecessary($type) vb.getValue(getFacesContext().getELContext());
+#end
+#end
+        }
+#if ($defaultValue)
+        return $defaultValue; 
+#elseif ($utils.isPrimitiveClass($type))
+        return $utils.primitiveDefaultValue($type);
+#else       
+        return null;
+#end
+#end
+    }
+
+#else
+    public $type $utils.getMethodReaderFromProperty($property.name, $type)()
+    {
+#if ($property.isLiteralOnly())
+#if ($defaultValue)
+        Object value = getStateHelper().get(PropertyKeys.$field);
+        if (value != null)
+        {
+            return $utils.castIfNecessary($type) value;        
+        }
+        return $defaultValue;        
+#else
+        return $utils.castIfNecessary($type) getStateHelper().get(PropertyKeys.$field);        
+#end
+#else
+#if ($defaultValue)
+        return $utils.castIfNecessary($type) getStateHelper().eval(PropertyKeys.$field, $defaultValue);
+#else
+        return $utils.castIfNecessary($type) getStateHelper().eval(PropertyKeys.$field);
+#end
+#end
+    }
+    
+#end
+#end
+##
+## -------------------------------
+## writePropertyStateHelperSetter
+## -------------------------------
+##
+#macro (writePropertyStateHelperSetter $property $type $field $defaultValue )
+#if ($property.isPartialStateHolder())
+    public void $utils.getPrefixedPropertyName("set", $property.name)($type $utils.getVariableFromName($property.name))
+    {
+        this.$field = $utils.getVariableFromName($property.name);
+        if (initialStateMarked())
+        {
+            getStateHelper().put(PropertyKeys.${property.name}Set,Boolean.TRUE);
+        }
+#if ($utils.isPrimitiveClass($type) && !$property.isTagExcluded() && $property.isSetMethod())
+        this.${field}Set = true;        
+#end
+    }
+
+#else
+    public void $utils.getPrefixedPropertyName("set", $property.name)($type $utils.getVariableFromName($property.name))
+    {
+        getStateHelper().put(PropertyKeys.$field, $utils.getVariableFromName($property.name) ); 
+#if ($utils.isPrimitiveClass($type) && !$property.isTagExcluded() && $property.isSetMethod())
+        this.${field}Set = true;        
+#end
+    }    
+
+#end
+#end
+##
 ## ----------------------------- END PROPERTY MACROS -------------------------
 ##
 ## ----------------------------- START PROPERTY RENDERING --------------------
@@ -190,12 +351,28 @@ public class ${utils.getClassFromFullCla
 #set ($defaultValue = false)
 #end
     // Property: $property.name
+#if ($converter.isEvaluateELOnExecution())
+#if ($property.name == "for")
+## To keep compatibility with RI, we should call it forVal
+#set ($field = "forVal")
+#else
+#set ($field = $property.name)
+#end
+## USING PARTIAL STATE SAVING STATE HELPER
+#writePropertyStateHelperDeclaration($property $type $field $defaultValue)
+#writeLocalPropertyStateHelperGetter ($property $type $field $defaultValue)
+#writePropertyStateHelperGetter ($property $type $field $defaultValue)
+#writePropertyStateHelperSetter ($property $type $field $defaultValue)
+#else
+## USING VARIABLES
 #writePropertyDeclaration($property $type $field $defaultValue)
 #writeLocalPropertyGetter ($property $type $field $defaultValue)
 #writePropertyGetter ($property $type $field $defaultValue)
 #writePropertySetter ($property $type $field $defaultValue)
 #end
+#end
 ## ----------------------------- END PROPERTY RENDERING ---------------------
+#if ( !($converter.isEvaluateELOnExecution()) )
 
     public Object saveState(FacesContext facesContext)
     {
@@ -259,4 +436,215 @@ public class ${utils.getClassFromFullCla
 #end
 #end
     }
+#else
+    enum PropertyKeys
+    {
+
+#set ($comma = "")
+#set ($addc = "false")
+#foreach( $property in $propertyList )
+#if ($property.name == "for")
+#set ($addc = "true")
+## To keep compatibility with RI, we should call it forVal
+#set ($field = "forVal")
+#else
+#set ($field = $property.name)
+#end
+#set ($type = $utils.getClassFromFullClass($property.className))
+#if($utils.getDefaultValueField($property)) 
+#set ($defaultValue = $utils.getDefaultValueField($property))
+#else
+#set ($defaultValue = false)
+#end
+#if ($property.name == "for")
+        $comma $field("for")
+#else
+#if ($property.isPartialStateHolder())
+        $comma ${field}Set
+#else
+        $comma $field
+#end
+#end
+#set($comma = ",")
+#end
+#if ("true" == $addc)
+        ;
+        String c;
+        
+        PropertyKeys()
+        {
+        }
+        
+        //Constructor needed by "for" property
+        PropertyKeys(String c)
+        { 
+            this.c = c;
+        }
+        
+        public String toString()
+        {
+            return ((this.c != null) ? this.c : super.toString());
+        }
+#end
+    }
+
+#set ($primitiveCount = 1) ## $propertyList.size() + 1 
+#foreach( $property in $propertyList )
+#if ($property.isPartialStateHolder())
+#set ($primitiveCount = $primitiveCount + 1)
+#if($utils.isPrimitiveClass($property.className))
+#set ($primitiveCount = $primitiveCount + 1)
+#end
+#end
+#end
+## saveState and restoreState methods only has sense if we have properties
+## that does not use StateHelper class.
+#if ($primitiveCount > 1)
+
+    public void markInitialState()
+    {
+        super.markInitialState();
+#foreach( $property in $propertyList )
+#set ($field = $property.fieldName)
+#if ($property.isPartialStateHolder())        
+        if ($field != null && 
+            $field instanceof PartialStateHolder)
+        {
+            ((PartialStateHolder)$field).markInitialState();
+        }
+#end
+#end
+    }
+    
+    public void clearInitialState()
+    {
+        if (initialStateMarked())
+        {
+            super.clearInitialState();
+#foreach( $property in $propertyList )
+#set ($field = $property.fieldName)
+#if ($property.isPartialStateHolder())
+##          //Only has sense propagate this method if is initialStateMarked
+            if ($field != null && 
+                $field instanceof PartialStateHolder)
+            {
+                ((PartialStateHolder)$field).clearInitialState();
+            }
+#end
+#end
+        }
+    }
+
+    @Override
+    public Object saveState(FacesContext facesContext)
+    {
+        if (initialStateMarked())
+        {
+            boolean nullDelta = true;
+            Object parentSaved = super.saveState(facesContext);
+#set ($arrayIndex = 0)
+#foreach( $property in $propertyList )
+#set ($field = $property.fieldName)
+#set ($type = $property.className)
+#if ($property.isPartialStateHolder())
+#set ($arrayIndex = $arrayIndex + 1)
+            Object ${property.name}Saved = null;
+            if (!_$utils.getPrefixedPropertyName("isSet", $property.name)() &&
+                $field != null && $field instanceof PartialStateHolder)
+            {
+                //Delta
+                StateHolder holder = (StateHolder) $field;
+                if (!holder.isTransient())
+                {
+                    Object attachedState = holder.saveState(facesContext);
+                    if (attachedState != null)
+                    {
+                        nullDelta = false;
+                    }
+                    ${property.name}Saved = new _AttachedDeltaWrapper(${field}.getClass(),
+                        attachedState);
+                }
+            }
+            else if (_$utils.getPrefixedPropertyName("isSet", $property.name)() || $field != null )
+            {
+                //Full
+                ${property.name}Saved = saveAttachedState(facesContext,$field);
+                nullDelta = false;
+            }        
+## StateHelper Properties does not need save and restore
+#end
+#end
+            if (parentSaved == null && nullDelta)
+            {
+                //No values
+                return null;
+            }
+            
+            Object[] values = new Object[$primitiveCount];
+            values[0] = parentSaved;
+## Save full state
+#set ($arrayIndex = 0)
+#foreach( $property in $propertyList )
+#set ($field = $property.fieldName)
+#set ($type = $property.className)
+#if ($property.isPartialStateHolder())
+#set ($arrayIndex = $arrayIndex + 1)
+            values[$arrayIndex] = ${property.name}Saved;
+## StateHelper Properties does not need save and restore
+#end
+#end
+            return values;
+        }
+        else
+        {
+            Object[] values = new Object[$primitiveCount];
+            values[0] = super.saveState(facesContext);
+## Save full state
+#set ($arrayIndex = 0)
+#foreach( $property in $propertyList )
+#set ($field = $property.fieldName)
+#set ($type = $property.className)
+#if ($property.isPartialStateHolder())
+#set ($arrayIndex = $arrayIndex + 1)
+            values[$arrayIndex] = saveAttachedState(facesContext,$field);
+## StateHelper Properties does not need save and restore
+#end
+#end
+            return values;
+        }
+    }
+
+    @Override
+    public void restoreState(FacesContext facesContext, Object state)
+    {
+        if (state == null)
+        {
+            return;
+        }
+        
+        Object[] values = (Object[])state;
+        super.restoreState(facesContext,values[0]);
+#set ($arrayIndex = 0)
+#foreach( $property in $propertyList )
+#set ($field = $property.fieldName)
+#set ($type = $property.className)
+#if ($property.isPartialStateHolder())
+#set ($arrayIndex = $arrayIndex + 1)
+        if (values[$arrayIndex] instanceof _AttachedDeltaWrapper)
+        {
+            //Delta
+            ((StateHolder)$field).restoreState(facesContext, ((_AttachedDeltaWrapper) values[$arrayIndex]).getWrappedStateObject());
+        }
+        else
+        {
+            //Full
+            $field = $utils.castIfNecessary($type) restoreAttachedState(facesContext,values[$arrayIndex]);
+        }         
+#else
+## StateHelper Properties does not need save and restore
+#end
+#end
+    }
+#end
+#end
 }

Modified: myfaces/commons/branches/jsf_20/myfaces-commons-validators/src/main/java/org/apache/myfaces/commons/validator/ValidatorBase.java
URL: http://svn.apache.org/viewvc/myfaces/commons/branches/jsf_20/myfaces-commons-validators/src/main/java/org/apache/myfaces/commons/validator/ValidatorBase.java?rev=1033329&r1=1033328&r2=1033329&view=diff
==============================================================================
--- myfaces/commons/branches/jsf_20/myfaces-commons-validators/src/main/java/org/apache/myfaces/commons/validator/ValidatorBase.java (original)
+++ myfaces/commons/branches/jsf_20/myfaces-commons-validators/src/main/java/org/apache/myfaces/commons/validator/ValidatorBase.java Wed Nov 10 02:11:46 2010
@@ -20,14 +20,14 @@ package org.apache.myfaces.commons.valid
 
 import java.io.Serializable;
 import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Iterator;
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
 
 import javax.el.ValueExpression;
 import javax.faces.application.FacesMessage;
+import javax.faces.component.PartialStateHolder;
+import javax.faces.component.StateHelper;
 import javax.faces.component.StateHolder;
 import javax.faces.context.FacesContext;
 import javax.faces.validator.Validator;
@@ -45,11 +45,13 @@ import org.apache.myfaces.commons.util.M
    evaluateELOnExecution = true,
    tagClass = "org.apache.myfaces.commons.validator.ValidatorBaseTag",
    tagHandler = "org.apache.myfaces.commons.validator.ValidatorBaseTagHandler")
-public abstract class ValidatorBase implements StateHolder, Validator {
+public abstract class ValidatorBase implements PartialStateHolder, Validator {
 
-    private String _summaryMessage = null;
-    private String _detailMessage = null;
     private boolean _transient = false;
+    
+    private transient FacesContext _facesContext;
+    private StateHelper _stateHelper = null;
+    private boolean _initialStateMarked = false;
 
     /**
      * alternate validation error summary message format string
@@ -59,9 +61,7 @@ public abstract class ValidatorBase impl
     @JSFProperty
     public String getSummaryMessage()
     {
-        if (_summaryMessage != null) return _summaryMessage;
-        ValueExpression expression = getValueExpression("summaryMessage");
-        return expression != null ? getStringValue(getFacesContext(), expression) : null;
+        return (String) getStateHelper().eval(PropertyKeys.summaryMessage);
     }
 
     /**
@@ -69,7 +69,7 @@ public abstract class ValidatorBase impl
      * @param message   The summary message to be displayed.
      */
     public void setSummaryMessage(String message) {
-        _summaryMessage = message;
+        getStateHelper().put(PropertyKeys.summaryMessage, message);
     }
 
     /**
@@ -102,9 +102,7 @@ public abstract class ValidatorBase impl
      */
     @JSFProperty
     public String getDetailMessage() {
-        if (_detailMessage != null) return _detailMessage;
-        ValueExpression vb = getValueExpression("detailMessage");
-        return vb != null ? getStringValue(getFacesContext(), vb) : null;
+        return (String) getStateHelper().eval(PropertyKeys.detailMessage);
     }
 
     /**
@@ -112,26 +110,34 @@ public abstract class ValidatorBase impl
      * @param message  The detail message to be displayed.
      */
     public void setDetailMessage(String message) {
-        _detailMessage = message;
+        getStateHelper().put(PropertyKeys.detailMessage, message);
     }
 
 
     /**
      * @param context
      */
-    public Object saveState(FacesContext context) {
-        Object[] state = new Object[3];
-        state[0] = _summaryMessage;
-        state[1] = _detailMessage;
-        state[2] = saveValueExpressionMap(context);
-        return state;
+    public Object saveState(FacesContext context)
+    {
+        if (context == null)
+        {
+            throw new NullPointerException ("context");
+        }
+        
+        StateHelper stateHelper = getStateHelper(false);
+        if (stateHelper != null)
+        {
+            return stateHelper.saveState(context);
+        }
+        else
+        {
+            return null;
+        }
     }
 
-    public void restoreState(FacesContext context, Object state) {
-        Object[] values = (Object[]) state;
-        _summaryMessage = (String) values[0];
-        _detailMessage = (String) values[1];
-        restoreValueExpressionMap(context, values[2]);
+    public void restoreState(FacesContext context, Object state)
+    {
+        getStateHelper().restoreState(context, state);
     }
 
     public boolean isTransient() {
@@ -166,69 +172,33 @@ public abstract class ValidatorBase impl
 
     // --------------------- borrowed from UIComponentBase ------------
 
-    private Map _valueExpressionMap = null;
-
+    @SuppressWarnings("unchecked")
     public ValueExpression getValueExpression(String name)
     {
         if (name == null) throw new NullPointerException("name");
-        if (_valueExpressionMap == null)
+        StateHelper helper = getStateHelper(false);
+        if (helper == null)
         {
             return null;
         }
-        else
+        Map<String,Object> bindings = (Map<String,Object>) helper.get(PropertyKeys.bindings); 
+        if (bindings == null)
         {
-            return (ValueExpression)_valueExpressionMap.get(name);
-        }
-    }
-
-    public void setValueExpression(String name,
-                                ValueExpression binding)
-    {
-        if (name == null) throw new NullPointerException("name");
-        if (_valueExpressionMap == null)
-        {
-            _valueExpressionMap = new HashMap();
-        }
-        _valueExpressionMap.put(name, binding);
-    }
-
-    private Object saveValueExpressionMap(FacesContext context)
-    {
-        if (_valueExpressionMap != null)
-        {
-            int initCapacity = (_valueExpressionMap.size() * 4 + 3) / 3;
-            HashMap stateMap = new HashMap(initCapacity);
-            for (Iterator it = _valueExpressionMap.entrySet().iterator(); it.hasNext(); )
-            {
-                Map.Entry entry = (Map.Entry)it.next();
-                stateMap.put(entry.getKey(),
-                             saveAttachedState(context, entry.getValue()));
-            }
-            return stateMap;
+            return null;
         }
         else
         {
-            return null;
+            return (ValueExpression) bindings.get(name);
         }
     }
-
-    private void restoreValueExpressionMap(FacesContext context, Object stateObj)
+    
+    public void setValueExpression(String name, ValueExpression expression)
     {
-        if (stateObj != null)
-        {
-            Map stateMap = (Map)stateObj;
-            int initCapacity = (stateMap.size() * 4 + 3) / 3;
-            _valueExpressionMap = new HashMap(initCapacity);
-            for (Iterator it = stateMap.entrySet().iterator(); it.hasNext(); )
-            {
-                Map.Entry entry = (Map.Entry)it.next();
-                _valueExpressionMap.put(entry.getKey(),
-                                     restoreAttachedState(context, entry.getValue()));
-            }
-        }
-        else
-        {
-            _valueExpressionMap = null;
+        if (name == null) throw new NullPointerException("name");
+        if (expression == null) {
+            getStateHelper().remove(PropertyKeys.bindings, name);
+        } else {
+            getStateHelper().put(PropertyKeys.bindings, name, expression);
         }
     }
 
@@ -257,30 +227,39 @@ public abstract class ValidatorBase impl
      * of the provided object. When deserialized, a default instance of that
      * type will be recreated.
      */
-    public static Object saveAttachedState(FacesContext context,
-                                           Object attachedObject)
+    public static Object saveAttachedState(FacesContext context, Object attachedObject)
     {
-        if (attachedObject == null) return null;
-        if (attachedObject instanceof List)
+        if (context == null)
         {
-            List lst = new ArrayList(((List)attachedObject).size());
-            for (Iterator it = ((List)attachedObject).iterator(); it.hasNext(); )
-            {
-                lst.add(saveAttachedState(context, it.next()));
-            }
-            return new _AttachedListStateWrapper(lst);
+            throw new NullPointerException ("context");
         }
-        else if (attachedObject instanceof StateHolder)
+        
+        if (attachedObject == null)
+            return null;
+        // StateHolder interface should take precedence over
+        // List children
+        if (attachedObject instanceof StateHolder)
         {
-            if (((StateHolder)attachedObject).isTransient())
+            StateHolder holder = (StateHolder) attachedObject;
+            if (holder.isTransient())
             {
                 return null;
             }
-            else
+
+            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)
             {
-                return new _AttachedStateWrapper(attachedObject.getClass(),
-                                                 ((StateHolder)attachedObject).saveState(context));
+                if (item != null)
+                {
+                    lst.add(saveAttachedState(context, item));
+                }
             }
+
+            return new _AttachedListStateWrapper(lst);
         }
         else if (attachedObject instanceof Serializable)
         {
@@ -292,25 +271,26 @@ public abstract class ValidatorBase impl
         }
     }
 
-    public static Object restoreAttachedState(FacesContext context,
-                                              Object stateObj)
-            throws IllegalStateException
+    @SuppressWarnings("unchecked")
+    public static Object restoreAttachedState(FacesContext context, Object stateObj) throws IllegalStateException
     {
-        if (context == null) throw new NullPointerException("context");
-        if (stateObj == null) return null;
+        if (context == null)
+            throw new NullPointerException("context");
+        if (stateObj == null)
+            return null;
         if (stateObj instanceof _AttachedListStateWrapper)
         {
-            List lst = ((_AttachedListStateWrapper)stateObj).getWrappedStateList();
-            List restoredList = new ArrayList(lst.size());
-            for (Iterator it = lst.iterator(); it.hasNext(); )
+            List<Object> lst = ((_AttachedListStateWrapper) stateObj).getWrappedStateList();
+            List<Object> restoredList = new ArrayList<Object>(lst.size());
+            for (Object item : lst)
             {
-                restoredList.add(restoreAttachedState(context, it.next()));
+                restoredList.add(restoreAttachedState(context, item));
             }
             return restoredList;
         }
         else if (stateObj instanceof _AttachedStateWrapper)
         {
-            Class clazz = ((_AttachedStateWrapper)stateObj).getClazz();
+            Class<?> clazz = ((_AttachedStateWrapper) stateObj).getClazz();
             Object restoredObject;
             try
             {
@@ -318,7 +298,8 @@ public abstract class ValidatorBase impl
             }
             catch (InstantiationException e)
             {
-                throw new RuntimeException("Could not restore StateHolder of type " + clazz.getName() + " (missing no-args constructor?)", e);
+                throw new RuntimeException("Could not restore StateHolder of type " + clazz.getName()
+                        + " (missing no-args constructor?)", e);
             }
             catch (IllegalAccessException e)
             {
@@ -326,8 +307,11 @@ public abstract class ValidatorBase impl
             }
             if (restoredObject instanceof StateHolder)
             {
-                Object wrappedState = ((_AttachedStateWrapper)stateObj).getWrappedStateObject();
-                ((StateHolder)restoredObject).restoreState(context, wrappedState);
+                _AttachedStateWrapper wrapper = (_AttachedStateWrapper) stateObj;
+                Object wrappedState = wrapper.getWrappedStateObject();
+
+                StateHolder holder = (StateHolder) restoredObject;
+                holder.restoreState(context, wrappedState);
             }
             return restoredObject;
         }
@@ -337,11 +321,63 @@ public abstract class ValidatorBase impl
         }
     }
 
-
     protected FacesContext getFacesContext()
     {
-        return FacesContext.getCurrentInstance();
+        if (_facesContext == null)
+        {
+            return FacesContext.getCurrentInstance();
+        }
+        else
+        {
+            return _facesContext;
+        }
+    }
+    
+    boolean isCachedFacesContext()
+    {
+        return _facesContext != null;
+    }
+    
+    void setCachedFacesContext(FacesContext facesContext)
+    {
+        _facesContext = facesContext;
     }
+    
+    protected StateHelper getStateHelper() {
+        return getStateHelper(true);
+    }
+
+    /**
+     * returns a delta state saving enabled state helper
+     * for the current component
+     * @param create if true a state helper is created if not already existing
+     * @return an implementation of the StateHelper interface or null if none exists and create is set to false
+     */
+    protected StateHelper getStateHelper(boolean create) {
+        if(_stateHelper != null) {
+            return _stateHelper;
+        }
+        if(create) {
+            _stateHelper = new _DeltaStateHelper(this);
+        }
+        return _stateHelper;
+    }
+    
+    public void clearInitialState()
+    {
+        _initialStateMarked = false;
+    }
+
+    public boolean initialStateMarked()
+    {
+        return _initialStateMarked;
+    }
+
+    public void markInitialState()
+    {
+        _initialStateMarked = true;
+    }
+
     protected String getStringValue(FacesContext context, ValueExpression vb)
     {
         Object value = vb.getValue(context.getELContext());
@@ -351,4 +387,11 @@ public abstract class ValidatorBase impl
         }
         return null;
     }
+    
+    enum PropertyKeys
+    {
+        bindings,
+        summaryMessage,
+        detailMessage
+    }
 }