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 [2/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...

Added: myfaces/commons/branches/jsf_20/myfaces-commons-validators/src/main/java/org/apache/myfaces/commons/validator/_DeltaStateHelper.java
URL: http://svn.apache.org/viewvc/myfaces/commons/branches/jsf_20/myfaces-commons-validators/src/main/java/org/apache/myfaces/commons/validator/_DeltaStateHelper.java?rev=1033329&view=auto
==============================================================================
--- myfaces/commons/branches/jsf_20/myfaces-commons-validators/src/main/java/org/apache/myfaces/commons/validator/_DeltaStateHelper.java (added)
+++ myfaces/commons/branches/jsf_20/myfaces-commons-validators/src/main/java/org/apache/myfaces/commons/validator/_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.validator;
+
+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 ValidatorBase _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(ValidatorBase 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-validators/src/main/resources/META-INF/validatorClass12.vm
URL: http://svn.apache.org/viewvc/myfaces/commons/branches/jsf_20/myfaces-commons-validators/src/main/resources/META-INF/validatorClass12.vm?rev=1033329&r1=1033328&r2=1033329&view=diff
==============================================================================
--- myfaces/commons/branches/jsf_20/myfaces-commons-validators/src/main/resources/META-INF/validatorClass12.vm (original)
+++ myfaces/commons/branches/jsf_20/myfaces-commons-validators/src/main/resources/META-INF/validatorClass12.vm Wed Nov 10 02:11:46 2010
@@ -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() || !($validator.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 ($validator.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 ( !($validator.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
 }