1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.myfaces.trinidad.component;
20
21 import java.io.IOException;
22 import java.io.ObjectInputStream;
23 import java.io.Serializable;
24
25 import java.util.AbstractMap;
26 import java.util.Collections;
27 import java.util.HashMap;
28 import java.util.List;
29 import java.util.Map;
30 import java.util.Set;
31
32 import javax.faces.FacesException;
33 import javax.faces.application.StateManager;
34 import javax.faces.component.ContextCallback;
35 import javax.faces.component.NamingContainer;
36 import javax.faces.component.UIComponent;
37 import javax.faces.component.visit.VisitCallback;
38 import javax.faces.component.visit.VisitContext;
39 import javax.faces.component.visit.VisitContextWrapper;
40 import javax.faces.component.visit.VisitResult;
41 import javax.faces.context.FacesContext;
42 import javax.faces.event.AbortProcessingException;
43 import javax.faces.event.ComponentSystemEvent;
44 import javax.faces.event.FacesEvent;
45 import javax.faces.event.PhaseId;
46 import javax.faces.render.Renderer;
47
48 import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFComponent;
49 import org.apache.myfaces.trinidad.bean.FacesBean;
50 import org.apache.myfaces.trinidad.bean.PropertyKey;
51 import org.apache.myfaces.trinidad.context.ComponentContextChange;
52 import org.apache.myfaces.trinidad.context.ComponentContextManager;
53 import org.apache.myfaces.trinidad.context.RequestContext;
54 import org.apache.myfaces.trinidad.event.SelectionEvent;
55 import org.apache.myfaces.trinidad.logging.TrinidadLogger;
56 import org.apache.myfaces.trinidad.model.CollectionModel;
57 import org.apache.myfaces.trinidad.model.LocalRowKeyIndex;
58 import org.apache.myfaces.trinidad.model.RowKeyChangeEvent;
59 import org.apache.myfaces.trinidad.model.RowKeyChangeListener;
60 import org.apache.myfaces.trinidad.model.SortCriterion;
61 import org.apache.myfaces.trinidad.render.ClientRowKeyManager;
62 import org.apache.myfaces.trinidad.render.ClientRowKeyManagerFactory;
63 import org.apache.myfaces.trinidad.util.Args;
64 import org.apache.myfaces.trinidad.util.ComponentUtils;
65
66
67
68
69
70
71
72
73 @JSFComponent
74 public abstract class UIXCollection extends UIXComponentBase
75 implements NamingContainer
76 {
77 static public final FacesBean.Type TYPE = new FacesBean.Type(
78 UIXComponentBase.TYPE);
79 static public final PropertyKey VAR_KEY =
80 TYPE.registerKey("var", String.class, PropertyKey.CAP_NOT_BOUND);
81
82 protected UIXCollection(String rendererType)
83 {
84 super(rendererType);
85 }
86
87 protected UIXCollection()
88 {
89 this(null);
90 }
91
92
93
94
95
96
97 final public String getVar()
98 {
99 return ComponentUtils.resolveString(getProperty(VAR_KEY));
100 }
101
102
103
104
105
106
107 final public void setVar(String var)
108 {
109 setProperty(VAR_KEY, (var));
110 InternalState iState = _getInternalState(false);
111 if (iState != null)
112 {
113 iState._var = var;
114 }
115 }
116
117
118
119
120
121
122
123 @Override
124 public void queueEvent(FacesEvent event)
125 {
126 if (event.getSource() == this)
127 {
128
129
130 if (!(event instanceof SelectionEvent))
131 {
132 InternalState iState = _getInternalState(true);
133 iState._hasEvent = true;
134 }
135 }
136
137
138
139
140 Object currencyKey = getRowKey();
141 event = new TableRowEvent(this, event, currencyKey);
142
143
144
145 super.queueEvent(new CollectionContextEvent(this, event));
146 }
147
148
149
150
151
152
153
154 @Override
155 public void broadcast(FacesEvent event)
156 throws AbortProcessingException
157 {
158 FacesContext context = getFacesContext();
159
160
161
162 if (event instanceof CollectionContextEvent)
163 {
164 boolean inContextAtMethodInvocation = _inContext;
165 if (!inContextAtMethodInvocation)
166 {
167 _setupContextChange();
168 }
169
170 try
171 {
172 CollectionContextEvent wrapperEvent = (CollectionContextEvent) event;
173 wrapperEvent.broadcastWrappedEvent(context);
174 }
175 finally
176 {
177 if (!inContextAtMethodInvocation)
178 {
179 _tearDownContextChange();
180 }
181 }
182 }
183 else
184 {
185
186
187 if (event instanceof TableRowEvent)
188 {
189 TableRowEvent rowEvent = (TableRowEvent) event;
190 Object old = getRowKey();
191 setRowKey(rowEvent.getCurrencyKey());
192 rowEvent.broadcastWrappedEvent(context);
193 setRowKey(old);
194 }
195 else
196 {
197 super.broadcast(event);
198 }
199 }
200 }
201
202
203
204
205
206
207 @Override
208 public final void processDecodes(FacesContext context)
209 {
210 if (context == null)
211 throw new NullPointerException();
212
213 boolean inContextAtMethodInvocation = _inContext;
214 if (!inContextAtMethodInvocation)
215 {
216 _setupContextChange();
217 }
218
219 try
220 {
221 _init();
222
223 InternalState iState = _getInternalState(true);
224 iState._isFirstRender = false;
225
226 if (!isRendered())
227 return;
228
229 __flushCachedModel();
230
231
232 iState._hasEvent = false;
233
234
235
236
237
238
239
240
241 decode(context);
242
243
244 decodeChildren(context);
245 }
246 finally
247 {
248 if (!inContextAtMethodInvocation)
249 {
250 _tearDownContextChange();
251 }
252 }
253 }
254
255 @Override
256 protected void decodeChildrenImpl(FacesContext context)
257 {
258 processFacetsAndChildren(context, PhaseId.APPLY_REQUEST_VALUES);
259 }
260
261 @Override
262 protected void validateChildrenImpl(FacesContext context)
263 {
264 processFacetsAndChildren(context, PhaseId.PROCESS_VALIDATIONS);
265 }
266
267 @Override
268 protected void updateChildrenImpl(FacesContext context)
269 {
270 processFacetsAndChildren(context, PhaseId.UPDATE_MODEL_VALUES);
271 }
272
273
274
275
276
277
278 public void resetStampState()
279 {
280 InternalState iState = _getInternalState(true);
281
282 Object initKey = _getCurrencyKeyForInitialStampState();
283
284
285
286 if (iState._stampState != null)
287 iState._stampState.clear(initKey);
288 }
289
290 @Override
291 public Object processSaveState(FacesContext context)
292 {
293 boolean inContextAtMethodInvocation = _inContext;
294 if (!inContextAtMethodInvocation)
295 {
296 _setupContextChange();
297 }
298
299 try
300 {
301 _stateSavingCurrencyKey = _resetCurrencyKeyForStateSaving(context);
302
303 Object savedState = super.processSaveState(context);
304
305 _restoreCurrencyKeyForStateSaving(_stateSavingCurrencyKey);
306 _resetInternalState();
307
308 return savedState;
309 }
310 finally
311 {
312 if (!inContextAtMethodInvocation)
313 {
314 _tearDownContextChange();
315 }
316 }
317 }
318
319 @Override
320 public Object saveState(FacesContext context)
321 {
322
323
324 Object superState = super.saveState(context);
325 final Object stampState, clientKeyMgr, idToIndexMap;
326
327
328
329
330 InternalState iState = _getInternalState(false);
331 if (iState != null)
332 {
333 stampState = iState._stampState;
334 clientKeyMgr = iState._clientKeyMgr;
335 idToIndexMap = iState._idToIndexMap;
336 }
337 else
338 {
339 stampState = null;
340 clientKeyMgr = null;
341 idToIndexMap = null;
342 }
343
344 if ((superState != null) || (stampState != null) ||
345 (clientKeyMgr != null) || (idToIndexMap != null))
346 return new Object[]{superState, stampState, clientKeyMgr, idToIndexMap};
347 return null;
348 }
349
350
351 @SuppressWarnings("unchecked")
352 @Override
353 public void restoreState(FacesContext context, Object state)
354 {
355 final Object superState, stampState, clientKeyMgr, idToIndexMap;
356 Object[] array = (Object[]) state;
357 if (array != null)
358 {
359 superState = array[0];
360 stampState = array[1];
361 clientKeyMgr = array[2];
362 idToIndexMap = array[3];
363 }
364 else
365 {
366 superState = null;
367 stampState = null;
368 clientKeyMgr = null;
369 idToIndexMap = null;
370 }
371 super.restoreState(context, superState);
372
373 if ((stampState != null) || (clientKeyMgr != null) || (idToIndexMap != null))
374 {
375 InternalState iState = _getInternalState(true);
376 iState._stampState = (StampState) stampState;
377 iState._clientKeyMgr = (ClientRowKeyManager) clientKeyMgr;
378 iState._idToIndexMap = (Map<String, String>) idToIndexMap;
379 }
380 else
381 {
382
383
384 InternalState iState = _getInternalState(false);
385 if (iState != null)
386 {
387 iState._stampState = null;
388 iState._clientKeyMgr = null;
389 iState._idToIndexMap = null;
390 }
391 }
392 }
393
394
395
396
397
398
399
400 public final boolean isRowAvailable()
401 {
402 return getCollectionModel().isRowAvailable();
403 }
404
405
406
407
408
409
410 public final boolean isRowAvailable(Object rowKey)
411 {
412 return getCollectionModel().isRowAvailable(rowKey);
413 }
414
415
416
417
418
419
420 public final Object getRowData(Object rowKey)
421 {
422 return getCollectionModel().getRowData(rowKey);
423 }
424
425
426
427
428
429
430 public final boolean areRowsAvailable(int rowCount)
431 {
432 return getCollectionModel().areRowsAvailable(rowCount);
433 }
434
435
436
437
438
439
440
441
442 public final boolean areRowsAvailable(int startIndex, int rowCount)
443 {
444 return getCollectionModel().areRowsAvailable(startIndex, rowCount);
445 }
446
447
448
449
450
451
452
453
454 public final boolean areRowsAvailable(Object startRowKey, int rowCount)
455 {
456 return getCollectionModel().areRowsAvailable(startRowKey, rowCount);
457 }
458
459
460
461
462
463
464
465
466 public final int getRowCount()
467 {
468 return getCollectionModel().getRowCount();
469 }
470
471
472
473
474
475
476 public final int getRowIndex()
477 {
478 return getCollectionModel().getRowIndex();
479 }
480
481
482
483
484
485
486 public final Object getRowKey()
487 {
488 InternalState iState = _getInternalState(true);
489 if (iState._currentRowKey == _NULL)
490 {
491
492
493
494
495
496 iState._currentRowKey = getCollectionModel().getRowKey();
497 iState._model.addRowKeyChangeListener(iState);
498 }
499
500 return iState._currentRowKey;
501 }
502
503
504
505
506
507
508 public final Object getRowData()
509 {
510 CollectionModel model = getCollectionModel();
511
512
513 return model.isRowAvailable() ? model.getRowData() : null;
514 }
515
516
517
518
519
520
521
522 public boolean isRowAvailable(int rowIndex)
523 {
524 return getCollectionModel().isRowAvailable(rowIndex);
525 }
526
527
528
529
530
531
532
533 public Object getRowData(int rowIndex)
534 {
535 return getCollectionModel().getRowData(rowIndex);
536 }
537
538
539
540
541
542 public abstract String getVarStatus();
543
544
545
546
547
548
549
550
551
552 public void setRowKey(Object rowKey)
553 {
554 _verifyComponentInContext();
555
556 preRowDataChange();
557 getCollectionModel().setRowKey(rowKey);
558 postRowDataChange();
559 if (_LOG.isFine() && (rowKey != null) && (!isRowAvailable()))
560 _LOG.fine("no row available for rowKey:"+rowKey);
561 }
562
563
564
565
566
567
568
569
570
571 public void setRowIndex(int rowIndex)
572 {
573 _verifyComponentInContext();
574
575 preRowDataChange();
576 getCollectionModel().setRowIndex(rowIndex);
577 postRowDataChange();
578 if (_LOG.isFine() && (rowIndex != -1) && (!isRowAvailable()))
579 _LOG.fine("no row available for rowIndex:"+rowIndex);
580 }
581
582
583
584
585
586
587 public final boolean isSortable(String property)
588 {
589 return getCollectionModel().isSortable(property);
590 }
591
592
593
594
595
596
597
598 public void setSortCriteria(List<SortCriterion> criteria)
599 {
600 getCollectionModel().setSortCriteria(criteria);
601 }
602
603
604
605
606
607
608
609
610 public final List<SortCriterion> getSortCriteria()
611 {
612 return getCollectionModel().getSortCriteria();
613 }
614
615
616
617
618
619
620
621
622
623 @Deprecated
624 protected void clearCurrencyStringCache()
625 {
626 _getInternalState(true)._clearTokenCache = true;
627 }
628
629
630
631
632 @Override
633 public final void encodeBegin(FacesContext context) throws IOException
634 {
635 _setupContextChange();
636 boolean teardown = true;
637 try
638 {
639 _init();
640
641 InternalState istate = _getInternalState(true);
642
643
644
645
646 if (istate._clearTokenCache)
647 {
648 istate._clearTokenCache = false;
649 ClientRowKeyManager keyMgr = getClientRowKeyManager();
650 if (keyMgr instanceof DefaultClientKeyManager)
651 ((DefaultClientKeyManager) keyMgr).clear();
652 }
653 __flushCachedModel();
654
655 Object assertKey = null;
656 assert ((assertKey = getRowKey()) != null) || true;
657 __encodeBegin(context);
658
659 assert _assertKeyPreserved(assertKey) : "CurrencyKey not preserved";
660
661 teardown = false;
662 }
663 finally
664 {
665 if (teardown)
666 {
667
668 _tearDownContextChange();
669 }
670 }
671 }
672
673 @Override
674 public void encodeEnd(FacesContext context) throws IOException
675 {
676 try
677 {
678 Object assertKey = null;
679 assert ((assertKey = getRowKey()) != null) || true;
680 super.encodeEnd(context);
681
682 assert _assertKeyPreserved(assertKey) : "CurrencyKey not preserved";
683 }
684 finally
685 {
686 _tearDownContextChange();
687 }
688 }
689
690 @Override
691 protected void setupVisitingContext(FacesContext context)
692 {
693 super.setupVisitingContext(context);
694 _setupContextChange();
695
696 if (Boolean.TRUE.equals(context.getAttributes().get(StateManager.IS_SAVING_STATE)))
697 {
698 _stateSavingCurrencyKey = _resetCurrencyKeyForStateSaving(context);
699 }
700 }
701
702 @Override
703 protected void tearDownVisitingContext(FacesContext context)
704 {
705 if (Boolean.TRUE.equals(context.getAttributes().get(StateManager.IS_SAVING_STATE)))
706 {
707 _restoreCurrencyKeyForStateSaving(_stateSavingCurrencyKey);
708 _resetInternalState();
709 }
710
711 _tearDownContextChange();
712 super.tearDownVisitingContext(context);
713 }
714
715 private boolean _assertKeyPreserved(Object oldKey)
716 {
717 Object newKey = getRowKey();
718 return (oldKey != null) ? oldKey.equals(newKey) : (newKey == null);
719 }
720
721 void __encodeBegin(FacesContext context) throws IOException
722 {
723 super.encodeBegin(context);
724 }
725
726
727
728
729
730 boolean __isFirstRender()
731 {
732 InternalState iState = _getInternalState(true);
733 return iState._isFirstRender;
734 }
735
736
737
738
739
740 @Deprecated
741 public String getCurrencyString()
742 {
743 return getClientRowKey();
744 }
745
746
747
748
749
750 @Deprecated
751 public void setCurrencyString(String currency)
752 {
753 setClientRowKey(currency);
754 }
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770 public String getClientRowKey()
771 {
772
773
774
775
776
777 Object currencyObject = _getCurrencyKey();
778 if (currencyObject == null)
779 return null;
780
781 Object initKey = _getCurrencyKeyForInitialStampState();
782 if (_equals(currencyObject, initKey))
783 return null;
784
785 FacesContext fc = FacesContext.getCurrentInstance();
786 String key = getClientRowKeyManager().getClientRowKey(fc, this, currencyObject);
787 return key;
788 }
789
790
791
792
793
794
795
796
797 private Object _getCurrencyKey()
798 {
799
800
801
802
803 InternalState iState = _getInternalState(false);
804 if (iState == null)
805 return null;
806
807 return (iState._model != null)
808 ? getRowKey()
809 : _getCurrencyKeyForInitialStampState();
810 }
811
812
813
814
815
816
817 public void setClientRowKey(String clientRowKey)
818 {
819 if (clientRowKey == null)
820 {
821 setRowKey(_getCurrencyKeyForInitialStampState());
822 return;
823 }
824
825 FacesContext fc = FacesContext.getCurrentInstance();
826 Object rowkey = getClientRowKeyManager().getRowKey(fc, this, clientRowKey);
827
828 if (rowkey == null)
829 {
830 _LOG.severe("CANNOT_FIND_ROWKEY",clientRowKey);
831 }
832 else
833 setRowKey(rowkey);
834 }
835
836 public void processRestoreState(
837 FacesContext context,
838 Object state)
839 {
840 boolean inContextAtMethodInvocation = _inContext;
841 if (!inContextAtMethodInvocation)
842 {
843 _setupContextChange();
844 }
845
846 try
847 {
848 super.processRestoreState(context, state);
849 }
850 finally
851 {
852 if (!inContextAtMethodInvocation)
853 {
854 _tearDownContextChange();
855 }
856 }
857 }
858
859 public void processUpdates(FacesContext context)
860 {
861 boolean inContextAtMethodInvocation = _inContext;
862 if (!inContextAtMethodInvocation)
863 {
864 _setupContextChange();
865 }
866
867 try
868 {
869 super.processUpdates(context);
870 }
871 finally
872 {
873 if (!inContextAtMethodInvocation)
874 {
875 _tearDownContextChange();
876 }
877 }
878 }
879
880 public void processValidators(FacesContext context)
881 {
882 boolean inContextAtMethodInvocation = _inContext;
883 if (!inContextAtMethodInvocation)
884 {
885 _setupContextChange();
886 }
887
888 try
889 {
890 super.processValidators(context);
891 }
892 finally
893 {
894 if (!inContextAtMethodInvocation)
895 {
896 _tearDownContextChange();
897 }
898 }
899 }
900
901 public void processEvent(ComponentSystemEvent event)
902 throws AbortProcessingException
903 {
904 boolean inContextAtMethodInvocation = _inContext;
905 if (!inContextAtMethodInvocation)
906 {
907 _setupContextChange();
908 }
909
910 try
911 {
912 super.processEvent(event);
913 }
914 finally
915 {
916 if (!inContextAtMethodInvocation)
917 {
918 _tearDownContextChange();
919 }
920 }
921 }
922
923
924
925
926
927
928
929
930
931
932 @Override
933 public final String getContainerClientId(FacesContext context)
934 {
935 String id = getClientId(context);
936 String key = getClientRowKey();
937 if (key != null)
938 {
939 StringBuilder bld = __getSharedStringBuilder();
940 bld.append(id).append(NamingContainer.SEPARATOR_CHAR).append(key);
941 id = bld.toString();
942 }
943
944 return id;
945 }
946
947
948
949
950
951
952
953 protected final void preRowDataChange()
954 {
955 _saveStampState();
956 InternalState iState = _getInternalState(true);
957
958 iState._currentRowKey = _NULL;
959
960 if (iState._model != null)
961 iState._model.removeRowKeyChangeListener(iState);
962 }
963
964
965
966
967
968
969
970
971 protected final void postRowDataChange()
972 {
973 Object rowData = getRowData();
974 if (_LOG.isFinest() && (rowData == null))
975 {
976 _LOG.finest("rowData is null at rowIndex:"+getRowIndex()+
977 " and currencyKey:"+getRowKey());
978 }
979
980 InternalState iState = _getInternalState(true);
981 if (rowData == null)
982 {
983
984
985 if (iState._prevVarValue != _NULL)
986 {
987 _setELVar(iState._var, iState._prevVarValue);
988 iState._prevVarValue = _NULL;
989 }
990 if (iState._prevVarStatus != _NULL)
991 {
992 _setELVar(iState._varStatus, iState._prevVarStatus);
993 iState._prevVarStatus = _NULL;
994 }
995 }
996 else
997 {
998 if (iState._var != null)
999 {
1000 Object oldData = _setELVar(iState._var, rowData);
1001 if (iState._prevVarValue == _NULL)
1002 iState._prevVarValue = oldData;
1003 }
1004
1005
1006
1007
1008 if ((iState._varStatus != null) && (iState._prevVarStatus == _NULL))
1009 {
1010 Map<String, Object> varStatusMap = createVarStatusMap();
1011 iState._prevVarStatus = _setELVar(iState._varStatus, varStatusMap);
1012 }
1013 }
1014
1015 _restoreStampState();
1016
1017
1018
1019
1020 List<UIComponent> stamps = getStamps();
1021
1022 for (UIComponent stamp : stamps)
1023 UIXComponent.clearCachedClientIds(stamp);
1024 }
1025
1026
1027
1028
1029
1030
1031 @SuppressWarnings("unchecked")
1032 protected List<UIComponent> getStamps()
1033 {
1034 return getChildren();
1035 }
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046 private Object _getCurrencyKeyForInitialStampState()
1047 {
1048 InternalState iState = _getInternalState(false);
1049 if (iState == null)
1050 return null;
1051
1052 Object rowKey = iState._initialStampStateKey;
1053 return (rowKey == _NULL) ? null : rowKey;
1054 }
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064 @SuppressWarnings("unchecked")
1065 protected Object saveStampState(FacesContext context, UIComponent stamp)
1066 {
1067 if (stamp.isTransient())
1068 return null;
1069
1070 boolean needsTearDownContext = false;
1071
1072 if(stamp instanceof FlattenedComponent && stamp instanceof UIXComponent)
1073 {
1074 ((UIXComponent)stamp).setupVisitingContext(context);
1075 needsTearDownContext = true;
1076 }
1077
1078 Object[] state = null;
1079
1080 try
1081 {
1082
1083
1084
1085
1086
1087
1088
1089
1090 Object stampState = StampState.saveStampState(context, stamp);
1091
1092
1093
1094
1095 assert(!(stampState instanceof Object[]));
1096
1097 int facetCount = stamp.getFacetCount();
1098
1099 if (facetCount > 0)
1100 {
1101 Map<String, Object> facetState = null;
1102
1103 Map<String, UIComponent> facetMap = stamp.getFacets();
1104
1105 for(Map.Entry<String, UIComponent> entry : facetMap.entrySet())
1106 {
1107 Object singleFacetState = saveStampState(context, entry.getValue());
1108 if (singleFacetState == null)
1109 continue;
1110
1111
1112
1113 if (facetState == null)
1114 {
1115 facetState = new HashMap<String, Object>(facetCount);
1116 }
1117
1118 facetState.put(entry.getKey(), singleFacetState);
1119 }
1120
1121
1122
1123 if (facetState != null)
1124 {
1125 state = new Object[3];
1126 state[2] = facetState;
1127 }
1128 }
1129
1130
1131
1132 Object childState = StampState.saveChildStampState(context,
1133 stamp,
1134 this);
1135 if (childState != null)
1136 {
1137
1138
1139 if (state == null)
1140 state = new Object[2];
1141 state[1] = childState;
1142 }
1143
1144
1145
1146 if (state == null)
1147 return stampState;
1148
1149
1150 state[0] = stampState;
1151 }
1152 finally
1153 {
1154 if(needsTearDownContext)
1155 ((UIXComponent)stamp).tearDownVisitingContext(context);
1156 }
1157 return state;
1158 }
1159
1160
1161
1162
1163
1164
1165
1166 @SuppressWarnings("unchecked")
1167 protected void restoreStampState(FacesContext context, UIComponent stamp,
1168 Object stampState)
1169 {
1170
1171 if (stampState == null)
1172 {
1173 return;
1174 }
1175
1176
1177
1178 if (!(stampState instanceof Object[]))
1179 {
1180 StampState.restoreStampState(context, stamp, stampState);
1181
1182 return;
1183 }
1184
1185 Object[] state = (Object[]) stampState;
1186 int stateSize = state.length;
1187
1188 assert(stateSize >= 1);
1189
1190 StampState.restoreStampState(context, stamp, state[0]);
1191
1192
1193
1194 if (stateSize >= 3 && (state[2] instanceof Map))
1195 {
1196 Map<String, Object> facetStateMap = (Map<String, Object>) state[2];
1197
1198
1199 assert(facetStateMap != null);
1200
1201 for (String facetName : facetStateMap.keySet())
1202 {
1203 Object facetState = facetStateMap.get(facetName);
1204 if (facetState != null)
1205 restoreStampState(context, stamp.getFacet(facetName), facetState);
1206 }
1207 }
1208
1209
1210 if (stateSize >= 2)
1211 {
1212 StampState.restoreChildStampState(context,
1213 stamp,
1214 this,
1215 state[1]);
1216 }
1217 }
1218
1219
1220
1221
1222
1223
1224
1225
1226 protected final void processComponent(
1227 FacesContext context,
1228 UIComponent component,
1229 PhaseId phaseId)
1230 {
1231 if (component != null)
1232 {
1233 if (phaseId == PhaseId.APPLY_REQUEST_VALUES)
1234 component.processDecodes(context);
1235 else if (phaseId == PhaseId.PROCESS_VALIDATIONS)
1236 component.processValidators(context);
1237 else if (phaseId == PhaseId.UPDATE_MODEL_VALUES)
1238 component.processUpdates(context);
1239 else
1240 throw new IllegalArgumentException(_LOG.getMessage(
1241 "BAD_PHASEID",phaseId));
1242 }
1243 }
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253 protected abstract void processFacetsAndChildren(
1254 FacesContext context,
1255 PhaseId phaseId);
1256
1257
1258
1259
1260 protected final CollectionModel getCollectionModel()
1261 {
1262 return getCollectionModel(true);
1263 }
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274 public final ClientRowKeyManager getClientRowKeyManager()
1275 {
1276
1277
1278
1279 InternalState iState = _getInternalState(true);
1280 if (iState._clientKeyMgr == null)
1281 {
1282 FacesContext fc = FacesContext.getCurrentInstance();
1283 Renderer r = getRenderer(fc);
1284 iState._clientKeyMgr = (r instanceof ClientRowKeyManagerFactory)
1285 ? ((ClientRowKeyManagerFactory) r).createClientRowKeyManager(fc, this)
1286 : new DefaultClientKeyManager();
1287 }
1288 return iState._clientKeyMgr;
1289 }
1290
1291 public boolean invokeOnComponent(FacesContext context,
1292 String clientId,
1293 ContextCallback callback)
1294 throws FacesException
1295 {
1296 boolean invokedComponent;
1297 setupVisitingContext(context);
1298
1299 try
1300 {
1301 String thisClientId = getClientId(context);
1302 if (clientId.equals(thisClientId))
1303 {
1304 if (!_getAndMarkFirstInvokeForRequest(context, clientId))
1305 {
1306
1307
1308 _init();
1309
1310 __flushCachedModel();
1311 }
1312
1313 RequestContext requestContext = RequestContext.getCurrentInstance();
1314 requestContext.pushCurrentComponent(context, this);
1315 pushComponentToEL(context, null);
1316
1317 try
1318 {
1319 callback.invokeContextCallback(context, this);
1320 }
1321 finally
1322 {
1323 popComponentFromEL(context);
1324 requestContext.popCurrentComponent(context, this);
1325 }
1326
1327 invokedComponent = true;
1328 }
1329 else
1330 {
1331
1332
1333 int thisClientIdLength = thisClientId.length();
1334 if (clientId.startsWith(thisClientId) &&
1335 (clientId.charAt(thisClientIdLength) == NamingContainer.SEPARATOR_CHAR))
1336 {
1337 if (!_getAndMarkFirstInvokeForRequest(context, thisClientId))
1338 {
1339
1340
1341 _init();
1342
1343 __flushCachedModel();
1344 }
1345
1346 String postId = clientId.substring(thisClientIdLength + 1);
1347 int sepIndex = postId.indexOf(NamingContainer.SEPARATOR_CHAR);
1348
1349
1350 if (sepIndex < 0)
1351 return invokeOnChildrenComponents(context, clientId, callback);
1352 else
1353 {
1354 String currencyString = postId.substring(0, sepIndex);
1355 Object rowKey = getClientRowKeyManager().getRowKey(context, this, currencyString);
1356
1357
1358
1359 if (rowKey != null)
1360 {
1361 Object oldRowKey = getRowKey();
1362 try
1363 {
1364 setRowKey(rowKey);
1365 invokedComponent = invokeOnChildrenComponents(context, clientId, callback);
1366 }
1367 finally
1368 {
1369
1370 setRowKey(oldRowKey);
1371 }
1372 }
1373 else
1374 {
1375 invokedComponent = invokeOnChildrenComponents(context, clientId, callback);
1376 }
1377 }
1378 }
1379 else
1380 {
1381
1382 invokedComponent = false;
1383 }
1384 }
1385 }
1386 finally
1387 {
1388 tearDownVisitingContext(context);
1389 }
1390
1391 return invokedComponent;
1392 }
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408 @Override
1409 protected boolean visitChildren(
1410 VisitContext visitContext,
1411 VisitCallback callback)
1412 {
1413 return defaultVisitChildren(visitContext, callback);
1414 }
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424 protected boolean visitChildrenWithoutIterating(
1425 VisitContext visitContext,
1426 VisitCallback callback)
1427 {
1428 return visitAllChildren(visitContext, callback);
1429 }
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439 protected final boolean defaultVisitChildren(
1440 VisitContext visitContext,
1441 VisitCallback callback)
1442 {
1443 if (ComponentUtils.isSkipIterationVisit(visitContext))
1444 {
1445 return visitChildrenWithoutIterating(visitContext, callback);
1446 }
1447 else
1448 {
1449 boolean doneVisiting;
1450
1451
1452
1453 int oldRowIndex = getRowIndex();
1454 setRowIndex(-1);
1455
1456 try
1457 {
1458
1459 doneVisiting = visitUnstampedFacets(visitContext, callback);
1460
1461 if (!doneVisiting)
1462 {
1463 doneVisiting = _visitStampedColumnFacets(visitContext, callback);
1464
1465
1466 if (!doneVisiting)
1467 {
1468 doneVisiting = visitData(visitContext, callback);
1469 }
1470 }
1471 }
1472 finally
1473 {
1474
1475 setRowIndex(oldRowIndex);
1476 }
1477
1478 return doneVisiting;
1479 }
1480 }
1481
1482
1483
1484
1485
1486
1487
1488 protected boolean visitUnstampedFacets(
1489 VisitContext visitContext,
1490 VisitCallback callback)
1491 {
1492
1493 if (getFacetCount() > 0)
1494 {
1495 for (UIComponent facet : getFacets().values())
1496 {
1497 if (UIXComponent.visitTree(visitContext, facet, callback))
1498 {
1499 return true;
1500 }
1501 }
1502 }
1503
1504 return false;
1505 }
1506
1507
1508
1509
1510
1511
1512 private static class ColumnFacetsOnlyVisitContext extends VisitContextWrapper
1513 {
1514 public ColumnFacetsOnlyVisitContext(VisitContext wrappedContext)
1515 {
1516 _wrapped = wrappedContext;
1517 }
1518
1519 @Override
1520 public VisitContext getWrapped()
1521 {
1522 return _wrapped;
1523 }
1524
1525 @Override
1526 public VisitResult invokeVisitCallback(UIComponent component, VisitCallback callback)
1527 {
1528 if (component instanceof UIXColumn)
1529 {
1530 if (component.getFacetCount() > 0)
1531 {
1532
1533 for (UIComponent facetChild : component.getFacets().values())
1534 {
1535 if (UIXComponent.visitTree(getWrapped(), facetChild, callback))
1536 return VisitResult.COMPLETE;
1537 }
1538
1539
1540 for (UIComponent child : component.getChildren())
1541 {
1542 if (UIXComponent.visitTree(this, child, callback))
1543 return VisitResult.COMPLETE;
1544 }
1545 }
1546 }
1547
1548
1549
1550 return VisitResult.REJECT;
1551 }
1552
1553 private final VisitContext _wrapped;
1554 }
1555
1556
1557
1558
1559
1560 protected static final class NoColumnFacetsVisitContext extends VisitContextWrapper
1561 {
1562 NoColumnFacetsVisitContext(VisitContext wrapped)
1563 {
1564 _wrapped = wrapped;
1565 }
1566
1567 @Override
1568 public VisitContext getWrapped()
1569 {
1570 return _wrapped;
1571 }
1572
1573 @Override
1574 public VisitResult invokeVisitCallback(UIComponent component, VisitCallback callback)
1575 {
1576 if (component instanceof UIXColumn)
1577 {
1578 if (component.getChildCount() > 0)
1579 {
1580
1581 for (UIComponent child : component.getChildren())
1582 {
1583 if (UIXComponent.visitTree(this, child, callback))
1584 return VisitResult.COMPLETE;
1585 }
1586 }
1587
1588 return VisitResult.REJECT;
1589 }
1590 else
1591 {
1592
1593
1594
1595
1596
1597 VisitContext wrappedContext = getWrapped();
1598 VisitResult visitResult = wrappedContext.invokeVisitCallback(component, callback);
1599
1600 if (visitResult == VisitResult.ACCEPT)
1601 {
1602
1603 return (UIXComponent.visitChildren(wrappedContext, component, callback)) ?
1604 VisitResult.COMPLETE : VisitResult.REJECT;
1605 }
1606 else
1607 {
1608 return visitResult;
1609 }
1610 }
1611 }
1612
1613 private final VisitContext _wrapped;
1614 }
1615
1616
1617
1618
1619 private boolean _visitStampedColumnFacets(
1620 VisitContext visitContext,
1621 VisitCallback callback)
1622 {
1623
1624 List<UIComponent> stamps = getStamps();
1625
1626 if (!stamps.isEmpty())
1627 {
1628 VisitContext columnVisitingContext = new ColumnFacetsOnlyVisitContext(visitContext);
1629
1630 for (UIComponent stamp : stamps)
1631 {
1632 if (UIXComponent.visitTree(columnVisitingContext, stamp, callback))
1633 {
1634 return true;
1635 }
1636 }
1637 }
1638
1639 return false;
1640 }
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653 protected abstract boolean visitData(
1654 VisitContext visitContext,
1655 VisitCallback callback);
1656
1657
1658
1659
1660
1661
1662 protected final CollectionModel getCollectionModel(
1663 boolean createIfNull)
1664 {
1665 InternalState iState = _getInternalState(true);
1666 if (iState._model == null && createIfNull)
1667 {
1668
1669
1670
1671
1672
1673
1674 _init();
1675
1676 iState._value = getValue();
1677 iState._model = createCollectionModel(null, iState._value);
1678 postCreateCollectionModel(iState._model);
1679 assert iState._model != null;
1680 }
1681
1682 if ((iState._initialStampStateKey == _NULL) &&
1683 (iState._model != null))
1684 {
1685
1686
1687
1688
1689
1690 iState._initialStampStateKey = iState._model.getRowKey();
1691 }
1692 return iState._model;
1693 }
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705 protected abstract CollectionModel createCollectionModel(
1706 CollectionModel current,
1707 Object value);
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718 protected void postCreateCollectionModel(CollectionModel model)
1719 {
1720
1721 }
1722
1723
1724
1725
1726
1727 protected abstract Object getValue();
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740 protected Map<String, Object> createVarStatusMap()
1741 {
1742 return new AbstractMap<String, Object>()
1743 {
1744 @Override
1745 public Object get(Object key)
1746 {
1747
1748
1749 if ("model".equals(key))
1750 return getCollectionModel();
1751 if ("rowKey".equals(key))
1752 return getRowKey();
1753 if ("index".equals(key))
1754 return Integer.valueOf(getRowIndex());
1755 if("hierarchicalIndex".equals(key))
1756 {
1757 int rowIndex = getRowIndex();
1758 return rowIndex>=0 ? new Integer[]{rowIndex}: new Integer[]{};
1759 }
1760 if("hierarchicalLabel".equals(key))
1761 {
1762 int rowIndex = getRowIndex();
1763 return rowIndex>=0 ? Integer.toString(rowIndex+1): "";
1764 }
1765 if ("current".equals(key))
1766 return getRowData();
1767 return null;
1768 }
1769
1770 @Override
1771 public Set<Map.Entry<String, Object>> entrySet()
1772 {
1773 return Collections.emptySet();
1774 }
1775 };
1776 }
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788 public boolean isRowLocallyAvailable(int rowIndex)
1789 {
1790 return getCollectionModel().isRowLocallyAvailable(rowIndex);
1791 }
1792
1793
1794
1795
1796
1797
1798 public boolean isRowLocallyAvailable(Object rowKey)
1799 {
1800 return getCollectionModel().isRowLocallyAvailable(rowKey);
1801 }
1802
1803
1804
1805
1806
1807
1808 public boolean areRowsLocallyAvailable(int rowCount)
1809 {
1810 return getCollectionModel().areRowsLocallyAvailable(rowCount);
1811 }
1812
1813
1814
1815
1816
1817
1818
1819 public boolean areRowsLocallyAvailable(int startIndex, int rowCount)
1820 {
1821 return getCollectionModel().areRowsLocallyAvailable(startIndex, rowCount);
1822 }
1823
1824
1825
1826
1827
1828
1829
1830 public boolean areRowsLocallyAvailable(Object startRowKey, int rowCount)
1831 {
1832 return getCollectionModel().areRowsLocallyAvailable(startRowKey, rowCount);
1833 }
1834
1835
1836
1837
1838
1839
1840 public int getEstimatedRowCount()
1841 {
1842 return getCollectionModel().getEstimatedRowCount();
1843 }
1844
1845
1846
1847
1848
1849
1850 public LocalRowKeyIndex.Confidence getEstimatedRowCountConfidence()
1851 {
1852 return getCollectionModel().getEstimatedRowCountConfidence();
1853 }
1854
1855
1856
1857
1858 public void clearLocalCache()
1859 {
1860 getCollectionModel().clearLocalCache();
1861 }
1862
1863
1864
1865
1866
1867
1868 public void clearCachedRows(int startingIndex, int rowsToClear)
1869 {
1870 getCollectionModel().clearCachedRows(startingIndex, rowsToClear);
1871 }
1872
1873
1874
1875
1876
1877
1878 public void clearCachedRows(Object startingRowKey, int rowsToClear)
1879 {
1880 getCollectionModel().clearCachedRows(startingRowKey, rowsToClear);
1881 }
1882
1883
1884
1885
1886
1887 public void clearCachedRow(int index)
1888 {
1889 getCollectionModel().clearCachedRow(index);
1890 }
1891
1892
1893
1894
1895
1896 public void clearCachedRow(Object rowKey)
1897 {
1898 getCollectionModel().clearCachedRow(rowKey);
1899 }
1900
1901
1902
1903
1904
1905
1906 public LocalRowKeyIndex.LocalCachingStrategy getCachingStrategy()
1907 {
1908 return getCollectionModel().getCachingStrategy();
1909 }
1910
1911
1912
1913
1914
1915
1916 public void ensureRowsAvailable(int rowCount)
1917 {
1918 getCollectionModel().ensureRowsAvailable(rowCount);
1919 }
1920
1921
1922
1923
1924
1925
1926 void __init()
1927 {
1928 InternalState iState = _getInternalState(true);
1929 iState._var = getVar();
1930 if (_LOG.isFine() && (iState._var == null))
1931 {
1932 _LOG.fine("'var' attribute is null.");
1933 }
1934 iState._varStatus = getVarStatus();
1935 if (_LOG.isFinest() && (iState._varStatus == null))
1936 {
1937 _LOG.finest("'varStatus' attribute is null.");
1938 }
1939 }
1940
1941
1942
1943
1944
1945
1946
1947
1948 protected void processFlattenedChildrenBegin(ComponentProcessingContext cpContext)
1949 {
1950
1951
1952 _init();
1953 __flushCachedModel();
1954 }
1955
1956 private void _init()
1957 {
1958 InternalState iState = _getInternalState(true);
1959 if (!iState._isInitialized)
1960 {
1961 assert iState._model == null;
1962 iState._isInitialized = true;
1963 __init();
1964 }
1965 }
1966
1967 void __flushCachedModel()
1968 {
1969 InternalState iState = _getInternalState(true);
1970 Object value = getValue();
1971 if (iState._value != value)
1972 {
1973 CollectionModel oldModel = iState._model;
1974 iState._value = value;
1975 iState._model = createCollectionModel(iState._model, value);
1976 postCreateCollectionModel(iState._model);
1977
1978
1979
1980
1981
1982 if (oldModel != iState._model)
1983 {
1984 if (oldModel != null)
1985 {
1986 oldModel.removeRowKeyChangeListener(iState);
1987 }
1988
1989 if (iState._currentRowKey != _NULL)
1990 {
1991 iState._model.addRowKeyChangeListener(iState);
1992 }
1993 }
1994 }
1995 }
1996
1997
1998
1999
2000 static private boolean _getAndMarkFirstInvokeForRequest(
2001 FacesContext context, String clientId)
2002 {
2003
2004
2005 Map<String, Object> requestMap = context.getExternalContext().getRequestMap();
2006 String key = _INVOKE_KEY + clientId;
2007
2008 if (requestMap.containsKey(key))
2009 return true;
2010
2011
2012 requestMap.put(key, Boolean.TRUE);
2013 return false;
2014 }
2015
2016
2017
2018
2019
2020 Object __getMyStampState()
2021 {
2022 return _state;
2023 }
2024
2025
2026
2027
2028
2029
2030 void __setMyStampState(Object stampState)
2031 {
2032 InternalState iState = (InternalState) stampState;
2033 _state = iState;
2034 }
2035
2036
2037
2038
2039
2040
2041
2042 void __resetMyStampState()
2043 {
2044 _state = null;
2045 }
2046
2047
2048
2049
2050
2051
2052 boolean __hasEvent()
2053 {
2054 InternalState iState = _getInternalState(true);
2055 return iState._hasEvent;
2056 }
2057
2058
2059
2060
2061
2062
2063
2064 private void _saveStampState()
2065 {
2066
2067
2068
2069 StampState stampState = _getStampState();
2070 Map<String, String> idToIndexMap = _getIdToIndexMap();
2071 FacesContext context = getFacesContext();
2072 Object currencyObj = getRowKey();
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084 for (UIComponent stamp : getStamps())
2085 {
2086 Object state = saveStampState(context, stamp);
2087
2088
2089
2090
2091 String compId = stamp.getId();
2092 String stampId = idToIndexMap.get(compId);
2093 if (stampId == null)
2094 {
2095 stampId = String.valueOf(idToIndexMap.size());
2096 idToIndexMap.put(compId, stampId);
2097 }
2098 stampState.put(currencyObj, stampId, state);
2099 if (_LOG.isFinest())
2100 _LOG.finest("saving stamp state for currencyObject:"+currencyObj+
2101 " and stampId:"+stampId);
2102 }
2103 }
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113 private void _restoreStampState()
2114 {
2115 StampState stampState = _getStampState();
2116 Map<String, String> idToIndexMap = _getIdToIndexMap();
2117 FacesContext context = getFacesContext();
2118 Object currencyObj = getRowKey();
2119 for(UIComponent stamp : getStamps())
2120 {
2121
2122
2123
2124
2125 String compId = stamp.getId();
2126 String stampId = idToIndexMap.get(compId);
2127 Object state = stampState.get(currencyObj, stampId);
2128 if (state == null)
2129 {
2130 Object iniStateObj = _getCurrencyKeyForInitialStampState();
2131 state = stampState.get(iniStateObj, stampId);
2132
2133
2134
2135
2136
2137
2138 }
2139 restoreStampState(context, stamp, state);
2140 }
2141 }
2142
2143 private Map<String, String> _getIdToIndexMap()
2144 {
2145 InternalState iState = _getInternalState(true);
2146 if (iState._idToIndexMap == null)
2147 iState._idToIndexMap = new HashMap<String, String>();
2148 return iState._idToIndexMap;
2149 }
2150
2151 private InternalState _getInternalState(boolean create)
2152 {
2153 if ((_state == null) && create)
2154 {
2155 _state = new InternalState();
2156 }
2157 return _state;
2158 }
2159
2160 private StampState _getStampState()
2161 {
2162 InternalState iState = _getInternalState(true);
2163 if (iState._stampState == null)
2164 iState._stampState = new StampState();
2165
2166 return iState._stampState;
2167 }
2168
2169
2170
2171
2172
2173
2174
2175 private Object _setELVar(String varName, Object newData)
2176 {
2177 if (varName == null)
2178 return null;
2179
2180
2181
2182
2183 return setupELVariable(getFacesContext(), varName, newData);
2184 }
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196 protected Object setupELVariable(
2197 FacesContext context,
2198 String name,
2199 Object value
2200 )
2201 {
2202 Args.notNull(name, "name");
2203 return TableUtils.setupELVariable(context, name, value);
2204 }
2205
2206 private static boolean _equals(Object a, Object b)
2207 {
2208 if (b == null)
2209 return (a == null);
2210
2211 return b.equals(a);
2212 }
2213
2214 private void _setupContextChange()
2215 {
2216 if (_inSuspendOrResume)
2217 {
2218
2219
2220 return;
2221 }
2222
2223 ComponentContextManager compCtxMgr =
2224 RequestContext.getCurrentInstance().getComponentContextManager();
2225
2226 compCtxMgr.pushChange(new CollectionComponentChange(this));
2227
2228 _inContext = true;
2229 }
2230
2231 private void _tearDownContextChange()
2232 {
2233 if (_inSuspendOrResume)
2234 {
2235
2236
2237 return;
2238 }
2239
2240 try
2241 {
2242 ComponentContextManager compCtxMgr =
2243 RequestContext.getCurrentInstance().getComponentContextManager();
2244 ComponentContextChange change = compCtxMgr.peekChange();
2245
2246 if (change instanceof CollectionComponentChange &&
2247 ((CollectionComponentChange)change)._component == this)
2248 {
2249
2250 compCtxMgr.popChange();
2251 }
2252 else
2253 {
2254 _LOG.severe("COLLECTION_CHANGE_TEARDOWN", new Object[] { getId(), change });
2255 }
2256 }
2257 catch (RuntimeException re)
2258 {
2259 _LOG.severe(re);
2260 }
2261 finally
2262 {
2263 _inContext = false;
2264 }
2265 }
2266
2267 private void _verifyComponentInContext()
2268 {
2269 if (_inSuspendOrResume)
2270 {
2271 return;
2272 }
2273
2274 if (!_inContext)
2275 {
2276 if (_LOG.isWarning())
2277 {
2278 _LOG.warning("COLLECTION_NOT_IN_CONTEXT",
2279 new Object[] { getParent() == null ? getId() : getClientId() });
2280 if (_LOG.isFine())
2281 {
2282 Thread.currentThread().dumpStack();
2283 }
2284 }
2285 }
2286 }
2287
2288
2289
2290
2291
2292
2293
2294
2295 private Object _resetCurrencyKeyForStateSaving(FacesContext context)
2296 {
2297
2298
2299
2300
2301
2302 Object currencyKey = _getCurrencyKey();
2303
2304
2305
2306 if (currencyKey != null)
2307 {
2308 if (_LOG.isWarning())
2309 {
2310 String scopedId = ComponentUtils.getScopedIdForComponent(this, context.getViewRoot());
2311 String viewId = context.getViewRoot() == null? null: context.getViewRoot().getViewId();
2312 _LOG.warning("ROWKEY_NOT_RESET", new Object[]
2313 { scopedId, viewId });
2314 }
2315 }
2316
2317 Object initKey = _getCurrencyKeyForInitialStampState();
2318 if (currencyKey != initKey)
2319 {
2320 setRowKey(initKey);
2321 }
2322
2323 return currencyKey;
2324 }
2325
2326
2327
2328
2329
2330
2331 private void _restoreCurrencyKeyForStateSaving(Object key)
2332 {
2333 Object currencyKey = key;
2334 Object initKey = _getCurrencyKeyForInitialStampState();
2335
2336 if (currencyKey != initKey)
2337 {
2338 setRowKey(currencyKey);
2339 }
2340 }
2341
2342
2343
2344
2345 private void _resetInternalState()
2346 {
2347 InternalState iState = _getInternalState(false);
2348 if (iState != null)
2349 {
2350 iState._value = null;
2351
2352 if (iState._model != null)
2353 {
2354 iState._model.removeRowKeyChangeListener(iState);
2355 iState._model = null;
2356 }
2357 }
2358 }
2359
2360 private static final class DefaultClientKeyManager extends ClientRowKeyManager
2361 {
2362 public void clear()
2363 {
2364 _currencyCache.clear();
2365 }
2366
2367
2368
2369
2370 @Override
2371 public Object getRowKey(FacesContext context, UIComponent component, String clientRowKey)
2372 {
2373 ValueMap<Object,String> currencyCache = _currencyCache;
2374 Object rowkey = currencyCache.getKey(clientRowKey);
2375 return rowkey;
2376 }
2377
2378
2379
2380
2381 @Override
2382 public String getClientRowKey(FacesContext context, UIComponent component, Object rowKey)
2383 {
2384 assert rowKey != null;
2385
2386 ValueMap<Object,String> currencyCache = _currencyCache;
2387 String key = currencyCache.get(rowKey);
2388
2389 if (key == null)
2390 {
2391
2392 key = _createToken(currencyCache);
2393
2394 if (_LOG.isFiner())
2395 _LOG.finer("Storing token:"+key+
2396 " for rowKey:"+rowKey);
2397
2398 currencyCache.put(rowKey, key);
2399 }
2400 return key;
2401 }
2402
2403
2404
2405
2406 @Override
2407 public boolean replaceRowKey(FacesContext context, UIComponent component, Object oldRowKey, Object newRowKey)
2408 {
2409 assert oldRowKey != null && newRowKey != null;
2410
2411 ValueMap<Object,String> currencyCache = _currencyCache;
2412 String key = currencyCache.remove(oldRowKey);
2413
2414 if (key != null)
2415 {
2416 currencyCache.put(newRowKey, key);
2417 }
2418 return key != null;
2419 }
2420
2421
2422
2423 private static String _createToken(ValueMap<Object,String> currencyCache)
2424 {
2425 String key = String.valueOf(currencyCache.size());
2426 return key;
2427 }
2428
2429 private ValueMap<Object,String> _currencyCache = new ValueMap<Object,String>();
2430 private static final long serialVersionUID = 1L;
2431 }
2432
2433
2434
2435
2436
2437
2438 private static final class InternalState implements RowKeyChangeListener, Serializable
2439 {
2440 private transient boolean _hasEvent = false;
2441 private transient Object _prevVarValue = _NULL;
2442 private transient Object _prevVarStatus = _NULL;
2443 private transient String _var = null;
2444 private transient String _varStatus = null;
2445 private transient Object _value = null;
2446 private transient CollectionModel _model = null;
2447 private transient Object _currentRowKey = _NULL;
2448 private transient boolean _clearTokenCache = false;
2449
2450
2451 private transient boolean _isFirstRender = true;
2452 private transient boolean _isInitialized = false;
2453
2454 private transient Object _initialStampStateKey = _NULL;
2455
2456 private ClientRowKeyManager _clientKeyMgr = null;
2457 private StampState _stampState = null;
2458
2459
2460
2461
2462
2463
2464 private Map<String, String> _idToIndexMap = null;
2465
2466 public void onRowKeyChange(RowKeyChangeEvent rowKeyChangeEvent)
2467 {
2468 Object newKey = rowKeyChangeEvent.getNewRowKey();
2469 Object oldKey = rowKeyChangeEvent.getOldRowKey();
2470
2471 if (newKey != null && oldKey != null && !newKey.equals(oldKey))
2472 {
2473
2474 if (oldKey.equals(_currentRowKey))
2475 _currentRowKey = newKey;
2476
2477
2478 if (_stampState == null || _idToIndexMap == null)
2479 return;
2480
2481 int stampCompCount = _idToIndexMap.size();
2482
2483 for (int index = 0; index < stampCompCount; index++)
2484 {
2485 String stampId = String.valueOf(index);
2486 Object state = _stampState.get(oldKey, stampId);
2487 if (state == null)
2488 continue;
2489 _stampState.put(oldKey, stampId, null);
2490 _stampState.put(newKey, stampId, state);
2491 }
2492 }
2493 }
2494
2495 private void readObject(ObjectInputStream in)
2496 throws IOException, ClassNotFoundException
2497 {
2498 in.defaultReadObject();
2499
2500 _prevVarValue = _NULL;
2501 _prevVarStatus = _NULL;
2502 _currentRowKey = _NULL;
2503 _initialStampStateKey = _NULL;
2504
2505
2506 _isFirstRender = false;
2507 }
2508
2509 private static final long serialVersionUID = 1L;
2510 }
2511
2512
2513
2514
2515
2516
2517 private static class CollectionComponentChange
2518 extends ComponentContextChange
2519 {
2520 private CollectionComponentChange(
2521 UIXCollection component)
2522 {
2523 _component = component;
2524 }
2525
2526 public void suspend(
2527 FacesContext facesContext)
2528 {
2529 _component._inSuspendOrResume = true;
2530
2531 try
2532 {
2533 InternalState iState = _component._getInternalState(false);
2534 if (iState == null || iState._model == null || iState._currentRowKey == _NULL)
2535 {
2536
2537
2538
2539
2540
2541
2542
2543
2544 _rowKey = null;
2545 }
2546 else
2547 {
2548 _rowKey = _component.getRowKey();
2549
2550
2551
2552
2553 if (_rowKey != null)
2554 {
2555 _component.setRowKey(null);
2556 }
2557 }
2558
2559 _component._inContext = false;
2560 }
2561 finally
2562 {
2563 _component._inSuspendOrResume = false;
2564 }
2565 }
2566
2567 public void resume(
2568 FacesContext facesContext)
2569 {
2570 _component._inSuspendOrResume = true;
2571 try
2572 {
2573
2574 if (_rowKey != null)
2575 {
2576 _component.setRowKey(_rowKey);
2577 }
2578
2579 _component._inContext = true;
2580 }
2581 finally
2582 {
2583 _component._inSuspendOrResume = false;
2584 }
2585 }
2586
2587 @Override
2588 public String toString()
2589 {
2590 String className = _component.getClass().getName();
2591 String componentId = _component.getId();
2592 return new StringBuilder(58 + className.length() + componentId.length())
2593 .append("UIXCollection.CollectionComponentChange[Component class: ")
2594 .append(className)
2595 .append(", component ID: ")
2596 .append(componentId)
2597 .append("]")
2598 .toString();
2599 }
2600
2601 private final UIXCollection _component;
2602 private CollectionModel _collectionModel;
2603 private Object _rowKey;
2604 }
2605
2606 private static class CollectionContextEvent
2607 extends WrapperEvent
2608 {
2609 public CollectionContextEvent(
2610 UIComponent source,
2611 FacesEvent event)
2612 {
2613 super(source, event);
2614 }
2615
2616 @SuppressWarnings("compatibility:-7639429485707197863")
2617 private static final long serialVersionUID = 1L;
2618 }
2619
2620
2621
2622
2623
2624 private InternalState _state = null;
2625 private boolean _inSuspendOrResume = false;
2626 private boolean _inContext = false;
2627
2628
2629
2630
2631 private static final Object _NULL = new Object();
2632 private static final String _INVOKE_KEY =
2633 UIXCollection.class.getName() + ".INVOKE";
2634
2635 private transient Object _stateSavingCurrencyKey = null;
2636
2637 private static final TrinidadLogger _LOG = TrinidadLogger.createTrinidadLogger(UIXCollection.class);
2638
2639
2640
2641
2642
2643
2644
2645 enum Transient { TRUE };
2646 }