1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.struts.taglib.logic;
19
20 import org.apache.struts.taglib.TagUtils;
21 import org.apache.struts.util.IteratorAdapter;
22 import org.apache.struts.util.MessageResources;
23
24 import javax.servlet.jsp.JspException;
25 import javax.servlet.jsp.tagext.BodyTagSupport;
26
27 import java.lang.reflect.Array;
28
29 import java.util.ArrayList;
30 import java.util.Arrays;
31 import java.util.Collection;
32 import java.util.Enumeration;
33 import java.util.Iterator;
34 import java.util.Map;
35
36 /***
37 * Custom tag that iterates the elements of a collection, which can be either
38 * an attribute or the property of an attribute. The collection can be any of
39 * the following: an array of objects, an Enumeration, an Iterator, a
40 * Collection (which includes Lists, Sets and Vectors), or a Map (which
41 * includes Hashtables) whose elements will be iterated over.
42 *
43 * @version $Rev: 421129 $ $Date: 2004-11-03 14:20:47 -0500 (Wed, 03 Nov 2004)
44 * $
45 */
46 public class IterateTag extends BodyTagSupport {
47 /***
48 * The message resources for this package.
49 */
50 protected static MessageResources messages =
51 MessageResources.getMessageResources(
52 "org.apache.struts.taglib.logic.LocalStrings");
53
54
55
56 /***
57 * Iterator of the elements of this collection, while we are actually
58 * running.
59 */
60 protected Iterator iterator = null;
61
62 /***
63 * The number of elements we have already rendered.
64 */
65 protected int lengthCount = 0;
66
67 /***
68 * The actual length value (calculated in the start tag).
69 */
70 protected int lengthValue = 0;
71
72 /***
73 * The actual offset value (calculated in the start tag).
74 */
75 protected int offsetValue = 0;
76
77 /***
78 * Has this tag instance been started?
79 */
80 protected boolean started = false;
81
82
83
84 /***
85 * The collection over which we will be iterating.
86 */
87 protected Object collection = null;
88
89 /***
90 * The name of the scripting variable to be exposed.
91 */
92 protected String id = null;
93
94 /***
95 * The name of the scripting variable to be exposed as the current index.
96 */
97 protected String indexId = null;
98
99 /***
100 * The length value or attribute name (<=0 means no limit).
101 */
102 protected String length = null;
103
104 /***
105 * The name of the collection or owning bean.
106 */
107 protected String name = null;
108
109 /***
110 * The starting offset (zero relative).
111 */
112 protected String offset = null;
113
114 /***
115 * The property name containing the collection.
116 */
117 protected String property = null;
118
119 /***
120 * The scope of the bean specified by the name property, if any.
121 */
122 protected String scope = null;
123
124 /***
125 * The Java class of each exposed element of the collection.
126 */
127 protected String type = null;
128
129 public Object getCollection() {
130 return (this.collection);
131 }
132
133 public void setCollection(Object collection) {
134 this.collection = collection;
135 }
136
137 public String getId() {
138 return (this.id);
139 }
140
141 public void setId(String id) {
142 this.id = id;
143 }
144
145 /***
146 * <p>Return the zero-relative index of the current iteration through the
147 * loop. If you specify an <code>offset</code>, the first iteration
148 * through the loop will have that value; otherwise, the first iteration
149 * will return zero.</p>
150 *
151 * <p>This property is read-only, and gives nested custom tags access to
152 * this information. Therefore, it is <strong>only</strong> valid in
153 * between calls to <code>doStartTag()</code> and <code>doEndTag()</code>.
154 * </p>
155 */
156 public int getIndex() {
157 if (started) {
158 return ((offsetValue + lengthCount) - 1);
159 } else {
160 return (0);
161 }
162 }
163
164 public String getIndexId() {
165 return (this.indexId);
166 }
167
168 public void setIndexId(String indexId) {
169 this.indexId = indexId;
170 }
171
172 public String getLength() {
173 return (this.length);
174 }
175
176 public void setLength(String length) {
177 this.length = length;
178 }
179
180 public String getName() {
181 return (this.name);
182 }
183
184 public void setName(String name) {
185 this.name = name;
186 }
187
188 public String getOffset() {
189 return (this.offset);
190 }
191
192 public void setOffset(String offset) {
193 this.offset = offset;
194 }
195
196 public String getProperty() {
197 return (this.property);
198 }
199
200 public void setProperty(String property) {
201 this.property = property;
202 }
203
204 public String getScope() {
205 return (this.scope);
206 }
207
208 public void setScope(String scope) {
209 this.scope = scope;
210 }
211
212 public String getType() {
213 return (this.type);
214 }
215
216 public void setType(String type) {
217 this.type = type;
218 }
219
220
221
222 /***
223 * Construct an iterator for the specified collection, and begin looping
224 * through the body once per element.
225 *
226 * @throws JspException if a JSP exception has occurred
227 */
228 public int doStartTag() throws JspException {
229
230 Object collection = this.collection;
231
232 if (collection == null) {
233 collection =
234 TagUtils.getInstance().lookup(pageContext, name, property,
235 scope);
236 }
237
238 if (collection == null) {
239 JspException e =
240 new JspException(messages.getMessage("iterate.collection"));
241
242 TagUtils.getInstance().saveException(pageContext, e);
243 throw e;
244 }
245
246
247 if (collection.getClass().isArray()) {
248 try {
249
250
251 iterator = Arrays.asList((Object[]) collection).iterator();
252 } catch (ClassCastException e) {
253
254 int length = Array.getLength(collection);
255 ArrayList c = new ArrayList(length);
256
257 for (int i = 0; i < length; i++) {
258 c.add(Array.get(collection, i));
259 }
260
261 iterator = c.iterator();
262 }
263 } else if (collection instanceof Collection) {
264 iterator = ((Collection) collection).iterator();
265 } else if (collection instanceof Iterator) {
266 iterator = (Iterator) collection;
267 } else if (collection instanceof Map) {
268 iterator = ((Map) collection).entrySet().iterator();
269 } else if (collection instanceof Enumeration) {
270 iterator = new IteratorAdapter((Enumeration) collection);
271 } else {
272 JspException e =
273 new JspException(messages.getMessage("iterate.iterator"));
274
275 TagUtils.getInstance().saveException(pageContext, e);
276 throw e;
277 }
278
279
280 if (offset == null) {
281 offsetValue = 0;
282 } else {
283 try {
284 offsetValue = Integer.parseInt(offset);
285 } catch (NumberFormatException e) {
286 Integer offsetObject =
287 (Integer) TagUtils.getInstance().lookup(pageContext,
288 offset, null);
289
290 if (offsetObject == null) {
291 offsetValue = 0;
292 } else {
293 offsetValue = offsetObject.intValue();
294 }
295 }
296 }
297
298 if (offsetValue < 0) {
299 offsetValue = 0;
300 }
301
302
303 if (length == null) {
304 lengthValue = 0;
305 } else {
306 try {
307 lengthValue = Integer.parseInt(length);
308 } catch (NumberFormatException e) {
309 Integer lengthObject =
310 (Integer) TagUtils.getInstance().lookup(pageContext,
311 length, null);
312
313 if (lengthObject == null) {
314 lengthValue = 0;
315 } else {
316 lengthValue = lengthObject.intValue();
317 }
318 }
319 }
320
321 if (lengthValue < 0) {
322 lengthValue = 0;
323 }
324
325 lengthCount = 0;
326
327
328 for (int i = 0; i < offsetValue; i++) {
329 if (iterator.hasNext()) {
330 iterator.next();
331 }
332 }
333
334
335 if (iterator.hasNext()) {
336 Object element = iterator.next();
337
338 if (element == null) {
339 pageContext.removeAttribute(id);
340 } else {
341 pageContext.setAttribute(id, element);
342 }
343
344 lengthCount++;
345 started = true;
346
347 if (indexId != null) {
348 pageContext.setAttribute(indexId, new Integer(getIndex()));
349 }
350
351 return (EVAL_BODY_TAG);
352 } else {
353 return (SKIP_BODY);
354 }
355 }
356
357 /***
358 * Make the next collection element available and loop, or finish the
359 * iterations if there are no more elements.
360 *
361 * @throws JspException if a JSP exception has occurred
362 */
363 public int doAfterBody() throws JspException {
364
365 if (bodyContent != null) {
366 TagUtils.getInstance().writePrevious(pageContext,
367 bodyContent.getString());
368 bodyContent.clearBody();
369 }
370
371
372 if ((lengthValue > 0) && (lengthCount >= lengthValue)) {
373 return (SKIP_BODY);
374 }
375
376 if (iterator.hasNext()) {
377 Object element = iterator.next();
378
379 if (element == null) {
380 pageContext.removeAttribute(id);
381 } else {
382 pageContext.setAttribute(id, element);
383 }
384
385 lengthCount++;
386
387 if (indexId != null) {
388 pageContext.setAttribute(indexId, new Integer(getIndex()));
389 }
390
391 return (EVAL_BODY_TAG);
392 } else {
393 return (SKIP_BODY);
394 }
395 }
396
397 /***
398 * Clean up after processing this enumeration.
399 *
400 * @throws JspException if a JSP exception has occurred
401 */
402 public int doEndTag() throws JspException {
403
404 started = false;
405 iterator = null;
406
407
408 return (EVAL_PAGE);
409 }
410
411 /***
412 * Release all allocated resources.
413 */
414 public void release() {
415 super.release();
416
417 iterator = null;
418 lengthCount = 0;
419 lengthValue = 0;
420 offsetValue = 0;
421
422 id = null;
423 collection = null;
424 length = null;
425 name = null;
426 offset = null;
427 property = null;
428 scope = null;
429 started = false;
430 }
431 }