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  * @author Werner Punz
141  * @author Leonardo Uribe (latest modification by $Author: lu4242 $)
142  * @version $Rev: 1352587 $ $Date: 2012-06-21 16:03:33 +0000 (Thu, 21 Jun 2012) $
143  */
144 class _DeltaStateHelper implements StateHelper, TransientStateHelper, TransientStateHolder
145 {
146 
147     /**
148      * We need to hold a component instance because:
149      * 
150      * - The component is the one who knows if we are on initial or delta mode
151      * - eval assume calls to component.ValueExpression
152      */
153     private UIComponent _component;
154 
155     /**
156      * This map holds the full current state
157      */
158     private Map<Serializable, Object> _fullState;
159 
160     /**
161      * This map only keep track of delta changes to be saved
162      */
163     private Map<Serializable, Object> _deltas;
164     
165     private Map<Object, Object> _transientState;
166     
167     //private Map<Serializable, Object> _initialState;
168     private Object[] _initialState;
169     
170     /**
171      * This map keep track of StateHolder keys, to be saved when
172      * saveState is called. 
173      */
174     //private Set<Serializable> _stateHolderKeys;  
175 
176     private boolean _transient = false;
177 
178     public _DeltaStateHelper(UIComponent component)
179     {
180         super();
181         this._component = component;
182         _fullState = new HashMap<Serializable, Object>();
183         _deltas = null;
184         _transientState = null;
185         //_stateHolderKeys = new HashSet<Serializable>();
186     }
187 
188     /**
189      * Used to create delta map on demand
190      * 
191      * @return
192      */
193     private boolean _createDeltas()
194     {
195         if (isInitialStateMarked())
196         {
197             if (_deltas == null)
198             {
199                 _deltas = new HashMap<Serializable, Object>(2);
200             }
201             return true;
202         }
203 
204         return false;
205     }
206     
207     protected boolean isInitialStateMarked()
208     {
209         return _component.initialStateMarked();
210     }
211 
212     public void add(Serializable key, Object value)
213     {
214         if (_createDeltas())
215         {
216             //Track delta case
217             Map<Object, Boolean> deltaListMapValues = (Map<Object, Boolean>) _deltas
218                     .get(key);
219             if (deltaListMapValues == null)
220             {
221                 deltaListMapValues = new InternalDeltaListMap<Object, Boolean>(
222                         3);
223                 _deltas.put(key, deltaListMapValues);
224             }
225             deltaListMapValues.put(value, Boolean.TRUE);
226         }
227 
228         //Handle change on full map
229         List<Object> fullListValues = (List<Object>) _fullState.get(key);
230         if (fullListValues == null)
231         {
232             fullListValues = new InternalList<Object>(3);
233             _fullState.put(key, fullListValues);
234         }
235         fullListValues.add(value);
236     }
237 
238     public Object eval(Serializable key)
239     {
240         Object returnValue = _fullState.get(key);
241         if (returnValue != null)
242         {
243             return returnValue;
244         }
245         ValueExpression expression = _component.getValueExpression(key
246                 .toString());
247         if (expression != null)
248         {
249             return expression.getValue(_component.getFacesContext()
250                     .getELContext());
251         }
252         return null;
253     }
254 
255     public Object eval(Serializable key, Object defaultValue)
256     {
257         Object returnValue = _fullState.get(key);
258         if (returnValue != null)
259         {
260             return returnValue;
261         }
262         ValueExpression expression = _component.getValueExpression(key
263                 .toString());
264         if (expression != null)
265         {
266             return expression.getValue(_component.getFacesContext()
267                     .getELContext());
268         }
269         return defaultValue;
270     }
271 
272     public Object get(Serializable key)
273     {
274         return _fullState.get(key);
275     }
276 
277     public Object put(Serializable key, Object value)
278     {
279         Object returnValue = null;
280         if (_createDeltas())
281         {
282             if (_deltas.containsKey(key))
283             {
284                 returnValue = _deltas.put(key, value);
285                 _fullState.put(key, value);
286             }
287             else if (value == null && !_fullState.containsKey(key))
288             {
289                 returnValue = null;
290             }
291             else
292             {
293                 _deltas.put(key, value);
294                 returnValue = _fullState.put(key, value);
295             }
296         }
297         else
298         {
299             /*
300             if (value instanceof StateHolder)
301             {
302                 _stateHolderKeys.add(key);
303             }
304             */
305             returnValue = _fullState.put(key, value);
306         }
307         return returnValue;
308     }
309 
310     public Object put(Serializable key, String mapKey, Object value)
311     {
312         boolean returnSet = false;
313         Object returnValue = null;
314         if (_createDeltas())
315         {
316             //Track delta case
317             Map<String, Object> mapValues = (Map<String, Object>) _deltas
318                     .get(key);
319             if (mapValues == null)
320             {
321                 mapValues = new InternalMap<String, Object>();
322                 _deltas.put(key, mapValues);
323             }
324             if (mapValues.containsKey(mapKey))
325             {
326                 returnValue = mapValues.put(mapKey, value);
327                 returnSet = true;
328             }
329             else
330             {
331                 mapValues.put(mapKey, value);
332             }
333         }
334 
335         //Handle change on full map
336         Map<String, Object> mapValues = (Map<String, Object>) _fullState
337                 .get(key);
338         if (mapValues == null)
339         {
340             mapValues = new InternalMap<String, Object>();
341             _fullState.put(key, mapValues);
342         }
343         if (returnSet)
344         {
345             mapValues.put(mapKey, value);
346         }
347         else
348         {
349             returnValue = mapValues.put(mapKey, value);
350         }
351         return returnValue;
352     }
353 
354     public Object remove(Serializable key)
355     {
356         Object returnValue = null;
357         if (_createDeltas())
358         {
359             if (_deltas.containsKey(key))
360             {
361                 // Keep track of the removed values using key/null pair on the delta map
362                 returnValue = _deltas.put(key, null);
363                 _fullState.remove(key);
364             }
365             else
366             {
367                 // Keep track of the removed values using key/null pair on the delta map
368                 _deltas.put(key, null);
369                 returnValue = _fullState.remove(key);
370             }
371         }
372         else
373         {
374             returnValue = _fullState.remove(key);
375         }
376         return returnValue;
377     }
378 
379     public Object remove(Serializable key, Object valueOrKey)
380     {
381         // Comment by lu4242 : The spec javadoc says if it is a Collection 
382         // or Map deal with it. But the intention of this method is work 
383         // with add(?,?) and put(?,?,?), this ones return instances of 
384         // InternalMap and InternalList to prevent mixing, so to be 
385         // consistent we'll cast to those classes here.
386         
387         Object collectionOrMap = _fullState.get(key);
388         Object returnValue = null;
389         if (collectionOrMap instanceof InternalMap)
390         {
391             if (_createDeltas())
392             {
393                 returnValue = _removeValueOrKeyFromMap(_deltas, key,
394                         valueOrKey, true);
395                 _removeValueOrKeyFromMap(_fullState, key, valueOrKey, false);
396             }
397             else
398             {
399                 returnValue = _removeValueOrKeyFromMap(_fullState, key,
400                         valueOrKey, false);
401             }
402         }
403         else if (collectionOrMap instanceof InternalList)
404         {
405             if (_createDeltas())
406             {
407                 returnValue = _removeValueOrKeyFromCollectionDelta(_deltas,
408                         key, valueOrKey);
409                 _removeValueOrKeyFromCollection(_fullState, key, valueOrKey);
410             }
411             else
412             {
413                 returnValue = _removeValueOrKeyFromCollection(_fullState, key,
414                         valueOrKey);
415             }
416         }
417         return returnValue;
418     }
419 
420     private static Object _removeValueOrKeyFromCollectionDelta(
421             Map<Serializable, Object> stateMap, Serializable key,
422             Object valueOrKey)
423     {
424         Object returnValue = null;
425         Map<Object, Boolean> c = (Map<Object, Boolean>) stateMap.get(key);
426         if (c != null)
427         {
428             if (c.containsKey(valueOrKey))
429             {
430                 returnValue = valueOrKey;
431             }
432             c.put(valueOrKey, Boolean.FALSE);
433         }
434         return returnValue;
435     }
436 
437     private static Object _removeValueOrKeyFromCollection(
438             Map<Serializable, Object> stateMap, Serializable key,
439             Object valueOrKey)
440     {
441         Object returnValue = null;
442         Collection c = (Collection) stateMap.get(key);
443         if (c != null)
444         {
445             if (c.remove(valueOrKey))
446             {
447                 returnValue = valueOrKey;
448             }
449             if (c.isEmpty())
450             {
451                 stateMap.remove(key);
452             }
453         }
454         return returnValue;
455     }
456 
457     private static Object _removeValueOrKeyFromMap(
458             Map<Serializable, Object> stateMap, Serializable key,
459             Object valueOrKey, boolean delta)
460     {
461         if (valueOrKey == null)
462         {
463             return null;
464         }
465 
466         Object returnValue = null;
467         Map<String, Object> map = (Map<String, Object>) stateMap.get(key);
468         if (map != null)
469         {
470             if (delta)
471             {
472                 // Keep track of the removed values using key/null pair on the delta map
473                 returnValue = map.put((String) valueOrKey, null);
474             }
475             else
476             {
477                 returnValue = map.remove(valueOrKey);
478             }
479 
480             if (map.isEmpty())
481             {
482                 //stateMap.remove(key);
483                 stateMap.put(key, null);
484             }
485         }
486         return returnValue;
487     }
488 
489     public boolean isTransient()
490     {
491         return _transient;
492     }
493 
494     /**
495      * Serializing cod
496      * the serialized data structure consists of key value pairs unless the value itself is an internal array
497      * or a map in case of an internal array or map the value itself is another array with its initial value
498      * myfaces.InternalArray, myfaces.internalMap
499      *
500      * the internal Array is then mapped to another array
501      *
502      * the internal Map again is then mapped to a map with key value pairs
503      *
504      *
505      */
506     public Object saveState(FacesContext context)
507     {
508         Map serializableMap = (isInitialStateMarked()) ? _deltas : _fullState;
509 
510         if (_initialState != null && _deltas != null && !_deltas.isEmpty()
511             && isInitialStateMarked())
512         {
513             // Before save the state, check if the property was changed from the
514             // initial state value. If the property was changed but it has the
515             // same value from the one in the initial state, we can remove it
516             // from delta, because when the view is built again, it will be
517             // restored to the same state. This check suppose some additional
518             // map.get() calls when saving the state, but using it only in properties
519             // that are expected to change over lifecycle (value, localValueSet,
520             // submittedValue, valid), is worth to do it, because those ones
521             // always generated delta changes.
522             for (int i = 0; i < _initialState.length; i+=2)
523             {
524                 Serializable key = (Serializable) _initialState[i];
525                 Object defaultValue = _initialState[i+1];
526                 
527                 // Check only if there is delta state for that property, in other
528                 // case it is not necessary. Remember it is possible to have
529                 // null values inside the Map.
530                 if (_deltas.containsKey(key))
531                 {
532                     Object deltaValue = _deltas.get(key);
533                     if (deltaValue == null && defaultValue == null)
534                     {
535                         _deltas.remove(key);
536                         if (_deltas.isEmpty())
537                         {
538                             break;
539                         }
540                     }
541                     if (deltaValue != null && deltaValue.equals(defaultValue))
542                     {
543                         _deltas.remove(key);
544                         if (_deltas.isEmpty())
545                         {
546                             break;
547                         }
548                     }
549                 }
550             }
551         }
552         if (serializableMap == null || serializableMap.size() == 0)
553         {
554             return null;
555         }
556         
557         /*
558         int stateHolderKeyCount = 0;
559         if (isInitalStateMarked())
560         {
561             for (Iterator<Serializable> it = _stateHolderKeys.iterator(); it.hasNext();)
562             {
563                 Serializable key = it.next();
564                 if (!_deltas.containsKey(key))
565                 {
566                     stateHolderKeyCount++;
567                 }
568             }
569         }*/
570         
571         Map.Entry<Serializable, Object> entry;
572         //entry == key, value, key, value
573         Object[] retArr = new Object[serializableMap.entrySet().size() * 2];
574         //Object[] retArr = new Object[serializableMap.entrySet().size() * 2 + stateHolderKeyCount]; 
575 
576         Iterator<Map.Entry<Serializable, Object>> it = serializableMap
577                 .entrySet().iterator();
578         int cnt = 0;
579         while (it.hasNext())
580         {
581             entry = it.next();
582             retArr[cnt] = entry.getKey();
583 
584             Object value = entry.getValue();
585             
586             // The condition in which the call to saveAttachedState
587             // is to handle List, StateHolder or non Serializable instances.
588             // we check it here, to prevent unnecessary calls.
589             if (value instanceof StateHolder ||
590                 value instanceof List ||
591                 !(value instanceof Serializable))
592             {
593                 Object savedValue = UIComponentBase.saveAttachedState(context,
594                     value);
595                 retArr[cnt + 1] = savedValue;
596             }
597             else
598             {
599                 retArr[cnt + 1] = value;
600             }
601             cnt += 2;
602         }
603         
604         /*
605         if (isInitalStateMarked())
606         {
607             for (Iterator<Serializable> it2 = _stateHolderKeys.iterator(); it.hasNext();)
608             {
609                 Serializable key = it2.next();
610                 if (!_deltas.containsKey(key))
611                 {
612                     retArr[cnt] = key;
613                     Object value = _fullState.get(key);
614                     if (value instanceof PartialStateHolder)
615                     {
616                         //Could contain delta, save it as _AttachedDeltaState
617                         PartialStateHolder holder = (PartialStateHolder) value;
618                         if (holder.isTransient())
619                         {
620                             retArr[cnt + 1] = null;
621                         }
622                         else
623                         {
624                             retArr[cnt + 1] = new _AttachedDeltaWrapper(value.getClass(), holder.saveState(context));
625                         }
626                     }
627                     else
628                     {
629                         //Save everything
630                         retArr[cnt + 1] = UIComponentBase.saveAttachedState(context, _fullState.get(key));
631                     }
632                     cnt += 2;
633                 }
634             }
635         }
636         */       
637         return retArr;
638     }
639 
640     public void restoreState(FacesContext context, Object state)
641     {
642         if (state == null)
643         {
644             return;
645         }
646 
647         Object[] serializedState = (Object[]) state;
648         
649         if (!isInitialStateMarked() && !_fullState.isEmpty())
650         {
651             _fullState.clear();
652             if(_deltas != null)
653             {
654                 _deltas.clear();
655             }
656         }
657 
658         for (int cnt = 0; cnt < serializedState.length; cnt += 2)
659         {
660             Serializable key = (Serializable) serializedState[cnt];
661             Object savedValue = UIComponentBase.restoreAttachedState(context,
662                     serializedState[cnt + 1]);
663 
664             if (isInitialStateMarked())
665             {
666                 if (savedValue instanceof InternalDeltaListMap)
667                 {
668                     for (Map.Entry<Object, Boolean> mapEntry : ((Map<Object, Boolean>) savedValue)
669                             .entrySet())
670                     {
671                         boolean addOrRemove = mapEntry.getValue();
672                         if (addOrRemove)
673                         {
674                             //add
675                             this.add(key, mapEntry.getKey());
676                         }
677                         else
678                         {
679                             //remove
680                             this.remove(key, mapEntry.getKey());
681                         }
682                     }
683                 }
684                 else if (savedValue instanceof InternalMap)
685                 {
686                     for (Map.Entry<String, Object> mapEntry : ((Map<String, Object>) savedValue)
687                             .entrySet())
688                     {
689                         this.put(key, mapEntry.getKey(), mapEntry.getValue());
690                     }
691                 }
692                 /*
693                 else if (savedValue instanceof _AttachedDeltaWrapper)
694                 {
695                     _AttachedStateWrapper wrapper = (_AttachedStateWrapper) savedValue;
696                     //Restore delta state
697                     ((PartialStateHolder)_fullState.get(key)).restoreState(context, wrapper.getWrappedStateObject());
698                     //Add this key as StateHolder key 
699                     _stateHolderKeys.add(key);
700                 }
701                 */
702                 else
703                 {
704                     put(key, savedValue);
705                 }
706             }
707             else
708             {
709                 put(key, savedValue);
710             }
711         }
712     }
713 
714     public void setTransient(boolean transientValue)
715     {
716         _transient = transientValue;
717     }
718 
719     //We use our own data structures just to make sure
720     //nothing gets mixed up internally
721     static class InternalMap<K, V> extends HashMap<K, V> implements StateHolder
722     {
723         public InternalMap()
724         {
725             super();
726         }
727 
728         public InternalMap(int initialCapacity, float loadFactor)
729         {
730             super(initialCapacity, loadFactor);
731         }
732 
733         public InternalMap(Map<? extends K, ? extends V> m)
734         {
735             super(m);
736         }
737 
738         public InternalMap(int initialSize)
739         {
740             super(initialSize);
741         }
742 
743         public boolean isTransient()
744         {
745             return false;
746         }
747 
748         public void setTransient(boolean newTransientValue)
749         {
750             // No op
751         }
752 
753         public void restoreState(FacesContext context, Object state)
754         {
755             Object[] listAsMap = (Object[]) state;
756             for (int cnt = 0; cnt < listAsMap.length; cnt += 2)
757             {
758                 this.put((K) listAsMap[cnt], (V) UIComponentBase
759                         .restoreAttachedState(context, listAsMap[cnt + 1]));
760             }
761         }
762 
763         public Object saveState(FacesContext context)
764         {
765             int cnt = 0;
766             Object[] mapArr = new Object[this.size() * 2];
767             for (Map.Entry<K, V> entry : this.entrySet())
768             {
769                 mapArr[cnt] = entry.getKey();
770                 Object value = entry.getValue();
771                 
772                 if (value instanceof StateHolder ||
773                     value instanceof List ||
774                     !(value instanceof Serializable))
775                 {
776                     mapArr[cnt + 1] = UIComponentBase.saveAttachedState(context, value);
777                 }
778                 else
779                 {
780                     mapArr[cnt + 1] = value;
781                 }
782                 cnt += 2;
783             }
784             return mapArr;
785         }
786     }
787 
788     /**
789      * Map used to keep track of list changes 
790      */
791     static class InternalDeltaListMap<K, V> extends InternalMap<K, V>
792     {
793 
794         public InternalDeltaListMap()
795         {
796             super();
797         }
798 
799         public InternalDeltaListMap(int initialCapacity, float loadFactor)
800         {
801             super(initialCapacity, loadFactor);
802         }
803 
804         public InternalDeltaListMap(int initialSize)
805         {
806             super(initialSize);
807         }
808 
809         public InternalDeltaListMap(Map<? extends K, ? extends V> m)
810         {
811             super(m);
812         }
813     }
814 
815     static class InternalList<T> extends ArrayList<T> implements StateHolder
816     {
817         public InternalList()
818         {
819             super();
820         }
821 
822         public InternalList(Collection<? extends T> c)
823         {
824             super(c);
825         }
826 
827         public InternalList(int initialSize)
828         {
829             super(initialSize);
830         }
831 
832         public boolean isTransient()
833         {
834             return false;
835         }
836 
837         public void setTransient(boolean newTransientValue)
838         {
839         }
840 
841         public void restoreState(FacesContext context, Object state)
842         {
843             Object[] listAsArr = (Object[]) state;
844             //since all other options would mean dual iteration 
845             //we have to do it the hard way
846             for (Object elem : listAsArr)
847             {
848                 add((T) UIComponentBase.restoreAttachedState(context, elem));
849             }
850         }
851 
852         public Object saveState(FacesContext context)
853         {
854             Object[] values = new Object[size()];
855             for (int i = 0; i < size(); i++)
856             {
857                 Object value = get(i);
858                 
859                 if (value instanceof StateHolder ||
860                     value instanceof List ||
861                     !(value instanceof Serializable))
862                 {
863                     values[i] = UIComponentBase.saveAttachedState(context, value);
864                 }
865                 else
866                 {
867                     values[i] = value;
868                 }                
869             }
870             return values;
871         }
872     }
873 
874     public Object getTransient(Object key)
875     {
876         return (_transientState == null) ? null : _transientState.get(key);
877     }
878 
879     public Object getTransient(Object key, Object defaultValue)
880     {
881         Object returnValue = (_transientState == null) ? null : _transientState.get(key);
882         if (returnValue != null)
883         {
884             return returnValue;
885         }
886         return defaultValue;
887     }
888 
889     public Object putTransient(Object key, Object value)
890     {
891         if (_transientState == null)
892         {
893             _transientState = new HashMap<Object, Object>();
894         }
895         return _transientState.put(key, value);
896     }
897 
898     @SuppressWarnings("unchecked")
899     public void restoreTransientState(FacesContext context, Object state)
900     {
901         _transientState = (Map<Object, Object>) state;
902     }
903     
904     public Object saveTransientState(FacesContext context)
905     {
906         return _transientState;
907     }
908 
909     public void markPropertyInInitialState(Object[] defaultInitialState)
910     {
911         // Check if in the fullState, one of the default properties were changed
912         boolean canApplyDefaultInitialState = true;
913         for (int i = 0; i < defaultInitialState.length; i+=2)
914         {
915             Serializable key = (Serializable) defaultInitialState[i];
916             if (_fullState.containsKey(key))
917             {
918                 canApplyDefaultInitialState = false;
919                 break;
920             }
921         }
922         if (canApplyDefaultInitialState)
923         {
924             // Most of the times the defaultInitialState is used.
925             _initialState = defaultInitialState;
926         }
927         else
928         {
929             // recalculate it
930             Object[] initialState = new Object[defaultInitialState.length];
931             for (int i = 0; i < defaultInitialState.length; i+=2)
932             {
933                 Serializable key = (Serializable) defaultInitialState[i];
934                 initialState[i] = key;
935                 if (_fullState.containsKey(key))
936                 {
937                     initialState[i+1] = _fullState.get(key);
938                 }
939                 else
940                 {
941                     initialState[i+1] = defaultInitialState[i+1];
942                 }
943             }
944             _initialState = initialState;
945         }
946     }
947 }