View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package javax.faces.component;
20  
21  import java.io.Serializable;
22  import java.util.ArrayList;
23  import java.util.Collection;
24  import java.util.HashMap;
25  import java.util.Iterator;
26  import java.util.List;
27  import java.util.Map;
28  
29  import javax.el.ValueExpression;
30  import javax.faces.context.FacesContext;
31  
32  /**
33   * A delta enabled state holder implementing the StateHolder Interface. 
34   * <p>
35   * Components implementing the PartalStateHolder interface have an initial state
36   * and delta states, the initial state is the one holding all root values
37   * and deltas store differences to the initial states
38   * </p>
39   * <p>
40   * For components not implementing partial state saving only the initial states are
41   * of importance, everything is stored and restored continously there
42   * </p> 
43   * <p>
44   * The state helper seems to have three internal storage mechanisms:
45   * one being a list which stores plain values,
46   * one being a key value pair which stores key values in maps
47   * add serves the plain list type while put serves the 
48   * key value type, 
49   * the third is the value which has to be stored plainly as is!
50   * </p>
51   * In other words, this map can be seen as a composite map. It has two maps: 
52   * initial state map and delta map.
53   * <p> 
54   * If delta map is used (method component.initialStateMarked() ), 
55   * base or initial state map cannot be changed, since all changes 
56   * should be tracked on delta map.
57   * </p>
58   * <p> 
59   * The intention of this class is just hold property values
60   * and do a clean separation between initial state and delta.
61   * </p>
62   * <p>
63   * The code from this class comes from a refactor of 
64   * org.apache.myfaces.trinidad.bean.util.PropertyHashMap
65   * </p>
66   * <p>
67   * The context from this class comes and that should be taken into account
68   * is this:
69   * </p>
70   * <p> 
71   * First request:
72   * </p>
73   * <ul>
74   *   <li> A new template is created (using 
75   *   javax.faces.view.ViewDeclarationLanguage.buildView method)
76   *   and component.markInitialState is called from its related TagHandler classes 
77   *  (see javax.faces.view.facelets.ComponentHandler ).
78   *   When this method is executed, the component tree was populated from the values
79   *   set in the facelet abstract syntax tree (or in other words composition of 
80   *   facelets templates). </li>
81   *   <li> From this point all updates on the variables are considered "delta". </li>
82   *   <li> SaveState, if initialStateMarked is true, only delta is saved. </li>
83   * </ul>
84   * <p>
85   * Second request (and next ones)
86   * </p>
87   * <ul>
88   *   <li> A new template is created and component.markInitialState is called from
89   *   its related TagHandler classes again. In this way, components like c:forEach 
90   *   or c:if, that add or remove components could notify about this and handle 
91   *   them properly (see javax.faces.view.StateManagementStrategy). Note that a 
92   *   component restored using this method is no different as the same component 
93   *   at the first request at the same time. </li>
94   *   <li> A call for restoreState is done, passing the delta as object value. If no 
95   *   delta, the state is complete and no call is triggered. </li>
96   *   <li> Lifecycle occur, changing the necessary stuff. </li>
97   *   <li> SaveState, if initialStateMarked is true, only delta is saved. </li>
98   * </ul>
99   * <p>
100  * From the previous analysis, the following conclusions arise:
101  * <ul>
102  *   <li>This class only needs to keep track of delta changes, so when 
103  *   restoreState/saveState is called, the right objects are passed.</li>
104  *   <li>UIComponent.clearInitialState is used to reset the partial
105  *   state holder to a non delta state, so the state to be saved by
106  *   saveState is no longer a delta instead is a full state. If a call
107  *   to clearInitialState occur it is not expected a call for 
108  *   UIComponent.markInitialState occur on the current request.</li>
109  *   <li>The state is handled in the same way on UIData, so components
110  *   inside UIData share its state on all rows. There is no way to save 
111  *   delta per row.</li>
112  *   <li>The map backed by method put(Serializable,String,Object) is
113  *   a replacement of UIComponentBase.attributesMap and UIComponent.bindings map.
114  *   Note that on jsf 1.2, instances saved on attributesMap should not be
115  *   StateHolder, but on jsf 2.0 it is possible to have it. PartialStateHolder
116  *   instances are not handled in this map, or in other words delta state is not
117  *   handled in this classes (markInitialState and clearInitialState is not propagated).</li>
118  *   <li>The list backed by method add(Serializable,Object) should be (is not) a 
119  *   replacement of UIComponentBase.facesListeners, but note that StateHelper
120  *   does not implement PartialStateHolder, and facesListener could have instances
121  *   of that class that needs to be notified when UIComponent.markInitialState or
122  *   UIComponent.clearInitialState is called, or in other words facesListeners
123  *   should deal with PartialStateHolder instances.</li>
124  *   <li>The list backed by method add(Serializable,Object) is 
125  *   a replacement of UIViewRoot.phaseListeners list. Note that instances of
126  *   PhaseListener are not expected to implement StateHolder or PartialStateHolder.</li>
127  * </ul>
128  * </p>
129  * <p>
130  * NOTE: The current implementation of StateHelper on RI does not handle
131  * stateHolder values internally. To prevent problems when developers create
132  * custom components we should do this too. But anyway, the code that 
133  * handle this case should be let here as comment, if some day this feature
134  * is provided. Note than stateHolder aware properties like converter,
135  * validator or listeners should deal with StateHolder or PartialStateHolder
136  * on component classes. 
137  * 
138  * </p>
139  */
140 class _DeltaStateHelper implements StateHelper, TransientStateHelper, TransientStateHolder
141 {
142 
143     /**
144      * We need to hold a component instance because:
145      * 
146      * - The component is the one who knows if we are on initial or delta mode
147      * - eval assume calls to component.ValueExpression
148      */
149     private UIComponent _component;
150 
151     /**
152      * This map holds the full current state
153      */
154     private Map<Serializable, Object> _fullState;
155 
156     /**
157      * This map only keep track of delta changes to be saved
158      */
159     private Map<Serializable, Object> _deltas;
160     
161     private Map<Object, Object> _transientState;
162     
163     //private Map<Serializable, Object> _initialState;
164     private Object[] _initialState;
165     
166     /**
167      * This map keep track of StateHolder keys, to be saved when
168      * saveState is called. 
169      */
170     //private Set<Serializable> _stateHolderKeys;  
171 
172     private boolean _transient = false;
173 
174     /**
175      * This is a copy-on-write map of the full state after markInitialState()
176      * was called, but before any delta is written that is not part of
177      * the initial state (value, localValueSet, submittedValue, valid).
178      * The intention is allow to reset the StateHelper when copyFullInitialState
179      * is set to true.
180      */
181     private Map<Serializable, Object> _initialFullState;
182     
183     /**
184      * Indicates if a copy-on-write map is created to allow reset the state
185      * of this StateHelper.
186      */
187     private boolean _copyFullInitialState;
188 
189     public _DeltaStateHelper(UIComponent component)
190     {
191         super();
192         this._component = component;
193         _fullState = new HashMap<Serializable, Object>();
194         _deltas = null;
195         _transientState = null;
196         _initialFullState = null;
197         _copyFullInitialState = false;
198         //_stateHolderKeys = new HashSet<Serializable>();
199     }
200 
201     /**
202      * Used to create delta map on demand
203      * 
204      * @return
205      */
206     private boolean _createDeltas(Serializable key)
207     {
208         if (isInitialStateMarked())
209         {
210             if (_copyFullInitialState && _initialFullState == null)
211             {
212                 if (_initialState == null)
213                 {
214                     // Copy it directly
215                     _initialFullState = new HashMap<Serializable, Object>();
216                     copyMap(_component.getFacesContext(), _fullState, _initialFullState);
217                 }
218                 else
219                 {
220                     // Create only if the passed key is not part of the defined initial state
221                     boolean keyInInitialState = false;
222                     for (int i = 0; i < _initialState.length; i+=2)
223                     {
224                         Serializable key2 = (Serializable) _initialState[i];
225                         if (key.equals(key2))
226                         {
227                             keyInInitialState = true;
228                             break;
229                         }
230                     }
231                     if (!keyInInitialState)
232                     {
233                         // Copy it directly, but note in this case if the initialFullState map
234                         // contains some key already defined in initialState, this key must be
235                         // overriden. It is better to do in that way, because it is possible
236                         // to skip resetState() if the view cannot be recycled.
237                         _initialFullState = new HashMap<Serializable, Object>();
238                         copyMap(_component.getFacesContext(), _fullState, _initialFullState);
239                         /*
240                         for (int i = 0; i < _initialState.length; i+=2)
241                         {
242                             Serializable key2 = (Serializable) _initialState[i];
243                             Object defaultValue = _initialState[i+1];
244                             _initialFullState.put(key2, defaultValue);
245                         }*/
246                     }
247                 }
248             }
249             if (_deltas == null)
250             {
251                 _deltas = new HashMap<Serializable, Object>(2);
252             }
253             return true;
254         }
255 
256         return false;
257     }
258     
259     void setCopyFullInitialState(boolean value)
260     {
261         _copyFullInitialState = value;
262     }
263     
264     private static void copyMap(FacesContext context, 
265             Map<Serializable, Object> sourceMap, 
266             Map<Serializable, Object> targetMap)
267     {
268         Map serializableMap = sourceMap;
269         Map.Entry<Serializable, Object> entry;
270 
271         Iterator<Map.Entry<Serializable, Object>> it = serializableMap.entrySet().iterator();
272         while (it.hasNext())
273         {
274             entry = it.next();
275             Serializable key = entry.getKey();
276             Object value = entry.getValue();
277 
278             // The condition in which the call to saveAttachedState
279             // is to handle List, StateHolder or non Serializable instances.
280             // we check it here, to prevent unnecessary calls.
281             if (value instanceof StateHolder ||
282                 value instanceof List ||
283                 !(value instanceof Serializable))
284             {
285                 Object savedValue = UIComponentBase.saveAttachedState(context, value);
286 
287                 targetMap.put(key, UIComponentBase.restoreAttachedState(context, savedValue));
288             }
289             else if (!(value instanceof Serializable))
290             {
291                 Object newInstance;
292                 try
293                 {
294                     newInstance = entry.getValue().getClass().newInstance();
295                 }
296                 catch (InstantiationException e)
297                 {
298                     throw new RuntimeException("Could not restore StateHolder of type " + 
299                             entry.getValue().getClass().getName()
300                             + " (missing no-args constructor?)", e);
301                 }
302                 catch (IllegalAccessException e)
303                 {
304                     throw new RuntimeException(e);
305                 }
306                 targetMap.put(key, newInstance);
307             }
308             else
309             {
310                 targetMap.put(key, value);
311             }
312         }
313     }
314     
315     protected boolean isInitialStateMarked()
316     {
317         return _component.initialStateMarked();
318     }
319 
320     @Override
321     public void add(Serializable key, Object value)
322     {
323         if (_createDeltas(key))
324         {
325             //Track delta case
326             Map<Object, Boolean> deltaListMapValues = (Map<Object, Boolean>) _deltas.get(key);
327             if (deltaListMapValues == null)
328             {
329                 deltaListMapValues = new InternalDeltaListMap<Object, Boolean>(3);
330                 _deltas.put(key, deltaListMapValues);
331             }
332             deltaListMapValues.put(value, Boolean.TRUE);
333         }
334 
335         //Handle change on full map
336         List<Object> fullListValues = (List<Object>) _fullState.get(key);
337         if (fullListValues == null)
338         {
339             fullListValues = new InternalList<Object>(3);
340             _fullState.put(key, fullListValues);
341         }
342         fullListValues.add(value);
343     }
344 
345     @Override
346     public Object eval(Serializable key)
347     {
348         Object returnValue = _fullState.get(key);
349         if (returnValue != null)
350         {
351             return returnValue;
352         }
353         ValueExpression expression = _component.getValueExpression(key.toString());
354         if (expression != null)
355         {
356             return expression.getValue(_component.getFacesContext().getELContext());
357         }
358         return null;
359     }
360 
361     @Override
362     public Object eval(Serializable key, Object defaultValue)
363     {
364         Object returnValue = _fullState.get(key);
365         if (returnValue != null)
366         {
367             return returnValue;
368         }
369         ValueExpression expression = _component.getValueExpression(key.toString());
370         if (expression != null)
371         {
372             return expression.getValue(_component.getFacesContext().getELContext());
373         }
374         return defaultValue;
375     }
376 
377     @Override
378     public Object get(Serializable key)
379     {
380         return _fullState.get(key);
381     }
382 
383     @Override
384     public Object put(Serializable key, Object value)
385     {
386         Object returnValue = null;
387         if (_createDeltas(key))
388         {
389             if (_deltas.containsKey(key))
390             {
391                 returnValue = _deltas.put(key, value);
392                 _fullState.put(key, value);
393             }
394             else if (value == null && !_fullState.containsKey(key))
395             {
396                 returnValue = null;
397             }
398             else
399             {
400                 _deltas.put(key, value);
401                 returnValue = _fullState.put(key, value);
402             }
403         }
404         else
405         {
406             /*
407             if (value instanceof StateHolder)
408             {
409                 _stateHolderKeys.add(key);
410             }
411             */
412             returnValue = _fullState.put(key, value);
413         }
414         return returnValue;
415     }
416 
417     @Override
418     public Object put(Serializable key, String mapKey, Object value)
419     {
420         boolean returnSet = false;
421         Object returnValue = null;
422         if (_createDeltas(key))
423         {
424             //Track delta case
425             Map<String, Object> mapValues = (Map<String, Object>) _deltas.get(key);
426             if (mapValues == null)
427             {
428                 mapValues = new InternalMap<String, Object>();
429                 _deltas.put(key, mapValues);
430             }
431             if (mapValues.containsKey(mapKey))
432             {
433                 returnValue = mapValues.put(mapKey, value);
434                 returnSet = true;
435             }
436             else
437             {
438                 mapValues.put(mapKey, value);
439             }
440         }
441 
442         //Handle change on full map
443         Map<String, Object> mapValues = (Map<String, Object>) _fullState.get(key);
444         if (mapValues == null)
445         {
446             mapValues = new InternalMap<String, Object>();
447             _fullState.put(key, mapValues);
448         }
449         if (returnSet)
450         {
451             mapValues.put(mapKey, value);
452         }
453         else
454         {
455             returnValue = mapValues.put(mapKey, value);
456         }
457         return returnValue;
458     }
459 
460     @Override
461     public Object remove(Serializable key)
462     {
463         Object returnValue = null;
464         if (_createDeltas(key))
465         {
466             if (_deltas.containsKey(key))
467             {
468                 // Keep track of the removed values using key/null pair on the delta map
469                 returnValue = _deltas.put(key, null);
470                 _fullState.remove(key);
471             }
472             else
473             {
474                 // Keep track of the removed values using key/null pair on the delta map
475                 _deltas.put(key, null);
476                 returnValue = _fullState.remove(key);
477             }
478         }
479         else
480         {
481             returnValue = _fullState.remove(key);
482         }
483         return returnValue;
484     }
485 
486     @Override
487     public Object remove(Serializable key, Object valueOrKey)
488     {
489         // Comment by lu4242 : The spec javadoc says if it is a Collection 
490         // or Map deal with it. But the intention of this method is work 
491         // with add(?,?) and put(?,?,?), this ones return instances of 
492         // InternalMap and InternalList to prevent mixing, so to be 
493         // consistent we'll cast to those classes here.
494         
495         Object collectionOrMap = _fullState.get(key);
496         Object returnValue = null;
497         if (collectionOrMap instanceof InternalMap)
498         {
499             if (_createDeltas(key))
500             {
501                 returnValue = _removeValueOrKeyFromMap(_deltas, key, valueOrKey, true);
502                 _removeValueOrKeyFromMap(_fullState, key, valueOrKey, false);
503             }
504             else
505             {
506                 returnValue = _removeValueOrKeyFromMap(_fullState, key, valueOrKey, false);
507             }
508         }
509         else if (collectionOrMap instanceof InternalList)
510         {
511             if (_createDeltas(key))
512             {
513                 returnValue = _removeValueOrKeyFromCollectionDelta(_deltas, key, valueOrKey);
514                 _removeValueOrKeyFromCollection(_fullState, key, valueOrKey);
515             }
516             else
517             {
518                 returnValue = _removeValueOrKeyFromCollection(_fullState, key, valueOrKey);
519             }
520         }
521         return returnValue;
522     }
523 
524     private static Object _removeValueOrKeyFromCollectionDelta(
525             Map<Serializable, Object> stateMap, Serializable key,
526             Object valueOrKey)
527     {
528         Object returnValue = null;
529         Map<Object, Boolean> c = (Map<Object, Boolean>) stateMap.get(key);
530         if (c != null)
531         {
532             if (c.containsKey(valueOrKey))
533             {
534                 returnValue = valueOrKey;
535             }
536             c.put(valueOrKey, Boolean.FALSE);
537         }
538         return returnValue;
539     }
540 
541     private static Object _removeValueOrKeyFromCollection(
542             Map<Serializable, Object> stateMap, Serializable key,
543             Object valueOrKey)
544     {
545         Object returnValue = null;
546         Collection c = (Collection) stateMap.get(key);
547         if (c != null)
548         {
549             if (c.remove(valueOrKey))
550             {
551                 returnValue = valueOrKey;
552             }
553             if (c.isEmpty())
554             {
555                 stateMap.remove(key);
556             }
557         }
558         return returnValue;
559     }
560 
561     private static Object _removeValueOrKeyFromMap(
562             Map<Serializable, Object> stateMap, Serializable key,
563             Object valueOrKey, boolean delta)
564     {
565         if (valueOrKey == null)
566         {
567             return null;
568         }
569 
570         Object returnValue = null;
571         Map<String, Object> map = (Map<String, Object>) stateMap.get(key);
572         if (map != null)
573         {
574             if (delta)
575             {
576                 // Keep track of the removed values using key/null pair on the delta map
577                 returnValue = map.put((String) valueOrKey, null);
578             }
579             else
580             {
581                 returnValue = map.remove(valueOrKey);
582             }
583 
584             if (map.isEmpty())
585             {
586                 //stateMap.remove(key);
587                 stateMap.put(key, null);
588             }
589         }
590         return returnValue;
591     }
592 
593     @Override
594     public boolean isTransient()
595     {
596         return _transient;
597     }
598 
599     /**
600      * Serializing cod
601      * the serialized data structure consists of key value pairs unless the value itself is an internal array
602      * or a map in case of an internal array or map the value itself is another array with its initial value
603      * myfaces.InternalArray, myfaces.internalMap
604      *
605      * the internal Array is then mapped to another array
606      *
607      * the internal Map again is then mapped to a map with key value pairs
608      *
609      *
610      */
611     @Override
612     public Object saveState(FacesContext context)
613     {
614         Map serializableMap = (isInitialStateMarked()) ? _deltas : _fullState;
615 
616         if (_initialState != null && _deltas != null && !_deltas.isEmpty()
617             && isInitialStateMarked())
618         {
619             // Before save the state, check if the property was changed from the
620             // initial state value. If the property was changed but it has the
621             // same value from the one in the initial state, we can remove it
622             // from delta, because when the view is built again, it will be
623             // restored to the same state. This check suppose some additional
624             // map.get() calls when saving the state, but using it only in properties
625             // that are expected to change over lifecycle (value, localValueSet,
626             // submittedValue, valid), is worth to do it, because those ones
627             // always generated delta changes.
628             for (int i = 0; i < _initialState.length; i+=2)
629             {
630                 Serializable key = (Serializable) _initialState[i];
631                 Object defaultValue = _initialState[i+1];
632                 
633                 // Check only if there is delta state for that property, in other
634                 // case it is not necessary. Remember it is possible to have
635                 // null values inside the Map.
636                 if (_deltas.containsKey(key))
637                 {
638                     Object deltaValue = _deltas.get(key);
639                     if (deltaValue == null && defaultValue == null)
640                     {
641                         _deltas.remove(key);
642                         if (_deltas.isEmpty())
643                         {
644                             break;
645                         }
646                     }
647                     if (deltaValue != null && deltaValue.equals(defaultValue))
648                     {
649                         _deltas.remove(key);
650                         if (_deltas.isEmpty())
651                         {
652                             break;
653                         }
654                     }
655                 }
656             }
657         }
658         if (serializableMap == null || serializableMap.isEmpty())
659         {
660             return null;
661         }
662         
663         /*
664         int stateHolderKeyCount = 0;
665         if (isInitalStateMarked())
666         {
667             for (Iterator<Serializable> it = _stateHolderKeys.iterator(); it.hasNext();)
668             {
669                 Serializable key = it.next();
670                 if (!_deltas.containsKey(key))
671                 {
672                     stateHolderKeyCount++;
673                 }
674             }
675         }*/
676         
677         Map.Entry<Serializable, Object> entry;
678         //entry == key, value, key, value
679         Object[] retArr = new Object[serializableMap.entrySet().size() * 2];
680         //Object[] retArr = new Object[serializableMap.entrySet().size() * 2 + stateHolderKeyCount]; 
681 
682         Iterator<Map.Entry<Serializable, Object>> it = serializableMap.entrySet().iterator();
683         int cnt = 0;
684         while (it.hasNext())
685         {
686             entry = it.next();
687             retArr[cnt] = entry.getKey();
688 
689             Object value = entry.getValue();
690             
691             // The condition in which the call to saveAttachedState
692             // is to handle List, StateHolder or non Serializable instances.
693             // we check it here, to prevent unnecessary calls.
694             if (value instanceof StateHolder ||
695                 value instanceof List ||
696                 !(value instanceof Serializable))
697             {
698                 Object savedValue = UIComponentBase.saveAttachedState(context,
699                     value);
700                 retArr[cnt + 1] = savedValue;
701             }
702             else
703             {
704                 retArr[cnt + 1] = value;
705             }
706             cnt += 2;
707         }
708         
709         /*
710         if (isInitalStateMarked())
711         {
712             for (Iterator<Serializable> it2 = _stateHolderKeys.iterator(); it.hasNext();)
713             {
714                 Serializable key = it2.next();
715                 if (!_deltas.containsKey(key))
716                 {
717                     retArr[cnt] = key;
718                     Object value = _fullState.get(key);
719                     if (value instanceof PartialStateHolder)
720                     {
721                         //Could contain delta, save it as _AttachedDeltaState
722                         PartialStateHolder holder = (PartialStateHolder) value;
723                         if (holder.isTransient())
724                         {
725                             retArr[cnt + 1] = null;
726                         }
727                         else
728                         {
729                             retArr[cnt + 1] = new _AttachedDeltaWrapper(value.getClass(), holder.saveState(context));
730                         }
731                     }
732                     else
733                     {
734                         //Save everything
735                         retArr[cnt + 1] = UIComponentBase.saveAttachedState(context, _fullState.get(key));
736                     }
737                     cnt += 2;
738                 }
739             }
740         }
741         */
742         return retArr;
743     }
744 
745     @Override
746     public void restoreState(FacesContext context, Object state)
747     {
748         if (state == null)
749         {
750             return;
751         }
752 
753         Object[] serializedState = (Object[]) state;
754         
755         if (!isInitialStateMarked() && !_fullState.isEmpty())
756         {
757             _fullState.clear();
758             if(_deltas != null)
759             {
760                 _deltas.clear();
761             }
762         }
763 
764         for (int cnt = 0; cnt < serializedState.length; cnt += 2)
765         {
766             Serializable key = (Serializable) serializedState[cnt];
767             Object savedValue = UIComponentBase.restoreAttachedState(context, serializedState[cnt + 1]);
768 
769             if (isInitialStateMarked())
770             {
771                 if (savedValue instanceof InternalDeltaListMap)
772                 {
773                     for (Map.Entry<Object, Boolean> mapEntry : ((Map<Object, Boolean>) savedValue).entrySet())
774                     {
775                         boolean addOrRemove = mapEntry.getValue();
776                         if (addOrRemove)
777                         {
778                             //add
779                             this.add(key, mapEntry.getKey());
780                         }
781                         else
782                         {
783                             //remove
784                             this.remove(key, mapEntry.getKey());
785                         }
786                     }
787                 }
788                 else if (savedValue instanceof InternalMap)
789                 {
790                     for (Map.Entry<String, Object> mapEntry : ((Map<String, Object>) savedValue).entrySet())
791                     {
792                         this.put(key, mapEntry.getKey(), mapEntry.getValue());
793                     }
794                 }
795                 /*
796                 else if (savedValue instanceof _AttachedDeltaWrapper)
797                 {
798                     _AttachedStateWrapper wrapper = (_AttachedStateWrapper) savedValue;
799                     //Restore delta state
800                     ((PartialStateHolder)_fullState.get(key)).restoreState(context, wrapper.getWrappedStateObject());
801                     //Add this key as StateHolder key 
802                     _stateHolderKeys.add(key);
803                 }
804                 */
805                 else
806                 {
807                     put(key, savedValue);
808                 }
809             }
810             else
811             {
812                 put(key, savedValue);
813             }
814         }
815     }
816     
817     /**
818      * Try to reset the state and then check if the reset was succesful or not,
819      * calling saveState().
820      */
821     public Object resetHardState(FacesContext context)
822     {
823         if (_transientState != null)
824         {
825             _transientState.clear();
826         }
827         if (_deltas != null && !_deltas.isEmpty() && isInitialStateMarked())
828         {
829             clearFullStateMap(context);
830         }
831         return saveState(context);
832     }
833     
834     /**
835      * Execute a "soft reset", which means only remove all transient state.
836      */
837     public Object resetSoftState(FacesContext context)
838     {
839         if (_transientState != null)
840         {
841             _transientState.clear();
842         }
843         return null;
844     }
845     
846     protected void clearFullStateMap(FacesContext context)
847     {
848         if (_deltas != null)
849         {
850             _deltas.clear();
851         }
852         if (_initialFullState != null)
853         {
854             // If there is no delta, fullState is not required to be cleared.
855             _fullState.clear();
856             copyMap(context, _initialFullState, _fullState);
857         }
858         if (_initialState != null)
859         {
860             // If initial state is defined, override properties in _initialFullState.
861             for (int i = 0; i < _initialState.length; i+=2)
862             {
863                 Serializable key2 = (Serializable) _initialState[i];
864                 Object defaultValue = _initialState[i+1];
865                 if (_fullState.containsKey(key2))
866                 {
867                     _fullState.put(key2, defaultValue);
868                 }
869             }
870         }
871     }
872 
873     @Override
874     public void setTransient(boolean transientValue)
875     {
876         _transient = transientValue;
877     }
878 
879     //We use our own data structures just to make sure
880     //nothing gets mixed up internally
881     static class InternalMap<K, V> extends HashMap<K, V> implements StateHolder
882     {
883         public InternalMap()
884         {
885             super();
886         }
887 
888         public InternalMap(int initialCapacity, float loadFactor)
889         {
890             super(initialCapacity, loadFactor);
891         }
892 
893         public InternalMap(Map<? extends K, ? extends V> m)
894         {
895             super(m);
896         }
897 
898         public InternalMap(int initialSize)
899         {
900             super(initialSize);
901         }
902 
903         @Override
904         public boolean isTransient()
905         {
906             return false;
907         }
908 
909         @Override
910         public void setTransient(boolean newTransientValue)
911         {
912             // No op
913         }
914 
915         @Override
916         public void restoreState(FacesContext context, Object state)
917         {
918             Object[] listAsMap = (Object[]) state;
919             for (int cnt = 0; cnt < listAsMap.length; cnt += 2)
920             {
921                 this.put((K) listAsMap[cnt], (V) UIComponentBase.restoreAttachedState(context, listAsMap[cnt + 1]));
922             }
923         }
924 
925         @Override
926         public Object saveState(FacesContext context)
927         {
928             int cnt = 0;
929             Object[] mapArr = new Object[this.size() * 2];
930             for (Map.Entry<K, V> entry : this.entrySet())
931             {
932                 mapArr[cnt] = entry.getKey();
933                 Object value = entry.getValue();
934                 
935                 if (value instanceof StateHolder ||
936                     value instanceof List ||
937                     !(value instanceof Serializable))
938                 {
939                     mapArr[cnt + 1] = UIComponentBase.saveAttachedState(context, value);
940                 }
941                 else
942                 {
943                     mapArr[cnt + 1] = value;
944                 }
945                 cnt += 2;
946             }
947             return mapArr;
948         }
949     }
950 
951     /**
952      * Map used to keep track of list changes 
953      */
954     static class InternalDeltaListMap<K, V> extends InternalMap<K, V>
955     {
956 
957         public InternalDeltaListMap()
958         {
959             super();
960         }
961 
962         public InternalDeltaListMap(int initialCapacity, float loadFactor)
963         {
964             super(initialCapacity, loadFactor);
965         }
966 
967         public InternalDeltaListMap(int initialSize)
968         {
969             super(initialSize);
970         }
971 
972         public InternalDeltaListMap(Map<? extends K, ? extends V> m)
973         {
974             super(m);
975         }
976     }
977 
978     static class InternalList<T> extends ArrayList<T> implements StateHolder
979     {
980         public InternalList()
981         {
982             super();
983         }
984 
985         public InternalList(Collection<? extends T> c)
986         {
987             super(c);
988         }
989 
990         public InternalList(int initialSize)
991         {
992             super(initialSize);
993         }
994 
995         @Override
996         public boolean isTransient()
997         {
998             return false;
999         }
1000 
1001         @Override
1002         public void setTransient(boolean newTransientValue)
1003         {
1004         }
1005 
1006         @Override
1007         public void restoreState(FacesContext context, Object state)
1008         {
1009             Object[] listAsArr = (Object[]) state;
1010             //since all other options would mean dual iteration 
1011             //we have to do it the hard way
1012             for (Object elem : listAsArr)
1013             {
1014                 add((T) UIComponentBase.restoreAttachedState(context, elem));
1015             }
1016         }
1017 
1018         @Override
1019         public Object saveState(FacesContext context)
1020         {
1021             Object[] values = new Object[size()];
1022             for (int i = 0; i < size(); i++)
1023             {
1024                 Object value = get(i);
1025                 
1026                 if (value instanceof StateHolder ||
1027                     value instanceof List ||
1028                     !(value instanceof Serializable))
1029                 {
1030                     values[i] = UIComponentBase.saveAttachedState(context, value);
1031                 }
1032                 else
1033                 {
1034                     values[i] = value;
1035                 }                
1036             }
1037             return values;
1038         }
1039     }
1040 
1041     public Object getTransient(Object key)
1042     {
1043         return (_transientState == null) ? null : _transientState.get(key);
1044     }
1045 
1046     public Object getTransient(Object key, Object defaultValue)
1047     {
1048         Object returnValue = (_transientState == null) ? null : _transientState.get(key);
1049         if (returnValue != null)
1050         {
1051             return returnValue;
1052         }
1053         return defaultValue;
1054     }
1055 
1056     @Override
1057     public Object putTransient(Object key, Object value)
1058     {
1059         if (_transientState == null)
1060         {
1061             _transientState = new HashMap<Object, Object>();
1062         }
1063         return _transientState.put(key, value);
1064     }
1065 
1066     @Override
1067     @SuppressWarnings("unchecked")
1068     public void restoreTransientState(FacesContext context, Object state)
1069     {
1070         _transientState = (Map<Object, Object>) state;
1071     }
1072     
1073     @Override
1074     public Object saveTransientState(FacesContext context)
1075     {
1076         return _transientState;
1077     }
1078 
1079     public void markPropertyInInitialState(Object[] defaultInitialState)
1080     {
1081         // Check if in the fullState, one of the default properties were changed
1082         boolean canApplyDefaultInitialState = true;
1083         for (int i = 0; i < defaultInitialState.length; i+=2)
1084         {
1085             Serializable key = (Serializable) defaultInitialState[i];
1086             if (_fullState.containsKey(key))
1087             {
1088                 canApplyDefaultInitialState = false;
1089                 break;
1090             }
1091         }
1092         if (canApplyDefaultInitialState)
1093         {
1094             // Most of the times the defaultInitialState is used.
1095             _initialState = defaultInitialState;
1096         }
1097         else
1098         {
1099             // recalculate it
1100             Object[] initialState = new Object[defaultInitialState.length];
1101             for (int i = 0; i < defaultInitialState.length; i+=2)
1102             {
1103                 Serializable key = (Serializable) defaultInitialState[i];
1104                 initialState[i] = key;
1105                 if (_fullState.containsKey(key))
1106                 {
1107                     initialState[i+1] = _fullState.get(key);
1108                 }
1109                 else
1110                 {
1111                     initialState[i+1] = defaultInitialState[i+1];
1112                 }
1113             }
1114             _initialState = initialState;
1115         }
1116     }
1117 }