package com.opensymphony.webwork.components;
import com.opensymphony.webwork.util.MakeIterator;
import com.opensymphony.webwork.views.jsp.IteratorStatus;
import com.opensymphony.xwork.util.OgnlValueStack;
import java.io.Writer;
import java.util.Iterator;
/**
* <!-- START SNIPPET: javadoc -->
*
* <p>Iterator will iterate over a value. An iterable value can be either of: java.util.Collection, java.util.Iterator,
* java.util.Enumeration, java.util.Map, array.</p> <p/> <!-- END SNIPPET: javadoc -->
*
* <!-- START SNIPPET: params -->
*
* <ul>
*
* <li>status (String) - if specified, an instanceof IteratorStatus will be pushed into stack upon each iteration</li>
*
* <li>value (Object) - the source to iterate over, must be iteratable, else an the object itself will be put into a
* newly created List (see MakeIterator#convert(Object)</li>
*
* <li>id (String) - if specified the current iteration object will be place with this id in webwork stack's context
* scope</li>
*
* </ul>
*
* <!-- END SNIPPET: params -->
*
* <!-- START SNIPPET: example1description -->
*
* <p>The following example retrieves the value of the getDays() method of the current object on the value stack and
* uses it to iterate over. The <ww:property/> tag prints out the current value of the iterator.</p>
*
* <!-- END SNIPPET: example1description -->
*
* <pre>
* <!-- START SNIPPET: example1code -->
* <ww:iterator value="days">
* <p>day is: <ww:property/></p>
* </ww:iterator>
* <!-- END SNIPPET: example1code -->
* </pre>
*
*
* <!-- START SNIPPET: example2description -->
*
* <p>The following example uses a {@link Bean} tag and places it into the ActionContext. The iterator tag will retrieve
* that object from the ActionContext and then calls its getDays() method as above. The status attribute is also used to
* create a {@link IteratorStatus} object, which in this example, its odd() method is used to alternate row
* colours:</p>
*
* <!-- END SNIPPET: example2description -->
*
*
* <pre>
* <!-- START SNIPPET: example2code -->
*
* <ww:bean name="com.opensymphony.webwork.example.IteratorExample" id="it">
* <ww:param name="day" value="'foo'"/>
* <ww:param name="day" value="'bar'"/>
* </ww:bean>
* <p/>
* <table border="0" cellspacing="0" cellpadding="1">
* <tr>
* <th>Days of the week</th>
* </tr>
* <p/>
* <ww:iterator value="#it.days" status="rowstatus">
* <tr>
* <ww:if test="#rowstatus.odd == true">
* <td style="background: grey"><ww:property/></td>
* </ww:if>
* <ww:else>
* <td><ww:property/></td>
* </ww:else>
* </tr>
* </ww:iterator>
* </table>
*
* <!-- END SNIPPET: example2code -->
* </pre>
*
* <!--START SNIPPET: example3description -->
*
* <p> The next example will further demonstrate the use of the status attribute, using a DAO obtained from the action
* class through OGNL, iterating over groups and their users (in a security context). The last() method indicates if the
* current object is the last available in the iteration, and if not, we need to seperate the users using a comma: </p>
*
* <!-- END SNIPPET: example3description -->
*
* <pre>
* <!-- START SNIPPET: example3code -->
*
* <webwork:iterator value="groupDao.groups" status="groupStatus">
* <tr class="<webwork:if test="#groupStatus.odd == true ">odd</webwork:if><webwork:else>even</webwork:else>">
* <td><webwork:property value="name" /></td>
* <td><webwork:property value="description" /></td>
* <td>
* <webwork:iterator value="users" status="userStatus">
* <webwork:property value="fullName" /><webwork:if test="!#userStatus.last">,</webwork:if>
* </webwork:iterator>
* </td>
* </tr>
* </webwork:iterator>
*
* <!-- END SNIPPET: example3code -->
* </pre>
* <p>
*
* <!-- START SNIPPET: example4description -->
*
* </p> The next example iterates over a an action collection and passes every iterator value to another action. The
* trick here lies in the use of the '[0]' operator. It takes the current iterator value and passes it on to the edit
* action. Using the '[0]' operator has the same effect as using >ww:property />. (The latter, however, does not
* work from inside the param tag). </p>
*
* <!-- END SNIPPET: example4description -->
*
* <pre>
* <!-- START SNIPPET: example4code -->
*
* <ww:action name="entries" id="entries"/>
* <ww:iterator value="#entries.entries" >
* <ww:property value="name" />
* <ww:property />
* <ww:push value="...">
* <ww:action name="edit" id="edit" >
* <ww:param name="entry" value="[0]" />
* </ww:action>
* </push>
* </ww:iterator>
*
* <!-- END SNIPPET: example4code -->
* </pre>
*
* <!-- START SNIPPET: example5description -->
*
* </p>To simulate a simple loop with iterator tag, the following could be done. It does the loop 5 times.
*
* <!-- END SNIPPET: example5description -->
*
* <pre>
* <!-- START SNIPPET: example5code -->
*
* <ww:iterator status="stat" value="{1,2,3,4,5}" >
* <!-- grab the index (start with 0 ... ) -->
* <ww:property value="#stat.index" />
*
* <!-- grab the top of the stack which should be the -->
* <!-- current iteration value (0, 1, ... 5) -->
* <ww:property value="top" />
* </ww:iterator>
*
* <!-- END SNIPPET: example5code -->
* </pre>
*
*
* @author $Author: tmjee $
* @author Rick Salsa (rsal@mb.sympatico.ca)
* @author tm_jee ( tm_jee(at)yahoo.co.uk )
* @version $Revision: 2573 $
* @ww.tag name="iterator" tld-body-content="JSP" tld-tag-class="com.opensymphony.webwork.views.jsp.IteratorTag"
* description="Iterate over a iterable value"
*/
public class IteratorComponent extends Component {
protected Iterator iterator;
protected IteratorStatus status;
protected Object oldStatus;
protected IteratorStatus.StatusState statusState;
protected String statusAttr;
protected String value;
public IteratorComponent(OgnlValueStack stack) {
super(stack);
}
public boolean start(Writer writer) {
//Create an iterator status if the status attribute was set.
if (statusAttr != null) {
statusState = new IteratorStatus.StatusState();
status = new IteratorStatus(statusState);
}
OgnlValueStack stack = getStack();
if (value == null) {
value = "top";
}
iterator = MakeIterator.convert(findValue(value));
// get the first
if ((iterator != null) && iterator.hasNext()) {
Object currentValue = iterator.next();
stack.push(currentValue);
String id = getId();
if ((id != null) && (currentValue != null)) {
//pageContext.setAttribute(id, currentValue);
//pageContext.setAttribute(id, currentValue, PageContext.REQUEST_SCOPE);
stack.getContext().put(id, currentValue);
}
// Status object
if (statusAttr != null) {
statusState.setLast(!iterator.hasNext());
oldStatus = stack.getContext().get(statusAttr);
stack.getContext().put(statusAttr, status);
}
return true;
} else {
super.end(writer, "");
return false;
}
}
public boolean end(Writer writer, String body) {
OgnlValueStack stack = getStack();
if (iterator != null) {
stack.pop();
}
if (iterator!=null && iterator.hasNext()) {
Object currentValue = iterator.next();
stack.push(currentValue);
String id = getId();
if ((id != null) && (currentValue != null)) {
//pageContext.setAttribute(id, currentValue);
//pageContext.setAttribute(id, currentValue, PageContext.REQUEST_SCOPE);
stack.getContext().put(id, currentValue);
}
// Update status
if (status != null) {
statusState.next(); // Increase counter
statusState.setLast(!iterator.hasNext());
}
return true;
} else {
// Reset status object in case someone else uses the same name in another iterator tag instance
if (status != null) {
if (oldStatus == null) {
stack.getContext().put(statusAttr, null);
} else {
stack.getContext().put(statusAttr, oldStatus);
}
}
super.end(writer, "");
return false;
}
}
/**
* if specified, an instanceof IteratorStatus will be pushed into stack upon each iteration
* @ww.tagattribute required="false" type="Boolean" default="false"
*/
public void setStatus(String status) {
this.statusAttr = status;
}
/**
* the iteratable source to iterate over, else an the object itself will be put into a newly created List
* @ww.tagattribute required="false"
*/
public void setValue(String value) {
this.value = value;
}
}
|