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