KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > commons > jelly > tags > core > ForEachTag


1 /*
2  * Copyright 2002,2004 The Apache Software Foundation.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16
17 package org.apache.commons.jelly.tags.core;
18
19 import java.util.Iterator JavaDoc;
20
21 import javax.servlet.jsp.jstl.core.LoopTagStatus;
22
23 import org.apache.commons.jelly.JellyTagException;
24 import org.apache.commons.jelly.MissingAttributeException;
25 import org.apache.commons.jelly.TagSupport;
26 import org.apache.commons.jelly.XMLOutput;
27 import org.apache.commons.jelly.expression.Expression;
28 import org.apache.commons.jelly.impl.BreakException;
29 import org.apache.commons.logging.Log;
30 import org.apache.commons.logging.LogFactory;
31
32 /**
33   * Iterates over a collection, iterator or an array of objects.
34   * Uses the same syntax as the <a HREF="http://java.sun.com/products/jsp/jstl/">JSTL</a>
35   * <code>forEach</code> tag does.
36   *
37   * @author <a HREF="mailto:jstrachan@apache.org">James Strachan</a>
38   * @version $Revision: 155420 $
39   */

40 public class ForEachTag extends TagSupport {
41
42     /** The Log to which logging calls will be made. */
43     private static final Log log = LogFactory.getLog(ForEachTag.class);
44
45     /** Holds the variable name to export for the item being iterated over. */
46     private Expression items;
47
48     /**
49      * If specified then the current item iterated through will be defined
50      * as the given variable name.
51      */

52     private String JavaDoc var;
53
54     /**
55      * If specified then the current index counter will be defined
56      * as the given variable name.
57      */

58     private String JavaDoc indexVar;
59     
60     /** variable to hold loop status */
61     private String JavaDoc statusVar;
62
63     /** The starting index value */
64     private int begin;
65
66     /** The ending index value */
67     private int end = Integer.MAX_VALUE;
68
69     /** The index increment step */
70     private int step = 1;
71
72     /** The iteration index */
73     private int index;
74
75     public ForEachTag() {
76     }
77
78     // Tag interface
79

80     //-------------------------------------------------------------------------
81
public void doTag(XMLOutput output) throws MissingAttributeException, JellyTagException {
82
83         if (log.isDebugEnabled()) {
84             log.debug("running with items: " + items);
85         }
86
87         try {
88             if (items != null) {
89                 Iterator JavaDoc iter = items.evaluateAsIterator(context);
90              
91                 if (log.isDebugEnabled()) {
92                     log.debug("Iterating through: " + iter);
93                 }
94
95                 // ignore the first items of the iterator
96
for (index = 0; index < begin && iter.hasNext(); index++ ) {
97                     iter.next();
98                 }
99                 
100                 // set up the status
101
LoopStatus status = null;
102                 if (statusVar != null)
103                 {
104                     // set up statii as required by JSTL
105
Integer JavaDoc statusBegin = (begin == 0) ? null : new Integer JavaDoc(begin);
106                     Integer JavaDoc statusEnd = (end == Integer.MAX_VALUE) ? null : new Integer JavaDoc(end);
107                     Integer JavaDoc statusStep = (step == 1) ? null : new Integer JavaDoc(step);
108                     status = new LoopStatus(statusBegin, statusEnd, statusStep);
109                     context.setVariable(statusVar, status);
110                 }
111
112                 boolean firstTime = true;
113                 int count = 0;
114                 while (iter.hasNext() && index <= end) {
115                     Object JavaDoc value = iter.next();
116                     if (var != null) {
117                         context.setVariable(var, value);
118                     }
119                     if (indexVar != null) {
120                         context.setVariable(indexVar, new Integer JavaDoc(index));
121                     }
122                     // set the status var up
123
if (statusVar != null) {
124                         count++;
125                         status.setCount(count);
126                         status.setCurrent(value);
127                         status.setFirst(firstTime);
128                         status.setIndex(index);
129                         // set first time up for the next iteration.
130
if (firstTime) {
131                             firstTime = !firstTime;
132                         }
133                     }
134                     // now we need to work out the next index for status isLast
135
// and also advance the iterator and index for the loop.
136
boolean finished = false;
137                     index++;
138                     for ( int i = 1; i < step && !finished; i++, index++ ) {
139                         if ( ! iter.hasNext() ) {
140                            finished = true;
141                         }
142                         else {
143                             iter.next();
144                         }
145                     }
146
147                     if (statusVar != null) {
148                         status.setLast(finished || !iter.hasNext() || index > end);
149                     }
150                     invokeBody(output);
151
152                 }
153             }
154             else {
155                 if ( end == Integer.MAX_VALUE && begin == 0 ) {
156                     throw new MissingAttributeException( "items" );
157                 }
158                 else {
159                     String JavaDoc varName = var;
160                     if ( varName == null ) {
161                         varName = indexVar;
162                     }
163                     // set up the status
164
LoopStatus status = null;
165                     if (statusVar != null)
166                     {
167                         // set up statii as required by JSTL
168
Integer JavaDoc statusBegin = new Integer JavaDoc(begin);
169                         Integer JavaDoc statusEnd = new Integer JavaDoc(end);
170                         Integer JavaDoc statusStep = new Integer JavaDoc(step);
171                         status = new LoopStatus(statusBegin, statusEnd, statusStep);
172                         context.setVariable(statusVar, status);
173                     }
174
175                     int count = 0;
176                     for (index = begin; index <= end; index += step ) {
177
178                         Object JavaDoc value = new Integer JavaDoc(index);
179                         if (varName != null) {
180                             context.setVariable(varName, value);
181                         }
182                         // set the status var up
183
if (status != null) {
184                             count++;
185                             status.setIndex(index);
186                             status.setCount(count);
187                             status.setCurrent(value);
188                             status.setFirst(index == begin);
189                             status.setLast(index > end - step);
190                         }
191                         invokeBody(output);
192                     }
193                 }
194             }
195         }
196         catch (BreakException e) {
197             if (log.isDebugEnabled()) {
198                 log.debug("loop terminated by break: " + e, e);
199             }
200         }
201     }
202
203     // Properties
204
//-------------------------------------------------------------------------
205

206     /**
207      * Sets the expression used to iterate over.
208      * This expression could resolve to an Iterator, Collection, Map, Array,
209      * Enumeration or comma separated String.
210      */

211     public void setItems(Expression items) {
212         this.items = items;
213     }
214
215     /** Sets the variable name to export for the item being iterated over
216      */

217     public void setVar(String JavaDoc var) {
218         this.var = var;
219     }
220
221     /** Sets the variable name to export the current index counter to
222      */

223     public void setIndexVar(String JavaDoc indexVar) {
224         this.indexVar = indexVar;
225     }
226
227     /** Sets the starting index value
228      */

229     public void setBegin(int begin) {
230         this.begin = begin;
231     }
232
233     /** Sets the ending index value
234      */

235     public void setEnd(int end) {
236         this.end = end;
237     }
238
239     /** Sets the index increment step
240      */

241     public void setStep(int step) {
242         this.step = step;
243     }
244
245     /**
246      * Sets the variable name to export the current status to.
247      * The status is an implementation of the JSTL LoopTagStatus interface that provides
248      * the following bean properties:
249      * <ul>
250      * <li>current - the current value of the loop items being iterated</li>
251      * <li>index - the current index of the items being iterated</li>
252      * <li>first - true if this is the first iteration, false otherwise</li>
253      * <li>last - true if this is the last iteration, false otherwise</li>
254      * <li>begin - the starting index of the loop</li>
255      * <li>step - the stepping value of the loop</li>
256      * <li>end - the end index of the loop</li>
257      * </ul>
258      */

259     public void setVarStatus(String JavaDoc var) {
260         this.statusVar = var;
261     }
262     
263     /**
264      * Holds the status of the loop.
265      */

266     public static final class LoopStatus implements LoopTagStatus
267     {
268         private Integer JavaDoc begin;
269         private int count;
270         private Object JavaDoc current;
271         private Integer JavaDoc end;
272         private int index;
273         private Integer JavaDoc step;
274         private boolean first;
275         private boolean last;
276         
277         public LoopStatus(Integer JavaDoc begin, Integer JavaDoc end, Integer JavaDoc step) {
278             this.begin = begin;
279             this.end = end;
280             this.step = step;
281         }
282         /**
283          * @return Returns the begin.
284          */

285         public Integer JavaDoc getBegin() {
286             return begin;
287         }
288         /**
289          * @return Returns the count.
290          */

291         public int getCount() {
292             return count;
293         }
294         /**
295          * @return Returns the current.
296          */

297         public Object JavaDoc getCurrent() {
298             return current;
299         }
300         /**
301          * @return Returns the end.
302          */

303         public Integer JavaDoc getEnd() {
304             return end;
305         }
306         /**
307          * @return Returns the first.
308          */

309         public boolean isFirst() {
310             return first;
311         }
312         /**
313          * @return Returns the index.
314          */

315         public int getIndex() {
316             return index;
317         }
318         /**
319          * @return Returns the last.
320          */

321         public boolean isLast() {
322             return last;
323         }
324         /**
325          * @return Returns the step.
326          */

327         public Integer JavaDoc getStep() {
328             return step;
329         }
330         /**
331          * @param count The count to set.
332          */

333         public void setCount(int count) {
334             this.count = count;
335         }
336         /**
337          * @param current The current to set.
338          */

339         public void setCurrent(Object JavaDoc current) {
340             this.current = current;
341         }
342         /**
343          * @param first The first to set.
344          */

345         public void setFirst(boolean first) {
346             this.first = first;
347         }
348         /**
349          * @param last The last to set.
350          */

351         public void setLast(boolean last) {
352             this.last = last;
353         }
354         /**
355          * @param index The index to set.
356          */

357         public void setIndex(int index) {
358             this.index = index;
359         }
360     }
361 }
362
Popular Tags