001: /*
002: * $Id: IteratorComponent.java 497654 2007-01-19 00:21:57Z rgielen $
003: *
004: * Licensed to the Apache Software Foundation (ASF) under one
005: * or more contributor license agreements. See the NOTICE file
006: * distributed with this work for additional information
007: * regarding copyright ownership. The ASF licenses this file
008: * to you under the Apache License, Version 2.0 (the
009: * "License"); you may not use this file except in compliance
010: * with the License. You may obtain a copy of the License at
011: *
012: * http://www.apache.org/licenses/LICENSE-2.0
013: *
014: * Unless required by applicable law or agreed to in writing,
015: * software distributed under the License is distributed on an
016: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017: * KIND, either express or implied. See the License for the
018: * specific language governing permissions and limitations
019: * under the License.
020: */
021: package org.apache.struts2.components;
022:
023: import java.io.Writer;
024: import java.util.Iterator;
025:
026: import org.apache.struts2.views.annotations.StrutsTag;
027: import org.apache.struts2.views.annotations.StrutsTagAttribute;
028: import org.apache.struts2.util.MakeIterator;
029: import org.apache.struts2.views.jsp.IteratorStatus;
030:
031: import com.opensymphony.xwork2.util.ValueStack;
032:
033: /**
034: * <!-- START SNIPPET: javadoc -->
035: *
036: * <p>Iterator will iterate over a value. An iterable value can be either of: java.util.Collection, java.util.Iterator,
037: * java.util.Enumeration, java.util.Map, array.</p> <p/> <!-- END SNIPPET: javadoc -->
038: *
039: * <!-- START SNIPPET: params -->
040: *
041: * <ul>
042: *
043: * <li>status (String) - if specified, an instanceof IteratorStatus will be pushed into stack upon each iteration</li>
044: *
045: * <li>value (Object) - the source to iterate over, must be iteratable, else an the object itself will be put into a
046: * newly created List (see MakeIterator#convert(Object)</li>
047: *
048: * <li>id (String) - if specified the current iteration object will be place with this id in Struts stack's context
049: * scope</li>
050: *
051: * </ul>
052: *
053: * <!-- END SNIPPET: params -->
054: *
055: * <!-- START SNIPPET: example1description -->
056: *
057: * <p>The following example retrieves the value of the getDays() method of the current object on the value stack and
058: * uses it to iterate over. The <s:property/> tag prints out the current value of the iterator.</p>
059: *
060: * <!-- END SNIPPET: example1description -->
061: *
062: * <pre>
063: * <!-- START SNIPPET: example1code -->
064: * <s:iterator value="days">
065: * <p>day is: <s:property/></p>
066: * </s:iterator>
067: * <!-- END SNIPPET: example1code -->
068: * </pre>
069: *
070: *
071: * <!-- START SNIPPET: example2description -->
072: *
073: * <p>The following example uses a {@link Bean} tag and places it into the ActionContext. The iterator tag will retrieve
074: * that object from the ActionContext and then calls its getDays() method as above. The status attribute is also used to
075: * create a {@link IteratorStatus} object, which in this example, its odd() method is used to alternate row
076: * colours:</p>
077: *
078: * <!-- END SNIPPET: example2description -->
079: *
080: *
081: * <pre>
082: * <!-- START SNIPPET: example2code -->
083: *
084: * <s:bean name="org.apache.struts2.example.IteratorExample" id="it">
085: * <s:param name="day" value="'foo'"/>
086: * <s:param name="day" value="'bar'"/>
087: * </s:bean>
088: * <p/>
089: * <table border="0" cellspacing="0" cellpadding="1">
090: * <tr>
091: * <th>Days of the week</th>
092: * </tr>
093: * <p/>
094: * <s:iterator value="#it.days" status="rowstatus">
095: * <tr>
096: * <s:if test="#rowstatus.odd == true">
097: * <td style="background: grey"><s:property/></td>
098: * </s:if>
099: * <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: //Create an iterator status if the status attribute was set.
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: // get the first
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: //pageContext.setAttribute(id, currentValue);
221: //pageContext.setAttribute(id, currentValue, PageContext.REQUEST_SCOPE);
222: stack.getContext().put(id, currentValue);
223: }
224:
225: // Status object
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: //pageContext.setAttribute(id, currentValue);
253: //pageContext.setAttribute(id, currentValue, PageContext.REQUEST_SCOPE);
254: stack.getContext().put(id, currentValue);
255: }
256:
257: // Update status
258: if (status != null) {
259: statusState.next(); // Increase counter
260: statusState.setLast(!iterator.hasNext());
261: }
262:
263: return true;
264: } else {
265: // Reset status object in case someone else uses the same name in another iterator tag instance
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",type="Boolean",defaultValue="false")
279: public void setStatus(String status) {
280: this .statusAttr = status;
281: }
282:
283: @StrutsTagAttribute(description="the iteratable source to iterate over, else an the object itself will be put into a newly created List")
284: public void setValue(String value) {
285: this.value = value;
286: }
287:
288: }
|