View Javadoc

    1   /*
    2    * $Id: IteratorComponent.java 497654 2007-01-19 00:21:57Z rgielen $
    3    *
    4    * Licensed to the Apache Software Foundation (ASF) under one
    5    * or more contributor license agreements.  See the NOTICE file
    6    * distributed with this work for additional information
    7    * regarding copyright ownership.  The ASF licenses this file
    8    * to you under the Apache License, Version 2.0 (the
    9    * "License"); you may not use this file except in compliance
    10   * with the License.  You may obtain a copy of the License at
    11   *
    12   *  http://www.apache.org/licenses/LICENSE-2.0
    13   *
    14   * Unless required by applicable law or agreed to in writing,
    15   * software distributed under the License is distributed on an
    16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    17   * KIND, either express or implied.  See the License for the
    18   * specific language governing permissions and limitations
    19   * under the License.
    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 &lt;s:property/&gt; tag prints out the current value of the iterator.</p>
    59   *
    60   * <!-- END SNIPPET: example1description -->
    61   *
    62   * <pre>
    63   * <!-- START SNIPPET: example1code -->
    64   * &lt;s:iterator value="days"&gt;
    65   *   &lt;p&gt;day is: &lt;s:property/&gt;&lt;/p&gt;
    66   * &lt;/s:iterator&gt;
    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   * &lt;s:bean name="org.apache.struts2.example.IteratorExample" id="it"&gt;
    85   *   &lt;s:param name="day" value="'foo'"/&gt;
    86   *   &lt;s:param name="day" value="'bar'"/&gt;
    87   * &lt;/s:bean&gt;
    88   * <p/>
    89   * &lt;table border="0" cellspacing="0" cellpadding="1"&gt;
    90   * &lt;tr&gt;
    91   *   &lt;th&gt;Days of the week&lt;/th&gt;
    92   * &lt;/tr&gt;
    93   * <p/>
    94   * &lt;s:iterator value="#it.days" status="rowstatus"&gt;
    95   *   &lt;tr&gt;
    96   *     &lt;s:if test="#rowstatus.odd == true"&gt;
    97   *       &lt;td style="background: grey"&gt;&lt;s:property/&gt;&lt;/td&gt;
    98   *     &lt;/s:if&gt;
    99   *     &lt;s:else&gt;
    100  *       &lt;td&gt;&lt;s:property/&gt;&lt;/td&gt;
    101  *     &lt;/s:else&gt;
    102  *   &lt;/tr&gt;
    103  * &lt;/s:iterator&gt;
    104  * &lt;/table&gt;
    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  *  &lt;s:iterator value="groupDao.groups" status="groupStatus"&gt;
    121  *      &lt;tr class="&lt;s:if test="#groupStatus.odd == true "&gt;odd&lt;/s:if&gt;&lt;s:else&gt;even&lt;/s:else&gt;"&gt;
    122  *          &lt;td&gt;&lt;s:property value="name" /&gt;&lt;/td&gt;
    123  *          &lt;td&gt;&lt;s:property value="description" /&gt;&lt;/td&gt;
    124  *          &lt;td&gt;
    125  *              &lt;s:iterator value="users" status="userStatus"&gt;
    126  *                  &lt;s:property value="fullName" /&gt;&lt;s:if test="!#userStatus.last"&gt;,&lt;/s:if&gt;
    127  *              &lt;/s:iterator&gt;
    128  *          &lt;/td&gt;
    129  *      &lt;/tr&gt;
    130  *  &lt;/s:iterator&gt;
    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 &gt;s:property /&gt;. (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  *      &lt;s:action name="entries" id="entries"/&gt;
    149  *      &lt;s:iterator value="#entries.entries" &gt;
    150  *          &lt;s:property value="name" /&gt;
    151  *          &lt;s:property /&gt;
    152  *          &lt;s:push value="..."&gt;
    153  *              &lt;s:action name="edit" id="edit" &gt;
    154  *                  &lt;s:param name="entry" value="[0]" /&gt;
    155  *              &lt;/s:action&gt;
    156  *          &lt;/push&gt;
    157  *      &lt;/s:iterator&gt;
    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  * &lt;s:iterator status="stat" value="{1,2,3,4,5}" &gt;
    173  *    &lt;!-- grab the index (start with 0 ... ) --&gt;
    174  *    &lt;s:property value="#stat.index" /&gt;
    175  *
    176  *    &lt;!-- grab the top of the stack which should be the --&gt;
    177  *    &lt;!-- current iteration value (0, 1, ... 5) --&gt;
    178  *    &lt;s:property value="top" /&gt;
    179  * &lt;/s:iterator&gt;
    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",
    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 }