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