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 org.apache.myfaces.commons.validator;
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.component.StateHelper;
31  import javax.faces.component.StateHolder;
32  import javax.faces.context.FacesContext;
33  
34  /**
35   * A delta enabled state holder implementing the StateHolder Interface. 
36   * <p>
37   * Components implementing the PartalStateHolder interface have an initial state
38   * and delta states, the initial state is the one holding all root values
39   * and deltas store differences to the initial states
40   * </p>
41   * <p>
42   * For components not implementing partial state saving only the initial states are
43   * of importance, everything is stored and restored continously there
44   * </p> 
45   * <p>
46   * The state helper seems to have three internal storage mechanisms:
47   * one being a list which stores plain values,
48   * one being a key value pair which stores key values in maps
49   * add serves the plain list type while put serves the 
50   * key value type, 
51   * the third is the value which has to be stored plainly as is!
52   * </p>
53   * In other words, this map can be seen as a composite map. It has two maps: 
54   * initial state map and delta map.
55   * <p> 
56   * If delta map is used (method component.initialStateMarked() ), 
57   * base or initial state map cannot be changed, since all changes 
58   * should be tracked on delta map.
59   * </p>
60   * <p> 
61   * The intention of this class is just hold property values
62   * and do a clean separation between initial state and delta.
63   * </p>
64   * <p>
65   * The code from this class comes from a refactor of 
66   * org.apache.myfaces.trinidad.bean.util.PropertyHashMap
67   * </p>
68   * <p>
69   * The context from this class comes and that should be taken into account
70   * is this:
71   * </p>
72   * <p> 
73   * First request:
74   * </p>
75   * <ul>
76   *   <li> A new template is created (using 
77   *   javax.faces.view.ViewDeclarationLanguage.buildView method)
78   *   and component.markInitialState is called from its related TagHandler classes 
79   *  (see javax.faces.view.facelets.ComponentHandler ).
80   *   When this method is executed, the component tree was populated from the values
81   *   set in the facelet abstract syntax tree (or in other words composition of 
82   *   facelets templates). </li>
83   *   <li> From this point all updates on the variables are considered "delta". </li>
84   *   <li> SaveState, if initialStateMarked is true, only delta is saved. </li>
85   * </ul>
86   * <p>
87   * Second request (and next ones)
88   * </p>
89   * <ul>
90   *   <li> A new template is created and component.markInitialState is called from
91   *   its related TagHandler classes again. In this way, components like c:forEach 
92   *   or c:if, that add or remove components could notify about this and handle 
93   *   them properly (see javax.faces.view.StateManagementStrategy). Note that a 
94   *   component restored using this method is no different as the same component 
95   *   at the first request at the same time. </li>
96   *   <li> A call for restoreState is done, passing the delta as object value. If no 
97   *   delta, the state is complete and no call is triggered. </li>
98   *   <li> Lifecycle occur, changing the necessary stuff. </li>
99   *   <li> SaveState, if initialStateMarked is true, only delta is saved. </li>
100  * </ul>
101  * <p>
102  * From the previous analysis, the following conclusions arise:
103  * <ul>
104  *   <li>This class only needs to keep track of delta changes, so when 
105  *   restoreState/saveState is called, the right objects are passed.</li>
106  *   <li>UIComponent.clearInitialState is used to reset the partial
107  *   state holder to a non delta state, so the state to be saved by
108  *   saveState is no longer a delta instead is a full state. If a call
109  *   to clearInitialState occur it is not expected a call for 
110  *   UIComponent.markInitialState occur on the current request.</li>
111  *   <li>The state is handled in the same way on UIData, so components
112  *   inside UIData share its state on all rows. There is no way to save 
113  *   delta per row.</li>
114  *   <li>The map backed by method put(Serializable,String,Object) is
115  *   a replacement of UIComponentBase.attributesMap and UIComponent.bindings map.
116  *   Note that on jsf 1.2, instances saved on attributesMap should not be
117  *   StateHolder, but on jsf 2.0 it is possible to have it. PartialStateHolder
118  *   instances are not handled in this map, or in other words delta state is not
119  *   handled in this classes (markInitialState and clearInitialState is not propagated).</li>
120  *   <li>The list backed by method add(Serializable,Object) should be (is not) a 
121  *   replacement of UIComponentBase.facesListeners, but note that StateHelper
122  *   does not implement PartialStateHolder, and facesListener could have instances
123  *   of that class that needs to be notified when UIComponent.markInitialState or
124  *   UIComponent.clearInitialState is called, or in other words facesListeners
125  *   should deal with PartialStateHolder instances.</li>
126  *   <li>The list backed by method add(Serializable,Object) is 
127  *   a replacement of UIViewRoot.phaseListeners list. Note that instances of
128  *   PhaseListener are not expected to implement StateHolder or PartialStateHolder.</li>
129  * </ul>
130  * </p>
131  * <p>
132  * NOTE: The current implementation of StateHelper on RI does not handle
133  * stateHolder values internally. To prevent problems when developers create
134  * custom components we should do this too. But anyway, the code that 
135  * handle this case should be let here as comment, if some day this feature
136  * is provided. Note than stateHolder aware properties like converter,
137  * validator or listeners should deal with StateHolder or PartialStateHolder
138  * on component classes. 
139  * 
140  * </p>
141  *
142  * @author Werner Punz
143  * @author Leonardo Uribe (latest modification by $Author: lu4242 $)
144  * @version $Rev: 980927 $ $Date: 2010-07-30 14:05:55 -0500 (Vie, 30 Jul 2010) $
145  */
146 class _DeltaStateHelper implements StateHelper
147 {
148 
149     /**
150      * We need to hold a component instance because:
151      * 
152      * - The component is the one who knows if we are on initial or delta mode
153      * - eval assume calls to component.ValueExpression
154      */
155     private ValidatorBase _component;
156 
157     /**
158      * This map holds the full current state
159      */
160     private Map<Serializable, Object> _fullState;
161 
162     /**
163      * This map only keep track of delta changes to be saved
164      */
165     private Map<Serializable, Object> _deltas;
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     public _DeltaStateHelper(ValidatorBase component)
176     {
177         super();
178         this._component = component;
179         _fullState = new HashMap<Serializable, Object>();
180         _deltas = null;
181         //_stateHolderKeys = new HashSet<Serializable>();
182     }
183 
184     /**
185      * Used to create delta map on demand
186      * 
187      * @return
188      */
189     private boolean _createDeltas()
190     {
191         if (isInitialStateMarked())
192         {
193             if (_deltas == null)
194             {
195                 _deltas = new HashMap<Serializable, Object>(2);
196             }
197             return true;
198         }
199 
200         return false;
201     }
202     
203     protected boolean isInitialStateMarked()
204     {
205         return _component.initialStateMarked();
206     }
207 
208     public void add(Serializable key, Object value)
209     {
210         if (_createDeltas())
211         {
212             //Track delta case
213             Map<Object, Boolean> deltaListMapValues = (Map<Object, Boolean>) _deltas
214                     .get(key);
215             if (deltaListMapValues == null)
216             {
217                 deltaListMapValues = new InternalDeltaListMap<Object, Boolean>(
218                         3);
219                 _deltas.put(key, deltaListMapValues);
220             }
221             deltaListMapValues.put(value, Boolean.TRUE);
222         }
223 
224         //Handle change on full map
225         List<Object> fullListValues = (List<Object>) _fullState.get(key);
226         if (fullListValues == null)
227         {
228             fullListValues = new InternalList<Object>(3);
229             _fullState.put(key, fullListValues);
230         }
231         fullListValues.add(value);
232     }
233 
234     public Object eval(Serializable key)
235     {
236         Object returnValue = _fullState.get(key);
237         if (returnValue != null)
238         {
239             return returnValue;
240         }
241         ValueExpression expression = _component.getValueExpression(key
242                 .toString());
243         if (expression != null)
244         {
245             return expression.getValue(_component.getFacesContext()
246                     .getELContext());
247         }
248         return null;
249     }
250 
251     public Object eval(Serializable key, Object defaultValue)
252     {
253         Object returnValue = _fullState.get(key);
254         if (returnValue != null)
255         {
256             return returnValue;
257         }
258         ValueExpression expression = _component.getValueExpression(key
259                 .toString());
260         if (expression != null)
261         {
262             return expression.getValue(_component.getFacesContext()
263                     .getELContext());
264         }
265         return defaultValue;
266     }
267 
268     public Object get(Serializable key)
269     {
270         return _fullState.get(key);
271     }
272 
273     public Object put(Serializable key, Object value)
274     {
275         Object returnValue = null;
276         if (_createDeltas())
277         {
278             if (_deltas.containsKey(key))
279             {
280                 returnValue = _deltas.put(key, value);
281                 _fullState.put(key, value);
282             }
283             else if (value == null && !_fullState.containsKey(key))
284             {
285                 returnValue = null;
286             }
287             else
288             {
289                 _deltas.put(key, value);
290                 returnValue = _fullState.put(key, value);
291             }
292         }
293         else
294         {
295             /*
296             if (value instanceof StateHolder)
297             {
298                 _stateHolderKeys.add(key);
299             }
300             */
301             returnValue = _fullState.put(key, value);
302         }
303         return returnValue;
304     }
305 
306     public Object put(Serializable key, String mapKey, Object value)
307     {
308         boolean returnSet = false;
309         Object returnValue = null;
310         if (_createDeltas())
311         {
312             //Track delta case
313             Map<String, Object> mapValues = (Map<String, Object>) _deltas
314                     .get(key);
315             if (mapValues == null)
316             {
317                 mapValues = new InternalMap<String, Object>();
318                 _deltas.put(key, mapValues);
319             }
320             if (mapValues.containsKey(mapKey))
321             {
322                 returnValue = mapValues.put(mapKey, value);
323                 returnSet = true;
324             }
325             else
326             {
327                 mapValues.put(mapKey, value);
328             }
329         }
330 
331         //Handle change on full map
332         Map<String, Object> mapValues = (Map<String, Object>) _fullState
333                 .get(key);
334         if (mapValues == null)
335         {
336             mapValues = new InternalMap<String, Object>();
337             _fullState.put(key, mapValues);
338         }
339         if (returnSet)
340         {
341             mapValues.put(mapKey, value);
342         }
343         else
344         {
345             returnValue = mapValues.put(mapKey, value);
346         }
347         return returnValue;
348     }
349 
350     public Object remove(Serializable key)
351     {
352         Object returnValue = null;
353         if (_createDeltas())
354         {
355             if (_deltas.containsKey(key))
356             {
357                 // Keep track of the removed values using key/null pair on the delta map
358                 returnValue = _deltas.put(key, null);
359                 _fullState.remove(key);
360             }
361             else
362             {
363                 // Keep track of the removed values using key/null pair on the delta map
364                 _deltas.put(key, null);
365                 returnValue = _fullState.remove(key);
366             }
367         }
368         else
369         {
370             returnValue = _fullState.remove(key);
371         }
372         return returnValue;
373     }
374 
375     public Object remove(Serializable key, Object valueOrKey)
376     {
377         // Comment by lu4242 : The spec javadoc says if it is a Collection 
378         // or Map deal with it. But the intention of this method is work 
379         // with add(?,?) and put(?,?,?), this ones return instances of 
380         // InternalMap and InternalList to prevent mixing, so to be 
381         // consistent we'll cast to those classes here.
382         
383         Object collectionOrMap = _fullState.get(key);
384         Object returnValue = null;
385         if (collectionOrMap instanceof InternalMap)
386         {
387             if (_createDeltas())
388             {
389                 returnValue = _removeValueOrKeyFromMap(_deltas, key,
390                         valueOrKey, true);
391                 _removeValueOrKeyFromMap(_fullState, key, valueOrKey, false);
392             }
393             else
394             {
395                 returnValue = _removeValueOrKeyFromMap(_fullState, key,
396                         valueOrKey, false);
397             }
398         }
399         else if (collectionOrMap instanceof InternalList)
400         {
401             if (_createDeltas())
402             {
403                 returnValue = _removeValueOrKeyFromCollectionDelta(_deltas,
404                         key, valueOrKey);
405                 _removeValueOrKeyFromCollection(_fullState, key, valueOrKey);
406             }
407             else
408             {
409                 returnValue = _removeValueOrKeyFromCollection(_fullState, key,
410                         valueOrKey);
411             }
412         }
413         return returnValue;
414     }
415 
416     private static Object _removeValueOrKeyFromCollectionDelta(
417             Map<Serializable, Object> stateMap, Serializable key,
418             Object valueOrKey)
419     {
420         Object returnValue = null;
421         Map<Object, Boolean> c = (Map<Object, Boolean>) stateMap.get(key);
422         if (c != null)
423         {
424             if (c.containsKey(valueOrKey))
425             {
426                 returnValue = valueOrKey;
427             }
428             c.put(valueOrKey, Boolean.FALSE);
429         }
430         return returnValue;
431     }
432 
433     private static Object _removeValueOrKeyFromCollection(
434             Map<Serializable, Object> stateMap, Serializable key,
435             Object valueOrKey)
436     {
437         Object returnValue = null;
438         Collection c = (Collection) stateMap.get(key);
439         if (c != null)
440         {
441             if (c.remove(valueOrKey))
442             {
443                 returnValue = valueOrKey;
444             }
445             if (c.isEmpty())
446             {
447                 stateMap.remove(key);
448             }
449         }
450         return returnValue;
451     }
452 
453     private static Object _removeValueOrKeyFromMap(
454             Map<Serializable, Object> stateMap, Serializable key,
455             Object valueOrKey, boolean delta)
456     {
457         if (valueOrKey == null)
458         {
459             return null;
460         }
461 
462         Object returnValue = null;
463         Map<String, Object> map = (Map<String, Object>) stateMap.get(key);
464         if (map != null)
465         {
466             if (delta)
467             {
468                 // Keep track of the removed values using key/null pair on the delta map
469                 returnValue = map.put((String) valueOrKey, null);
470             }
471             else
472             {
473                 returnValue = map.remove(valueOrKey);
474             }
475 
476             if (map.isEmpty())
477             {
478                 //stateMap.remove(key);
479                 stateMap.put(key, null);
480             }
481         }
482         return returnValue;
483     }
484 
485     public boolean isTransient()
486     {
487         return _transient;
488     }
489 
490     /**
491      * Serializing cod
492      * the serialized data structure consists of key value pairs unless the value itself is an internal array
493      * or a map in case of an internal array or map the value itself is another array with its initial value
494      * myfaces.InternalArray, myfaces.internalMap
495      *
496      * the internal Array is then mapped to another array
497      *
498      * the internal Map again is then mapped to a map with key value pairs
499      *
500      *
501      */
502     public Object saveState(FacesContext context)
503     {
504         Map serializableMap = (isInitialStateMarked()) ? _deltas : _fullState;
505 
506         if (serializableMap == null || serializableMap.size() == 0)
507         {
508             return null;
509         }
510         
511         /*
512         int stateHolderKeyCount = 0;
513         if (isInitalStateMarked())
514         {
515             for (Iterator<Serializable> it = _stateHolderKeys.iterator(); it.hasNext();)
516             {
517                 Serializable key = it.next();
518                 if (!_deltas.containsKey(key))
519                 {
520                     stateHolderKeyCount++;
521                 }
522             }
523         }*/
524         
525         Map.Entry<Serializable, Object> entry;
526         //entry == key, value, key, value
527         Object[] retArr = new Object[serializableMap.entrySet().size() * 2];
528         //Object[] retArr = new Object[serializableMap.entrySet().size() * 2 + stateHolderKeyCount]; 
529 
530         Iterator<Map.Entry<Serializable, Object>> it = serializableMap
531                 .entrySet().iterator();
532         int cnt = 0;
533         while (it.hasNext())
534         {
535             entry = it.next();
536             retArr[cnt] = entry.getKey();
537 
538             Object value = entry.getValue();
539             
540             // The condition in which the call to saveAttachedState
541             // is to handle List, StateHolder or non Serializable instances.
542             // we check it here, to prevent unnecessary calls.
543             if (value instanceof StateHolder ||
544                 value instanceof List ||
545                 !(value instanceof Serializable))
546             {
547                 Object savedValue = ValidatorBase.saveAttachedState(context,
548                     value);
549                 retArr[cnt + 1] = savedValue;
550             }
551             else
552             {
553                 retArr[cnt + 1] = value;
554             }
555             cnt += 2;
556         }
557         
558         /*
559         if (isInitalStateMarked())
560         {
561             for (Iterator<Serializable> it2 = _stateHolderKeys.iterator(); it.hasNext();)
562             {
563                 Serializable key = it2.next();
564                 if (!_deltas.containsKey(key))
565                 {
566                     retArr[cnt] = key;
567                     Object value = _fullState.get(key);
568                     if (value instanceof PartialStateHolder)
569                     {
570                         //Could contain delta, save it as _AttachedDeltaState
571                         PartialStateHolder holder = (PartialStateHolder) value;
572                         if (holder.isTransient())
573                         {
574                             retArr[cnt + 1] = null;
575                         }
576                         else
577                         {
578                             retArr[cnt + 1] = new _AttachedDeltaWrapper(value.getClass(), holder.saveState(context));
579                         }
580                     }
581                     else
582                     {
583                         //Save everything
584                         retArr[cnt + 1] = ValidatorBase.saveAttachedState(context, _fullState.get(key));
585                     }
586                     cnt += 2;
587                 }
588             }
589         }
590         */       
591         return retArr;
592     }
593 
594     public void restoreState(FacesContext context, Object state)
595     {
596         if (state == null)
597             return;
598 
599         Object[] serializedState = (Object[]) state;
600         
601         if (!isInitialStateMarked() && !_fullState.isEmpty())
602         {
603             _fullState.clear();
604             if(_deltas != null)
605             {
606                 _deltas.clear();
607             }
608         }
609 
610         for (int cnt = 0; cnt < serializedState.length; cnt += 2)
611         {
612             Serializable key = (Serializable) serializedState[cnt];
613             Object savedValue = ValidatorBase.restoreAttachedState(context,
614                     serializedState[cnt + 1]);
615 
616             if (isInitialStateMarked())
617             {
618                 if (savedValue instanceof InternalDeltaListMap)
619                 {
620                     for (Map.Entry<Object, Boolean> mapEntry : ((Map<Object, Boolean>) savedValue)
621                             .entrySet())
622                     {
623                         boolean addOrRemove = mapEntry.getValue();
624                         if (addOrRemove)
625                         {
626                             //add
627                             this.add(key, mapEntry.getKey());
628                         }
629                         else
630                         {
631                             //remove
632                             this.remove(key, mapEntry.getKey());
633                         }
634                     }
635                 }
636                 else if (savedValue instanceof InternalMap)
637                 {
638                     for (Map.Entry<String, Object> mapEntry : ((Map<String, Object>) savedValue)
639                             .entrySet())
640                     {
641                         this.put(key, mapEntry.getKey(), mapEntry.getValue());
642                     }
643                 }
644                 /*
645                 else if (savedValue instanceof _AttachedDeltaWrapper)
646                 {
647                     _AttachedStateWrapper wrapper = (_AttachedStateWrapper) savedValue;
648                     //Restore delta state
649                     ((PartialStateHolder)_fullState.get(key)).restoreState(context, wrapper.getWrappedStateObject());
650                     //Add this key as StateHolder key 
651                     _stateHolderKeys.add(key);
652                 }
653                 */
654                 else
655                 {
656                     put(key, savedValue);
657                 }
658             }
659             else
660             {
661                 put(key, savedValue);
662             }
663         }
664     }
665 
666     public void setTransient(boolean transientValue)
667     {
668         _transient = transientValue;
669     }
670 
671     //We use our own data structures just to make sure
672     //nothing gets mixed up internally
673     static class InternalMap<K, V> extends HashMap<K, V> implements StateHolder
674     {
675         public InternalMap()
676         {
677             super();
678         }
679 
680         public InternalMap(int initialCapacity, float loadFactor)
681         {
682             super(initialCapacity, loadFactor);
683         }
684 
685         public InternalMap(Map<? extends K, ? extends V> m)
686         {
687             super(m);
688         }
689 
690         public InternalMap(int initialSize)
691         {
692             super(initialSize);
693         }
694 
695         public boolean isTransient()
696         {
697             return false;
698         }
699 
700         public void setTransient(boolean newTransientValue)
701         {
702             // No op
703         }
704 
705         public void restoreState(FacesContext context, Object state)
706         {
707             Object[] listAsMap = (Object[]) state;
708             for (int cnt = 0; cnt < listAsMap.length; cnt += 2)
709             {
710                 this.put((K) listAsMap[cnt], (V) ValidatorBase
711                         .restoreAttachedState(context, listAsMap[cnt + 1]));
712             }
713         }
714 
715         public Object saveState(FacesContext context)
716         {
717             int cnt = 0;
718             Object[] mapArr = new Object[this.size() * 2];
719             for (Map.Entry<K, V> entry : this.entrySet())
720             {
721                 mapArr[cnt] = entry.getKey();
722                 Object value = entry.getValue();
723                 
724                 if (value instanceof StateHolder ||
725                     value instanceof List ||
726                     !(value instanceof Serializable))
727                 {
728                     mapArr[cnt + 1] = ValidatorBase.saveAttachedState(context, value);
729                 }
730                 else
731                 {
732                     mapArr[cnt + 1] = value;
733                 }
734                 cnt += 2;
735             }
736             return mapArr;
737         }
738     }
739 
740     /**
741      * Map used to keep track of list changes 
742      */
743     static class InternalDeltaListMap<K, V> extends InternalMap<K, V>
744     {
745 
746         public InternalDeltaListMap()
747         {
748             super();
749         }
750 
751         public InternalDeltaListMap(int initialCapacity, float loadFactor)
752         {
753             super(initialCapacity, loadFactor);
754         }
755 
756         public InternalDeltaListMap(int initialSize)
757         {
758             super(initialSize);
759         }
760 
761         public InternalDeltaListMap(Map<? extends K, ? extends V> m)
762         {
763             super(m);
764         }
765     }
766 
767     static class InternalList<T> extends ArrayList<T> implements StateHolder
768     {
769         public InternalList()
770         {
771             super();
772         }
773 
774         public InternalList(Collection<? extends T> c)
775         {
776             super(c);
777         }
778 
779         public InternalList(int initialSize)
780         {
781             super(initialSize);
782         }
783 
784         public boolean isTransient()
785         {
786             return false;
787         }
788 
789         public void setTransient(boolean newTransientValue)
790         {
791         }
792 
793         public void restoreState(FacesContext context, Object state)
794         {
795             Object[] listAsArr = (Object[]) state;
796             //since all other options would mean dual iteration 
797             //we have to do it the hard way
798             for (Object elem : listAsArr)
799             {
800                 add((T) ValidatorBase.restoreAttachedState(context, elem));
801             }
802         }
803 
804         public Object saveState(FacesContext context)
805         {
806             Object[] values = new Object[size()];
807             for (int i = 0; i < size(); i++)
808             {
809                 Object value = get(i);
810                 
811                 if (value instanceof StateHolder ||
812                     value instanceof List ||
813                     !(value instanceof Serializable))
814                 {
815                     values[i] = ValidatorBase.saveAttachedState(context, value);
816                 }
817                 else
818                 {
819                     values[i] = value;
820                 }                
821             }
822             return values;
823         }
824     }
825 }