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