KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > taglibs > standard > tag > common > core > ForEachSupport


1 /*
2  * Copyright 1999-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.taglibs.standard.tag.common.core;
18
19 import java.util.Arrays JavaDoc;
20 import java.util.Collection JavaDoc;
21 import java.util.Enumeration JavaDoc;
22 import java.util.Iterator JavaDoc;
23 import java.util.Map JavaDoc;
24 import java.util.StringTokenizer JavaDoc;
25
26 import javax.servlet.jsp.JspTagException JavaDoc;
27 import javax.servlet.jsp.jstl.core.LoopTagSupport;
28
29 import org.apache.taglibs.standard.resources.Resources;
30
31 /**
32  * <p>Support for tag handlers for &lt;forEach&gt;, the core iteration
33  * tag in JSTL 1.0. This class extends LoopTagSupport and provides
34  * ForEach-specific functionality. The rtexprvalue library and the
35  * expression-evaluating library each have handlers that extend this
36  * class.</p>
37  *
38  * <p>Localized here is the logic for handling the veritable smorgasbord
39  * of types supported by &lt;forEach&gt;, including arrays,
40  * Collections, and others. To see how the actual iteration is controlled,
41  * review the javax.servlet.jsp.jstl.core.LoopTagSupport class instead.
42  * </p>
43  *
44  * @see javax.servlet.jsp.jstl.core.LoopTagSupport
45  * @author Shawn Bayern
46  */

47
48 public abstract class ForEachSupport extends LoopTagSupport {
49
50     //*********************************************************************
51
// Implementation overview
52

53     /*
54      * This particular handler is essentially a large switching mechanism
55      * to support the various types that the <forEach> tag handles. The
56      * class is organized around the private ForEachIterator interface,
57      * which serves as the basis for relaying information to the iteration
58      * implementation we inherit from LoopTagSupport.
59      *
60      * We expect to receive our 'items' from one of our subclasses
61      * (presumably from the rtexprvalue or expression-evaluating libraries).
62      * If 'items' is missing, we construct an Integer[] array representing
63      * iteration indices, in line with the spec draft. From doStartTag(),
64      * we analyze and 'digest' the data we're passed. Then, we simply
65      * relay items as necessary to the iteration implementation that
66      * we inherit from LoopTagSupport.
67      */

68
69
70     //*********************************************************************
71
// Internal, supporting classes and interfaces
72

73     /*
74      * Acts as a focal point for converting the various types we support.
75      * It would have been ideal to use Iterator here except for one problem:
76      * Iterator.hasNext() and Iterator.next() can't throw the JspTagException
77      * we want to throw. So instead, we'll encapsulate the hasNext() and
78      * next() methods we want to provide inside this local class.
79      * (Other implementations are more than welcome to implement hasNext()
80      * and next() explicitly, not in terms of a back-end supporting class.
81      * For the forEach tag handler, however, this class acts as a convenient
82      * organizational mechanism, for we support so many different classes.
83      * This encapsulation makes it easier to localize implementations
84      * in support of particular types -- e.g., changing the implementation
85      * of primitive-array iteration to wrap primitives only on request,
86      * instead of in advance, would involve changing only those methods that
87      * handle primitive arrays.
88      */

89     protected static interface ForEachIterator {
90         public boolean hasNext() throws JspTagException JavaDoc;
91         public Object JavaDoc next() throws JspTagException JavaDoc;
92     }
93
94     /*
95      * Simple implementation of ForEachIterator that adapts from
96      * an Iterator. This is appropriate for cases where hasNext() and
97      * next() don't need to throw JspTagException. Such cases are common.core.
98      */

99     protected class SimpleForEachIterator implements ForEachIterator {
100         private Iterator JavaDoc i;
101         public SimpleForEachIterator(Iterator JavaDoc i) {
102             this.i = i;
103         }
104         public boolean hasNext() {
105             return i.hasNext();
106         }
107         public Object JavaDoc next() {
108             return i.next();
109         }
110     }
111
112
113     //*********************************************************************
114
// ForEach-specifc state (protected)
115

116     protected ForEachIterator items; // our 'digested' items
117
protected Object JavaDoc rawItems; // our 'raw' items
118

119
120     //*********************************************************************
121
// Iteration control methods (based on processed 'items' object)
122

123     // (We inherit semantics and Javadoc from LoopTagSupport.)
124

125     protected boolean hasNext() throws JspTagException JavaDoc {
126         return items.hasNext();
127     }
128
129     protected Object JavaDoc next() throws JspTagException JavaDoc {
130         return items.next();
131     }
132
133     protected void prepare() throws JspTagException JavaDoc {
134         // produce the right sort of ForEachIterator
135
if (rawItems != null) {
136             // extract an iterator over the 'items' we've got
137
items = supportedTypeForEachIterator(rawItems);
138         } else {
139             // no 'items', so use 'begin' and 'end'
140
items = beginEndForEachIterator();
141         }
142
143         /* ResultSet no more supported in <c:forEach>
144         // step must be 1 when ResultSet is passed in
145         if (rawItems instanceof ResultSet && step != 1)
146             throw new JspTagException(
147         Resources.getMessage("FOREACH_STEP_NO_RESULTSET"));
148         */

149     }
150
151
152     //*********************************************************************
153
// Tag logic and lifecycle management
154

155     // Releases any resources we may have (or inherit)
156
public void release() {
157         super.release();
158         items = null;
159         rawItems = null;
160     }
161
162
163     //*********************************************************************
164
// Private generation methods for the ForEachIterators we produce
165

166     /* Extracts a ForEachIterator given an object of a supported type. */
167     protected ForEachIterator supportedTypeForEachIterator(Object JavaDoc o)
168             throws JspTagException JavaDoc {
169
170         /*
171          * This is, of necessity, just a big, simple chain, matching in
172          * order. Since we are passed on Object because of all the
173          * various types we support, we cannot rely on the language's
174          * mechanism for resolving overloaded methods. (Method overloading
175          * resolves via early binding, so the type of the 'o' reference,
176          * not the type of the eventual value that 'o' references, is
177          * all that's available.)
178          *
179          * Currently, we 'match' on the object we have through an
180          * if/else chain that picks the first interface (or class match)
181          * found for an Object.
182          */

183
184         ForEachIterator items;
185
186         if (o instanceof Object JavaDoc[])
187             items = toForEachIterator((Object JavaDoc[]) o);
188         else if (o instanceof boolean[])
189             items = toForEachIterator((boolean[]) o);
190         else if (o instanceof byte[])
191             items = toForEachIterator((byte[]) o);
192         else if (o instanceof char[])
193             items = toForEachIterator((char[]) o);
194         else if (o instanceof short[])
195             items = toForEachIterator((short[]) o);
196         else if (o instanceof int[])
197             items = toForEachIterator((int[]) o);
198         else if (o instanceof long[])
199             items = toForEachIterator((long[]) o);
200         else if (o instanceof float[])
201             items = toForEachIterator((float[]) o);
202         else if (o instanceof double[])
203             items = toForEachIterator((double[]) o);
204         else if (o instanceof Collection JavaDoc)
205             items = toForEachIterator((Collection JavaDoc) o);
206         else if (o instanceof Iterator JavaDoc)
207             items = toForEachIterator((Iterator JavaDoc) o);
208         else if (o instanceof Enumeration JavaDoc)
209             items = toForEachIterator((Enumeration JavaDoc) o);
210         else if (o instanceof Map JavaDoc)
211             items = toForEachIterator((Map JavaDoc) o);
212         /*
213         else if (o instanceof ResultSet)
214             items = toForEachIterator((ResultSet) o);
215         */

216         else if (o instanceof String JavaDoc)
217             items = toForEachIterator((String JavaDoc) o);
218         else
219             items = toForEachIterator(o);
220
221         return (items);
222     }
223
224     /*
225      * Creates a ForEachIterator of Integers from 'begin' to 'end'
226      * in support of cases where our tag handler isn't passed an
227      * explicit collection over which to iterate.
228      */

229     private ForEachIterator beginEndForEachIterator() {
230         /*
231          * To plug into existing support, we need to keep 'begin', 'end',
232          * and 'step' as they are. So we'll simply create an Integer[]
233          * from 0 to 'end', inclusive, and let the existing implementation
234          * handle the subsetting and stepping operations. (Other than
235          * localizing the cost of creating this Integer[] to the start
236          * of the operation instead of spreading it out over the lifetime
237          * of the iteration, this implementation isn't worse than one that
238          * created new Integers() as needed from next(). Such an adapter
239          * to ForEachIterator could easily be written but, like I said,
240          * wouldn't provide much benefit.)
241          */

242         Integer JavaDoc[] ia = new Integer JavaDoc[end + 1];
243         for (int i = 0; i <= end; i++)
244             ia[i] = new Integer JavaDoc(i);
245         return new SimpleForEachIterator(Arrays.asList(ia).iterator());
246     }
247
248
249     //*********************************************************************
250
// Private conversion methods to handle the various types we support
251

252     // catch-all method whose invocation currently signals a 'matching error'
253
protected ForEachIterator toForEachIterator(Object JavaDoc o)
254             throws JspTagException JavaDoc {
255         throw new JspTagException JavaDoc(Resources.getMessage("FOREACH_BAD_ITEMS"));
256     }
257
258     // returns an iterator over an Object array (via List)
259
protected ForEachIterator toForEachIterator(Object JavaDoc[] a) {
260         return new SimpleForEachIterator(Arrays.asList(a).iterator());
261     }
262
263     // returns an iterator over a boolean[] array, wrapping items in Boolean
264
protected ForEachIterator toForEachIterator(boolean[] a) {
265         Boolean JavaDoc[] wrapped = new Boolean JavaDoc[a.length];
266         for (int i = 0; i < a.length; i++)
267             wrapped[i] = new Boolean JavaDoc(a[i]);
268         return new SimpleForEachIterator(Arrays.asList(wrapped).iterator());
269     }
270
271     // returns an iterator over a byte[] array, wrapping items in Byte
272
protected ForEachIterator toForEachIterator(byte[] a) {
273         Byte JavaDoc[] wrapped = new Byte JavaDoc[a.length];
274         for (int i = 0; i < a.length; i++)
275             wrapped[i] = new Byte JavaDoc(a[i]);
276         return new SimpleForEachIterator(Arrays.asList(wrapped).iterator());
277     }
278
279     // returns an iterator over a char[] array, wrapping items in Character
280
protected ForEachIterator toForEachIterator(char[] a) {
281         Character JavaDoc[] wrapped = new Character JavaDoc[a.length];
282         for (int i = 0; i < a.length; i++)
283             wrapped[i] = new Character JavaDoc(a[i]);
284         return new SimpleForEachIterator(Arrays.asList(wrapped).iterator());
285     }
286
287     // returns an iterator over a short[] array, wrapping items in Short
288
protected ForEachIterator toForEachIterator(short[] a) {
289         Short JavaDoc[] wrapped = new Short JavaDoc[a.length];
290         for (int i = 0; i < a.length; i++)
291             wrapped[i] = new Short JavaDoc(a[i]);
292         return new SimpleForEachIterator(Arrays.asList(wrapped).iterator());
293     }
294
295     // returns an iterator over an int[] array, wrapping items in Integer
296
protected ForEachIterator toForEachIterator(int[] a) {
297         Integer JavaDoc[] wrapped = new Integer JavaDoc[a.length];
298         for (int i = 0; i < a.length; i++)
299             wrapped[i] = new Integer JavaDoc(a[i]);
300         return new SimpleForEachIterator(Arrays.asList(wrapped).iterator());
301     }
302
303     // returns an iterator over a long[] array, wrapping items in Long
304
protected ForEachIterator toForEachIterator(long[] a) {
305         Long JavaDoc[] wrapped = new Long JavaDoc[a.length];
306         for (int i = 0; i < a.length; i++)
307             wrapped[i] = new Long JavaDoc(a[i]);
308         return new SimpleForEachIterator(Arrays.asList(wrapped).iterator());
309     }
310
311     // returns an iterator over a float[] array, wrapping items in Float
312
protected ForEachIterator toForEachIterator(float[] a) {
313         Float JavaDoc[] wrapped = new Float JavaDoc[a.length];
314         for (int i = 0; i < a.length; i++)
315             wrapped[i] = new Float JavaDoc(a[i]);
316         return new SimpleForEachIterator(Arrays.asList(wrapped).iterator());
317     }
318
319     // returns an iterator over a double[] array, wrapping items in Double
320
protected ForEachIterator toForEachIterator(double[] a) {
321         Double JavaDoc[] wrapped = new Double JavaDoc[a.length];
322         for (int i = 0; i < a.length; i++)
323             wrapped[i] = new Double JavaDoc(a[i]);
324         return new SimpleForEachIterator(Arrays.asList(wrapped).iterator());
325     }
326
327     // retrieves an iterator from a Collection
328
protected ForEachIterator toForEachIterator(Collection JavaDoc c) {
329         return new SimpleForEachIterator(c.iterator());
330     }
331
332     // simply passes an Iterator through...
333
protected ForEachIterator toForEachIterator(Iterator JavaDoc i) {
334         return new SimpleForEachIterator(i);
335     }
336
337     // converts an Enumeration to an Iterator via a local adapter
338
protected ForEachIterator toForEachIterator(Enumeration JavaDoc e) {
339
340         // local adapter
341
class EnumerationAdapter implements ForEachIterator {
342             private Enumeration JavaDoc e;
343             public EnumerationAdapter(Enumeration JavaDoc e) {
344                 this.e = e;
345             }
346             public boolean hasNext() {
347                 return e.hasMoreElements();
348             }
349             public Object JavaDoc next() {
350                 return e.nextElement();
351             }
352         }
353
354         return new EnumerationAdapter(e);
355     }
356
357     // retrieves an iterator over the Map.Entry items in a Map
358
protected ForEachIterator toForEachIterator(Map JavaDoc m) {
359         return new SimpleForEachIterator(m.entrySet().iterator());
360     }
361
362     /* No more supported in JSTL. See interface Result instead.
363     // thinly wraps a ResultSet in an appropriate Iterator
364     protected ForEachIterator toForEachIterator(ResultSet rs)
365             throws JspTagException {
366
367         // local adapter
368         class ResultSetAdapter implements ForEachIterator {
369             private ResultSet rs;
370             public ResultSetAdapter(ResultSet rs) {
371                 this.rs = rs;
372             }
373             public boolean hasNext() throws JspTagException {
374                 try {
375                     return !(rs.isLast()); // dependent on JDBC 2.0
376                 } catch (java.sql.SQLException ex) {
377                     throw new JspTagException(ex.getMessage());
378                 }
379             }
380             public Object next() throws JspTagException {
381                 try {
382                     rs.next();
383                     return rs;
384                 } catch (java.sql.SQLException ex) {
385                     throw new JspTagException(ex.getMessage());
386                 }
387             }
388         }
389
390         return new ResultSetAdapter(rs);
391     }
392     */

393
394     // tokenizes a String as a CSV and returns an iterator over it
395
protected ForEachIterator toForEachIterator(String JavaDoc s) {
396         StringTokenizer JavaDoc st = new StringTokenizer JavaDoc(s, ",");
397         return toForEachIterator(st); // convert from Enumeration
398
}
399
400 }
401
Popular Tags