View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    * 
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   * 
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  
19  package org.apache.struts2.jasper.tagplugins.jstl.core;
20  
21  import org.apache.struts2.jasper.compiler.tagplugin.TagPlugin;
22  import org.apache.struts2.jasper.compiler.tagplugin.TagPluginContext;
23  
24  public final class ForEach implements TagPlugin {
25  
26      private boolean hasVar, hasBegin, hasEnd, hasStep;
27  
28      public void doTag(TagPluginContext ctxt) {
29  
30          String index = null;
31  
32          boolean hasVarStatus = ctxt.isAttributeSpecified("varStatus");
33          if (hasVarStatus) {
34              ctxt.dontUseTagPlugin();
35              return;
36          }
37  
38          hasVar = ctxt.isAttributeSpecified("var");
39          hasBegin = ctxt.isAttributeSpecified("begin");
40          hasEnd = ctxt.isAttributeSpecified("end");
41          hasStep = ctxt.isAttributeSpecified("step");
42  
43          boolean hasItems = ctxt.isAttributeSpecified("items");
44          if (hasItems) {
45              doCollection(ctxt);
46              return;
47          }
48  
49          // We must have a begin and end attributes
50          index = ctxt.getTemporaryVariableName();
51          ctxt.generateJavaSource("for (int " + index + " = ");
52          ctxt.generateAttribute("begin");
53          ctxt.generateJavaSource("; " + index + " <= ");
54          ctxt.generateAttribute("end");
55          if (hasStep) {
56              ctxt.generateJavaSource("; " + index + "+=");
57              ctxt.generateAttribute("step");
58              ctxt.generateJavaSource(") {");
59          } else {
60              ctxt.generateJavaSource("; " + index + "++) {");
61          }
62  
63          // If var is specified and the body contains an EL, then sycn
64          // the var attribute
65          if (hasVar /* && ctxt.hasEL() */) {
66              ctxt.generateJavaSource("_jspx_page_context.setAttribute(");
67              ctxt.generateAttribute("var");
68              ctxt.generateJavaSource(", String.valueOf(" + index + "));");
69          }
70          ctxt.generateBody();
71          ctxt.generateJavaSource("}");
72      }
73  
74      /***
75       * Generate codes for Collections
76       * The pseudo code is:
77       */
78      private void doCollection(TagPluginContext ctxt) {
79  
80          ctxt.generateImport("java.util.*");
81          generateIterators(ctxt);
82  
83          String itemsV = ctxt.getTemporaryVariableName();
84          ctxt.generateJavaSource("Object " + itemsV + "= ");
85          ctxt.generateAttribute("items");
86          ctxt.generateJavaSource(";");
87  
88          String indexV = null, beginV = null, endV = null, stepV = null;
89          if (hasBegin) {
90              beginV = ctxt.getTemporaryVariableName();
91              ctxt.generateJavaSource("int " + beginV + " = ");
92              ctxt.generateAttribute("begin");
93              ctxt.generateJavaSource(";");
94          }
95          if (hasEnd) {
96              indexV = ctxt.getTemporaryVariableName();
97              ctxt.generateJavaSource("int " + indexV + " = 0;");
98              endV = ctxt.getTemporaryVariableName();
99              ctxt.generateJavaSource("int " + endV + " = ");
100             ctxt.generateAttribute("end");
101             ctxt.generateJavaSource(";");
102         }
103         if (hasStep) {
104             stepV = ctxt.getTemporaryVariableName();
105             ctxt.generateJavaSource("int " + stepV + " = ");
106             ctxt.generateAttribute("step");
107             ctxt.generateJavaSource(";");
108         }
109 
110         String iterV = ctxt.getTemporaryVariableName();
111         ctxt.generateJavaSource("Iterator " + iterV + " = null;");
112         // Object[]
113         ctxt.generateJavaSource("if (" + itemsV + " instanceof Object[])");
114         ctxt.generateJavaSource(iterV + "=toIterator((Object[])" + itemsV + ");");
115         // boolean[]
116         ctxt.generateJavaSource("else if (" + itemsV + " instanceof boolean[])");
117         ctxt.generateJavaSource(iterV + "=toIterator((boolean[])" + itemsV + ");");
118         // byte[]
119         ctxt.generateJavaSource("else if (" + itemsV + " instanceof byte[])");
120         ctxt.generateJavaSource(iterV + "=toIterator((byte[])" + itemsV + ");");
121         // char[]
122         ctxt.generateJavaSource("else if (" + itemsV + " instanceof char[])");
123         ctxt.generateJavaSource(iterV + "=toIterator((char[])" + itemsV + ");");
124         // short[]
125         ctxt.generateJavaSource("else if (" + itemsV + " instanceof short[])");
126         ctxt.generateJavaSource(iterV + "=toIterator((short[])" + itemsV + ");");
127         // int[]
128         ctxt.generateJavaSource("else if (" + itemsV + " instanceof int[])");
129         ctxt.generateJavaSource(iterV + "=toIterator((int[])" + itemsV + ");");
130         // long[]
131         ctxt.generateJavaSource("else if (" + itemsV + " instanceof long[])");
132         ctxt.generateJavaSource(iterV + "=toIterator((long[])" + itemsV + ");");
133         // float[]
134         ctxt.generateJavaSource("else if (" + itemsV + " instanceof float[])");
135         ctxt.generateJavaSource(iterV + "=toIterator((float[])" + itemsV + ");");
136         // double[]
137         ctxt.generateJavaSource("else if (" + itemsV + " instanceof double[])");
138         ctxt.generateJavaSource(iterV + "=toIterator((double[])" + itemsV + ");");
139 
140         // Collection
141         ctxt.generateJavaSource("else if (" + itemsV + " instanceof Collection)");
142         ctxt.generateJavaSource(iterV + "=((Collection)" + itemsV + ").iterator();");
143 
144         // Iterator
145         ctxt.generateJavaSource("else if (" + itemsV + " instanceof Iterator)");
146         ctxt.generateJavaSource(iterV + "=(Iterator)" + itemsV + ";");
147 
148         // Enumeration
149         ctxt.generateJavaSource("else if (" + itemsV + " instanceof Enumeration)");
150         ctxt.generateJavaSource(iterV + "=toIterator((Enumeration)" + itemsV + ");");
151 
152         // Map
153         ctxt.generateJavaSource("else if (" + itemsV + " instanceof Map)");
154         ctxt.generateJavaSource(iterV + "=((Map)" + itemsV + ").entrySet().iterator();");
155 
156         if (hasBegin) {
157             String tV = ctxt.getTemporaryVariableName();
158             ctxt.generateJavaSource("for (int " + tV + "=" + beginV + ";" +
159                     tV + ">0 && " + iterV + ".hasNext(); " +
160                     tV + "--)");
161             ctxt.generateJavaSource(iterV + ".next();");
162         }
163 
164         ctxt.generateJavaSource("while (" + iterV + ".hasNext()){");
165         if (hasVar) {
166             ctxt.generateJavaSource("_jspx_page_context.setAttribute(");
167             ctxt.generateAttribute("var");
168             ctxt.generateJavaSource(", " + iterV + ".next());");
169         }
170 
171         ctxt.generateBody();
172 
173         if (hasStep) {
174             String tV = ctxt.getTemporaryVariableName();
175             ctxt.generateJavaSource("for (int " + tV + "=" + stepV + "-1;" +
176                     tV + ">0 && " + iterV + ".hasNext(); " +
177                     tV + "--)");
178             ctxt.generateJavaSource(iterV + ".next();");
179         }
180         if (hasEnd) {
181             if (hasStep) {
182                 ctxt.generateJavaSource(indexV + "+=" + stepV + ";");
183             } else {
184                 ctxt.generateJavaSource(indexV + "++;");
185             }
186             if (hasBegin) {
187                 ctxt.generateJavaSource("if(" + beginV + "+" + indexV +
188                         ">" + endV + ")");
189             } else {
190                 ctxt.generateJavaSource("if(" + indexV + ">" + endV + ")");
191             }
192             ctxt.generateJavaSource("break;");
193         }
194         ctxt.generateJavaSource("}");    // while
195     }
196 
197     /***
198      * Generate iterators for data types supported in items
199      */
200     private void generateIterators(TagPluginContext ctxt) {
201 
202         // Object[]
203         ctxt.generateDeclaration("ObjectArrayIterator",
204                 "private Iterator toIterator(final Object[] a){\n" +
205                         "  return (new Iterator() {\n" +
206                         "    int index=0;\n" +
207                         "    public boolean hasNext() {\n" +
208                         "      return index < a.length;}\n" +
209                         "    public Object next() {\n" +
210                         "      return a[index++];}\n" +
211                         "    public void remove() {}\n" +
212                         "  });\n" +
213                         "}"
214         );
215 
216         // boolean[]
217         ctxt.generateDeclaration("booleanArrayIterator",
218                 "private Iterator toIterator(final boolean[] a){\n" +
219                         "  return (new Iterator() {\n" +
220                         "    int index=0;\n" +
221                         "    public boolean hasNext() {\n" +
222                         "      return index < a.length;}\n" +
223                         "    public Object next() {\n" +
224                         "      return new Boolean(a[index++]);}\n" +
225                         "    public void remove() {}\n" +
226                         "  });\n" +
227                         "}"
228         );
229 
230         // byte[]
231         ctxt.generateDeclaration("byteArrayIterator",
232                 "private Iterator toIterator(final byte[] a){\n" +
233                         "  return (new Iterator() {\n" +
234                         "    int index=0;\n" +
235                         "    public boolean hasNext() {\n" +
236                         "      return index < a.length;}\n" +
237                         "    public Object next() {\n" +
238                         "      return new Byte(a[index++]);}\n" +
239                         "    public void remove() {}\n" +
240                         "  });\n" +
241                         "}"
242         );
243 
244         // char[]
245         ctxt.generateDeclaration("charArrayIterator",
246                 "private Iterator toIterator(final char[] a){\n" +
247                         "  return (new Iterator() {\n" +
248                         "    int index=0;\n" +
249                         "    public boolean hasNext() {\n" +
250                         "      return index < a.length;}\n" +
251                         "    public Object next() {\n" +
252                         "      return new Character(a[index++]);}\n" +
253                         "    public void remove() {}\n" +
254                         "  });\n" +
255                         "}"
256         );
257 
258         // short[]
259         ctxt.generateDeclaration("shortArrayIterator",
260                 "private Iterator toIterator(final short[] a){\n" +
261                         "  return (new Iterator() {\n" +
262                         "    int index=0;\n" +
263                         "    public boolean hasNext() {\n" +
264                         "      return index < a.length;}\n" +
265                         "    public Object next() {\n" +
266                         "      return new Short(a[index++]);}\n" +
267                         "    public void remove() {}\n" +
268                         "  });\n" +
269                         "}"
270         );
271 
272         // int[]
273         ctxt.generateDeclaration("intArrayIterator",
274                 "private Iterator toIterator(final int[] a){\n" +
275                         "  return (new Iterator() {\n" +
276                         "    int index=0;\n" +
277                         "    public boolean hasNext() {\n" +
278                         "      return index < a.length;}\n" +
279                         "    public Object next() {\n" +
280                         "      return new Integer(a[index++]);}\n" +
281                         "    public void remove() {}\n" +
282                         "  });\n" +
283                         "}"
284         );
285 
286         // long[]
287         ctxt.generateDeclaration("longArrayIterator",
288                 "private Iterator toIterator(final long[] a){\n" +
289                         "  return (new Iterator() {\n" +
290                         "    int index=0;\n" +
291                         "    public boolean hasNext() {\n" +
292                         "      return index < a.length;}\n" +
293                         "    public Object next() {\n" +
294                         "      return new Long(a[index++]);}\n" +
295                         "    public void remove() {}\n" +
296                         "  });\n" +
297                         "}"
298         );
299 
300         // float[]
301         ctxt.generateDeclaration("floatArrayIterator",
302                 "private Iterator toIterator(final float[] a){\n" +
303                         "  return (new Iterator() {\n" +
304                         "    int index=0;\n" +
305                         "    public boolean hasNext() {\n" +
306                         "      return index < a.length;}\n" +
307                         "    public Object next() {\n" +
308                         "      return new Float(a[index++]);}\n" +
309                         "    public void remove() {}\n" +
310                         "  });\n" +
311                         "}"
312         );
313 
314         // double[]
315         ctxt.generateDeclaration("doubleArrayIterator",
316                 "private Iterator toIterator(final double[] a){\n" +
317                         "  return (new Iterator() {\n" +
318                         "    int index=0;\n" +
319                         "    public boolean hasNext() {\n" +
320                         "      return index < a.length;}\n" +
321                         "    public Object next() {\n" +
322                         "      return new Double(a[index++]);}\n" +
323                         "    public void remove() {}\n" +
324                         "  });\n" +
325                         "}"
326         );
327 
328         // Enumeration
329         ctxt.generateDeclaration("enumIterator",
330                 "private Iterator toIterator(final Enumeration e){\n" +
331                         "  return (new Iterator() {\n" +
332                         "    public boolean hasNext() {\n" +
333                         "      return e.hasMoreElements();}\n" +
334                         "    public Object next() {\n" +
335                         "      return e.nextElement();}\n" +
336                         "    public void remove() {}\n" +
337                         "  });\n" +
338                         "}"
339         );
340 
341     }
342 }