KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > cocoon > taglib > 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.cocoon.taglib.core;
18
19 import java.sql.ResultSet JavaDoc;
20 import java.util.Arrays JavaDoc;
21 import java.util.Collection JavaDoc;
22 import java.util.Enumeration JavaDoc;
23 import java.util.Iterator JavaDoc;
24 import java.util.Map JavaDoc;
25 import java.util.StringTokenizer JavaDoc;
26
27 import org.apache.commons.lang.BooleanUtils;
28 import org.xml.sax.SAXException JavaDoc;
29
30 /**
31  * <p>Support for tag handlers for &lt;forEach&gt;, the core iteration
32  * tag in JSTL 1.0. This class extends LoopTagSupport and provides
33  * ForEach-specific functionality. The rtexprvalue library and the
34  * expression-evaluating library each have handlers that extend this
35  * class.</p>
36  *
37  * <p>Localized here is the logic for handling the veritable smorgasbord
38  * of types supported by &lt;forEach&gt;, including arrays,
39  * Collections, and others. To see how the actual iteration is controlled,
40  * review the org.apache.cocoon.taglib.core.LoopTagSupport class instead.
41  * </p>
42  *
43  * @see org.apache.cocoon.taglib.core.LoopTagSupport
44  *
45  * Migration from JSTL1.0
46  * @see org.apache.taglibs.standard.tag.common.core
47  *
48  * @author <a HREF="mailto:volker.schmitt@basf-it-services.com">Volker Schmitt</a>
49  * @version CVS $Id: ForEachSupport.java 124685 2005-01-08 22:20:56Z antonio $
50  */

51 public abstract class ForEachSupport extends LoopTagSupport {
52
53     //*********************************************************************
54
// Implementation overview
55

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

71
72     //*********************************************************************
73
// Internal, supporting classes and interfaces
74

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

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

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

117     protected ForEachIterator items; // our 'digested' items
118
protected Object JavaDoc rawItems; // our 'raw' items
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 SAXException JavaDoc {
126         return items.hasNext();
127     }
128
129     protected Object JavaDoc next() throws SAXException JavaDoc {
130         return items.next();
131     }
132
133     protected void prepare() throws SAXException 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         // step must be 1 when ResultSet is passed in
144
if (rawItems instanceof ResultSet JavaDoc && step != 1)
145             throw new SAXException JavaDoc("FOREACH_STEP_NO_RESULTSET");
146     }
147
148     //*********************************************************************
149
// Tag logic and lifecycle management
150

151     // Releases any resources we may have (or inherit)
152
public void recycle() {
153         super.recycle();
154         items = null;
155         rawItems = null;
156     }
157
158     //*********************************************************************
159
// Private generation methods for the ForEachIterators we produce
160

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

177
178         ForEachIterator items;
179
180         if (o instanceof Object JavaDoc[])
181             items = toForEachIterator((Object JavaDoc[]) o);
182         else if (o instanceof boolean[])
183             items = toForEachIterator((boolean[]) o);
184         else if (o instanceof byte[])
185             items = toForEachIterator((byte[]) o);
186         else if (o instanceof char[])
187             items = toForEachIterator((char[]) o);
188         else if (o instanceof short[])
189             items = toForEachIterator((short[]) o);
190         else if (o instanceof int[])
191             items = toForEachIterator((int[]) o);
192         else if (o instanceof long[])
193             items = toForEachIterator((long[]) o);
194         else if (o instanceof float[])
195             items = toForEachIterator((float[]) o);
196         else if (o instanceof double[])
197             items = toForEachIterator((double[]) o);
198         else if (o instanceof Collection JavaDoc)
199             items = toForEachIterator((Collection JavaDoc) o);
200         else if (o instanceof Iterator JavaDoc)
201             items = toForEachIterator((Iterator JavaDoc) o);
202         else if (o instanceof Enumeration JavaDoc)
203             items = toForEachIterator((Enumeration JavaDoc) o);
204         else if (o instanceof Map JavaDoc)
205             items = toForEachIterator((Map JavaDoc) o);
206         else if (o instanceof ResultSet JavaDoc)
207             items = toForEachIterator((ResultSet JavaDoc) o);
208         else if (o instanceof String JavaDoc)
209             items = toForEachIterator((String JavaDoc) o);
210         else
211             items = toForEachIterator(o);
212
213         return (items);
214     }
215
216     /*
217      * Creates a ForEachIterator of Integers from 'begin' to 'end'
218      * in support of cases where our tag handler isn't passed an
219      * explicit collection over which to iterate.
220      */

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

234         Integer JavaDoc[] ia = new Integer JavaDoc[end + 1];
235         for (int i = 0; i <= end; i++)
236             ia[i] = new Integer JavaDoc(i);
237         return new SimpleForEachIterator(Arrays.asList(ia).iterator());
238     }
239
240     //*********************************************************************
241
// Private conversion methods to handle the various types we support
242

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