1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.myfaces.trinidad.change;
20
21 import java.io.IOException;
22 import java.io.InvalidObjectException;
23 import java.io.Serializable;
24
25 import java.util.ArrayList;
26 import java.util.Collections;
27 import java.util.HashSet;
28 import java.util.Iterator;
29 import java.util.List;
30 import java.util.ListIterator;
31 import java.util.Map;
32 import java.util.Queue;
33 import java.util.Set;
34 import java.util.concurrent.ConcurrentHashMap;
35 import java.util.concurrent.ConcurrentLinkedQueue;
36 import java.util.concurrent.ConcurrentMap;
37 import java.util.concurrent.CopyOnWriteArrayList;
38
39 import javax.faces.component.NamingContainer;
40 import javax.faces.component.UIComponent;
41 import javax.faces.component.UIViewRoot;
42 import javax.faces.context.ExternalContext;
43 import javax.faces.context.FacesContext;
44
45 import org.apache.myfaces.trinidad.logging.TrinidadLogger;
46 import org.apache.myfaces.trinidad.util.CollectionUtils;
47 import org.apache.myfaces.trinidad.util.ComponentUtils;
48
49 import org.w3c.dom.Document;
50
51
52
53
54
55
56
57
58
59
60
61 public class SessionChangeManager extends BaseChangeManager
62 {
63
64
65
66
67 @Override
68 public void applyComponentChangesForCurrentView(FacesContext context)
69 {
70 _applyComponentChanges(context, null);
71 }
72
73
74
75
76
77 @Override
78 public void applyComponentChangesForSubtree(
79 FacesContext context,
80 NamingContainer root
81 )
82 {
83 String rootId = null;
84
85 if (root != null)
86 {
87 if (!(root instanceof UIComponent))
88 {
89 throw new IllegalArgumentException(_LOG.getMessage(
90 "INVALID_TYPE", root));
91 }
92
93 rootId = ComponentUtils.getScopedIdForComponent((UIComponent)root, context.getViewRoot());
94 }
95
96 _applyComponentChanges(context, rootId);
97 }
98
99
100
101
102 @Override
103 public void applySimpleComponentChanges(FacesContext context, UIComponent component)
104 {
105
106
107 if (!_isStateRestored(context))
108 {
109 String sessionKey = _getSessionKey(context);
110 ChangesForView changesForView = _getChangesForView(context, sessionKey, false);
111
112 if (changesForView != null)
113 {
114 changesForView.applySimpleComponentChanges(context, component);
115 }
116 }
117 }
118
119
120
121
122 @Override
123 @SuppressWarnings("deprecation")
124 public void addDocumentChange(
125 FacesContext facesContext,
126 UIComponent uiComponent,
127 DocumentChange change)
128 {
129 addDocumentChangeWithOutcome(facesContext, uiComponent, change);
130 }
131
132
133
134
135 @Override
136 public ChangeOutcome addDocumentChangeWithOutcome(
137 FacesContext facesContext,
138 UIComponent uiComponent,
139 DocumentChange change)
140 {
141 if (facesContext == null || uiComponent == null || change == null)
142 throw new IllegalArgumentException(_LOG.getMessage(
143 "CANNOT_ADD_CHANGE_WITH_FACECONTEXT_OR_UICOMPONENT_OR_NULL"));
144
145 return ChangeOutcome.CHANGE_NOT_APPLIED;
146 }
147
148
149
150
151
152 @Override
153 public NotificationOutcome documentChangeApplied(
154 FacesContext facesContext,
155 UIComponent component,
156 ComponentChange componentChange)
157 {
158 NotificationOutcome outcome = super.documentChangeApplied(facesContext,
159 component,
160 componentChange);
161
162 if (componentChange instanceof AttributeComponentChange)
163 {
164 AttributeComponentChange attributeChange = (AttributeComponentChange)componentChange;
165
166
167 ComponentChange removedChange = _removeSimpleComponentChange(facesContext,
168 component,
169 attributeChange);
170
171 if (removedChange != null)
172 {
173 if (_LOG.isFine())
174 {
175 _LOG.fine("REMOVED_DOC_CHANGE_BECAUSE_COMP_CHANGE_ADDED", new Object[] {attributeChange.getAttributeName(), component});
176 }
177
178 outcome = NotificationOutcome.HANDLED;
179 }
180 }
181
182 return outcome;
183 }
184
185
186
187
188
189
190
191
192
193
194 protected void addComponentChangeImpl(
195 FacesContext context,
196 UIComponent targetComponent,
197 ComponentChange componentChange)
198 {
199
200
201 if (componentChange instanceof AttributeComponentChange)
202 {
203 _replaceAttributeChange(context,
204 targetComponent,
205 ((AttributeComponentChange)componentChange).getAttributeName(),
206 (AttributeComponentChange)componentChange,
207 false);
208 }
209 else
210 {
211 String sessionKey = _getSessionKey(context);
212 ChangesForView changesForView = _getChangesForView(context, sessionKey, true);
213
214
215
216 String scopedIdForTargetComponent =
217 ComponentUtils.getScopedIdForComponent(targetComponent, context.getViewRoot());
218
219 String logicalScopedIdForTargetComponent =
220 ComponentUtils.getLogicalScopedIdForComponent(targetComponent, context.getViewRoot());
221
222 _insertComponentChange(changesForView,
223 scopedIdForTargetComponent,
224 logicalScopedIdForTargetComponent,
225 componentChange);
226
227
228 context.getExternalContext().getSessionMap().put(sessionKey, changesForView);
229 }
230 }
231
232
233
234
235 @Override
236 public AttributeComponentChange replaceAttributeChangeIfPresent(
237 FacesContext context,
238 UIComponent component,
239 AttributeComponentChange attributeComponentChange)
240 {
241 return _replaceAttributeChange(context,
242 component,
243 attributeComponentChange.getAttributeName(),
244 attributeComponentChange,
245 true);
246 }
247
248
249
250
251 @Override
252 protected Document getDocument(FacesContext context)
253 {
254 return null;
255 }
256
257
258
259
260
261
262
263 private ComponentChange _removeSimpleComponentChange(
264 FacesContext facesContext,
265 UIComponent component,
266 AttributeComponentChange componentChange)
267 {
268 String sessionKey = _getSessionKey(facesContext);
269 ChangesForView changesForView = _getChangesForView(facesContext, sessionKey, true);
270 String logicalScopedId =
271 ComponentUtils.getLogicalScopedIdForComponent(component, facesContext.getViewRoot());
272
273
274 changesForView.removeAttributeChange(logicalScopedId, componentChange);
275
276
277
278
279 return _replaceAttributeChange(facesContext,
280 component,
281 componentChange.getAttributeName(),
282 null,
283 true);
284 }
285
286
287
288
289
290
291
292
293
294
295 private AttributeComponentChange _replaceAttributeChange(
296 FacesContext context,
297 UIComponent component,
298 String attributeName,
299 AttributeComponentChange attributeComponentChange,
300 boolean onlyIfPresent)
301 {
302
303
304 String scopedIdForTargetComponent = ComponentUtils.getScopedIdForComponent(
305 component,
306 context.getViewRoot());
307
308
309
310 String sessionKey = _getSessionKey(context);
311 ChangesForView changesForView = _getChangesForView(context, sessionKey, true);
312
313
314 AttributeComponentChange replaced = _extractAttributeChange(changesForView,
315 scopedIdForTargetComponent,
316 attributeName);
317
318
319 if ( attributeComponentChange != null && (!onlyIfPresent || (replaced != null)) )
320 {
321
322 if ( !(attributeName.equals(attributeComponentChange.getAttributeName())) )
323 {
324 throw new IllegalArgumentException("The supplied attribute name does not match the " +
325 "attribute name in the supplied attribute change");
326 }
327
328 String logicalScopedIdForTargetComponent = ComponentUtils.getLogicalScopedIdForComponent(
329 component,
330 context.getViewRoot());
331
332 _insertComponentChange(changesForView,
333 scopedIdForTargetComponent,
334 logicalScopedIdForTargetComponent,
335 attributeComponentChange);
336
337
338 context.getExternalContext().getSessionMap().put(sessionKey, changesForView);
339 }
340
341 return replaced;
342 }
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357 private AttributeComponentChange _extractAttributeChange(
358 ChangesForView changesForView,
359 String scopedIdForTargetComponent,
360 String attributeName)
361 {
362 AttributeComponentChange extracted = null;
363
364
365
366 Iterator<QualifiedComponentChange> changes =
367 changesForView.getComponentChangesForView().iterator();
368
369
370
371 Iterator<MoveChildComponentChange> renameChanges =
372 changesForView.getRenameChanges(scopedIdForTargetComponent);
373
374
375
376 MoveChildComponentChange nextRenameChange;
377 String currTargetScopedId;
378
379 if (renameChanges.hasNext())
380 {
381
382
383 nextRenameChange = renameChanges.next();
384 currTargetScopedId = nextRenameChange.getSourceScopedId();
385 }
386 else
387 {
388 nextRenameChange = null;
389 currTargetScopedId = scopedIdForTargetComponent;
390 }
391
392
393 while (changes.hasNext())
394 {
395 QualifiedComponentChange currQualifiedChange = changes.next();
396
397 if (currQualifiedChange.getComponentChange() == nextRenameChange)
398 {
399
400 currTargetScopedId = nextRenameChange.getDestinationScopedId();
401
402 nextRenameChange = (renameChanges.hasNext())
403 ? renameChanges.next()
404 : null;
405 }
406 else if (currQualifiedChange.getTargetComponentScopedId().equals(currTargetScopedId))
407 {
408
409 ComponentChange currChange = currQualifiedChange.getComponentChange();
410
411 if (currChange instanceof AttributeComponentChange)
412 {
413 AttributeComponentChange currAttributeChange = (AttributeComponentChange)currChange;
414
415
416 if (attributeName.equals(currAttributeChange.getAttributeName()))
417 {
418
419
420 changes.remove();
421 extracted = currAttributeChange;
422 break;
423 }
424 }
425 }
426 }
427
428 return extracted;
429 }
430
431
432
433
434
435
436
437
438
439 private void _insertComponentChange(ChangesForView changesForView,
440 String scopedIdForTargetComponent,
441 String logicalScopedIdForTargetComponent,
442 ComponentChange componentChange)
443 {
444 QualifiedComponentChange newQualifiedChange =
445 new QualifiedComponentChange(scopedIdForTargetComponent,
446 logicalScopedIdForTargetComponent,
447 componentChange);
448
449 changesForView.addChange(newQualifiedChange);
450 }
451
452
453
454
455
456
457
458
459
460 private void _applyComponentChanges(
461 FacesContext context,
462 String rootId
463 )
464 {
465 ChangesForView changesForView = _getReadOnlyChangesForView(context);
466
467 UIViewRoot viewRoot = context.getViewRoot();
468
469
470 boolean isStateRestored = _isStateRestored(context);
471
472
473
474 Set<String> attributeForcedComponents = new HashSet<String>();
475
476
477 for (QualifiedComponentChange qualifiedChange : changesForView.getComponentChangesForView())
478 {
479 ComponentChange componentChange = qualifiedChange.getComponentChange();
480 String targetComponentScopedId = qualifiedChange.getTargetComponentScopedId();
481
482
483
484
485
486
487
488
489 if (isStateRestored &&
490 componentChange instanceof AttributeComponentChange &&
491 !attributeForcedComponents.contains(targetComponentScopedId))
492 {
493 continue;
494 }
495
496
497 if (!_acceptChange(qualifiedChange, rootId))
498 continue;
499
500 UIComponent targetComponent = viewRoot.findComponent(targetComponentScopedId);
501
502
503 if (targetComponent == null)
504 {
505 _LOG.info(this.getClass().getName(),
506 "applyComponentChangesForCurrentView",
507 "TARGET_COMPONENT_MISSING_CHANGE_FAILED",
508 targetComponentScopedId);
509 continue;
510 }
511
512
513 componentChange.changeComponent(targetComponent);
514
515
516
517
518 if (componentChange instanceof MoveChildComponentChange)
519 {
520 String destinationScopedId =
521 ((MoveChildComponentChange)componentChange).getDestinationScopedId();
522
523
524 attributeForcedComponents.remove(targetComponentScopedId);
525 attributeForcedComponents.add(destinationScopedId);
526 }
527 else if (componentChange instanceof SetFacetChildComponentChange)
528 {
529 String facetName = ((SetFacetChildComponentChange)componentChange).getFacetName();
530 UIComponent facetComponent = targetComponent.getFacet(facetName);
531
532 if (facetComponent != null)
533 {
534 String facetScopedId = ComponentUtils.getScopedIdForComponent(facetComponent, viewRoot);
535
536 attributeForcedComponents.add(facetScopedId);
537 }
538 }
539 else if (componentChange instanceof AddChildComponentChange)
540 {
541
542
543
544 String addedComponentId = ((AddChildComponentChange)componentChange).getComponent().getId();
545
546
547 UIComponent addedComponent = ComponentUtils.findRelativeComponent(targetComponent,
548 addedComponentId);
549
550 if (addedComponent != null)
551 {
552 String addedChildComponentScopedId= ComponentUtils.getScopedIdForComponent(addedComponent,
553 viewRoot);
554 attributeForcedComponents.add(addedChildComponentScopedId);
555 }
556 }
557 }
558 }
559
560
561
562
563
564
565 private boolean _isStateRestored(FacesContext facesContext)
566 {
567
568
569
570
571 return false;
572
573
574
575 }
576
577
578
579
580
581
582
583
584
585
586
587
588
589 private boolean _acceptChange(
590 QualifiedComponentChange qualifiedChange,
591 String rootId
592 )
593 {
594 if (rootId != null)
595 {
596 String id = qualifiedChange.getTargetComponentScopedId();
597 return (id.startsWith(rootId) && (id.length() != rootId.length()));
598 }
599 else
600 {
601 return true;
602 }
603 }
604
605 private ChangesForView _getReadOnlyChangesForView(FacesContext context)
606 {
607 String sessionKey = _getSessionKey(context);
608
609 return _getChangesForView(context, sessionKey, false);
610 }
611
612
613
614
615
616
617
618
619
620
621
622
623 private ChangesForView _getChangesForView(
624 FacesContext context,
625 String sessionKey,
626 boolean createIfNecessary)
627 {
628 ExternalContext extContext = context.getExternalContext();
629 Map<String, Object> sessionMap = extContext.getSessionMap();
630
631 Object changes = sessionMap.get(sessionKey);
632
633 if (changes == null)
634 {
635 if (createIfNecessary)
636 {
637
638 Object session = extContext.getSession(true);
639
640 synchronized (session)
641 {
642 changes = sessionMap.get(sessionKey);
643
644 if (changes == null)
645 {
646 ChangesForView changesForView = new ChangesForView(true);
647
648 sessionMap.put(sessionKey, changesForView);
649
650 return changesForView;
651 }
652 else
653 {
654 return (ChangesForView)changes;
655 }
656 }
657 }
658 else
659 {
660 return _EMPTY_CHANGES;
661 }
662 }
663 else
664 {
665 return (ChangesForView)changes;
666 }
667 }
668
669
670
671
672
673
674
675
676 private String _getSessionKey(FacesContext context)
677 {
678 String viewId = context.getViewRoot().getViewId();
679
680 StringBuilder builder = new StringBuilder(viewId.length() +
681 _COMPONENT_CHANGES_MAP_FOR_SESSION_KEY.length());
682
683 return builder.append(_COMPONENT_CHANGES_MAP_FOR_SESSION_KEY).append(viewId).toString();
684 }
685
686
687
688
689
690 private static final class ChangesForView implements Serializable
691 {
692 protected ChangesForView(boolean rw)
693 {
694 if (rw)
695 {
696 _componentChangesForView = new ConcurrentLinkedQueue<QualifiedComponentChange>();
697 _renameChanges = new CopyOnWriteArrayList<MoveChildComponentChange>();
698 }
699 else
700 {
701 _componentChangesForView = CollectionUtils.emptyQueue();
702 _renameChanges = Collections.emptyList();
703 }
704 }
705
706 @Override
707 public String toString()
708 {
709 return super.toString() + "[componentChange=" + _componentChangesForView +
710 " renameChanges=" + _renameChanges + "]";
711 }
712
713 @Override
714 public boolean equals(Object o)
715 {
716 if (o == this)
717 return true;
718
719 if (!(o instanceof ChangesForView))
720 return false;
721
722 ChangesForView other = (ChangesForView)o;
723
724 return _componentChangesForView.equals(other._componentChangesForView) &&
725 _renameChanges.equals(other._renameChanges);
726 }
727
728 @Override
729 public int hashCode()
730 {
731 return _componentChangesForView.hashCode() + 37 * _renameChanges.hashCode();
732 }
733
734
735
736
737 protected Iterable<QualifiedComponentChange> getComponentChangesForView()
738 {
739 return _componentChangesForView;
740 }
741
742
743
744
745
746
747 protected void addChange(QualifiedComponentChange qualifiedChange)
748 {
749
750
751 _componentChangesForView.add(qualifiedChange);
752
753 ComponentChange componentChange = qualifiedChange.getComponentChange();
754
755 if (componentChange instanceof AttributeComponentChange)
756 {
757
758 _updateAttributeChange(_attrChanges, _renameMap, qualifiedChange);
759 }
760 else if (componentChange instanceof MoveChildComponentChange)
761 {
762
763
764 MoveChildComponentChange moveComponentChange = (MoveChildComponentChange)componentChange;
765
766 if (!moveComponentChange.getSourceScopedId().equals(moveComponentChange.getDestinationScopedId()))
767 {
768 _renameChanges.add(moveComponentChange);
769
770
771
772 _updateRenameMap(_renameMap, moveComponentChange);
773 }
774 }
775 }
776
777
778
779
780
781
782
783 protected AttributeComponentChange removeAttributeChange(
784 String logicalScopedId,
785 AttributeComponentChange attributeChange)
786 {
787
788
789 return _removeAttributeChange(_attrChanges,
790 _renameMap,
791 logicalScopedId,
792 attributeChange);
793 }
794
795
796
797
798
799 protected Iterator<MoveChildComponentChange> getRenameChanges(String targetScopedId)
800 {
801 if (!_renameChanges.isEmpty())
802 {
803 String currTargetScopedId = targetScopedId;
804 List<MoveChildComponentChange> renameChanges = null;
805
806
807
808 ListIterator<MoveChildComponentChange> moveChanges =
809 _renameChanges.listIterator(_renameChanges.size());
810
811 while (moveChanges.hasPrevious())
812 {
813 MoveChildComponentChange currMoveChange = moveChanges.previous();
814
815 if (currTargetScopedId.equals(currMoveChange.getDestinationScopedId()))
816 {
817
818 if (renameChanges == null)
819 renameChanges = new ArrayList<MoveChildComponentChange>();
820
821 renameChanges.add(currMoveChange);
822
823
824 currTargetScopedId = currMoveChange.getSourceScopedId();
825 }
826 }
827
828 if (renameChanges != null)
829 {
830 if (renameChanges.size() > 1)
831 {
832
833
834 Collections.reverse(renameChanges);
835 }
836
837 return renameChanges.iterator();
838 }
839 }
840
841 return CollectionUtils.emptyIterator();
842 }
843
844
845
846
847
848
849 protected void applySimpleComponentChanges(FacesContext context, UIComponent component)
850 {
851
852
853 String scopedId = ComponentUtils.getLogicalScopedIdForComponent(component, context.getViewRoot());
854
855 ConcurrentMap<String, AttributeComponentChange> attributeCmponentChanges = _attrChanges.get(scopedId);
856
857 if (attributeCmponentChanges != null)
858 {
859 for (ComponentChange change : attributeCmponentChanges.values())
860 {
861 change.changeComponent(component);
862 }
863 }
864 }
865
866 private void _updateAttributeChange(
867 ConcurrentMap<String, ConcurrentMap<String, AttributeComponentChange>> attrChanges,
868 ConcurrentMap<String, String> renameMap,
869 QualifiedComponentChange qAttrChange)
870 {
871
872
873 ConcurrentMap<String, AttributeComponentChange> changesForComponent =
874 _getAttributeChangesAfterHandlingMove(attrChanges,
875 renameMap,
876 qAttrChange.getTargetComponentLogicalScopedId(),
877 true);
878
879 AttributeComponentChange attrChange = (AttributeComponentChange)
880 qAttrChange.getComponentChange();
881
882
883 String attrName = attrChange.getAttributeName();
884
885 changesForComponent.put(attrName, attrChange);
886 }
887
888 private AttributeComponentChange _removeAttributeChange(
889 ConcurrentMap<String, ConcurrentMap<String, AttributeComponentChange>> attrChanges,
890 ConcurrentMap<String, String> renameMap,
891 String logicalScopedId,
892 AttributeComponentChange componentChange)
893 {
894
895 ConcurrentMap<String, AttributeComponentChange> changesForComponent =
896 _getAttributeChangesAfterHandlingMove(attrChanges, renameMap, logicalScopedId, false);
897
898 if (changesForComponent != null)
899 {
900 return changesForComponent.remove(componentChange.getAttributeName());
901 }
902
903 return null;
904 }
905
906
907
908
909
910
911
912
913
914
915
916
917 private ConcurrentMap<String, AttributeComponentChange> _getAttributeChangesAfterHandlingMove(
918 ConcurrentMap<String, ConcurrentMap<String, AttributeComponentChange>> attrChanges,
919 ConcurrentMap<String, String> renameMap,
920 String logicalScopedId,
921 boolean createIfNecessary)
922 {
923
924 String originalScopedId = renameMap.get(logicalScopedId);
925
926
927
928 if (originalScopedId == null)
929 {
930 originalScopedId = logicalScopedId;
931 }
932
933
934 ConcurrentMap<String, AttributeComponentChange> changesForComponent =
935 attrChanges.get(originalScopedId);
936
937
938 if (changesForComponent == null && createIfNecessary)
939 {
940
941
942 changesForComponent = new ConcurrentHashMap<String, AttributeComponentChange>();
943 attrChanges.put(originalScopedId, changesForComponent);
944 }
945
946 return changesForComponent;
947 }
948
949
950
951
952
953
954 private void _updateRenameMap(
955 ConcurrentMap<String, String> renameMap,
956 MoveChildComponentChange moveChange)
957 {
958 String sourceScopedId = moveChange.getSourceLogicalScopedId();
959 String destinationScopedId = moveChange.getDestinationLogicalScopedId();
960
961
962 if (!(sourceScopedId.equals(destinationScopedId)))
963 {
964
965 String originalScodeId = renameMap.remove(sourceScopedId);
966
967
968
969
970 if (originalScodeId == null)
971 originalScodeId = sourceScopedId;
972
973
974 renameMap.put(destinationScopedId, originalScodeId);
975 }
976 }
977
978 private void readObject(java.io.ObjectInputStream in)
979 throws IOException, ClassNotFoundException
980 {
981 throw new InvalidObjectException("proxy required");
982 }
983
984 private Object writeReplace()
985 {
986 return new SerializationProxy(this);
987 }
988
989 private static class SerializationProxy implements Serializable
990 {
991 SerializationProxy(ChangesForView changesForView)
992 {
993 _componentChangesForView =
994 new ArrayList<QualifiedComponentChange>(changesForView._componentChangesForView);
995
996 if (changesForView._renameChanges==Collections.EMPTY_LIST)
997 _rw = false;
998 else
999 _rw = true;
1000 }
1001
1002 private Object readResolve()
1003 {
1004 ChangesForView changesForView = new ChangesForView(_rw);
1005 for (QualifiedComponentChange qualifiedChange : _componentChangesForView)
1006 {
1007 changesForView.addChange(qualifiedChange);
1008 }
1009
1010 return changesForView;
1011 }
1012
1013 private final List<QualifiedComponentChange> _componentChangesForView;
1014 private final boolean _rw;
1015
1016 private static final long serialVersionUID = 1L;
1017 }
1018
1019 private final Queue<QualifiedComponentChange> _componentChangesForView;
1020 private final List<MoveChildComponentChange> _renameChanges;
1021
1022
1023
1024 private final ConcurrentMap<String, ConcurrentMap<String, AttributeComponentChange>> _attrChanges =
1025 new ConcurrentHashMap<String, ConcurrentMap<String, AttributeComponentChange>>();
1026
1027
1028
1029 private final ConcurrentMap<String, String> _renameMap =
1030 new ConcurrentHashMap<String, String>();
1031
1032 private static final long serialVersionUID = 1L;
1033 }
1034
1035 private static final ChangesForView _EMPTY_CHANGES = new ChangesForView(false);
1036
1037 private static class QualifiedComponentChange implements Serializable
1038 {
1039 public QualifiedComponentChange(String targetComponentScopedId,
1040 String targetComponentLogicalScopedId,
1041 ComponentChange componentChange)
1042 {
1043
1044 if (targetComponentScopedId == null || componentChange == null)
1045 throw new IllegalArgumentException("Target component scoped id and " +
1046 "component change is required");
1047
1048 _targetComponentScopedId = targetComponentScopedId;
1049 _targetComponentLogicalScopedId = (targetComponentScopedId.equals(targetComponentLogicalScopedId)) ? null :
1050 targetComponentLogicalScopedId;
1051 _componentChange = componentChange;
1052 }
1053
1054 public String getTargetComponentScopedId()
1055 {
1056 return _targetComponentScopedId;
1057 }
1058
1059 public String getTargetComponentLogicalScopedId()
1060 {
1061 return _targetComponentLogicalScopedId != null ? _targetComponentLogicalScopedId : _targetComponentScopedId;
1062 }
1063
1064 public ComponentChange getComponentChange()
1065 {
1066 return _componentChange;
1067 }
1068
1069 @Override
1070 public boolean equals(Object o)
1071 {
1072 if (o == this)
1073 return true;
1074
1075 if (!(o instanceof QualifiedComponentChange))
1076 return false;
1077
1078 QualifiedComponentChange other = (QualifiedComponentChange)o;
1079
1080 return getTargetComponentLogicalScopedId().equals(other.getTargetComponentLogicalScopedId()) &&
1081 _componentChange.equals(other._componentChange);
1082 }
1083
1084 @Override
1085 public int hashCode()
1086 {
1087 return getTargetComponentLogicalScopedId().hashCode() + 37 * _componentChange.hashCode();
1088 }
1089
1090 @Override
1091 public String toString()
1092 {
1093 return super.toString() + "[target=" + _targetComponentScopedId + " logical_target=" + getTargetComponentLogicalScopedId() +
1094 " change=" + _componentChange + "]";
1095 }
1096
1097 private final String _targetComponentScopedId;
1098 private final String _targetComponentLogicalScopedId;
1099 private final ComponentChange _componentChange;
1100
1101 private static final long serialVersionUID = 1L;
1102 }
1103
1104 private static final String _COMPONENT_CHANGES_MAP_FOR_SESSION_KEY =
1105 "org.apache.myfaces.trinidadinternal.ComponentChangesMapForSession";
1106
1107 private static final TrinidadLogger _LOG =
1108 TrinidadLogger.createTrinidadLogger(SessionChangeManager.class);
1109 }