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