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