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