Coverage report

  %line %branch
org.apache.commons.jelly.tags.core.ForEachTag
89% 
100% 

 1  
 /*
 2  
  * Copyright 2002,2004 The Apache Software Foundation.
 3  
  *
 4  
  * Licensed under the Apache License, Version 2.0 (the "License");
 5  
  * you may not use this file except in compliance with the License.
 6  
  * You may obtain a copy of the License at
 7  
  *
 8  
  *      http://www.apache.org/licenses/LICENSE-2.0
 9  
  *
 10  
  * Unless required by applicable law or agreed to in writing, software
 11  
  * distributed under the License is distributed on an "AS IS" BASIS,
 12  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 13  
  * See the License for the specific language governing permissions and
 14  
  * limitations under the License.
 15  
  */
 16  
 
 17  
 package org.apache.commons.jelly.tags.core;
 18  
 
 19  
 import java.util.Iterator;
 20  
 
 21  
 import javax.servlet.jsp.jstl.core.LoopTagStatus;
 22  
 
 23  
 import org.apache.commons.jelly.JellyTagException;
 24  
 import org.apache.commons.jelly.MissingAttributeException;
 25  
 import org.apache.commons.jelly.TagSupport;
 26  
 import org.apache.commons.jelly.XMLOutput;
 27  
 import org.apache.commons.jelly.expression.Expression;
 28  
 import org.apache.commons.jelly.impl.BreakException;
 29  
 import org.apache.commons.logging.Log;
 30  
 import org.apache.commons.logging.LogFactory;
 31  
 
 32  
 /**
 33  
   * Iterates over a collection, iterator or an array of objects.
 34  
   * Uses the same syntax as the <a href="http://java.sun.com/products/jsp/jstl/">JSTL</a>
 35  
   * <code>forEach</code> tag does.
 36  
   *
 37  
   * @author <a href="mailto:jstrachan@apache.org">James Strachan</a>
 38  
   * @version $Revision: 155420 $
 39  
   */
 40  
 public class ForEachTag extends TagSupport {
 41  
 
 42  
     /** The Log to which logging calls will be made. */
 43  546
     private static final Log log = LogFactory.getLog(ForEachTag.class);
 44  
 
 45  
     /** Holds the variable name to export for the item being iterated over. */
 46  
     private Expression items;
 47  
 
 48  
     /**
 49  
      * If specified then the current item iterated through will be defined
 50  
      * as the given variable name.
 51  
      */
 52  
     private String var;
 53  
 
 54  
     /**
 55  
      * If specified then the current index counter will be defined
 56  
      * as the given variable name.
 57  
      */
 58  
     private String indexVar;
 59  
     
 60  
     /** variable to hold loop status */
 61  
     private String statusVar;
 62  
 
 63  
     /** The starting index value */
 64  
     private int begin;
 65  
 
 66  
     /** The ending index value */
 67  351
     private int end = Integer.MAX_VALUE;
 68  
 
 69  
     /** The index increment step */
 70  351
     private int step = 1;
 71  
 
 72  
     /** The iteration index */
 73  
     private int index;
 74  
 
 75  351
     public ForEachTag() {
 76  351
     }
 77  
 
 78  
     // Tag interface
 79  
 
 80  
     //-------------------------------------------------------------------------
 81  
     public void doTag(XMLOutput output) throws MissingAttributeException, JellyTagException {
 82  
 
 83  351
         if (log.isDebugEnabled()) {
 84  0
             log.debug("running with items: " + items);
 85  
         }
 86  
 
 87  
         try {
 88  351
             if (items != null) {
 89  52
                 Iterator iter = items.evaluateAsIterator(context);
 90  
              
 91  52
                 if (log.isDebugEnabled()) {
 92  0
                     log.debug("Iterating through: " + iter);
 93  
                 }
 94  
 
 95  
                 // ignore the first items of the iterator
 96  78
                 for (index = 0; index < begin && iter.hasNext(); index++ ) {
 97  26
                     iter.next();
 98  
                 }
 99  
                 
 100  
                 // set up the status
 101  52
                 LoopStatus status = null;
 102  52
                 if (statusVar != null)
 103  
                 {
 104  
                     // set up statii as required by JSTL
 105  13
                     Integer statusBegin = (begin == 0) ? null : new Integer(begin);
 106  13
                     Integer statusEnd = (end == Integer.MAX_VALUE) ? null : new Integer(end);
 107  13
                     Integer statusStep = (step == 1) ? null : new Integer(step);
 108  13
                     status = new LoopStatus(statusBegin, statusEnd, statusStep);
 109  13
                     context.setVariable(statusVar, status);
 110  
                 }
 111  
 
 112  52
                 boolean firstTime = true;
 113  52
                 int count = 0;
 114  195
                 while (iter.hasNext() && index <= end) {
 115  143
                     Object value = iter.next();
 116  143
                     if (var != null) {
 117  143
                         context.setVariable(var, value);
 118  
                     }
 119  143
                     if (indexVar != null) {
 120  0
                         context.setVariable(indexVar, new Integer(index));
 121  
                     }
 122  
                     // set the status var up
 123  143
                     if (statusVar != null) {
 124  39
                         count++;
 125  39
                         status.setCount(count);
 126  39
                         status.setCurrent(value);
 127  39
                         status.setFirst(firstTime);
 128  39
                         status.setIndex(index);
 129  
                         // set first time up for the next iteration.
 130  39
                         if (firstTime) {
 131  13
                             firstTime = !firstTime;
 132  
                         }
 133  
                     }
 134  
                     // now we need to work out the next index for status isLast
 135  
                     // and also advance the iterator and index for the loop.
 136  143
                     boolean finished = false;
 137  143
                     index++;
 138  182
                     for ( int i = 1; i < step && !finished; i++, index++ ) {
 139  39
                         if ( ! iter.hasNext() ) {
 140  0
                            finished = true;
 141  0
                         }
 142  
                         else {
 143  39
                             iter.next();
 144  
                         }
 145  
                     }
 146  
 
 147  143
                     if (statusVar != null) {
 148  39
                         status.setLast(finished || !iter.hasNext() || index > end);
 149  
                     }
 150  143
                     invokeBody(output);
 151  
 
 152  143
                 }
 153  52
             }
 154  
             else {
 155  299
                 if ( end == Integer.MAX_VALUE && begin == 0 ) {
 156  0
                     throw new MissingAttributeException( "items" );
 157  
                 }
 158  
                 else {
 159  299
                     String varName = var;
 160  299
                     if ( varName == null ) {
 161  0
                         varName = indexVar;
 162  
                     }
 163  
                     // set up the status
 164  299
                     LoopStatus status = null;
 165  299
                     if (statusVar != null)
 166  
                     {
 167  
                         // set up statii as required by JSTL
 168  13
                         Integer statusBegin = new Integer(begin);
 169  13
                         Integer statusEnd = new Integer(end);
 170  13
                         Integer statusStep = new Integer(step);
 171  13
                         status = new LoopStatus(statusBegin, statusEnd, statusStep);
 172  13
                         context.setVariable(statusVar, status);
 173  
                     }
 174  
 
 175  299
                     int count = 0;
 176  1716
                     for (index = begin; index <= end; index += step ) {
 177  
 
 178  1599
                         Object value = new Integer(index);
 179  1599
                         if (varName != null) {
 180  1599
                             context.setVariable(varName, value);
 181  
                         }
 182  
                         // set the status var up
 183  1599
                         if (status != null) {
 184  39
                             count++;
 185  39
                             status.setIndex(index);
 186  39
                             status.setCount(count);
 187  39
                             status.setCurrent(value);
 188  39
                             status.setFirst(index == begin);
 189  39
                             status.setLast(index > end - step);
 190  
                         }
 191  1599
                         invokeBody(output);
 192  
                     }
 193  
                 }
 194  
             }
 195  
         }
 196  182
         catch (BreakException e) {
 197  182
             if (log.isDebugEnabled()) {
 198  0
                 log.debug("loop terminated by break: " + e, e);
 199  
             }
 200  169
         }
 201  351
     }
 202  
 
 203  
     // Properties
 204  
     //-------------------------------------------------------------------------
 205  
 
 206  
     /**
 207  
      * Sets the expression used to iterate over.
 208  
      * This expression could resolve to an Iterator, Collection, Map, Array,
 209  
      * Enumeration or comma separated String.
 210  
      */
 211  
     public void setItems(Expression items) {
 212  52
         this.items = items;
 213  52
     }
 214  
 
 215  
     /** Sets the variable name to export for the item being iterated over
 216  
      */
 217  
     public void setVar(String var) {
 218  351
         this.var = class="keyword">var;
 219  351
     }
 220  
 
 221  
     /** Sets the variable name to export the current index counter to
 222  
      */
 223  
     public void setIndexVar(String indexVar) {
 224  0
         this.indexVar = indexVar;
 225  0
     }
 226  
 
 227  
     /** Sets the starting index value
 228  
      */
 229  
     public void setBegin(int begin) {
 230  312
         this.begin = begin;
 231  312
     }
 232  
 
 233  
     /** Sets the ending index value
 234  
      */
 235  
     public void setEnd(int end) {
 236  312
         this.end = end;
 237  312
     }
 238  
 
 239  
     /** Sets the index increment step
 240  
      */
 241  
     public void setStep(int step) {
 242  26
         this.step = step;
 243  26
     }
 244  
 
 245  
     /**
 246  
      * Sets the variable name to export the current status to.
 247  
      * The status is an implementation of the JSTL LoopTagStatus interface that provides
 248  
      * the following bean properties:
 249  
      * <ul>
 250  
      *   <li>current - the current value of the loop items being iterated</li>
 251  
      *   <li>index   - the current index of the items being iterated</li>
 252  
      *   <li>first   - true if this is the first iteration, false otherwise</li>
 253  
      *   <li>last    - true if this is the last iteration, false otherwise</li>
 254  
      *   <li>begin   - the starting index of the loop</li>
 255  
      *   <li>step    - the stepping value of the loop</li>
 256  
      *   <li>end     - the end index of the loop</li>
 257  
      * </ul>
 258  
      */
 259  
     public void setVarStatus(String var) {
 260  26
         this.statusVar = var;
 261  26
     }
 262  
     
 263  
     /**
 264  
      * Holds the status of the loop. 
 265  
      */
 266  
     public static final class LoopStatus implements LoopTagStatus
 267  
     {
 268  
         private Integer begin;
 269  
         private int count;
 270  
         private Object current;
 271  
         private Integer end;
 272  
         private int index;
 273  
         private Integer step;
 274  
         private boolean first;
 275  
         private boolean last;
 276  
         
 277  
         public LoopStatus(Integer begin, Integer end, Integer step) {
 278  
             this.begin = begin;
 279  
             this.end = end;
 280  
             this.step = step;
 281  
         }
 282  
         /**
 283  
          * @return Returns the begin.
 284  
          */
 285  
         public Integer getBegin() {
 286  
             return begin;
 287  
         }
 288  
         /**
 289  
          * @return Returns the count.
 290  
          */
 291  
         public int getCount() {
 292  
             return count;
 293  
         }
 294  
         /**
 295  
          * @return Returns the current.
 296  
          */
 297  
         public Object getCurrent() {
 298  
             return current;
 299  
         }
 300  
         /**
 301  
          * @return Returns the end.
 302  
          */
 303  
         public Integer getEnd() {
 304  
             return end;
 305  
         }
 306  
         /**
 307  
          * @return Returns the first.
 308  
          */
 309  
         public boolean isFirst() {
 310  
             return first;
 311  
         }
 312  
         /**
 313  
          * @return Returns the index.
 314  
          */
 315  
         public int getIndex() {
 316  
             return index;
 317  
         }
 318  
         /**
 319  
          * @return Returns the last.
 320  
          */
 321  
         public boolean isLast() {
 322  
             return last;
 323  
         }
 324  
         /**
 325  
          * @return Returns the step.
 326  
          */
 327  
         public Integer getStep() {
 328  
             return step;
 329  
         }
 330  
         /**
 331  
          * @param count The count to set.
 332  
          */
 333  
         public void setCount(int count) {
 334  
             this.count = count;
 335  
         }
 336  
         /**
 337  
          * @param current The current to set.
 338  
          */
 339  
         public void setCurrent(Object current) {
 340  
             this.current = current;
 341  
         }
 342  
         /**
 343  
          * @param first The first to set.
 344  
          */
 345  
         public void setFirst(boolean first) {
 346  
             this.first = first;
 347  
         }
 348  
         /**
 349  
          * @param last The last to set.
 350  
          */
 351  
         public void setLast(boolean last) {
 352  
             this.last = last;
 353  
         }
 354  
         /**
 355  
          * @param index The index to set.
 356  
          */
 357  
         public void setIndex(int index) {
 358  
             this.index = index;
 359  
         }
 360  
     }
 361  
 }

This report is generated by jcoverage, Maven and Maven JCoverage Plugin.