1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.myfaces.view.facelets;
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.HashSet;
26 import java.util.Iterator;
27 import java.util.List;
28 import java.util.Map;
29 import java.util.Set;
30
31 import javax.faces.FacesException;
32 import javax.faces.FactoryFinder;
33 import javax.faces.application.ProjectStage;
34 import javax.faces.application.StateManager;
35 import javax.faces.component.ContextCallback;
36 import javax.faces.component.UIComponent;
37 import javax.faces.component.UIComponentBase;
38 import javax.faces.component.UIViewParameter;
39 import javax.faces.component.UIViewRoot;
40 import javax.faces.component.visit.VisitCallback;
41 import javax.faces.component.visit.VisitContext;
42 import javax.faces.component.visit.VisitContextFactory;
43 import javax.faces.component.visit.VisitHint;
44 import javax.faces.component.visit.VisitResult;
45 import javax.faces.context.ExternalContext;
46 import javax.faces.context.FacesContext;
47 import javax.faces.event.PostAddToViewEvent;
48 import javax.faces.event.PreRemoveFromViewEvent;
49 import javax.faces.event.SystemEvent;
50 import javax.faces.event.SystemEventListener;
51 import javax.faces.render.RenderKitFactory;
52 import javax.faces.render.ResponseStateManager;
53 import javax.faces.view.StateManagementStrategy;
54 import javax.faces.view.ViewDeclarationLanguage;
55 import javax.faces.view.ViewDeclarationLanguageFactory;
56 import javax.faces.view.ViewMetadata;
57
58 import org.apache.myfaces.application.StateManagerImpl;
59 import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFWebConfigParam;
60 import org.apache.myfaces.context.RequestViewContext;
61 import org.apache.myfaces.shared.config.MyfacesConfig;
62 import org.apache.myfaces.shared.util.ClassUtils;
63 import org.apache.myfaces.shared.util.HashMapUtils;
64 import org.apache.myfaces.shared.util.WebConfigParamUtils;
65 import org.apache.myfaces.view.facelets.compiler.CheckDuplicateIdFaceletUtils;
66 import org.apache.myfaces.view.facelets.tag.jsf.ComponentSupport;
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105 public class DefaultFaceletsStateManagementStrategy extends StateManagementStrategy
106 {
107 public static final String CLIENTIDS_ADDED = "oam.CLIENTIDS_ADDED";
108
109 public static final String CLIENTIDS_REMOVED = "oam.CLIENTIDS_REMOVED";
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125 public static final String COMPONENT_ADDED_AFTER_BUILD_VIEW = "oam.COMPONENT_ADDED_AFTER_BUILD_VIEW";
126
127
128
129
130
131
132
133 @JSFWebConfigParam(since="2.0.8, 2.1.2", defaultValue="true", expectedValues="true, false",
134 group="state", tags="performance")
135 public static final String SAVE_STATE_WITH_VISIT_TREE_ON_PSS
136 = "org.apache.myfaces.SAVE_STATE_WITH_VISIT_TREE_ON_PSS";
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153 @JSFWebConfigParam(since="2.0.12, 2.1.6", defaultValue="auto", expectedValues="true, auto, false",
154 group="state", tags="performance")
155 public static final String CHECK_ID_PRODUCTION_MODE
156 = "org.apache.myfaces.CHECK_ID_PRODUCTION_MODE";
157
158 private static final String CHECK_ID_PRODUCTION_MODE_DEFAULT = "auto";
159 private static final String CHECK_ID_PRODUCTION_MODE_TRUE = "true";
160 private static final String CHECK_ID_PRODUCTION_MODE_FALSE = "false";
161 private static final String CHECK_ID_PRODUCTION_MODE_AUTO = "auto";
162
163 private static final String SKIP_ITERATION_HINT = "javax.faces.visit.SKIP_ITERATION";
164
165 private static final String SERIALIZED_VIEW_REQUEST_ATTR =
166 StateManagerImpl.class.getName() + ".SERIALIZED_VIEW";
167
168 private static final Object[] EMPTY_STATES = new Object[]{null, null};
169
170 private static final String UNIQUE_ID_COUNTER_KEY =
171 "oam.view.uniqueIdCounter";
172
173 private ViewDeclarationLanguageFactory _vdlFactory;
174
175 private RenderKitFactory _renderKitFactory = null;
176
177 private VisitContextFactory _visitContextFactory = null;
178
179 private Boolean _saveStateWithVisitTreeOnPSS;
180
181 private String _checkIdsProductionMode;
182
183 public DefaultFaceletsStateManagementStrategy ()
184 {
185 _vdlFactory = (ViewDeclarationLanguageFactory)
186 FactoryFinder.getFactory(FactoryFinder.VIEW_DECLARATION_LANGUAGE_FACTORY);
187
188
189 }
190
191 @SuppressWarnings("unchecked")
192 @Override
193 public UIViewRoot restoreView (FacesContext context, String viewId, String renderKitId)
194 {
195 ResponseStateManager manager;
196 Object state[];
197 Map<String, Object> states;
198 UIViewRoot view = null;
199
200
201
202 final boolean oldContextEventState = context.isProcessingEvents();
203
204 manager = getRenderKitFactory().getRenderKit(context, renderKitId).getResponseStateManager();
205
206 state = (Object[]) manager.getState(context, viewId);
207
208 if (state == null)
209 {
210
211 return null;
212 }
213
214 if (state[1] instanceof Object[])
215 {
216 Object[] fullState = (Object[]) state[1];
217 view = (UIViewRoot) internalRestoreTreeStructure((TreeStructComponent)fullState[0]);
218
219 if (view != null)
220 {
221 context.setViewRoot (view);
222 view.processRestoreState(context, fullState[1]);
223
224
225
226
227 RequestViewContext.getCurrentInstance(context).
228 refreshRequestViewContext(context, view);
229 }
230 }
231 else
232 {
233
234 ViewDeclarationLanguage vdl = _vdlFactory.getViewDeclarationLanguage(viewId);
235 Object faceletViewState = null;
236 try
237 {
238 ViewMetadata metadata = vdl.getViewMetadata (context, viewId);
239
240 Collection<UIViewParameter> viewParameters = null;
241
242 if (metadata != null)
243 {
244 view = metadata.createMetadataView(context);
245
246 if (view != null)
247 {
248 viewParameters = metadata.getViewParameters(view);
249 }
250 }
251 if (view == null)
252 {
253 view = context.getApplication().getViewHandler().createView(context, viewId);
254 }
255
256 context.setViewRoot (view);
257
258 if (state != null && state[1] != null)
259 {
260 states = (Map<String, Object>) state[1];
261 faceletViewState = UIComponentBase.restoreAttachedState(
262 context,states.get(ComponentSupport.FACELET_STATE_INSTANCE));
263 if (faceletViewState != null)
264 {
265 view.getAttributes().put(ComponentSupport.FACELET_STATE_INSTANCE, faceletViewState);
266 }
267 if (state.length == 3)
268 {
269 if (view.getId() == null)
270 {
271 view.setId(view.createUniqueId(context, null));
272 }
273
274 view.getAttributes().put(UNIQUE_ID_COUNTER_KEY, state[2]);
275 }
276 }
277
278
279
280
281
282
283 try
284 {
285 context.setProcessingEvents (true);
286 vdl.buildView (context, view);
287
288
289
290
291
292 suscribeListeners(view);
293 }
294 finally
295 {
296 context.setProcessingEvents (oldContextEventState);
297 }
298 }
299 catch (Throwable e)
300 {
301 throw new FacesException ("unable to create view \"" + viewId + "\"", e);
302 }
303
304 if (state != null && state[1] != null)
305 {
306 states = (Map<String, Object>) state[1];
307
308 Long lastUniqueIdCounter = (Long) view.getAttributes().get(UNIQUE_ID_COUNTER_KEY);
309
310
311 boolean emptyState = false;
312 boolean containsFaceletState = states.containsKey(
313 ComponentSupport.FACELET_STATE_INSTANCE);
314 if (states.isEmpty())
315 {
316 emptyState = true;
317 }
318 else if (states.size() == 1 &&
319 containsFaceletState)
320 {
321 emptyState = true;
322 }
323
324 if (!emptyState)
325 {
326
327
328
329 if ((states.size() == 1 && !containsFaceletState) ||
330 (states.size() == 2 && containsFaceletState))
331 {
332 Object viewState = states.get(view.getClientId(context));
333 if (viewState != null)
334 {
335 restoreViewRootOnlyFromMap(context,viewState, view);
336 }
337 else
338 {
339
340 restoreStateFromMap(context, states, view);
341 }
342 }
343 else
344 {
345 restoreStateFromMap(context, states, view);
346 }
347 }
348 if (faceletViewState != null)
349 {
350 view.getAttributes().put(ComponentSupport.FACELET_STATE_INSTANCE, faceletViewState);
351 }
352 if (lastUniqueIdCounter != null)
353 {
354 Long newUniqueIdCounter = (Long) view.getAttributes().get(UNIQUE_ID_COUNTER_KEY);
355 if (newUniqueIdCounter != null &&
356 lastUniqueIdCounter.longValue() > newUniqueIdCounter.longValue())
357 {
358
359
360
361 view.getAttributes().put(UNIQUE_ID_COUNTER_KEY, lastUniqueIdCounter);
362 }
363 }
364 handleDynamicAddedRemovedComponents(context, view, states);
365 }
366 }
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386 return view;
387 }
388
389 public void handleDynamicAddedRemovedComponents(FacesContext context, UIViewRoot view, Map<String, Object> states)
390 {
391 List<String> clientIdsRemoved = getClientIdsRemoved(view);
392
393 if (clientIdsRemoved != null)
394 {
395 Set<String> idsRemovedSet = new HashSet<String>(HashMapUtils.calcCapacity(clientIdsRemoved.size()));
396 context.getAttributes().put(FaceletViewDeclarationLanguage.REMOVING_COMPONENTS_BUILD, Boolean.TRUE);
397 try
398 {
399
400 for (int i = 0, size = clientIdsRemoved.size(); i < size; i++)
401 {
402 String clientId = clientIdsRemoved.get(i);
403 if (!idsRemovedSet.contains(clientId))
404 {
405 RemoveComponentCallback callback = new RemoveComponentCallback();
406 view.invokeOnComponent(context, clientId, callback);
407 if (callback.isComponentFound())
408 {
409
410 idsRemovedSet.add(clientId);
411 }
412 }
413 }
414 clientIdsRemoved.clear();
415 clientIdsRemoved.addAll(idsRemovedSet);
416 }
417 finally
418 {
419 context.getAttributes().remove(FaceletViewDeclarationLanguage.REMOVING_COMPONENTS_BUILD);
420 }
421 }
422 List<String> clientIdsAdded = getClientIdsAdded(view);
423 if (clientIdsAdded != null)
424 {
425 Set<String> idsAddedSet = new HashSet<String>(HashMapUtils.calcCapacity(clientIdsAdded.size()));
426
427 for (int i = 0, size = clientIdsAdded.size(); i < size; i++)
428 {
429 String clientId = clientIdsAdded.get(i);
430 if (!idsAddedSet.contains(clientId))
431 {
432 final AttachedFullStateWrapper wrapper = (AttachedFullStateWrapper) states.get(clientId);
433 if (wrapper != null)
434 {
435 final Object[] addedState = (Object[]) wrapper.getWrappedStateObject();
436 if (addedState != null)
437 {
438 if (addedState.length == 2)
439 {
440 view = (UIViewRoot)
441 internalRestoreTreeStructure((TreeStructComponent) addedState[0]);
442 view.processRestoreState(context, addedState[1]);
443 break;
444 }
445 else
446 {
447 final String parentClientId = (String) addedState[0];
448 view.invokeOnComponent(context, parentClientId,
449 new AddComponentCallback(addedState));
450 }
451 }
452 }
453 idsAddedSet.add(clientId);
454 }
455 }
456
457
458 clientIdsAdded.clear();
459
460
461
462
463 RequestViewContext.getCurrentInstance(context).
464 refreshRequestViewContext(context, view);
465 }
466 }
467
468 public static class RemoveComponentCallback implements ContextCallback
469 {
470 private boolean componentFound;
471
472 public RemoveComponentCallback()
473 {
474 this.componentFound = false;
475 }
476
477 public void invokeContextCallback(FacesContext context,
478 UIComponent target)
479 {
480 if (target.getParent() != null &&
481 !target.getParent().getChildren().remove(target))
482 {
483 String key = null;
484 if (target.getParent().getFacetCount() > 0)
485 {
486 for (Map.Entry<String, UIComponent> entry :
487 target.getParent().getFacets().entrySet())
488 {
489 if (entry.getValue()==target)
490 {
491 key = entry.getKey();
492 break;
493 }
494 }
495 }
496 if (key != null)
497 {
498 UIComponent removedTarget = target.getParent().getFacets().remove(key);
499 if (removedTarget != null)
500 {
501 this.componentFound = true;
502 }
503 }
504 }
505 else
506 {
507 this.componentFound = true;
508 }
509 }
510
511 public boolean isComponentFound()
512 {
513 return this.componentFound;
514 }
515 }
516
517 public static class AddComponentCallback implements ContextCallback
518 {
519 private final Object[] addedState;
520
521 public AddComponentCallback(Object[] addedState)
522 {
523 this.addedState = addedState;
524 }
525
526 public void invokeContextCallback(FacesContext context,
527 UIComponent target)
528 {
529 if (addedState[1] != null)
530 {
531 String facetName = (String) addedState[1];
532 UIComponent child
533 = internalRestoreTreeStructure((TreeStructComponent)
534 addedState[3]);
535 child.processRestoreState(context, addedState[4]);
536 target.getFacets().put(facetName,child);
537 }
538 else
539 {
540 Integer childIndex = (Integer) addedState[2];
541 UIComponent child
542 = internalRestoreTreeStructure((TreeStructComponent)
543 addedState[3]);
544 child.processRestoreState(context, addedState[4]);
545
546 boolean done = false;
547
548 if (child.getAttributes().containsKey(ComponentSupport.MARK_CREATED))
549 {
550
551
552
553 UIComponent parent = target;
554 if (parent.getChildCount() > 0)
555 {
556 String tagId = (String) child.getAttributes().get(ComponentSupport.MARK_CREATED);
557 if (childIndex < parent.getChildCount())
558 {
559
560 UIComponent dup = parent.getChildren().get(childIndex);
561 if (tagId.equals(dup.getAttributes().get(ComponentSupport.MARK_CREATED)))
562 {
563
564 parent.getChildren().remove(childIndex.intValue());
565 parent.getChildren().add(childIndex, child);
566 done = true;
567 }
568 }
569 if (!done)
570 {
571
572 for (int i = 0, childCount = parent.getChildCount(); i < childCount; i ++)
573 {
574 UIComponent dup = parent.getChildren().get(i);
575 if (tagId.equals(dup.getAttributes().get(ComponentSupport.MARK_CREATED)))
576 {
577
578 parent.getChildren().remove(i);
579 parent.getChildren().add(i, child);
580 done = true;
581 break;
582 }
583 }
584 }
585 }
586 }
587 if (!done)
588 {
589 try
590 {
591 target.getChildren().add(childIndex, child);
592 }
593 catch (IndexOutOfBoundsException e)
594 {
595
596
597 target.getChildren().add(child);
598 }
599 }
600 }
601 }
602 }
603
604 @Override
605 public Object saveView (FacesContext context)
606 {
607 UIViewRoot view = context.getViewRoot();
608 Object states;
609
610 if (view == null)
611 {
612
613
614 return null;
615 }
616
617 if (view.isTransient())
618 {
619
620
621 return null;
622 }
623
624 ExternalContext externalContext = context.getExternalContext();
625
626 Object serializedView = context.getAttributes()
627 .get(SERIALIZED_VIEW_REQUEST_ATTR);
628
629
630
631 if (serializedView == null)
632 {
633
634
635
636 if (context.isProjectStage(ProjectStage.Production))
637 {
638 if (CHECK_ID_PRODUCTION_MODE_AUTO.equals(getCheckIdProductionMode(context)))
639 {
640 CheckDuplicateIdFaceletUtils.checkIdsStatefulComponents(context, view);
641 }
642 else if (CHECK_ID_PRODUCTION_MODE_TRUE.equals(getCheckIdProductionMode(context)))
643 {
644 CheckDuplicateIdFaceletUtils.checkIds(context, view);
645 }
646 }
647 else
648 {
649 CheckDuplicateIdFaceletUtils.checkIds(context, view);
650 }
651
652
653
654
655
656 if (view.getAttributes().containsKey(COMPONENT_ADDED_AFTER_BUILD_VIEW))
657 {
658 ensureClearInitialState(view);
659 states = new Object[]{
660 internalBuildTreeStructureToSave(view),
661 view.processSaveState(context)};
662 }
663 else
664 {
665 states = new HashMap<String, Object>();
666
667 Object faceletViewState = view.getAttributes().get(ComponentSupport.FACELET_STATE_INSTANCE);
668 if (faceletViewState != null)
669 {
670 ((Map<String, Object>)states).put(ComponentSupport.FACELET_STATE_INSTANCE,
671 UIComponentBase.saveAttachedState(context, faceletViewState));
672
673 view.getAttributes().remove(ComponentSupport.FACELET_STATE_INSTANCE);
674 }
675 if (isSaveStateWithVisitTreeOnPSS(context))
676 {
677 saveStateOnMapVisitTree(context,(Map<String,Object>) states, view);
678 }
679 else
680 {
681 saveStateOnMap(context,(Map<String,Object>) states, view);
682 }
683
684 if ( ((Map<String,Object>)states).isEmpty())
685 {
686 states = null;
687 }
688 }
689
690
691
692
693
694 Long uniqueIdCount = (Long) view.getAttributes().get(UNIQUE_ID_COUNTER_KEY);
695 if (uniqueIdCount != null && !uniqueIdCount.equals(1L))
696 {
697 serializedView = new Object[] { null, states, uniqueIdCount };
698 }
699 else if (states == null)
700 {
701 serializedView = EMPTY_STATES;
702 }
703 else
704 {
705 serializedView = new Object[] { null, states };
706 }
707
708
709
710
711 context.getAttributes().put(SERIALIZED_VIEW_REQUEST_ATTR, serializedView);
712
713 }
714
715
716
717
718
719
720 return serializedView;
721 }
722
723 private void restoreViewRootOnlyFromMap(
724 final FacesContext context, final Object viewState,
725 final UIComponent view)
726 {
727
728
729 try
730 {
731
732 view.pushComponentToEL(context, view);
733 if (viewState != null)
734 {
735 if (!(viewState instanceof AttachedFullStateWrapper))
736 {
737 try
738 {
739 view.restoreState(context, viewState);
740 }
741 catch(Exception e)
742 {
743 throw new IllegalStateException(
744 "Error restoring component: "+
745 view.getClientId(context), e);
746 }
747 }
748 }
749 }
750 finally
751 {
752 view.popComponentFromEL(context);
753 }
754 }
755
756 private void restoreStateFromMap(final FacesContext context, final Map<String,Object> states,
757 final UIComponent component)
758 {
759 if (states == null)
760 {
761 return;
762 }
763
764 try
765 {
766
767 component.pushComponentToEL(context, component);
768 Object state = states.get(component.getClientId(context));
769 if (state != null)
770 {
771 if (state instanceof AttachedFullStateWrapper)
772 {
773
774 return;
775 }
776 try
777 {
778 component.restoreState(context, state);
779 }
780 catch(Exception e)
781 {
782 throw new IllegalStateException("Error restoring component: "+component.getClientId(context), e);
783 }
784 }
785
786
787 if (component.getChildCount() > 0)
788 {
789
790
791 List<UIComponent> children = component.getChildren();
792 for (int i = 0; i < children.size(); i++)
793 {
794 UIComponent child = children.get(i);
795 if (child != null && !child.isTransient())
796 {
797 restoreStateFromMap( context, states, child);
798 }
799 }
800 }
801
802
803 if (component.getFacetCount() > 0)
804 {
805 Map<String, UIComponent> facetMap = component.getFacets();
806
807 for (Map.Entry<String, UIComponent> entry : facetMap.entrySet())
808 {
809 UIComponent child = entry.getValue();
810 if (child != null && !child.isTransient())
811 {
812
813 restoreStateFromMap( context, states, child);
814 }
815 }
816 }
817 }
818 finally
819 {
820 component.popComponentFromEL(context);
821 }
822 }
823
824 static List<String> getClientIdsAdded(UIViewRoot root)
825 {
826 return (List<String>) root.getAttributes().get(CLIENTIDS_ADDED);
827 }
828
829 static void setClientsIdsAdded(UIViewRoot root, List<String> clientIdsList)
830 {
831 root.getAttributes().put(CLIENTIDS_ADDED, clientIdsList);
832 }
833
834 static List<String> getClientIdsRemoved(UIViewRoot root)
835 {
836 return (List<String>) root.getAttributes().get(CLIENTIDS_REMOVED);
837 }
838
839 static void setClientsIdsRemoved(UIViewRoot root, List<String> clientIdsList)
840 {
841 root.getAttributes().put(CLIENTIDS_REMOVED, clientIdsList);
842 }
843
844 @SuppressWarnings("unchecked")
845 private void registerOnAddRemoveList(FacesContext facesContext, String clientId)
846 {
847 UIViewRoot uiViewRoot = facesContext.getViewRoot();
848
849 List<String> clientIdsAdded = (List<String>) getClientIdsAdded(uiViewRoot);
850 if (clientIdsAdded == null)
851 {
852
853 clientIdsAdded = new ArrayList<String>();
854 }
855 clientIdsAdded.add(clientId);
856
857 setClientsIdsAdded(uiViewRoot, clientIdsAdded);
858
859 List<String> clientIdsRemoved = (List<String>) getClientIdsRemoved(uiViewRoot);
860 if (clientIdsRemoved == null)
861 {
862
863 clientIdsRemoved = new ArrayList<String>();
864 }
865
866 clientIdsRemoved.add(clientId);
867
868 setClientsIdsRemoved(uiViewRoot, clientIdsRemoved);
869 }
870
871 @SuppressWarnings("unchecked")
872 private void registerOnAddList(FacesContext facesContext, String clientId)
873 {
874 UIViewRoot uiViewRoot = facesContext.getViewRoot();
875
876 List<String> clientIdsAdded = (List<String>) getClientIdsAdded(uiViewRoot);
877 if (clientIdsAdded == null)
878 {
879
880 clientIdsAdded = new ArrayList<String>();
881 }
882 clientIdsAdded.add(clientId);
883
884 setClientsIdsAdded(uiViewRoot, clientIdsAdded);
885 }
886
887 public boolean isSaveStateWithVisitTreeOnPSS(FacesContext facesContext)
888 {
889 if (_saveStateWithVisitTreeOnPSS == null)
890 {
891 _saveStateWithVisitTreeOnPSS
892 = WebConfigParamUtils.getBooleanInitParameter(facesContext.getExternalContext(),
893 SAVE_STATE_WITH_VISIT_TREE_ON_PSS, Boolean.TRUE);
894 }
895 return Boolean.TRUE.equals(_saveStateWithVisitTreeOnPSS);
896 }
897
898 private void saveStateOnMapVisitTree(final FacesContext facesContext, final Map<String,Object> states,
899 final UIViewRoot uiViewRoot)
900 {
901 facesContext.getAttributes().put(SKIP_ITERATION_HINT, Boolean.TRUE);
902 try
903 {
904 uiViewRoot.visitTree( getVisitContextFactory().getVisitContext(
905 facesContext, null, null), new VisitCallback()
906 {
907 public VisitResult visit(VisitContext context, UIComponent target)
908 {
909 FacesContext facesContext = context.getFacesContext();
910 Object state;
911
912 if ((target == null) || target.isTransient())
913 {
914
915
916 return VisitResult.REJECT;
917 }
918
919 ComponentState componentAddedAfterBuildView
920 = (ComponentState) target.getAttributes().get(COMPONENT_ADDED_AFTER_BUILD_VIEW);
921
922
923 if (componentAddedAfterBuildView != null && (target.getParent() != null))
924 {
925 if (ComponentState.REMOVE_ADD.equals(componentAddedAfterBuildView))
926 {
927 registerOnAddRemoveList(facesContext, target.getClientId(facesContext));
928 target.getAttributes().put(COMPONENT_ADDED_AFTER_BUILD_VIEW, ComponentState.ADDED);
929 }
930 else if (ComponentState.ADD.equals(componentAddedAfterBuildView))
931 {
932 registerOnAddList(facesContext, target.getClientId(facesContext));
933 target.getAttributes().put(COMPONENT_ADDED_AFTER_BUILD_VIEW, ComponentState.ADDED);
934 }
935 else if (ComponentState.ADDED.equals(componentAddedAfterBuildView))
936 {
937 registerOnAddList(facesContext, target.getClientId(facesContext));
938 }
939 ensureClearInitialState(target);
940
941
942
943 int childIndex = target.getParent().getChildren().indexOf(target);
944 if (childIndex >= 0)
945 {
946 states.put(target.getClientId(facesContext), new AttachedFullStateWrapper(
947 new Object[]{
948 target.getParent().getClientId(facesContext),
949 null,
950 childIndex,
951 internalBuildTreeStructureToSave(target),
952 target.processSaveState(facesContext)}));
953 }
954 else
955 {
956 String facetName = null;
957 if (target.getParent().getFacetCount() > 0)
958 {
959 for (Map.Entry<String, UIComponent> entry : target.getParent().getFacets().entrySet())
960 {
961 if (target.equals(entry.getValue()))
962 {
963 facetName = entry.getKey();
964 break;
965 }
966 }
967 }
968 states.put(target.getClientId(facesContext),new AttachedFullStateWrapper(new Object[]{
969 target.getParent().getClientId(facesContext),
970 facetName,
971 null,
972 internalBuildTreeStructureToSave(target),
973 target.processSaveState(facesContext)}));
974 }
975 return VisitResult.REJECT;
976 }
977 else if (target.getParent() != null)
978 {
979 state = target.saveState (facesContext);
980
981 if (state != null)
982 {
983
984
985 states.put (target.getClientId (facesContext), state);
986 }
987
988 return VisitResult.ACCEPT;
989 }
990 else
991 {
992
993 return VisitResult.ACCEPT;
994 }
995 }
996 });
997 }
998 finally
999 {
1000 facesContext.getAttributes().remove(SKIP_ITERATION_HINT);
1001 }
1002
1003 Object state = uiViewRoot.saveState (facesContext);
1004 if (state != null)
1005 {
1006
1007
1008 states.put (uiViewRoot.getClientId (facesContext), state);
1009 }
1010 }
1011
1012 private void saveStateOnMap(final FacesContext context, final Map<String,Object> states,
1013 final UIComponent component)
1014 {
1015 ComponentState componentAddedAfterBuildView = null;
1016 try
1017 {
1018 component.pushComponentToEL(context, component);
1019
1020
1021 if (component.getChildCount() > 0)
1022 {
1023 List<UIComponent> children = component.getChildren();
1024 for (int i = 0; i < children.size(); i++)
1025 {
1026 UIComponent child = children.get(i);
1027 if (child != null && !child.isTransient())
1028 {
1029 componentAddedAfterBuildView
1030 = (ComponentState) child.getAttributes().get(COMPONENT_ADDED_AFTER_BUILD_VIEW);
1031 if (componentAddedAfterBuildView != null)
1032 {
1033 if (ComponentState.REMOVE_ADD.equals(componentAddedAfterBuildView))
1034 {
1035 registerOnAddRemoveList(context, child.getClientId(context));
1036 child.getAttributes().put(COMPONENT_ADDED_AFTER_BUILD_VIEW, ComponentState.ADDED);
1037 }
1038 else if (ComponentState.ADD.equals(componentAddedAfterBuildView))
1039 {
1040 registerOnAddList(context, child.getClientId(context));
1041 child.getAttributes().put(COMPONENT_ADDED_AFTER_BUILD_VIEW, ComponentState.ADDED);
1042 }
1043 else if (ComponentState.ADDED.equals(componentAddedAfterBuildView))
1044 {
1045 registerOnAddList(context, child.getClientId(context));
1046 }
1047 ensureClearInitialState(child);
1048
1049
1050 states.put(child.getClientId(context), new AttachedFullStateWrapper(
1051 new Object[]{
1052 component.getClientId(context),
1053 null,
1054 i,
1055 internalBuildTreeStructureToSave(child),
1056 child.processSaveState(context)}));
1057 }
1058 else
1059 {
1060 saveStateOnMap( context, states, child);
1061 }
1062 }
1063 }
1064 }
1065
1066
1067
1068 if (component.getFacetCount() > 0)
1069 {
1070 Map<String, UIComponent> facetMap = component.getFacets();
1071
1072 for (Map.Entry<String, UIComponent> entry : facetMap.entrySet())
1073 {
1074 UIComponent child = entry.getValue();
1075 if (child != null && !child.isTransient())
1076 {
1077 String facetName = entry.getKey();
1078 componentAddedAfterBuildView
1079 = (ComponentState) child.getAttributes().get(COMPONENT_ADDED_AFTER_BUILD_VIEW);
1080 if (componentAddedAfterBuildView != null)
1081 {
1082 if (ComponentState.REMOVE_ADD.equals(componentAddedAfterBuildView))
1083 {
1084 registerOnAddRemoveList(context, child.getClientId(context));
1085 child.getAttributes().put(COMPONENT_ADDED_AFTER_BUILD_VIEW, ComponentState.ADDED);
1086 }
1087 else if (ComponentState.ADD.equals(componentAddedAfterBuildView))
1088 {
1089 registerOnAddList(context, child.getClientId(context));
1090 child.getAttributes().put(COMPONENT_ADDED_AFTER_BUILD_VIEW, ComponentState.ADDED);
1091 }
1092 else if (ComponentState.ADDED.equals(componentAddedAfterBuildView))
1093 {
1094 registerOnAddList(context, child.getClientId(context));
1095 }
1096
1097
1098 ensureClearInitialState(child);
1099 states.put(child.getClientId(context),new AttachedFullStateWrapper(new Object[]{
1100 component.getClientId(context),
1101 facetName,
1102 null,
1103 internalBuildTreeStructureToSave(child),
1104 child.processSaveState(context)}));
1105 }
1106 else
1107 {
1108 saveStateOnMap( context, states, child);
1109 }
1110 }
1111 }
1112 }
1113
1114
1115 Object savedState = component.saveState(context);
1116
1117
1118 if (savedState != null)
1119 {
1120 states.put(component.getClientId(context), savedState);
1121 }
1122 }
1123 finally
1124 {
1125 component.popComponentFromEL(context);
1126 }
1127 }
1128
1129 protected void ensureClearInitialState(UIComponent c)
1130 {
1131 c.clearInitialState();
1132 if (c.getChildCount() > 0)
1133 {
1134 for (int i = 0, childCount = c.getChildCount(); i < childCount; i++)
1135 {
1136 UIComponent child = c.getChildren().get(i);
1137 ensureClearInitialState(child);
1138 }
1139 }
1140 if (c.getFacetCount() > 0)
1141 {
1142 for (UIComponent child : c.getFacets().values())
1143 {
1144 ensureClearInitialState(child);
1145 }
1146 }
1147 }
1148
1149 public void suscribeListeners(UIViewRoot uiViewRoot)
1150 {
1151 boolean listenerSubscribed = false;
1152 List<SystemEventListener> pavList = uiViewRoot.getViewListenersForEventClass(PostAddToViewEvent.class);
1153 if (pavList != null)
1154 {
1155 for (SystemEventListener listener : pavList)
1156 {
1157 if (listener instanceof PostAddPreRemoveFromViewListener)
1158 {
1159 listenerSubscribed = true;
1160 break;
1161 }
1162 }
1163 }
1164 if (!listenerSubscribed)
1165 {
1166 PostAddPreRemoveFromViewListener componentListener = new PostAddPreRemoveFromViewListener();
1167 uiViewRoot.subscribeToViewEvent(PostAddToViewEvent.class, componentListener);
1168 uiViewRoot.subscribeToViewEvent(PreRemoveFromViewEvent.class, componentListener);
1169 }
1170 }
1171
1172 private void checkIds (FacesContext context, UIComponent component, Set<String> existingIds)
1173 {
1174 String id;
1175 Iterator<UIComponent> children;
1176
1177 if (component == null)
1178 {
1179 return;
1180 }
1181
1182
1183
1184 id = component.getClientId (context);
1185
1186 if (existingIds.contains (id))
1187 {
1188 throw new IllegalStateException ("component with duplicate id \"" + id + "\" found");
1189 }
1190
1191 existingIds.add (id);
1192
1193 int facetCount = component.getFacetCount();
1194 if (facetCount > 0)
1195 {
1196 for (UIComponent facet : component.getFacets().values())
1197 {
1198 checkIds (context, facet, existingIds);
1199 }
1200 }
1201 for (int i = 0, childCount = component.getChildCount(); i < childCount; i++)
1202 {
1203 UIComponent child = component.getChildren().get(i);
1204 checkIds (context, child, existingIds);
1205 }
1206 }
1207
1208 protected RenderKitFactory getRenderKitFactory()
1209 {
1210 if (_renderKitFactory == null)
1211 {
1212 _renderKitFactory = (RenderKitFactory)FactoryFinder.getFactory(FactoryFinder.RENDER_KIT_FACTORY);
1213 }
1214 return _renderKitFactory;
1215 }
1216
1217 protected VisitContextFactory getVisitContextFactory()
1218 {
1219 if (_visitContextFactory == null)
1220 {
1221 _visitContextFactory = (VisitContextFactory)FactoryFinder.getFactory(FactoryFinder.VISIT_CONTEXT_FACTORY);
1222 }
1223 return _visitContextFactory;
1224 }
1225
1226 protected String getCheckIdProductionMode(FacesContext facesContext)
1227 {
1228 if (_checkIdsProductionMode == null)
1229 {
1230 _checkIdsProductionMode
1231 = WebConfigParamUtils.getStringInitParameter(facesContext.getExternalContext(),
1232 CHECK_ID_PRODUCTION_MODE, CHECK_ID_PRODUCTION_MODE_DEFAULT);
1233 }
1234 return _checkIdsProductionMode;
1235 }
1236
1237
1238 public static class PostAddPreRemoveFromViewListener implements SystemEventListener
1239 {
1240 private transient FacesContext _facesContext;
1241
1242 private transient Boolean _isRefreshOnTransientBuildPreserveState;
1243
1244 public boolean isListenerForSource(Object source)
1245 {
1246
1247
1248 return (source instanceof UIComponent);
1249 }
1250
1251 private boolean isRefreshOnTransientBuildPreserveState()
1252 {
1253 if (_isRefreshOnTransientBuildPreserveState == null)
1254 {
1255 _isRefreshOnTransientBuildPreserveState = MyfacesConfig.getCurrentInstance(
1256 _facesContext.getExternalContext()).isRefreshTransientBuildOnPSSPreserveState();
1257 }
1258 return _isRefreshOnTransientBuildPreserveState;
1259 }
1260
1261 public void processEvent(SystemEvent event)
1262 {
1263 UIComponent component = (UIComponent) event.getSource();
1264
1265 if (component.isTransient())
1266 {
1267 return;
1268 }
1269
1270
1271
1272
1273 if (_facesContext == null)
1274 {
1275 _facesContext = FacesContext.getCurrentInstance();
1276 }
1277
1278
1279
1280
1281
1282
1283 if (event instanceof PostAddToViewEvent)
1284 {
1285 if (!isRefreshOnTransientBuildPreserveState() &&
1286 Boolean.TRUE.equals(_facesContext.getAttributes().get("javax.faces.IS_BUILDING_INITIAL_STATE")))
1287 {
1288 return;
1289 }
1290
1291
1292 component.getAttributes().put(COMPONENT_ADDED_AFTER_BUILD_VIEW, ComponentState.ADD);
1293 }
1294 else
1295 {
1296
1297
1298
1299
1300
1301 if (FaceletViewDeclarationLanguage.isRemovingComponentBuild(_facesContext))
1302 {
1303 return;
1304 }
1305
1306 if (!isRefreshOnTransientBuildPreserveState() &&
1307 FaceletCompositionContext.getCurrentInstance(_facesContext) != null &&
1308 (component.getAttributes().containsKey(ComponentSupport.MARK_CREATED) ||
1309 component.getAttributes().containsKey(ComponentSupport.COMPONENT_ADDED_BY_HANDLER_MARKER))
1310 )
1311 {
1312
1313
1314
1315
1316
1317
1318
1319 return;
1320 }
1321
1322
1323 UIViewRoot uiViewRoot = _facesContext.getViewRoot();
1324
1325 List<String> clientIdsRemoved = getClientIdsRemoved(uiViewRoot);
1326 if (clientIdsRemoved == null)
1327 {
1328
1329 clientIdsRemoved = new ArrayList<String>();
1330 }
1331 clientIdsRemoved.add(component.getClientId(_facesContext));
1332 setClientsIdsRemoved(uiViewRoot, clientIdsRemoved);
1333 }
1334 }
1335 }
1336
1337 private static TreeStructComponent internalBuildTreeStructureToSave(UIComponent component)
1338 {
1339 TreeStructComponent structComp = new TreeStructComponent(component.getClass().getName(),
1340 component.getId());
1341
1342
1343 if (component.getChildCount() > 0)
1344 {
1345 List<TreeStructComponent> structChildList = new ArrayList<TreeStructComponent>();
1346 for (int i = 0, childCount = component.getChildCount(); i < childCount; i++)
1347 {
1348 UIComponent child = component.getChildren().get(i);
1349 if (!child.isTransient())
1350 {
1351 TreeStructComponent structChild = internalBuildTreeStructureToSave(child);
1352 structChildList.add(structChild);
1353 }
1354 }
1355
1356 TreeStructComponent[] childArray = structChildList.toArray(new TreeStructComponent[structChildList.size()]);
1357 structComp.setChildren(childArray);
1358 }
1359
1360
1361
1362 if (component.getFacetCount() > 0)
1363 {
1364 Map<String, UIComponent> facetMap = component.getFacets();
1365 List<Object[]> structFacetList = new ArrayList<Object[]>();
1366 for (Map.Entry<String, UIComponent> entry : facetMap.entrySet())
1367 {
1368 UIComponent child = entry.getValue();
1369 if (!child.isTransient())
1370 {
1371 String facetName = entry.getKey();
1372 TreeStructComponent structChild = internalBuildTreeStructureToSave(child);
1373 structFacetList.add(new Object[] {facetName, structChild});
1374 }
1375 }
1376
1377 Object[] facetArray = structFacetList.toArray(new Object[structFacetList.size()]);
1378 structComp.setFacets(facetArray);
1379 }
1380
1381 return structComp;
1382 }
1383
1384 private static UIComponent internalRestoreTreeStructure(TreeStructComponent treeStructComp)
1385 {
1386 String compClass = treeStructComp.getComponentClass();
1387 String compId = treeStructComp.getComponentId();
1388 UIComponent component = (UIComponent)ClassUtils.newInstance(compClass);
1389 component.setId(compId);
1390
1391
1392 TreeStructComponent[] childArray = treeStructComp.getChildren();
1393 if (childArray != null)
1394 {
1395 List<UIComponent> childList = component.getChildren();
1396 for (int i = 0, len = childArray.length; i < len; i++)
1397 {
1398 UIComponent child = internalRestoreTreeStructure(childArray[i]);
1399 childList.add(child);
1400 }
1401 }
1402
1403
1404 Object[] facetArray = treeStructComp.getFacets();
1405 if (facetArray != null)
1406 {
1407 Map<String, UIComponent> facetMap = component.getFacets();
1408 for (int i = 0, len = facetArray.length; i < len; i++)
1409 {
1410 Object[] tuple = (Object[])facetArray[i];
1411 String facetName = (String)tuple[0];
1412 TreeStructComponent structChild = (TreeStructComponent)tuple[1];
1413 UIComponent child = internalRestoreTreeStructure(structChild);
1414 facetMap.put(facetName, child);
1415 }
1416 }
1417
1418 return component;
1419 }
1420
1421 public static class TreeStructComponent implements Serializable
1422 {
1423 private static final long serialVersionUID = 5069109074684737231L;
1424 private String _componentClass;
1425 private String _componentId;
1426 private TreeStructComponent[] _children = null;
1427 private Object[] _facets = null;
1428
1429 TreeStructComponent(String componentClass, String componentId)
1430 {
1431 _componentClass = componentClass;
1432 _componentId = componentId;
1433 }
1434
1435 public String getComponentClass()
1436 {
1437 return _componentClass;
1438 }
1439
1440 public String getComponentId()
1441 {
1442 return _componentId;
1443 }
1444
1445 void setChildren(TreeStructComponent[] children)
1446 {
1447 _children = children;
1448 }
1449
1450 TreeStructComponent[] getChildren()
1451 {
1452 return _children;
1453 }
1454
1455 Object[] getFacets()
1456 {
1457 return _facets;
1458 }
1459
1460 void setFacets(Object[] facets)
1461 {
1462 _facets = facets;
1463 }
1464 }
1465
1466 }