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: 980927 $ $Date: 2010-07-30 14:05:55 -0500 (Fri, 30 Jul 2010) $
143  */
144 class _DeltaStateHelper implements StateHelper
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     /**
166      * This map keep track of StateHolder keys, to be saved when
167      * saveState is called. 
168      */
169     //private Set<Serializable> _stateHolderKeys;  
170 
171     private boolean _transient = false;
172 
173     public _DeltaStateHelper(UIComponent component)
174     {
175         super();
176         this._component = component;
177         _fullState = new HashMap<Serializable, Object>();
178         _deltas = null;
179         //_stateHolderKeys = new HashSet<Serializable>();
180     }
181 
182     /**
183      * Used to create delta map on demand
184      * 
185      * @return
186      */
187     private boolean _createDeltas()
188     {
189         if (isInitialStateMarked())
190         {
191             if (_deltas == null)
192             {
193                 _deltas = new HashMap<Serializable, Object>(2);
194             }
195             return true;
196         }
197 
198         return false;
199     }
200     
201     protected boolean isInitialStateMarked()
202     {
203         return _component.initialStateMarked();
204     }
205 
206     public void add(Serializable key, Object value)
207     {
208         if (_createDeltas())
209         {
210             //Track delta case
211             Map<Object, Boolean> deltaListMapValues = (Map<Object, Boolean>) _deltas
212                     .get(key);
213             if (deltaListMapValues == null)
214             {
215                 deltaListMapValues = new InternalDeltaListMap<Object, Boolean>(
216                         3);
217                 _deltas.put(key, deltaListMapValues);
218             }
219             deltaListMapValues.put(value, Boolean.TRUE);
220         }
221 
222         //Handle change on full map
223         List<Object> fullListValues = (List<Object>) _fullState.get(key);
224         if (fullListValues == null)
225         {
226             fullListValues = new InternalList<Object>(3);
227             _fullState.put(key, fullListValues);
228         }
229         fullListValues.add(value);
230     }
231 
232     public Object eval(Serializable key)
233     {
234         Object returnValue = _fullState.get(key);
235         if (returnValue != null)
236         {
237             return returnValue;
238         }
239         ValueExpression expression = _component.getValueExpression(key
240                 .toString());
241         if (expression != null)
242         {
243             return expression.getValue(_component.getFacesContext()
244                     .getELContext());
245         }
246         return null;
247     }
248 
249     public Object eval(Serializable key, Object defaultValue)
250     {
251         Object returnValue = _fullState.get(key);
252         if (returnValue != null)
253         {
254             return returnValue;
255         }
256         ValueExpression expression = _component.getValueExpression(key
257                 .toString());
258         if (expression != null)
259         {
260             return expression.getValue(_component.getFacesContext()
261                     .getELContext());
262         }
263         return defaultValue;
264     }
265 
266     public Object get(Serializable key)
267     {
268         return _fullState.get(key);
269     }
270 
271     public Object put(Serializable key, Object value)
272     {
273         Object returnValue = null;
274         if (_createDeltas())
275         {
276             if (_deltas.containsKey(key))
277             {
278                 returnValue = _deltas.put(key, value);
279                 _fullState.put(key, value);
280             }
281             else if (value == null && !_fullState.containsKey(key))
282             {
283                 returnValue = null;
284             }
285             else
286             {
287                 _deltas.put(key, value);
288                 returnValue = _fullState.put(key, value);
289             }
290         }
291         else
292         {
293             /*
294             if (value instanceof StateHolder)
295             {
296                 _stateHolderKeys.add(key);
297             }
298             */
299             returnValue = _fullState.put(key, value);
300         }
301         return returnValue;
302     }
303 
304     public Object put(Serializable key, String mapKey, Object value)
305     {
306         boolean returnSet = false;
307         Object returnValue = null;
308         if (_createDeltas())
309         {
310             //Track delta case
311             Map<String, Object> mapValues = (Map<String, Object>) _deltas
312                     .get(key);
313             if (mapValues == null)
314             {
315                 mapValues = new InternalMap<String, Object>();
316                 _deltas.put(key, mapValues);
317             }
318             if (mapValues.containsKey(mapKey))
319             {
320                 returnValue = mapValues.put(mapKey, value);
321                 returnSet = true;
322             }
323             else
324             {
325                 mapValues.put(mapKey, value);
326             }
327         }
328 
329         //Handle change on full map
330         Map<String, Object> mapValues = (Map<String, Object>) _fullState
331                 .get(key);
332         if (mapValues == null)
333         {
334             mapValues = new InternalMap<String, Object>();
335             _fullState.put(key, mapValues);
336         }
337         if (returnSet)
338         {
339             mapValues.put(mapKey, value);
340         }
341         else
342         {
343             returnValue = mapValues.put(mapKey, value);
344         }
345         return returnValue;
346     }
347 
348     public Object remove(Serializable key)
349     {
350         Object returnValue = null;
351         if (_createDeltas())
352         {
353             if (_deltas.containsKey(key))
354             {
355                 // Keep track of the removed values using key/null pair on the delta map
356                 returnValue = _deltas.put(key, null);
357                 _fullState.remove(key);
358             }
359             else
360             {
361                 // Keep track of the removed values using key/null pair on the delta map
362                 _deltas.put(key, null);
363                 returnValue = _fullState.remove(key);
364             }
365         }
366         else
367         {
368             returnValue = _fullState.remove(key);
369         }
370         return returnValue;
371     }
372 
373     public Object remove(Serializable key, Object valueOrKey)
374     {
375         // Comment by lu4242 : The spec javadoc says if it is a Collection 
376         // or Map deal with it. But the intention of this method is work 
377         // with add(?,?) and put(?,?,?), this ones return instances of 
378         // InternalMap and InternalList to prevent mixing, so to be 
379         // consistent we'll cast to those classes here.
380         
381         Object collectionOrMap = _fullState.get(key);
382         Object returnValue = null;
383         if (collectionOrMap instanceof InternalMap)
384         {
385             if (_createDeltas())
386             {
387                 returnValue = _removeValueOrKeyFromMap(_deltas, key,
388                         valueOrKey, true);
389                 _removeValueOrKeyFromMap(_fullState, key, valueOrKey, false);
390             }
391             else
392             {
393                 returnValue = _removeValueOrKeyFromMap(_fullState, key,
394                         valueOrKey, false);
395             }
396         }
397         else if (collectionOrMap instanceof InternalList)
398         {
399             if (_createDeltas())
400             {
401                 returnValue = _removeValueOrKeyFromCollectionDelta(_deltas,
402                         key, valueOrKey);
403                 _removeValueOrKeyFromCollection(_fullState, key, valueOrKey);
404             }
405             else
406             {
407                 returnValue = _removeValueOrKeyFromCollection(_fullState, key,
408                         valueOrKey);
409             }
410         }
411         return returnValue;
412     }
413 
414     private static Object _removeValueOrKeyFromCollectionDelta(
415             Map<Serializable, Object> stateMap, Serializable key,
416             Object valueOrKey)
417     {
418         Object returnValue = null;
419         Map<Object, Boolean> c = (Map<Object, Boolean>) stateMap.get(key);
420         if (c != null)
421         {
422             if (c.containsKey(valueOrKey))
423             {
424                 returnValue = valueOrKey;
425             }
426             c.put(valueOrKey, Boolean.FALSE);
427         }
428         return returnValue;
429     }
430 
431     private static Object _removeValueOrKeyFromCollection(
432             Map<Serializable, Object> stateMap, Serializable key,
433             Object valueOrKey)
434     {
435         Object returnValue = null;
436         Collection c = (Collection) stateMap.get(key);
437         if (c != null)
438         {
439             if (c.remove(valueOrKey))
440             {
441                 returnValue = valueOrKey;
442             }
443             if (c.isEmpty())
444             {
445                 stateMap.remove(key);
446             }
447         }
448         return returnValue;
449     }
450 
451     private static Object _removeValueOrKeyFromMap(
452             Map<Serializable, Object> stateMap, Serializable key,
453             Object valueOrKey, boolean delta)
454     {
455         if (valueOrKey == null)
456         {
457             return null;
458         }
459 
460         Object returnValue = null;
461         Map<String, Object> map = (Map<String, Object>) stateMap.get(key);
462         if (map != null)
463         {
464             if (delta)
465             {
466                 // Keep track of the removed values using key/null pair on the delta map
467                 returnValue = map.put((String) valueOrKey, null);
468             }
469             else
470             {
471                 returnValue = map.remove(valueOrKey);
472             }
473 
474             if (map.isEmpty())
475             {
476                 //stateMap.remove(key);
477                 stateMap.put(key, null);
478             }
479         }
480         return returnValue;
481     }
482 
483     public boolean isTransient()
484     {
485         return _transient;
486     }
487 
488     /**
489      * Serializing cod
490      * the serialized data structure consists of key value pairs unless the value itself is an internal array
491      * or a map in case of an internal array or map the value itself is another array with its initial value
492      * myfaces.InternalArray, myfaces.internalMap
493      *
494      * the internal Array is then mapped to another array
495      *
496      * the internal Map again is then mapped to a map with key value pairs
497      *
498      *
499      */
500     public Object saveState(FacesContext context)
501     {
502         Map serializableMap = (isInitialStateMarked()) ? _deltas : _fullState;
503 
504         if (serializableMap == null || serializableMap.size() == 0)
505         {
506             return null;
507         }
508         
509         /*
510         int stateHolderKeyCount = 0;
511         if (isInitalStateMarked())
512         {
513             for (Iterator<Serializable> it = _stateHolderKeys.iterator(); it.hasNext();)
514             {
515                 Serializable key = it.next();
516                 if (!_deltas.containsKey(key))
517                 {
518                     stateHolderKeyCount++;
519                 }
520             }
521         }*/
522         
523         Map.Entry<Serializable, Object> entry;
524         //entry == key, value, key, value
525         Object[] retArr = new Object[serializableMap.entrySet().size() * 2];
526         //Object[] retArr = new Object[serializableMap.entrySet().size() * 2 + stateHolderKeyCount]; 
527 
528         Iterator<Map.Entry<Serializable, Object>> it = serializableMap
529                 .entrySet().iterator();
530         int cnt = 0;
531         while (it.hasNext())
532         {
533             entry = it.next();
534             retArr[cnt] = entry.getKey();
535 
536             Object value = entry.getValue();
537             
538             // The condition in which the call to saveAttachedState
539             // is to handle List, StateHolder or non Serializable instances.
540             // we check it here, to prevent unnecessary calls.
541             if (value instanceof StateHolder ||
542                 value instanceof List ||
543                 !(value instanceof Serializable))
544             {
545                 Object savedValue = UIComponentBase.saveAttachedState(context,
546                     value);
547                 retArr[cnt + 1] = savedValue;
548             }
549             else
550             {
551                 retArr[cnt + 1] = value;
552             }
553             cnt += 2;
554         }
555         
556         /*
557         if (isInitalStateMarked())
558         {
559             for (Iterator<Serializable> it2 = _stateHolderKeys.iterator(); it.hasNext();)
560             {
561                 Serializable key = it2.next();
562                 if (!_deltas.containsKey(key))
563                 {
564                     retArr[cnt] = key;
565                     Object value = _fullState.get(key);
566                     if (value instanceof PartialStateHolder)
567                     {
568                         //Could contain delta, save it as _AttachedDeltaState
569                         PartialStateHolder holder = (PartialStateHolder) value;
570                         if (holder.isTransient())
571                         {
572                             retArr[cnt + 1] = null;
573                         }
574                         else
575                         {
576                             retArr[cnt + 1] = new _AttachedDeltaWrapper(value.getClass(), holder.saveState(context));
577                         }
578                     }
579                     else
580                     {
581                         //Save everything
582                         retArr[cnt + 1] = UIComponentBase.saveAttachedState(context, _fullState.get(key));
583                     }
584                     cnt += 2;
585                 }
586             }
587         }
588         */       
589         return retArr;
590     }
591 
592     public void restoreState(FacesContext context, Object state)
593     {
594         if (state == null)
595             return;
596 
597         Object[] serializedState = (Object[]) state;
598         
599         if (!isInitialStateMarked() && !_fullState.isEmpty())
600         {
601             _fullState.clear();
602             if(_deltas != null)
603             {
604                 _deltas.clear();
605             }
606         }
607 
608         for (int cnt = 0; cnt < serializedState.length; cnt += 2)
609         {
610             Serializable key = (Serializable) serializedState[cnt];
611             Object savedValue = UIComponentBase.restoreAttachedState(context,
612                     serializedState[cnt + 1]);
613 
614             if (isInitialStateMarked())
615             {
616                 if (savedValue instanceof InternalDeltaListMap)
617                 {
618                     for (Map.Entry<Object, Boolean> mapEntry : ((Map<Object, Boolean>) savedValue)
619                             .entrySet())
620                     {
621                         boolean addOrRemove = mapEntry.getValue();
622                         if (addOrRemove)
623                         {
624                             //add
625                             this.add(key, mapEntry.getKey());
626                         }
627                         else
628                         {
629                             //remove
630                             this.remove(key, mapEntry.getKey());
631                         }
632                     }
633                 }
634                 else if (savedValue instanceof InternalMap)
635                 {
636                     for (Map.Entry<String, Object> mapEntry : ((Map<String, Object>) savedValue)
637                             .entrySet())
638                     {
639                         this.put(key, mapEntry.getKey(), mapEntry.getValue());
640                     }
641                 }
642                 /*
643                 else if (savedValue instanceof _AttachedDeltaWrapper)
644                 {
645                     _AttachedStateWrapper wrapper = (_AttachedStateWrapper) savedValue;
646                     //Restore delta state
647                     ((PartialStateHolder)_fullState.get(key)).restoreState(context, wrapper.getWrappedStateObject());
648                     //Add this key as StateHolder key 
649                     _stateHolderKeys.add(key);
650                 }
651                 */
652                 else
653                 {
654                     put(key, savedValue);
655                 }
656             }
657             else
658             {
659                 put(key, savedValue);
660             }
661         }
662     }
663 
664     public void setTransient(boolean transientValue)
665     {
666         _transient = transientValue;
667     }
668 
669     //We use our own data structures just to make sure
670     //nothing gets mixed up internally
671     static class InternalMap<K, V> extends HashMap<K, V> implements StateHolder
672     {
673         public InternalMap()
674         {
675             super();
676         }
677 
678         public InternalMap(int initialCapacity, float loadFactor)
679         {
680             super(initialCapacity, loadFactor);
681         }
682 
683         public InternalMap(Map<? extends K, ? extends V> m)
684         {
685             super(m);
686         }
687 
688         public InternalMap(int initialSize)
689         {
690             super(initialSize);
691         }
692 
693         public boolean isTransient()
694         {
695             return false;
696         }
697 
698         public void setTransient(boolean newTransientValue)
699         {
700             // No op
701         }
702 
703         public void restoreState(FacesContext context, Object state)
704         {
705             Object[] listAsMap = (Object[]) state;
706             for (int cnt = 0; cnt < listAsMap.length; cnt += 2)
707             {
708                 this.put((K) listAsMap[cnt], (V) UIComponentBase
709                         .restoreAttachedState(context, listAsMap[cnt + 1]));
710             }
711         }
712 
713         public Object saveState(FacesContext context)
714         {
715             int cnt = 0;
716             Object[] mapArr = new Object[this.size() * 2];
717             for (Map.Entry<K, V> entry : this.entrySet())
718             {
719                 mapArr[cnt] = entry.getKey();
720                 Object value = entry.getValue();
721                 
722                 if (value instanceof StateHolder ||
723                     value instanceof List ||
724                     !(value instanceof Serializable))
725                 {
726                     mapArr[cnt + 1] = UIComponentBase.saveAttachedState(context, value);
727                 }
728                 else
729                 {
730                     mapArr[cnt + 1] = value;
731                 }
732                 cnt += 2;
733             }
734             return mapArr;
735         }
736     }
737 
738     /**
739      * Map used to keep track of list changes 
740      */
741     static class InternalDeltaListMap<K, V> extends InternalMap<K, V>
742     {
743 
744         public InternalDeltaListMap()
745         {
746             super();
747         }
748 
749         public InternalDeltaListMap(int initialCapacity, float loadFactor)
750         {
751             super(initialCapacity, loadFactor);
752         }
753 
754         public InternalDeltaListMap(int initialSize)
755         {
756             super(initialSize);
757         }
758 
759         public InternalDeltaListMap(Map<? extends K, ? extends V> m)
760         {
761             super(m);
762         }
763     }
764 
765     static class InternalList<T> extends ArrayList<T> implements StateHolder
766     {
767         public InternalList()
768         {
769             super();
770         }
771 
772         public InternalList(Collection<? extends T> c)
773         {
774             super(c);
775         }
776 
777         public InternalList(int initialSize)
778         {
779             super(initialSize);
780         }
781 
782         public boolean isTransient()
783         {
784             return false;
785         }
786 
787         public void setTransient(boolean newTransientValue)
788         {
789         }
790 
791         public void restoreState(FacesContext context, Object state)
792         {
793             Object[] listAsArr = (Object[]) state;
794             //since all other options would mean dual iteration 
795             //we have to do it the hard way
796             for (Object elem : listAsArr)
797             {
798                 add((T) UIComponentBase.restoreAttachedState(context, elem));
799             }
800         }
801 
802         public Object saveState(FacesContext context)
803         {
804             Object[] values = new Object[size()];
805             for (int i = 0; i < size(); i++)
806             {
807                 Object value = get(i);
808                 
809                 if (value instanceof StateHolder ||
810                     value instanceof List ||
811                     !(value instanceof Serializable))
812                 {
813                     values[i] = UIComponentBase.saveAttachedState(context, value);
814                 }
815                 else
816                 {
817                     values[i] = value;
818                 }                
819             }
820             return values;
821         }
822     }
823 }