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.behavior;
20  
21  import javax.faces.component.StateHelper;
22  import javax.faces.component.StateHolder;
23  import javax.faces.component.UIComponentBase;
24  import javax.faces.component.PartialStateHolder;
25  import javax.faces.context.FacesContext;
26  import javax.el.ValueExpression;
27  import java.io.Serializable;
28  import java.util.*;
29  
30   /**
31   * @author Werner Punz (latest modification by $Author: bommel $)
32   * @version $Revision: 1187700 $ $Date: 2011-10-22 07:19:37 -0500 (Sat, 22 Oct 2011) $
33   *
34   * Delta state helper to deal with the ajax
35   * behavior delta states, cross ported
36   * from our generic delta state, due to limitations
37   * in the spec (sorry for the somewhat dirty code here maybe
38    * we can unify both implementations by isolating a common protected interface)
39   *
40   * @since 2.0
41   */
42  class _AjaxBehaviorDeltaStateHelper <A extends AjaxBehavior> implements StateHelper {
43        /**
44       * We need to hold a component instance because:
45       * <p/>
46       * - The component is the one who knows if we are on initial or delta mode
47       * - eval assume calls to component.ValueExpression
48       */
49      private A _target;
50  
51      /**
52       * This map holds the full current state
53       */
54      private Map<Serializable, Object> _fullState;
55  
56      /**
57       * This map only keep track of delta changes to be saved
58       */
59      private Map<Serializable, Object> _deltas;
60  
61      /**
62       * This map keep track of StateHolder keys, to be saved when
63       * saveState is called.
64       */
65      //private Set<Serializable> _stateHolderKeys;
66  
67      private boolean _transient = false;
68  
69      public _AjaxBehaviorDeltaStateHelper(A component) {
70          super();
71          this._target = component;
72          _fullState = new HashMap<Serializable, Object>();
73          _deltas = null;
74          //_stateHolderKeys = new HashSet<Serializable>();
75      }
76  
77      /**
78       * Used to create delta map on demand
79       *
80       * @return
81       */
82      private boolean _createDeltas() {
83          if (isInitialStateMarked()) {
84              if (_deltas == null) {
85                  _deltas = new HashMap<Serializable, Object>(2);
86              }
87              return true;
88          }
89  
90          return false;
91      }
92  
93      protected boolean isInitialStateMarked() {
94          return _target.initialStateMarked();
95      }
96  
97      public void add(Serializable key, Object value) {
98          if (_createDeltas()) {
99              //Track delta case
100             Map<Object, Boolean> deltaListMapValues = (Map<Object, Boolean>) _deltas
101                     .get(key);
102             if (deltaListMapValues == null) {
103                 deltaListMapValues = new InternalDeltaListMap<Object, Boolean>(
104                         3);
105                 _deltas.put(key, deltaListMapValues);
106             }
107             deltaListMapValues.put(value, Boolean.TRUE);
108         }
109 
110         //Handle change on full map
111         List<Object> fullListValues = (List<Object>) _fullState.get(key);
112         if (fullListValues == null) {
113             fullListValues = new InternalList<Object>(3);
114             _fullState.put(key, fullListValues);
115         }
116         fullListValues.add(value);
117     }
118 
119     public Object eval(Serializable key) {
120         Object returnValue = _fullState.get(key);
121         if (returnValue != null) {
122             return returnValue;
123         }
124         ValueExpression expression = _target.getValueExpression(key
125                 .toString());
126         if (expression != null) {
127             return expression.getValue(FacesContext.getCurrentInstance()
128                     .getELContext());
129         }
130         return null;
131     }
132 
133     public Object eval(Serializable key, Object defaultValue) {
134         Object returnValue = _fullState.get(key);
135         if (returnValue != null) {
136             return returnValue;
137         }
138         ValueExpression expression = _target.getValueExpression(key
139                 .toString());
140         if (expression != null) {
141             return expression.getValue(FacesContext.getCurrentInstance()
142                     .getELContext());
143         }
144         return defaultValue;
145     }
146 
147     public Object get(Serializable key) {
148         return _fullState.get(key);
149     }
150 
151     public Object put(Serializable key, Object value) {
152         Object returnValue = null;
153         if (_createDeltas()) {
154             if (_deltas.containsKey(key)) {
155                 returnValue = _deltas.put(key, value);
156                 _fullState.put(key, value);
157             } else {
158                 _deltas.put(key, value);
159                 returnValue = _fullState.put(key, value);
160             }
161         } else {
162             /*
163             if (value instanceof StateHolder)
164             {
165                 _stateHolderKeys.add(key);
166             }
167             */
168             returnValue = _fullState.put(key, value);
169         }
170         return returnValue;
171     }
172 
173     public Object put(Serializable key, String mapKey, Object value) {
174         boolean returnSet = false;
175         Object returnValue = null;
176         if (_createDeltas()) {
177             //Track delta case
178             Map<String, Object> mapValues = (Map<String, Object>) _deltas
179                     .get(key);
180             if (mapValues == null) {
181                 mapValues = new InternalMap<String, Object>();
182                 _deltas.put(key, mapValues);
183             }
184             if (mapValues.containsKey(mapKey)) {
185                 returnValue = mapValues.put(mapKey, value);
186                 returnSet = true;
187             } else {
188                 mapValues.put(mapKey, value);
189             }
190         }
191 
192         //Handle change on full map
193         Map<String, Object> mapValues = (Map<String, Object>) _fullState
194                 .get(key);
195         if (mapValues == null) {
196             mapValues = new InternalMap<String, Object>();
197             _fullState.put(key, mapValues);
198         }
199         if (returnSet) {
200             mapValues.put(mapKey, value);
201         } else {
202             returnValue = mapValues.put(mapKey, value);
203         }
204         return returnValue;
205     }
206 
207     public Object remove(Serializable key) {
208         Object returnValue = null;
209         if (_createDeltas()) {
210             if (_deltas.containsKey(key)) {
211                 // Keep track of the removed values using key/null pair on the delta map
212                 returnValue = _deltas.put(key, null);
213                 _fullState.remove(key);
214             } else {
215                 // Keep track of the removed values using key/null pair on the delta map
216                 _deltas.put(key, null);
217                 returnValue = _fullState.remove(key);
218             }
219         } else {
220             returnValue = _fullState.remove(key);
221         }
222         return returnValue;
223     }
224 
225     public Object remove(Serializable key, Object valueOrKey) {
226         // Comment by lu4242 : The spec javadoc says if it is a Collection
227         // or Map deal with it. But the intention of this method is work
228         // with add(?,?) and put(?,?,?), this ones return instances of
229         // InternalMap and InternalList to prevent mixing, so to be
230         // consistent we'll cast to those classes here.
231 
232         Object collectionOrMap = _fullState.get(key);
233         Object returnValue = null;
234         if (collectionOrMap instanceof InternalMap) {
235             if (_createDeltas()) {
236                 returnValue = _removeValueOrKeyFromMap(_deltas, key,
237                                                        valueOrKey, true);
238                 _removeValueOrKeyFromMap(_fullState, key, valueOrKey, false);
239             } else {
240                 returnValue = _removeValueOrKeyFromMap(_fullState, key,
241                                                        valueOrKey, false);
242             }
243         } else if (collectionOrMap instanceof InternalList) {
244             if (_createDeltas()) {
245                 returnValue = _removeValueOrKeyFromCollectionDelta(_deltas,
246                                                                    key, valueOrKey);
247                 _removeValueOrKeyFromCollection(_fullState, key, valueOrKey);
248             } else {
249                 returnValue = _removeValueOrKeyFromCollection(_fullState, key,
250                                                               valueOrKey);
251             }
252         }
253         return returnValue;
254     }
255 
256     private static Object _removeValueOrKeyFromCollectionDelta(
257             Map<Serializable, Object> stateMap, Serializable key,
258             Object valueOrKey) {
259         Object returnValue = null;
260         Map<Object, Boolean> c = (Map<Object, Boolean>) stateMap.get(key);
261         if (c != null) {
262             if (c.containsKey(valueOrKey)) {
263                 returnValue = valueOrKey;
264             }
265             c.put(valueOrKey, Boolean.FALSE);
266         }
267         return returnValue;
268     }
269 
270     private static Object _removeValueOrKeyFromCollection(
271             Map<Serializable, Object> stateMap, Serializable key,
272             Object valueOrKey) {
273         Object returnValue = null;
274         Collection c = (Collection) stateMap.get(key);
275         if (c != null) {
276             if (c.remove(valueOrKey)) {
277                 returnValue = valueOrKey;
278             }
279             if (c.isEmpty()) {
280                 stateMap.remove(key);
281             }
282         }
283         return returnValue;
284     }
285 
286     private static Object _removeValueOrKeyFromMap(
287             Map<Serializable, Object> stateMap, Serializable key,
288             Object valueOrKey, boolean delta) {
289         if (valueOrKey == null) {
290             return null;
291         }
292 
293         Object returnValue = null;
294         Map<String, Object> map = (Map<String, Object>) stateMap.get(key);
295         if (map != null) {
296             if (delta) {
297                 // Keep track of the removed values using key/null pair on the delta map
298                 returnValue = map.put((String) valueOrKey, null);
299             } else {
300                 returnValue = map.remove(valueOrKey);
301             }
302 
303             if (map.isEmpty()) {
304                 //stateMap.remove(key);
305                 stateMap.put(key, null);
306             }
307         }
308         return returnValue;
309     }
310 
311     public boolean isTransient() {
312         return _transient;
313     }
314 
315     /**
316      * Serializing cod
317      * the serialized data structure consists of key value pairs unless the value itself is an internal array
318      * or a map in case of an internal array or map the value itself is another array with its initial value
319      * myfaces.InternalArray, myfaces.internalMap
320      * <p/>
321      * the internal Array is then mapped to another array
322      * <p/>
323      * the internal Map again is then mapped to a map with key value pairs
324      */
325 
326     public Object saveState(FacesContext context) {
327         Map serializableMap = (isInitialStateMarked()) ? _deltas : _fullState;
328 
329         if (serializableMap == null || serializableMap.size() == 0) {
330             return null;
331         }
332 
333         /*
334         int stateHolderKeyCount = 0;
335         if (isInitalStateMarked())
336         {
337             for (Iterator<Serializable> it = _stateHolderKeys.iterator(); it.hasNext();)
338             {
339                 Serializable key = it.next();
340                 if (!_deltas.containsKey(key))
341                 {
342                     stateHolderKeyCount++;
343                 }
344             }
345         }*/
346 
347         Map.Entry<Serializable, Object> entry;
348         //entry == key, value, key, value
349         Object[] retArr = new Object[serializableMap.entrySet().size() * 2];
350         //Object[] retArr = new Object[serializableMap.entrySet().size() * 2 + stateHolderKeyCount];
351 
352         Iterator<Map.Entry<Serializable, Object>> it = serializableMap
353                 .entrySet().iterator();
354         int cnt = 0;
355         while (it.hasNext()) {
356             entry = it.next();
357             retArr[cnt] = entry.getKey();
358 
359             Object value = entry.getValue();
360 
361             // The condition in which the call to saveAttachedState
362             // is to handle List, StateHolder or non Serializable instances.
363             // we check it here, to prevent unnecessary calls.
364             if (value instanceof StateHolder ||
365                 value instanceof List ||
366                 !(value instanceof Serializable)) {
367                 Object savedValue = UIComponentBase.saveAttachedState(context,
368                                                                       value);
369                 retArr[cnt + 1] = savedValue;
370             } else {
371                 retArr[cnt + 1] = value;
372             }
373             cnt += 2;
374         }
375 
376         /*
377         if (isInitalStateMarked())
378         {
379             for (Iterator<Serializable> it2 = _stateHolderKeys.iterator(); it.hasNext();)
380             {
381                 Serializable key = it2.next();
382                 if (!_deltas.containsKey(key))
383                 {
384                     retArr[cnt] = key;
385                     Object value = _fullState.get(key);
386                     if (value instanceof PartialStateHolder)
387                     {
388                         //Could contain delta, save it as _AttachedDeltaState
389                         PartialStateHolder holder = (PartialStateHolder) value;
390                         if (holder.isTransient())
391                         {
392                             retArr[cnt + 1] = null;
393                         }
394                         else
395                         {
396                             retArr[cnt + 1] = new _AttachedDeltaWrapper(value.getClass(), holder.saveState(context));
397                         }
398                     }
399                     else
400                     {
401                         //Save everything
402                         retArr[cnt + 1] = UIComponentBase.saveAttachedState(context, _fullState.get(key));
403                     }
404                     cnt += 2;
405                 }
406             }
407         }
408         */
409         return retArr;
410     }
411 
412 
413     public void restoreState(FacesContext context, Object state) {
414         if (state == null)
415             return;
416 
417         Object[] serializedState = (Object[]) state;
418 
419         for (int cnt = 0; cnt < serializedState.length; cnt += 2) {
420             Serializable key = (Serializable) serializedState[cnt];
421 
422             Object savedValue = UIComponentBase.restoreAttachedState(context,
423                                                                      serializedState[cnt + 1]);
424 
425             if (isInitialStateMarked()) {
426                 if (savedValue instanceof InternalDeltaListMap) {
427                     for (Map.Entry<Object, Boolean> mapEntry : ((Map<Object, Boolean>) savedValue)
428                             .entrySet()) {
429                         boolean addOrRemove = mapEntry.getValue();
430                         if (addOrRemove) {
431                             //add
432                             this.add(key, mapEntry.getKey());
433                         } else {
434                             //remove
435                             this.remove(key, mapEntry.getKey());
436                         }
437                     }
438                 } else if (savedValue instanceof InternalMap) {
439                     for (Map.Entry<String, Object> mapEntry : ((Map<String, Object>) savedValue)
440                             .entrySet()) {
441                         this.put(key, mapEntry.getKey(), mapEntry.getValue());
442                     }
443                 }
444                 /*
445                 else if (savedValue instanceof _AttachedDeltaWrapper)
446                 {
447                     _AttachedStateWrapper wrapper = (_AttachedStateWrapper) savedValue;
448                     //Restore delta state
449                     ((PartialStateHolder)_fullState.get(key)).restoreState(context, wrapper.getWrappedStateObject());
450                     //Add this key as StateHolder key
451                     _stateHolderKeys.add(key);
452                 }
453                 */
454                 else {
455                     put(key, savedValue);
456                 }
457             } else {
458                 put(key, savedValue);
459             }
460         }
461     }
462 
463     public void setTransient(boolean transientValue) {
464         _transient = transientValue;
465     }
466 
467     //We use our own data structures just to make sure
468     //nothing gets mixed up internally
469     static class InternalMap<K, V> extends HashMap<K, V> implements StateHolder {
470         public InternalMap() {
471             super();
472         }
473 
474         public InternalMap(int initialCapacity, float loadFactor) {
475             super(initialCapacity, loadFactor);
476         }
477 
478         public InternalMap(Map<? extends K, ? extends V> m) {
479             super(m);
480         }
481 
482         public InternalMap(int initialSize) {
483             super(initialSize);
484         }
485 
486         public boolean isTransient() {
487             return false;
488         }
489 
490         public void setTransient(boolean newTransientValue) {
491             // No op
492         }
493 
494         public void restoreState(FacesContext context, Object state) {
495             Object[] listAsMap = (Object[]) state;
496             for (int cnt = 0; cnt < listAsMap.length; cnt += 2) {
497                 this.put((K) listAsMap[cnt], (V) UIComponentBase
498                         .restoreAttachedState(context, listAsMap[cnt + 1]));
499             }
500         }
501 
502         public Object saveState(FacesContext context) {
503             int cnt = 0;
504             Object[] mapArr = new Object[this.size() * 2];
505             for (Map.Entry<K, V> entry : this.entrySet()) {
506                 mapArr[cnt] = entry.getKey();
507                 Object value = entry.getValue();
508 
509                 if (value instanceof StateHolder ||
510                     value instanceof List ||
511                     !(value instanceof Serializable)) {
512                     mapArr[cnt + 1] = UIComponentBase.saveAttachedState(context, value);
513                 } else {
514                     mapArr[cnt + 1] = value;
515                 }
516                 cnt += 2;
517             }
518             return mapArr;
519         }
520     }
521 
522     /**
523      * Map used to keep track of list changes
524      */
525     static class InternalDeltaListMap<K, V> extends InternalMap<K, V> {
526 
527         public InternalDeltaListMap() {
528             super();
529         }
530 
531         public InternalDeltaListMap(int initialCapacity, float loadFactor) {
532             super(initialCapacity, loadFactor);
533         }
534 
535         public InternalDeltaListMap(int initialSize) {
536             super(initialSize);
537         }
538 
539         public InternalDeltaListMap(Map<? extends K, ? extends V> m) {
540             super(m);
541         }
542     }
543 
544     static class InternalList<T> extends ArrayList<T> implements StateHolder {
545         public InternalList() {
546             super();
547         }
548 
549         public InternalList(Collection<? extends T> c) {
550             super(c);
551         }
552 
553         public InternalList(int initialSize) {
554             super(initialSize);
555         }
556 
557         public boolean isTransient() {
558             return false;
559         }
560 
561         public void setTransient(boolean newTransientValue) {
562         }
563 
564         public void restoreState(FacesContext context, Object state) {
565             Object[] listAsArr = (Object[]) state;
566             //since all other options would mean dual iteration
567             //we have to do it the hard way
568             for (Object elem : listAsArr) {
569                 add((T) UIComponentBase.restoreAttachedState(context, elem));
570             }
571         }
572 
573         public Object saveState(FacesContext context) {
574             Object[] values = new Object[size()];
575             for (int i = 0; i < size(); i++) {
576                 Object value = get(i);
577 
578                 if (value instanceof StateHolder ||
579                     value instanceof List ||
580                     !(value instanceof Serializable)) {
581                     values[i] = UIComponentBase.saveAttachedState(context, value);
582                 } else {
583                     values[i] = value;
584                 }
585             }
586             return values;
587         }
588     }
589 }