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.component;
20
21 import java.io.IOException;
22 import java.io.Serializable;
23 import java.sql.ResultSet;
24 import java.util.ArrayList;
25 import java.util.Collection;
26 import java.util.Collections;
27 import java.util.HashMap;
28 import java.util.Iterator;
29 import java.util.List;
30 import java.util.Map;
31
32 import javax.el.ValueExpression;
33 import javax.faces.FacesException;
34 import javax.faces.application.FacesMessage;
35 import javax.faces.component.ContextCallback;
36 import javax.faces.component.EditableValueHolder;
37 import javax.faces.component.NamingContainer;
38 import javax.faces.component.UIComponent;
39 import javax.faces.component.UIComponentBase;
40 import javax.faces.component.visit.VisitCallback;
41 import javax.faces.component.visit.VisitContext;
42 import javax.faces.component.visit.VisitHint;
43 import javax.faces.component.visit.VisitResult;
44 import javax.faces.context.FacesContext;
45 import javax.faces.event.AbortProcessingException;
46 import javax.faces.event.FacesEvent;
47 import javax.faces.event.FacesListener;
48 import javax.faces.event.PhaseId;
49 import javax.faces.model.ArrayDataModel;
50 import javax.faces.model.CollectionDataModel;
51 import javax.faces.model.DataModel;
52 import javax.faces.model.IterableDataModel;
53 import javax.faces.model.ListDataModel;
54 import javax.faces.model.ResultSetDataModel;
55 import javax.faces.model.ScalarDataModel;
56 import javax.faces.render.Renderer;
57
58 import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFComponent;
59 import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFProperty;
60 import org.apache.myfaces.cdi.model.DataModelBuilderProxy;
61 import org.apache.myfaces.shared.renderkit.html.util.SharedStringBuilder;
62 import org.apache.myfaces.util.ExternalSpecifications;
63
64
65
66
67 @JSFComponent(name="ui:repeat", defaultRendererType="facelets.ui.Repeat")
68 public class UIRepeat extends UIComponentBase implements NamingContainer
69 {
70 public static final String COMPONENT_TYPE = "facelets.ui.Repeat";
71
72 public static final String COMPONENT_FAMILY = "facelets";
73
74 private static final String STRING_BUILDER_KEY
75 = UIRepeat.class.getName() + ".SHARED_STRING_BUILDER";
76
77 private final static DataModel<?> EMPTY_MODEL = new ListDataModel<Object>(Collections.emptyList());
78
79 private static final Class<Object[]> OBJECT_ARRAY_CLASS = Object[].class;
80
81 private static final Object[] LEAF_NO_STATE = new Object[]{null,null};
82
83 private Object _initialDescendantComponentState = null;
84
85
86
87
88 private Map<String, Collection<Object[]>> _rowStates = new HashMap<String, Collection<Object[]>>();
89
90
91
92
93
94
95 private Map<String, DataModel> _dataModelMap = new HashMap<String, DataModel>();
96
97
98 private boolean _isValidChilds = true;
99
100 private boolean _emptyModel = false;
101
102 private int _end = -1;
103
104 private int _count;
105
106 private int _index = -1;
107
108 private transient Object _origValue;
109 private transient Object _origVarStatus;
110
111 private transient FacesContext _facesContext;
112
113 static final Integer RESET_MODE_OFF = 0;
114 static final Integer RESET_MODE_SOFT = 1;
115 static final Integer RESET_MODE_HARD = 2;
116
117 public UIRepeat()
118 {
119 setRendererType("facelets.ui.Repeat");
120 }
121
122 @Override
123 public String getFamily()
124 {
125 return COMPONENT_FAMILY;
126 }
127
128 @JSFProperty
129 public int getOffset()
130 {
131 return (Integer) getStateHelper().eval(PropertyKeys.offset, 0);
132 }
133
134 public void setOffset(int offset)
135 {
136 getStateHelper().put(PropertyKeys.offset, offset );
137 }
138
139 @JSFProperty
140 public int getSize()
141 {
142 return (Integer) getStateHelper().eval(PropertyKeys.size, -1);
143 }
144
145 public void setSize(int size)
146 {
147 getStateHelper().put(PropertyKeys.size, size );
148 }
149
150 @JSFProperty
151 public int getStep()
152 {
153 return (Integer) getStateHelper().eval(PropertyKeys.step, 1);
154 }
155
156 public void setStep(int step)
157 {
158 getStateHelper().put(PropertyKeys.step, step );
159 }
160
161 @JSFProperty
162 public int getBegin()
163 {
164 return (Integer) getStateHelper().eval(PropertyKeys.begin, -1);
165 }
166
167 public void setBegin(int begin)
168 {
169 getStateHelper().put(PropertyKeys.begin, begin );
170 }
171
172 @JSFProperty
173 public int getEnd()
174 {
175 return (Integer) getStateHelper().eval(PropertyKeys.end, -1);
176 }
177
178 public void setEnd(int end)
179 {
180 getStateHelper().put(PropertyKeys.end, end );
181 }
182
183 @JSFProperty(literalOnly=true)
184 public String getVar()
185 {
186 return (String) getStateHelper().get(PropertyKeys.var);
187 }
188
189 public void setVar(String var)
190 {
191 getStateHelper().put(PropertyKeys.var, var );
192 }
193
194 @JSFProperty(literalOnly=true)
195 public String getVarStatus ()
196 {
197 return (String) getStateHelper().get(PropertyKeys.varStatus);
198 }
199
200 public void setVarStatus (String varStatus)
201 {
202 getStateHelper().put(PropertyKeys.varStatus, varStatus );
203 }
204
205 protected DataModel getDataModel()
206 {
207 DataModel dataModel;
208 String clientID = "";
209
210 UIComponent parent = getParent();
211 if (parent != null)
212 {
213 clientID = parent.getContainerClientId(getFacesContext());
214 }
215 dataModel = _dataModelMap.get(clientID);
216 if (dataModel == null)
217 {
218 dataModel = createDataModel();
219 _dataModelMap.put(clientID, dataModel);
220 }
221 return dataModel;
222 }
223
224 private DataModel createDataModel()
225 {
226 Object value = getValue();
227
228 if (value == null)
229 {
230 return EMPTY_MODEL;
231 }
232 else if (value instanceof DataModel)
233 {
234 return (DataModel) value;
235 }
236 else
237 {
238 DataModel dataModel = null;
239 if (ExternalSpecifications.isCDIAvailable(getFacesContext().getExternalContext()))
240 {
241 dataModel = (new DataModelBuilderProxy()).createDataModel(
242 getFacesContext(), value.getClass(), value);
243 }
244 if (dataModel == null)
245 {
246 if (value instanceof List)
247 {
248 return new ListDataModel((List<?>) value);
249 }
250 else if (OBJECT_ARRAY_CLASS.isAssignableFrom(value.getClass()))
251 {
252 return new ArrayDataModel((Object[]) value);
253 }
254 else if (value instanceof ResultSet)
255 {
256 return new ResultSetDataModel((ResultSet) value);
257 }
258 else if (value instanceof Iterable)
259 {
260 return new IterableDataModel<>((Iterable<?>) value);
261 }
262 else if (value instanceof Map)
263 {
264 return new IterableDataModel<>(((Map<?, ?>) value).entrySet());
265 }
266 else if (value instanceof Collection)
267 {
268 return new CollectionDataModel((Collection) value);
269 }
270 else
271 {
272 return new ScalarDataModel(value);
273 }
274 }
275 else
276 {
277 return dataModel;
278 }
279 }
280 }
281
282 @Override
283 public void setValueExpression(String name, ValueExpression binding)
284 {
285 if (name == null)
286 {
287 throw new NullPointerException("name");
288 }
289 else if (name.equals("value"))
290 {
291 _dataModelMap.clear();
292 }
293 else if (name.equals("rowIndex"))
294 {
295 throw new IllegalArgumentException("name " + name);
296 }
297 super.setValueExpression(name, binding);
298 }
299
300 @JSFProperty
301 public Object getValue()
302 {
303 return getStateHelper().eval(PropertyKeys.value);
304 }
305
306 public void setValue(Object value)
307 {
308 getStateHelper().put(PropertyKeys.value, value);
309 _dataModelMap.clear();
310 _rowStates.clear();
311 _isValidChilds = true;
312 }
313
314 @Override
315 public String getContainerClientId(FacesContext context)
316 {
317
318 String clientId = super.getContainerClientId(context);
319
320 int index = getIndex();
321 if (index == -1)
322 {
323 return clientId;
324 }
325
326 StringBuilder sb = SharedStringBuilder.get(context, STRING_BUILDER_KEY);
327 return sb.append(clientId).append(context.getNamingContainerSeparatorChar()).append(index).toString();
328 }
329
330 private RepeatStatus _getRepeatStatus()
331 {
332 int begin = getBegin();
333 if (begin == -1)
334 {
335 begin = getOffset();
336 }
337
338 return new RepeatStatus(_count == 0, _index + getStep() >= getRowCount(),
339 _count, _index, begin, _end, getStep());
340
341 }
342
343 private void _captureScopeValues()
344 {
345 String var = getVar();
346 if (var != null)
347 {
348 _origValue = getFacesContext().getExternalContext().getRequestMap().get(var);
349 }
350 String varStatus = getVarStatus();
351 if (varStatus != null)
352 {
353 _origVarStatus = getFacesContext().getExternalContext().getRequestMap().get(varStatus);
354 }
355 }
356
357 private boolean _isIndexAvailable()
358 {
359 return _emptyModel || getDataModel().isRowAvailable();
360 }
361
362 private void _restoreScopeValues()
363 {
364 String var = getVar();
365 if (var != null)
366 {
367 Map<String, Object> attrs = getFacesContext().getExternalContext().getRequestMap();
368 if (_origValue != null)
369 {
370 attrs.put(var, _origValue);
371 _origValue = null;
372 }
373 else
374 {
375 attrs.remove(var);
376 }
377 }
378 String varStatus = getVarStatus();
379 if (getVarStatus() != null)
380 {
381 Map<String, Object> attrs = getFacesContext().getExternalContext().getRequestMap();
382 if (_origVarStatus != null)
383 {
384 attrs.put(varStatus, _origVarStatus);
385 _origVarStatus = null;
386 }
387 else
388 {
389 attrs.remove(varStatus);
390 }
391 }
392 }
393
394
395
396
397
398
399
400
401 @SuppressWarnings("unchecked")
402 private void restoreDescendantComponentStates(UIComponent parent, boolean iterateFacets, Object state,
403 boolean restoreChildFacets)
404 {
405 int descendantStateIndex = -1;
406 List<? extends Object[]> stateCollection = null;
407
408 if (iterateFacets && parent.getFacetCount() > 0)
409 {
410 Iterator<UIComponent> childIterator = parent.getFacets().values().iterator();
411
412 while (childIterator.hasNext())
413 {
414 UIComponent component = childIterator.next();
415
416
417 component.setId(component.getId());
418 if (!component.isTransient())
419 {
420 if (descendantStateIndex == -1)
421 {
422 stateCollection = ((List<? extends Object[]>) state);
423 descendantStateIndex = stateCollection.isEmpty() ? -1 : 0;
424 }
425
426 if (descendantStateIndex != -1 && descendantStateIndex < stateCollection.size())
427 {
428 Object[] object = stateCollection.get(descendantStateIndex);
429 if (object[0] != null && component instanceof EditableValueHolder)
430 {
431 ((SavedState) object[0]).restoreState((EditableValueHolder) component);
432 }
433
434
435 if (object[1] != null)
436 {
437 restoreDescendantComponentStates(component, restoreChildFacets, object[1], true);
438 }
439 else
440 {
441 restoreDescendantComponentWithoutRestoreState(component, restoreChildFacets, true);
442 }
443 }
444 else
445 {
446 restoreDescendantComponentWithoutRestoreState(component, restoreChildFacets, true);
447 }
448 descendantStateIndex++;
449 }
450 }
451 }
452
453 if (parent.getChildCount() > 0)
454 {
455 for (int i = 0; i < parent.getChildCount(); i++)
456 {
457 UIComponent component = parent.getChildren().get(i);
458
459
460 component.setId(component.getId());
461 if (!component.isTransient())
462 {
463 if (descendantStateIndex == -1)
464 {
465 stateCollection = ((List<? extends Object[]>) state);
466 descendantStateIndex = stateCollection.isEmpty() ? -1 : 0;
467 }
468
469 if (descendantStateIndex != -1 && descendantStateIndex < stateCollection.size())
470 {
471 Object[] object = stateCollection.get(descendantStateIndex);
472 if (object[0] != null && component instanceof EditableValueHolder)
473 {
474 ((SavedState) object[0]).restoreState((EditableValueHolder) component);
475 }
476
477
478 if (object[1] != null)
479 {
480 restoreDescendantComponentStates(component, restoreChildFacets, object[1], true);
481 }
482 else
483 {
484 restoreDescendantComponentWithoutRestoreState(component, restoreChildFacets, true);
485 }
486 }
487 else
488 {
489 restoreDescendantComponentWithoutRestoreState(component, restoreChildFacets, true);
490 }
491 descendantStateIndex++;
492 }
493 }
494 }
495 }
496
497
498
499
500
501
502
503
504
505
506 private void restoreDescendantComponentWithoutRestoreState(UIComponent parent, boolean iterateFacets,
507 boolean restoreChildFacets)
508 {
509 if (iterateFacets && parent.getFacetCount() > 0)
510 {
511 Iterator<UIComponent> childIterator = parent.getFacets().values().iterator();
512
513 while (childIterator.hasNext())
514 {
515 UIComponent component = childIterator.next();
516
517
518 component.setId(component.getId());
519 if (!component.isTransient())
520 {
521 restoreDescendantComponentWithoutRestoreState(component, restoreChildFacets, true);
522 }
523 }
524 }
525
526 if (parent.getChildCount() > 0)
527 {
528 for (int i = 0; i < parent.getChildCount(); i++)
529 {
530 UIComponent component = parent.getChildren().get(i);
531
532
533 component.setId(component.getId());
534 if (!component.isTransient())
535 {
536 restoreDescendantComponentWithoutRestoreState(component, restoreChildFacets, true);
537 }
538 }
539 }
540 }
541
542
543
544
545
546
547
548
549
550
551
552
553
554 private Collection<Object[]> saveDescendantComponentStates(UIComponent parent, boolean iterateFacets,
555 boolean saveChildFacets)
556 {
557 Collection<Object[]> childStates = null;
558
559 int childEmptyIndex = 0;
560 int totalChildCount = 0;
561
562 if (iterateFacets && parent.getFacetCount() > 0)
563 {
564 Iterator<UIComponent> childIterator = parent.getFacets().values().iterator();
565
566 while (childIterator.hasNext())
567 {
568 UIComponent child = childIterator.next();
569 if (!child.isTransient())
570 {
571
572
573
574
575
576 if (child instanceof EditableValueHolder)
577 {
578 if (childStates == null)
579 {
580 childStates = new ArrayList<Object[]>(
581 parent.getFacetCount()
582 + parent.getChildCount()
583 - totalChildCount
584 + childEmptyIndex);
585 for (int ci = 0; ci < childEmptyIndex; ci++)
586 {
587 childStates.add(LEAF_NO_STATE);
588 }
589 }
590
591 childStates.add(child.getChildCount() > 0 ?
592 new Object[]{new SavedState((EditableValueHolder) child),
593 saveDescendantComponentStates(child, saveChildFacets, true)} :
594 new Object[]{new SavedState((EditableValueHolder) child),
595 null});
596 }
597 else if (child.getChildCount() > 0 || (saveChildFacets && child.getFacetCount() > 0))
598 {
599 Object descendantSavedState = saveDescendantComponentStates(child, saveChildFacets, true);
600
601 if (descendantSavedState == null)
602 {
603 if (childStates == null)
604 {
605 childEmptyIndex++;
606 }
607 else
608 {
609 childStates.add(LEAF_NO_STATE);
610 }
611 }
612 else
613 {
614 if (childStates == null)
615 {
616 childStates = new ArrayList<Object[]>(
617 parent.getFacetCount()
618 + parent.getChildCount()
619 - totalChildCount
620 + childEmptyIndex);
621 for (int ci = 0; ci < childEmptyIndex; ci++)
622 {
623 childStates.add(LEAF_NO_STATE);
624 }
625 }
626 childStates.add(new Object[]{null, descendantSavedState});
627 }
628 }
629 else
630 {
631 if (childStates == null)
632 {
633 childEmptyIndex++;
634 }
635 else
636 {
637 childStates.add(LEAF_NO_STATE);
638 }
639 }
640 }
641 totalChildCount++;
642 }
643 }
644
645 if (parent.getChildCount() > 0)
646 {
647 for (int i = 0; i < parent.getChildCount(); i++)
648 {
649 UIComponent child = parent.getChildren().get(i);
650 if (!child.isTransient())
651 {
652
653
654
655
656
657 if (child instanceof EditableValueHolder)
658 {
659 if (childStates == null)
660 {
661 childStates = new ArrayList<Object[]>(
662 parent.getFacetCount()
663 + parent.getChildCount()
664 - totalChildCount
665 + childEmptyIndex);
666 for (int ci = 0; ci < childEmptyIndex; ci++)
667 {
668 childStates.add(LEAF_NO_STATE);
669 }
670 }
671
672 childStates.add(child.getChildCount() > 0 ?
673 new Object[]{new SavedState((EditableValueHolder) child),
674 saveDescendantComponentStates(child, saveChildFacets, true)} :
675 new Object[]{new SavedState((EditableValueHolder) child),
676 null});
677 }
678 else if (child.getChildCount() > 0 || (saveChildFacets && child.getFacetCount() > 0))
679 {
680 Object descendantSavedState = saveDescendantComponentStates(child, saveChildFacets, true);
681
682 if (descendantSavedState == null)
683 {
684 if (childStates == null)
685 {
686 childEmptyIndex++;
687 }
688 else
689 {
690 childStates.add(LEAF_NO_STATE);
691 }
692 }
693 else
694 {
695 if (childStates == null)
696 {
697 childStates = new ArrayList<Object[]>(
698 parent.getFacetCount()
699 + parent.getChildCount()
700 - totalChildCount
701 + childEmptyIndex);
702 for (int ci = 0; ci < childEmptyIndex; ci++)
703 {
704 childStates.add(LEAF_NO_STATE);
705 }
706 }
707 childStates.add(new Object[]{null, descendantSavedState});
708 }
709 }
710 else
711 {
712 if (childStates == null)
713 {
714 childEmptyIndex++;
715 }
716 else
717 {
718 childStates.add(LEAF_NO_STATE);
719 }
720 }
721 }
722 totalChildCount++;
723 }
724 }
725
726 return childStates;
727 }
728
729
730
731
732
733 public int getRowCount()
734 {
735 if (_emptyModel)
736 {
737 return (getEnd() - getBegin())/(getStep() <= 0 ? 1 : getStep());
738 }
739 else
740 {
741 return getDataModel().getRowCount();
742 }
743 }
744
745
746
747
748 public int getIndex()
749 {
750 return _index;
751 }
752
753 public void setRowIndex(int index)
754 {
755 _setIndex(index);
756 }
757
758 private void _setIndex(int index)
759 {
760
761
762 if (index < -1)
763 {
764 throw new IllegalArgumentException("rowIndex is less than -1");
765 }
766
767 if (_index == index)
768 {
769 return;
770 }
771
772 FacesContext facesContext = getFacesContext();
773
774 if (_index == -1)
775 {
776 if (_initialDescendantComponentState == null)
777 {
778
779
780
781
782 _initialDescendantComponentState = saveDescendantComponentStates(this, true, true);
783 }
784 }
785 else
786 {
787
788
789
790 if (_initialDescendantComponentState != null)
791 {
792
793
794
795
796 Collection<Object[]> savedRowState = saveDescendantComponentStates(this, true, true);
797 if (savedRowState != null)
798 {
799 _rowStates.put(getContainerClientId(facesContext), savedRowState);
800 }
801 }
802 }
803
804 _index = index;
805
806 DataModel<?> localModel = getDataModel();
807 localModel.setRowIndex(index);
808
809 if (_index != -1)
810 {
811 String var = getVar();
812 if (var != null && (_emptyModel || localModel.isRowAvailable()))
813 {
814 if (_emptyModel)
815 {
816 getFacesContext().getExternalContext().getRequestMap().put(var, _index);
817 }
818 else
819 {
820 getFacesContext().getExternalContext().getRequestMap().put(var, localModel.getRowData());
821 }
822 }
823 String varStatus = getVarStatus();
824 if (varStatus != null)
825 {
826 getFacesContext().getExternalContext().getRequestMap()
827 .put(varStatus, _getRepeatStatus());
828 }
829 }
830
831
832
833
834 if (_index == -1)
835 {
836
837
838 if (_initialDescendantComponentState != null)
839 {
840 restoreDescendantComponentStates(this, true, _initialDescendantComponentState, true);
841 }
842 else
843 {
844 restoreDescendantComponentWithoutRestoreState(this, true, true);
845 }
846 }
847 else
848 {
849 Object rowState = _rowStates.get(getContainerClientId(facesContext));
850 if (rowState == null)
851 {
852
853
854
855
856 if (_initialDescendantComponentState != null)
857 {
858 restoreDescendantComponentStates(this, true, _initialDescendantComponentState, true);
859 }
860 else
861 {
862 restoreDescendantComponentWithoutRestoreState(this, true, true);
863 }
864 }
865 else
866 {
867
868
869
870
871 restoreDescendantComponentStates(this, true, rowState, true);
872 }
873 }
874 }
875
876
877
878
879
880
881 private int _calculateCountForIndex(int index)
882 {
883 return (index - getOffset()) / getStep();
884 }
885
886 private void _validateAttributes() throws FacesException
887 {
888
889 int begin = getBegin();
890 int end = getEnd();
891 int size = getSize();
892 _emptyModel = getDataModel() == EMPTY_MODEL && begin != -1 && end != -1;
893 int count = getRowCount();
894 int offset = getOffset();
895 if (begin == -1)
896 {
897 if (size >= 0)
898 {
899 end = getOffset() + getSize();
900 }
901 }
902
903 if (end == -1 && size == -1)
904 {
905 if (begin == -1)
906 {
907 end = getDataModel().getRowCount();
908 }
909 else
910 {
911 end = getDataModel().getRowCount() - 1;
912 }
913 }
914
915 int step = getStep();
916 boolean sizeIsEnd = _emptyModel;
917 boolean countdown = _emptyModel && end < begin;
918
919 if (size == -1)
920 {
921 if (begin == -1)
922 {
923 size = end;
924 sizeIsEnd = true;
925 }
926 else
927 {
928 size = countdown ? (begin - end + 1)/step : (end - begin + 1)/step;
929 }
930 }
931
932 step = countdown && step > 0 ? -step : step;
933
934 if (_emptyModel)
935 {
936 if (step > 0 && (end < begin))
937 {
938 throw new FacesException("on empty models, end cannot be less than begin " +
939 "when the step is positive");
940 }
941 else if (step < 0 && (end > begin))
942 {
943 throw new FacesException("on empty models, end cannot be greater than begin " +
944 "when the step is negative");
945 }
946 setStep(step);
947 }
948 else if (end >= 0)
949 {
950 if (size < 0)
951 {
952 throw new FacesException("iteration size cannot be less " +
953 "than zero");
954 }
955 else if (!sizeIsEnd && (begin == -1) && (offset + size) > end)
956 {
957 throw new FacesException("iteration size cannot be greater " +
958 "than collection size");
959 }
960 else if (!sizeIsEnd && (begin == -1) && (offset + size) > count)
961 {
962 throw new FacesException("iteration size cannot be greater " +
963 "than collection size");
964 }
965 else if (!sizeIsEnd && (begin >= 0) && (begin + size) > end+1)
966 {
967 throw new FacesException("iteration size cannot be greater " +
968 "than collection size");
969 }
970 else if(!sizeIsEnd && (begin >= 0) && (end+1 > count))
971 {
972 throw new FacesException("end cannot be greater " +
973 "than collection size");
974 }
975 else if(!sizeIsEnd && (begin >= 0) && (begin > count))
976 {
977 throw new FacesException("begin cannot be greater " +
978 "than collection size");
979 }
980 }
981 if (!_emptyModel && (begin >= 0) && (begin > end))
982 {
983 throw new FacesException("begin cannot be greater " +
984 "than end");
985 }
986 if (!_emptyModel && (size > -1) && (offset > end))
987 {
988 throw new FacesException("iteration offset cannot be greater " +
989 "than collection size");
990 }
991
992 if (!_emptyModel && step == -1)
993 {
994 setStep(1);
995 }
996
997 if (!_emptyModel && step < 0)
998 {
999 throw new FacesException("iteration step size cannot be less " +
1000 "than zero");
1001 }
1002
1003 else if (step == 0)
1004 {
1005 throw new FacesException("iteration step size cannot be equal " +
1006 "to zero");
1007 }
1008
1009 _end = end;
1010
1011 }
1012
1013 public void process(FacesContext faces, PhaseId phase)
1014 {
1015
1016 if (!isRendered())
1017 {
1018 return;
1019 }
1020
1021
1022 _validateAttributes();
1023
1024
1025 _captureScopeValues();
1026 _setIndex(-1);
1027
1028 try
1029 {
1030
1031 if (getChildCount() > 0)
1032 {
1033 int i = getOffset();
1034
1035 int begin = getBegin();
1036 int end = getEnd();
1037 if (begin == -1)
1038 {
1039 end = getSize();
1040 end = (end >= 0) ? i + end - 1 : Integer.MAX_VALUE - 1;
1041 }
1042
1043 if (begin >= 0)
1044 {
1045 i = begin;
1046 }
1047 int step = getStep();
1048
1049 String rendererType = getRendererType();
1050 Renderer renderer = null;
1051 if (rendererType != null)
1052 {
1053 renderer = getRenderer(faces);
1054 }
1055
1056 _count = 0;
1057
1058 _setIndex(i);
1059
1060 while (((step > 0 && i <= end) || (step < 0 && i >= end)) && _isIndexAvailable())
1061 {
1062
1063 if (PhaseId.RENDER_RESPONSE.equals(phase) && renderer != null)
1064 {
1065 renderer.encodeChildren(faces, this);
1066 }
1067 else
1068 {
1069 for (int j = 0, childCount = getChildCount(); j < childCount; j++)
1070 {
1071 UIComponent child = getChildren().get(j);
1072 if (PhaseId.APPLY_REQUEST_VALUES.equals(phase))
1073 {
1074 child.processDecodes(faces);
1075 }
1076 else if (PhaseId.PROCESS_VALIDATIONS.equals(phase))
1077 {
1078 child.processValidators(faces);
1079 }
1080 else if (PhaseId.UPDATE_MODEL_VALUES.equals(phase))
1081 {
1082 child.processUpdates(faces);
1083 }
1084 else if (PhaseId.RENDER_RESPONSE.equals(phase))
1085 {
1086 child.encodeAll(faces);
1087 }
1088 }
1089 }
1090
1091 ++_count;
1092
1093 i += step;
1094
1095 _setIndex(i);
1096 }
1097 }
1098 }
1099 catch (IOException e)
1100 {
1101 throw new FacesException(e);
1102 }
1103 finally
1104 {
1105 _setIndex(-1);
1106 _restoreScopeValues();
1107 }
1108 }
1109
1110 @Override
1111 public boolean invokeOnComponent(FacesContext context, String clientId,
1112 ContextCallback callback) throws FacesException
1113 {
1114 if (context == null || clientId == null || callback == null)
1115 {
1116 throw new NullPointerException();
1117 }
1118
1119 final String baseClientId = getClientId(context);
1120
1121
1122 boolean returnValue = baseClientId.equals(clientId);
1123
1124 boolean isCachedFacesContext = isTemporalFacesContext();
1125 if (!isCachedFacesContext)
1126 {
1127 setTemporalFacesContext(context);
1128 }
1129
1130 pushComponentToEL(context, this);
1131 try
1132 {
1133 if (returnValue)
1134 {
1135 try
1136 {
1137 callback.invokeContextCallback(context, this);
1138 return true;
1139 }
1140 catch (Exception e)
1141 {
1142 throw new FacesException(e);
1143 }
1144 }
1145
1146
1147 if (this.getFacetCount() > 0)
1148 {
1149 for (Iterator<UIComponent> it = this.getFacets().values().iterator(); !returnValue && it.hasNext();)
1150 {
1151 returnValue = it.next().invokeOnComponent(context, clientId, callback);
1152 }
1153 }
1154
1155 if (returnValue)
1156 {
1157 return returnValue;
1158 }
1159
1160
1161 if (clientId.startsWith(baseClientId))
1162 {
1163
1164
1165 char separator = context.getNamingContainerSeparatorChar();
1166 String subId = clientId.substring(baseClientId.length() + 1);
1167
1168
1169 if (clientId.charAt(baseClientId.length()) == separator &&
1170 subId.matches("[0-9]+"+separator+".*"))
1171 {
1172 String clientRow = subId.substring(0, subId.indexOf(separator));
1173
1174
1175 final int prevIndex = _index;
1176 final int prevCount = _count;
1177
1178 try
1179 {
1180 int invokeIndex = Integer.parseInt(clientRow);
1181
1182 _captureScopeValues();
1183 if (invokeIndex != -1)
1184 {
1185
1186 _count = _calculateCountForIndex(invokeIndex);
1187 }
1188 _setIndex(invokeIndex);
1189
1190 if (!_isIndexAvailable())
1191 {
1192 return false;
1193 }
1194
1195 for (Iterator<UIComponent> it1 = getChildren().iterator();
1196 !returnValue && it1.hasNext();)
1197 {
1198
1199 returnValue = it1.next().invokeOnComponent(context, clientId, callback);
1200 }
1201 }
1202 finally
1203 {
1204
1205 _count = prevCount;
1206 _setIndex(prevIndex);
1207 _restoreScopeValues();
1208 }
1209 }
1210 else
1211 {
1212
1213 if (this.getChildCount() > 0)
1214 {
1215
1216 for (Iterator<UIComponent> it = this.getChildren().iterator(); !returnValue && it.hasNext();)
1217 {
1218 returnValue = it.next().invokeOnComponent(context, clientId, callback);
1219 }
1220 }
1221 }
1222 }
1223 }
1224 finally
1225 {
1226
1227 popComponentFromEL(context);
1228 if (!isCachedFacesContext)
1229 {
1230 setTemporalFacesContext(null);
1231 }
1232 }
1233
1234 return returnValue;
1235 }
1236
1237 @Override
1238 protected FacesContext getFacesContext()
1239 {
1240 if (_facesContext == null)
1241 {
1242 return super.getFacesContext();
1243 }
1244 else
1245 {
1246 return _facesContext;
1247 }
1248 }
1249
1250 private boolean isTemporalFacesContext()
1251 {
1252 return _facesContext != null;
1253 }
1254
1255 private void setTemporalFacesContext(FacesContext facesContext)
1256 {
1257 _facesContext = facesContext;
1258 }
1259
1260 @Override
1261 public boolean visitTree(VisitContext context, VisitCallback callback)
1262 {
1263
1264
1265
1266 boolean skipIterationHint = context.getHints().contains(VisitHint.SKIP_ITERATION);
1267 if (skipIterationHint)
1268 {
1269 return super.visitTree(context, callback);
1270 }
1271
1272 pushComponentToEL(context.getFacesContext(), this);
1273 try
1274 {
1275 if (!isVisitable(context))
1276 {
1277 return false;
1278 }
1279
1280
1281 final int prevIndex = _index;
1282 final int prevCount = _count;
1283
1284
1285 _captureScopeValues();
1286 _setIndex(-1);
1287
1288 try
1289 {
1290 VisitResult res = context.invokeVisitCallback(this, callback);
1291 switch (res)
1292 {
1293
1294 case COMPLETE:
1295 return true;
1296
1297 case REJECT:
1298 return false;
1299
1300
1301 default:
1302
1303
1304 Collection<String> subtreeIdsToVisit = context
1305 .getSubtreeIdsToVisit(this);
1306 boolean doVisitChildren = subtreeIdsToVisit != null
1307 && !subtreeIdsToVisit.isEmpty();
1308 if (doVisitChildren)
1309 {
1310
1311 _validateAttributes();
1312
1313
1314 if (getFacetCount() > 0)
1315 {
1316 for (UIComponent facet : getFacets().values())
1317 {
1318 if (facet.visitTree(context, callback))
1319 {
1320 return true;
1321 }
1322 }
1323 }
1324
1325
1326 if (getChildCount() > 0)
1327 {
1328 int i = getOffset();
1329 int end = getSize();
1330 int step = getStep();
1331 end = (end >= 0) ? i + end : Integer.MAX_VALUE - 1;
1332 _count = 0;
1333
1334 _setIndex(i);
1335 while (i < end && _isIndexAvailable())
1336 {
1337 for (int j = 0, childCount = getChildCount(); j < childCount; j++)
1338 {
1339 UIComponent child = getChildren().get(j);
1340 if (child.visitTree(context, callback))
1341 {
1342 return true;
1343 }
1344 }
1345
1346 _count++;
1347 i += step;
1348
1349 _setIndex(i);
1350 }
1351 }
1352 }
1353 return false;
1354 }
1355 }
1356 finally
1357 {
1358
1359
1360 _count = prevCount;
1361 _setIndex(prevIndex);
1362 _restoreScopeValues();
1363 }
1364 }
1365 finally
1366 {
1367
1368 popComponentFromEL(context.getFacesContext());
1369 }
1370 }
1371
1372 @Override
1373 public void processDecodes(FacesContext faces)
1374 {
1375 if (!isRendered())
1376 {
1377 return;
1378 }
1379
1380 process(faces, PhaseId.APPLY_REQUEST_VALUES);
1381 decode(faces);
1382 }
1383
1384 @Override
1385 public void processUpdates(FacesContext faces)
1386 {
1387 if (!isRendered())
1388 {
1389 return;
1390 }
1391
1392 process(faces, PhaseId.UPDATE_MODEL_VALUES);
1393
1394 if (faces.getRenderResponse())
1395 {
1396 _isValidChilds = false;
1397 }
1398 }
1399
1400 @Override
1401 public void processValidators(FacesContext faces)
1402 {
1403 if (!isRendered())
1404 {
1405 return;
1406 }
1407
1408 process(faces, PhaseId.PROCESS_VALIDATIONS);
1409
1410
1411 if (faces.getRenderResponse())
1412 {
1413 _isValidChilds = false;
1414 }
1415 }
1416
1417
1418 private final static class SavedState implements Serializable
1419 {
1420 private boolean _localValueSet;
1421 private Object _submittedValue;
1422 private boolean _valid = true;
1423 private Object _value;
1424
1425 private static final long serialVersionUID = 2920252657338389849L;
1426
1427 public SavedState(EditableValueHolder evh)
1428 {
1429 _value = evh.getLocalValue();
1430 _localValueSet = evh.isLocalValueSet();
1431 _valid = evh.isValid();
1432 _submittedValue = evh.getSubmittedValue();
1433 }
1434
1435 Object getSubmittedValue()
1436 {
1437 return (_submittedValue);
1438 }
1439
1440 void setSubmittedValue(Object submittedValue)
1441 {
1442 _submittedValue = submittedValue;
1443 }
1444
1445 boolean isValid()
1446 {
1447 return (_valid);
1448 }
1449
1450 void setValid(boolean valid)
1451 {
1452 _valid = valid;
1453 }
1454
1455 Object getValue()
1456 {
1457 return _value;
1458 }
1459
1460 public void setValue(Object value)
1461 {
1462 _value = value;
1463 }
1464
1465 boolean isLocalValueSet()
1466 {
1467 return _localValueSet;
1468 }
1469
1470 public void setLocalValueSet(boolean localValueSet)
1471 {
1472 _localValueSet = localValueSet;
1473 }
1474
1475 @Override
1476 public String toString()
1477 {
1478 return ("submittedValue: " + _submittedValue + " value: " + _value + " localValueSet: " + _localValueSet);
1479 }
1480
1481 public void restoreState(EditableValueHolder evh)
1482 {
1483 evh.setValue(_value);
1484 evh.setValid(_valid);
1485 evh.setSubmittedValue(_submittedValue);
1486 evh.setLocalValueSet(_localValueSet);
1487 }
1488
1489 public void populate(EditableValueHolder evh)
1490 {
1491 _value = evh.getLocalValue();
1492 _valid = evh.isValid();
1493 _submittedValue = evh.getSubmittedValue();
1494 _localValueSet = evh.isLocalValueSet();
1495 }
1496
1497 public void apply(EditableValueHolder evh)
1498 {
1499 evh.setValue(_value);
1500 evh.setValid(_valid);
1501 evh.setSubmittedValue(_submittedValue);
1502 evh.setLocalValueSet(_localValueSet);
1503 }
1504 }
1505
1506 private final class IndexedEvent extends FacesEvent
1507 {
1508 private final FacesEvent _target;
1509
1510 private final int _index;
1511
1512 public IndexedEvent(UIRepeat owner, FacesEvent target, int index)
1513 {
1514 super(owner);
1515 _target = target;
1516 _index = index;
1517 }
1518
1519 @Override
1520 public PhaseId getPhaseId()
1521 {
1522 return _target.getPhaseId();
1523 }
1524
1525 @Override
1526 public void setPhaseId(PhaseId phaseId)
1527 {
1528 _target.setPhaseId(phaseId);
1529 }
1530
1531 @Override
1532 public boolean isAppropriateListener(FacesListener listener)
1533 {
1534 return _target.isAppropriateListener(listener);
1535 }
1536
1537 @Override
1538 public void processListener(FacesListener listener)
1539 {
1540 UIRepeat owner = (UIRepeat) getComponent();
1541
1542
1543 final int prevIndex = owner._index;
1544 final int prevCount = owner._count;
1545
1546 try
1547 {
1548 owner._captureScopeValues();
1549 if (this._index != -1)
1550 {
1551
1552 _count = _calculateCountForIndex(this._index);
1553 }
1554 owner._setIndex(this._index);
1555 if (owner._isIndexAvailable())
1556 {
1557 _target.processListener(listener);
1558 }
1559 }
1560 finally
1561 {
1562
1563 owner._count = prevCount;
1564 owner._setIndex(prevIndex);
1565 owner._restoreScopeValues();
1566 }
1567 }
1568
1569 public int getIndex()
1570 {
1571 return _index;
1572 }
1573
1574 public FacesEvent getTarget()
1575 {
1576 return _target;
1577 }
1578
1579 }
1580
1581 @Override
1582 public void broadcast(FacesEvent event) throws AbortProcessingException
1583 {
1584 if (event instanceof IndexedEvent)
1585 {
1586 IndexedEvent idxEvent = (IndexedEvent) event;
1587
1588
1589 final int prevIndex = _index;
1590 final int prevCount = _count;
1591
1592 try
1593 {
1594 _captureScopeValues();
1595 if (idxEvent.getIndex() != -1)
1596 {
1597
1598 _count = _calculateCountForIndex(idxEvent.getIndex());
1599 }
1600 _setIndex(idxEvent.getIndex());
1601 if (_isIndexAvailable())
1602 {
1603
1604 FacesEvent target = idxEvent.getTarget();
1605 FacesContext facesContext = getFacesContext();
1606
1607
1608
1609
1610
1611 UIComponent targetComponent = target.getComponent();
1612 UIComponent compositeParent = UIComponent
1613 .getCompositeComponentParent(targetComponent);
1614 if (compositeParent != null)
1615 {
1616 pushComponentToEL(facesContext, compositeParent);
1617 }
1618 pushComponentToEL(facesContext, targetComponent);
1619
1620 try
1621 {
1622
1623 targetComponent.broadcast(target);
1624 }
1625 finally
1626 {
1627
1628 popComponentFromEL(facesContext);
1629 if (compositeParent != null)
1630 {
1631 popComponentFromEL(facesContext);
1632 }
1633 }
1634 }
1635 }
1636 finally
1637 {
1638
1639 _count = prevCount;
1640 _setIndex(prevIndex);
1641 _restoreScopeValues();
1642 }
1643 }
1644 else
1645 {
1646 super.broadcast(event);
1647 }
1648 }
1649
1650 @Override
1651 public void queueEvent(FacesEvent event)
1652 {
1653 super.queueEvent(new IndexedEvent(this, event, _index));
1654 }
1655
1656 @Override
1657 public void restoreState(FacesContext context, Object state)
1658 {
1659 if (state == null)
1660 {
1661 return;
1662 }
1663
1664 Object values[] = (Object[]) state;
1665 super.restoreState(context, values[0]);
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679 if (values.length > 2)
1680 {
1681 Object rs = UIComponentBase.restoreAttachedState(context, values[2]);
1682 if (rs == null)
1683 {
1684 if (!_rowStates.isEmpty())
1685 {
1686 _rowStates.clear();
1687 }
1688 }
1689 else
1690 {
1691 _rowStates = (Map<String, Collection<Object[]> >) rs;
1692 }
1693 }
1694 }
1695
1696 @Override
1697 public Object saveState(FacesContext context)
1698 {
1699 if (context.getViewRoot() != null)
1700 {
1701 if (context.getViewRoot().getAttributes().get("oam.view.resetSaveStateMode") == RESET_MODE_SOFT)
1702 {
1703 _dataModelMap.clear();
1704 _isValidChilds=true;
1705
1706 }
1707 if (context.getViewRoot().getAttributes().get("oam.view.resetSaveStateMode") == RESET_MODE_HARD)
1708 {
1709 _dataModelMap.clear();
1710 _isValidChilds=true;
1711
1712 _rowStates.clear();
1713
1714 }
1715 }
1716 if (initialStateMarked())
1717 {
1718 Object parentSaved = super.saveState(context);
1719 if (context.getCurrentPhaseId() != null &&
1720 !PhaseId.RENDER_RESPONSE.equals(context.getCurrentPhaseId()))
1721 {
1722 if (parentSaved == null
1723 {
1724 return null;
1725 }
1726 else
1727 {
1728 Object values[] = new Object[3];
1729 values[0] = super.saveState(context);
1730
1731 values[1] = null;
1732 values[2] = UIComponentBase.saveAttachedState(context, _rowStates);
1733 return values;
1734 }
1735 }
1736 else
1737 {
1738 if (parentSaved == null
1739 {
1740 return null;
1741 }
1742 else
1743 {
1744 Object values[] = new Object[2];
1745 values[0] = super.saveState(context);
1746
1747 values[1] = null;
1748 return values;
1749 }
1750 }
1751 }
1752 else
1753 {
1754 if (context.getCurrentPhaseId() != null &&
1755 !PhaseId.RENDER_RESPONSE.equals(context.getCurrentPhaseId()))
1756 {
1757 Object values[] = new Object[3];
1758 values[0] = super.saveState(context);
1759
1760 values[1] = null;
1761 values[2] = UIComponentBase.saveAttachedState(context, _rowStates);
1762 return values;
1763 }
1764 else
1765 {
1766 Object values[] = new Object[2];
1767 values[0] = super.saveState(context);
1768
1769 values[1] = null;
1770 return values;
1771 }
1772 }
1773 }
1774
1775 @Override
1776 public void encodeBegin(FacesContext context) throws IOException
1777 {
1778 _initialDescendantComponentState = null;
1779 if (_isValidChilds && !hasErrorMessages(context))
1780 {
1781
1782
1783
1784 _dataModelMap.clear();
1785
1786
1787
1788
1789
1790 _rowStates.clear();
1791 }
1792 super.encodeBegin(context);
1793 }
1794
1795 private boolean hasErrorMessages(FacesContext context)
1796 {
1797 for (Iterator<FacesMessage> iter = context.getMessages(); iter.hasNext();)
1798 {
1799 FacesMessage message = iter.next();
1800 if (FacesMessage.SEVERITY_ERROR.compareTo(message.getSeverity()) <= 0)
1801 {
1802 return true;
1803 }
1804 }
1805 return false;
1806 }
1807
1808 @Override
1809 public void encodeChildren(FacesContext faces) throws IOException
1810 {
1811 if (!isRendered())
1812 {
1813 return;
1814 }
1815
1816 process(faces, PhaseId.RENDER_RESPONSE);
1817 }
1818
1819 @Override
1820 public boolean getRendersChildren()
1821 {
1822 if (getRendererType() != null)
1823 {
1824 Renderer renderer = getRenderer(getFacesContext());
1825 if (renderer != null)
1826 {
1827 return renderer.getRendersChildren();
1828 }
1829 }
1830
1831 return true;
1832 }
1833
1834 enum PropertyKeys
1835 {
1836 value
1837 , var
1838 , size
1839 , varStatus
1840 , offset
1841 , step
1842 , begin
1843 , end
1844 }
1845 }