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