1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 package org.apache.struts2.components;
22
23 import java.io.Writer;
24 import java.util.Iterator;
25
26 import org.apache.struts2.views.annotations.StrutsTag;
27 import org.apache.struts2.views.annotations.StrutsTagAttribute;
28 import org.apache.struts2.util.MakeIterator;
29 import org.apache.struts2.views.jsp.IteratorStatus;
30
31 import com.opensymphony.xwork2.util.ValueStack;
32
33 /***
34 * <!-- START SNIPPET: javadoc -->
35 *
36 * <p>Iterator will iterate over a value. An iterable value can be either of: java.util.Collection, java.util.Iterator,
37 * java.util.Enumeration, java.util.Map, array.</p> <p/> <!-- END SNIPPET: javadoc -->
38 *
39 * <!-- START SNIPPET: params -->
40 *
41 * <ul>
42 *
43 * <li>status (String) - if specified, an instanceof IteratorStatus will be pushed into stack upon each iteration</li>
44 *
45 * <li>value (Object) - the source to iterate over, must be iteratable, else an the object itself will be put into a
46 * newly created List (see MakeIterator#convert(Object)</li>
47 *
48 * <li>id (String) - if specified the current iteration object will be place with this id in Struts stack's context
49 * scope</li>
50 *
51 * </ul>
52 *
53 * <!-- END SNIPPET: params -->
54 *
55 * <!-- START SNIPPET: example1description -->
56 *
57 * <p>The following example retrieves the value of the getDays() method of the current object on the value stack and
58 * uses it to iterate over. The <s:property/> tag prints out the current value of the iterator.</p>
59 *
60 * <!-- END SNIPPET: example1description -->
61 *
62 * <pre>
63 * <!-- START SNIPPET: example1code -->
64 * <s:iterator value="days">
65 * <p>day is: <s:property/></p>
66 * </s:iterator>
67 * <!-- END SNIPPET: example1code -->
68 * </pre>
69 *
70 *
71 * <!-- START SNIPPET: example2description -->
72 *
73 * <p>The following example uses a {@link Bean} tag and places it into the ActionContext. The iterator tag will retrieve
74 * that object from the ActionContext and then calls its getDays() method as above. The status attribute is also used to
75 * create a {@link IteratorStatus} object, which in this example, its odd() method is used to alternate row
76 * colours:</p>
77 *
78 * <!-- END SNIPPET: example2description -->
79 *
80 *
81 * <pre>
82 * <!-- START SNIPPET: example2code -->
83 *
84 * <s:bean name="org.apache.struts2.example.IteratorExample" id="it">
85 * <s:param name="day" value="'foo'"/>
86 * <s:param name="day" value="'bar'"/>
87 * </s:bean>
88 * <p/>
89 * <table border="0" cellspacing="0" cellpadding="1">
90 * <tr>
91 * <th>Days of the week</th>
92 * </tr>
93 * <p/>
94 * <s:iterator value="#it.days" status="rowstatus">
95 * <tr>
96 * <s:if test="#rowstatus.odd == true">
97 * <td style="background: grey"><s:property/></td>
98 * </s:if>
99 * <s:else>
100 * <td><s:property/></td>
101 * </s:else>
102 * </tr>
103 * </s:iterator>
104 * </table>
105 *
106 * <!-- END SNIPPET: example2code -->
107 * </pre>
108 *
109 * <!--START SNIPPET: example3description -->
110 *
111 * <p> The next example will further demonstrate the use of the status attribute, using a DAO obtained from the action
112 * class through OGNL, iterating over groups and their users (in a security context). The last() method indicates if the
113 * current object is the last available in the iteration, and if not, we need to seperate the users using a comma: </p>
114 *
115 * <!-- END SNIPPET: example3description -->
116 *
117 * <pre>
118 * <!-- START SNIPPET: example3code -->
119 *
120 * <s:iterator value="groupDao.groups" status="groupStatus">
121 * <tr class="<s:if test="#groupStatus.odd == true ">odd</s:if><s:else>even</s:else>">
122 * <td><s:property value="name" /></td>
123 * <td><s:property value="description" /></td>
124 * <td>
125 * <s:iterator value="users" status="userStatus">
126 * <s:property value="fullName" /><s:if test="!#userStatus.last">,</s:if>
127 * </s:iterator>
128 * </td>
129 * </tr>
130 * </s:iterator>
131 *
132 * <!-- END SNIPPET: example3code -->
133 * </pre>
134 * <p>
135 *
136 * <!-- START SNIPPET: example4description -->
137 *
138 * </p> The next example iterates over a an action collection and passes every iterator value to another action. The
139 * trick here lies in the use of the '[0]' operator. It takes the current iterator value and passes it on to the edit
140 * action. Using the '[0]' operator has the same effect as using >s:property />. (The latter, however, does not
141 * work from inside the param tag). </p>
142 *
143 * <!-- END SNIPPET: example4description -->
144 *
145 * <pre>
146 * <!-- START SNIPPET: example4code -->
147 *
148 * <s:action name="entries" id="entries"/>
149 * <s:iterator value="#entries.entries" >
150 * <s:property value="name" />
151 * <s:property />
152 * <s:push value="...">
153 * <s:action name="edit" id="edit" >
154 * <s:param name="entry" value="[0]" />
155 * </s:action>
156 * </push>
157 * </s:iterator>
158 *
159 * <!-- END SNIPPET: example4code -->
160 * </pre>
161 *
162 * <!-- START SNIPPET: example5description -->
163 *
164 * </p>To simulate a simple loop with iterator tag, the following could be done.
165 * It does the loop 5 times.
166 *
167 * <!-- END SNIPPET: example5description -->
168 *
169 * <pre>
170 * <!-- START SNIPPET: example5code -->
171 *
172 * <s:iterator status="stat" value="{1,2,3,4,5}" >
173 * <!-- grab the index (start with 0 ... ) -->
174 * <s:property value="#stat.index" />
175 *
176 * <!-- grab the top of the stack which should be the -->
177 * <!-- current iteration value (0, 1, ... 5) -->
178 * <s:property value="top" />
179 * </s:iterator>
180 *
181 * <!-- END SNIPPET: example5code -->
182 * </pre>
183 *
184 */
185 @StrutsTag(name="iterator", tldTagClass="org.apache.struts2.views.jsp.IteratorTag", description="Iterate over a iterable value")
186 public class IteratorComponent extends Component {
187 protected Iterator iterator;
188 protected IteratorStatus status;
189 protected Object oldStatus;
190 protected IteratorStatus.StatusState statusState;
191 protected String statusAttr;
192 protected String value;
193
194 public IteratorComponent(ValueStack stack) {
195 super(stack);
196 }
197
198 public boolean start(Writer writer) {
199
200 if (statusAttr != null) {
201 statusState = new IteratorStatus.StatusState();
202 status = new IteratorStatus(statusState);
203 }
204
205 ValueStack stack = getStack();
206
207 if (value == null) {
208 value = "top";
209 }
210 iterator = MakeIterator.convert(findValue(value));
211
212
213 if ((iterator != null) && iterator.hasNext()) {
214 Object currentValue = iterator.next();
215 stack.push(currentValue);
216
217 String id = getId();
218
219 if ((id != null) && (currentValue != null)) {
220
221
222 stack.getContext().put(id, currentValue);
223 }
224
225
226 if (statusAttr != null) {
227 statusState.setLast(!iterator.hasNext());
228 oldStatus = stack.getContext().get(statusAttr);
229 stack.getContext().put(statusAttr, status);
230 }
231
232 return true;
233 } else {
234 super.end(writer, "");
235 return false;
236 }
237 }
238
239 public boolean end(Writer writer, String body) {
240 ValueStack stack = getStack();
241 if (iterator != null) {
242 stack.pop();
243 }
244
245 if (iterator!=null && iterator.hasNext()) {
246 Object currentValue = iterator.next();
247 stack.push(currentValue);
248
249 String id = getId();
250
251 if ((id != null) && (currentValue != null)) {
252
253
254 stack.getContext().put(id, currentValue);
255 }
256
257
258 if (status != null) {
259 statusState.next();
260 statusState.setLast(!iterator.hasNext());
261 }
262
263 return true;
264 } else {
265
266 if (status != null) {
267 if (oldStatus == null) {
268 stack.getContext().put(statusAttr, null);
269 } else {
270 stack.getContext().put(statusAttr, oldStatus);
271 }
272 }
273 super.end(writer, "");
274 return false;
275 }
276 }
277
278 @StrutsTagAttribute(description="If specified, an instanceof IteratorStatus will be pushed into stack upon each iteration",
279 type="Boolean", defaultValue="false")
280 public void setStatus(String status) {
281 this.statusAttr = status;
282 }
283
284 @StrutsTagAttribute(description="the iteratable source to iterate over, else an the object itself will be put into a newly created List")
285 public void setValue(String value) {
286 this.value = value;
287 }
288
289 }