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.tag.jstl.core;
20
21 import java.io.IOException;
22 import java.lang.reflect.Array;
23 import java.util.Collection;
24 import java.util.Iterator;
25 import java.util.List;
26 import java.util.Map;
27
28 import javax.el.ELException;
29 import javax.el.ValueExpression;
30 import javax.el.VariableMapper;
31 import javax.faces.FacesException;
32 import javax.faces.component.UIComponent;
33 import javax.faces.view.facelets.FaceletContext;
34 import javax.faces.view.facelets.FaceletException;
35 import javax.faces.view.facelets.TagAttribute;
36 import javax.faces.view.facelets.TagAttributeException;
37 import javax.faces.view.facelets.TagConfig;
38 import javax.faces.view.facelets.TagHandler;
39
40 import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFFaceletAttribute;
41 import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFFaceletTag;
42 import org.apache.myfaces.view.facelets.FaceletCompositionContext;
43 import org.apache.myfaces.view.facelets.tag.ComponentContainerHandler;
44 import org.apache.myfaces.view.facelets.tag.jsf.ComponentSupport;
45
46
47
48
49
50
51
52
53
54
55 @JSFFaceletTag(name="c:forEach")
56 public final class ForEachHandler extends TagHandler implements ComponentContainerHandler
57 {
58
59 private static class ArrayIterator implements Iterator<Object>
60 {
61
62 protected final Object array;
63
64 protected int i;
65
66 protected final int len;
67
68 public ArrayIterator(Object src)
69 {
70 this.i = 0;
71 this.array = src;
72 this.len = Array.getLength(src);
73 }
74
75 public boolean hasNext()
76 {
77 return this.i < this.len;
78 }
79
80 public Object next()
81 {
82 return Array.get(this.array, this.i++);
83 }
84
85 public void remove()
86 {
87 throw new UnsupportedOperationException();
88 }
89 }
90
91
92
93
94
95
96
97
98
99
100 @JSFFaceletAttribute(className="int")
101 private final TagAttribute begin;
102
103
104
105
106
107
108
109
110
111 @JSFFaceletAttribute(className="int")
112 private final TagAttribute end;
113
114
115
116
117 @JSFFaceletAttribute(className="javax.el.ValueExpression")
118 private final TagAttribute items;
119
120
121
122
123
124 @JSFFaceletAttribute(className="int")
125 private final TagAttribute step;
126
127 private final TagAttribute tranzient;
128
129
130
131
132
133
134
135 @JSFFaceletAttribute(className="java.lang.String")
136 private final TagAttribute var;
137
138
139
140
141
142 @JSFFaceletAttribute(className="java.lang.String")
143 private final TagAttribute varStatus;
144
145
146
147
148 public ForEachHandler(TagConfig config)
149 {
150 super(config);
151 this.items = this.getAttribute("items");
152 this.var = this.getAttribute("var");
153 this.begin = this.getAttribute("begin");
154 this.end = this.getAttribute("end");
155 this.step = this.getAttribute("step");
156 this.varStatus = this.getAttribute("varStatus");
157 this.tranzient = this.getAttribute("transient");
158
159 if (this.items == null && this.begin != null && this.end == null)
160 {
161 throw new TagAttributeException(this.tag, this.begin,
162 "If the 'items' attribute is not specified, but the 'begin' attribute is, then the 'end' attribute is required");
163 }
164 }
165
166 public void apply(FaceletContext ctx, UIComponent parent) throws IOException, FacesException, FaceletException,
167 ELException
168 {
169
170 int s = this.getBegin(ctx);
171 int e = this.getEnd(ctx);
172 int m = this.getStep(ctx);
173 Integer sO = this.begin != null ? Integer.valueOf(s) : null;
174 Integer eO = this.end != null ? Integer.valueOf(e) : null;
175 Integer mO = this.step != null ? Integer.valueOf(m) : null;
176
177 boolean t = this.getTransient(ctx);
178 Object src = null;
179 ValueExpression srcVE = null;
180 if (this.items != null)
181 {
182 srcVE = this.items.getValueExpression(ctx, Object.class);
183 src = srcVE.getValue(ctx);
184 }
185 else
186 {
187 byte[] b = new byte[e + 1];
188 for (int i = 0; i < b.length; i++)
189 {
190 b[i] = (byte) i;
191 }
192 src = b;
193 }
194 FaceletCompositionContext fcc = FaceletCompositionContext.getCurrentInstance(ctx);
195 if (src != null)
196 {
197 fcc.startComponentUniqueIdSection();
198 Iterator<?> itr = this.toIterator(src);
199 if (itr != null)
200 {
201 int i = 0;
202
203
204 while (i < s && itr.hasNext())
205 {
206 itr.next();
207 i++;
208 }
209
210 String v = this.getVarName(ctx);
211 String vs = this.getVarStatusName(ctx);
212 VariableMapper vars = ctx.getVariableMapper();
213 ValueExpression ve = null;
214 ValueExpression vO = this.capture(v, vars);
215 ValueExpression vsO = this.capture(vs, vars);
216 int mi = 0;
217 Object value = null;
218 try
219 {
220 boolean first = true;
221 while (i <= e && itr.hasNext())
222 {
223 value = itr.next();
224
225
226 if (v != null)
227 {
228 if (t || srcVE == null)
229 {
230 ctx.setAttribute(v, value);
231 }
232 else
233 {
234 ve = this.getVarExpr(srcVE, src, value, i);
235 vars.setVariable(v, ve);
236 }
237 }
238
239
240 if (vs != null)
241 {
242 IterationStatus itrS = new IterationStatus(first, !itr.hasNext(), i, sO, eO, mO, value);
243 if (t || srcVE == null)
244 {
245 ctx.setAttribute(vs, itrS);
246 }
247 else
248 {
249 ve = new IterationStatusExpression(itrS);
250 vars.setVariable(vs, ve);
251 }
252 }
253
254
255 this.nextHandler.apply(ctx, parent);
256
257
258 mi = 1;
259 while (mi < m && itr.hasNext())
260 {
261 itr.next();
262 mi++;
263 i++;
264 }
265 i++;
266
267 first = false;
268 }
269 }
270 finally
271 {
272 if (v != null)
273 {
274 vars.setVariable(v, vO);
275 }
276 if (vs != null)
277 {
278 vars.setVariable(vs, vsO);
279 }
280 }
281 }
282 fcc.endComponentUniqueIdSection();
283 }
284
285 if (fcc.isUsingPSSOnThisView() && fcc.isRefreshTransientBuildOnPSS() && !fcc.isRefreshingTransientBuild())
286 {
287
288 ComponentSupport.markComponentToRestoreFully(ctx.getFacesContext(), parent);
289 }
290 }
291
292 private final ValueExpression capture(String name, VariableMapper vars)
293 {
294 if (name != null)
295 {
296 return vars.setVariable(name, null);
297 }
298 return null;
299 }
300
301 private final int getBegin(FaceletContext ctx)
302 {
303 if (this.begin != null)
304 {
305 return this.begin.getInt(ctx);
306 }
307 return 0;
308 }
309
310 private final int getEnd(FaceletContext ctx)
311 {
312 if (this.end != null)
313 {
314 return this.end.getInt(ctx);
315 }
316 return Integer.MAX_VALUE - 1;
317 }
318
319 private final int getStep(FaceletContext ctx)
320 {
321 if (this.step != null)
322 {
323 return this.step.getInt(ctx);
324 }
325 return 1;
326 }
327
328 private final boolean getTransient(FaceletContext ctx)
329 {
330 if (this.tranzient != null)
331 {
332 return this.tranzient.getBoolean(ctx);
333 }
334 return false;
335 }
336
337 private final ValueExpression getVarExpr(ValueExpression ve, Object src, Object value, int i)
338 {
339 if (src instanceof List || src.getClass().isArray())
340 {
341 return new IndexedValueExpression(ve, i);
342 }
343 else if (src instanceof Map && value instanceof Map.Entry)
344 {
345 return new MappedValueExpression(ve, (Map.Entry) value);
346 }
347 else if (src instanceof Collection)
348 {
349 return new IteratedValueExpression(ve, value);
350 }
351 throw new IllegalStateException("Cannot create VE for: " + src);
352 }
353
354 private final String getVarName(FaceletContext ctx)
355 {
356 if (this.var != null)
357 {
358 return this.var.getValue(ctx);
359 }
360 return null;
361 }
362
363 private final String getVarStatusName(FaceletContext ctx)
364 {
365 if (this.varStatus != null)
366 {
367 return this.varStatus.getValue(ctx);
368 }
369 return null;
370 }
371
372 private final Iterator<?> toIterator(Object src)
373 {
374 if (src == null)
375 {
376 return null;
377 }
378 else if (src instanceof Collection)
379 {
380 return ((Collection<?>) src).iterator();
381 }
382 else if (src instanceof Map)
383 {
384 return ((Map<?, ?>) src).entrySet().iterator();
385 }
386 else if (src.getClass().isArray())
387 {
388 return new ArrayIterator(src);
389 }
390 else
391 {
392 throw new TagAttributeException(this.tag, this.items, "Must evaluate to a Collection, Map, Array, or null.");
393 }
394 }
395
396 }