Coverage report

  %line %branch
org.apache.commons.jelly.tags.core.ForEachTag
90% 
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: 1.29 $
 39  
   */
 40  63
 public class ForEachTag extends TagSupport {
 41  
 
 42  
     /** The Log to which logging calls will be made. */
 43  63
     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  78
     private int end = Integer.MAX_VALUE;
 68  
 
 69  
     /** The index increment step */
 70  78
     private int step = 1;
 71  
 
 72  
     /** The iteration index */
 73  
     private int index;
 74  
 
 75  78
     public ForEachTag() {
 76  78
     }
 77  
 
 78  
     // Tag interface
 79  
 
 80  
     //-------------------------------------------------------------------------
 81  
     public void doTag(XMLOutput output) throws MissingAttributeException, JellyTagException {
 82  
 
 83  78
         if (log.isDebugEnabled()) {
 84  0
             log.debug("running with items: " + items);
 85  
         }
 86  
 
 87  
         try {
 88  78
             if (items != null) {
 89  9
                 Iterator iter = items.evaluateAsIterator(context);
 90  
              
 91  9
                 if (log.isDebugEnabled()) {
 92  0
                     log.debug("Iterating through: " + iter);
 93  
                 }
 94  
 
 95  
                 // ignore the first items of the iterator
 96  15
                 for (index = 0; index < begin && iter.hasNext(); index++ ) {
 97  6
                     iter.next();
 98  
                 }
 99  
                 
 100  
                 // set up the status
 101  9
                 LoopStatus status = null;
 102  9
                 if (statusVar != null)
 103  
                 {
 104  
                     // set up statii as required by JSTL
 105  3
                     Integer statusBegin = (begin == 0) ? null : new Integer(begin);
 106  3
                     Integer statusEnd = (end == Integer.MAX_VALUE) ? null : new Integer(end);
 107  3
                     Integer statusStep = (step == 1) ? null : new Integer(step);
 108  3
                     status = new LoopStatus(statusBegin, statusEnd, statusStep);
 109  3
                     context.setVariable(statusVar, status);
 110  
                 }
 111  
 
 112  9
                 boolean firstTime = true;
 113  9
                 int count = 0;
 114  45
                 while (iter.hasNext() && index <= end) {
 115  27
                     Object value = iter.next();
 116  27
                     if (var != null) {
 117  27
                         context.setVariable(var, value);
 118  
                     }
 119  27
                     if (indexVar != null) {
 120  0
                         context.setVariable(indexVar, new Integer(index));
 121  
                     }
 122  
                     // set the status var up
 123  27
                     if (statusVar != null) {
 124  9
                         count++;
 125  9
                         status.setCount(count);
 126  9
                         status.setCurrent(value);
 127  9
                         status.setFirst(firstTime);
 128  9
                         status.setIndex(index);
 129  
                         // set first time up for the next iteration.
 130  9
                         if (firstTime) {
 131  3
                             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  27
                     boolean finished = false;
 137  27
                     index++;
 138  36
                     for ( int i = 1; i < step && !finished; i++, index++ ) {
 139  9
                         if ( ! iter.hasNext() ) {
 140  0
                            finished = true;
 141  
                         }
 142  
                         else {
 143  9
                             iter.next();
 144  
                         }
 145  
                     }
 146  
 
 147  27
                     if (statusVar != null) {
 148  9
                         status.setLast(finished || !iter.hasNext() || index > end);
 149  
                     }
 150  27
                     invokeBody(output);
 151  
 
 152  
                 }
 153  
             }
 154  
             else {
 155  69
                 if ( end == Integer.MAX_VALUE && begin == 0 ) {
 156  0
                     throw new MissingAttributeException( "items" );
 157  
                 }
 158  
                 else {
 159  69
                     String varName = var;
 160  69
                     if ( varName == null ) {
 161  0
                         varName = indexVar;
 162  
                     }
 163  
                     // set up the status
 164  69
                     LoopStatus status = null;
 165  69
                     if (statusVar != null)
 166  
                     {
 167  
                         // set up statii as required by JSTL
 168  3
                         Integer statusBegin = new Integer(begin);
 169  3
                         Integer statusEnd = new Integer(end);
 170  3
                         Integer statusStep = new Integer(step);
 171  3
                         status = new LoopStatus(statusBegin, statusEnd, statusStep);
 172  3
                         context.setVariable(statusVar, status);
 173  
                     }
 174  
 
 175  69
                     int count = 0;
 176  396
                     for (index = begin; index <= end; index += step ) {
 177  
 
 178  369
                         Object value = new Integer(index);
 179  369
                         if (varName != null) {
 180  369
                             context.setVariable(varName, value);
 181  
                         }
 182  
                         // set the status var up
 183  369
                         if (status != null) {
 184  9
                             count++;
 185  9
                             status.setIndex(index);
 186  9
                             status.setCount(count);
 187  9
                             status.setCurrent(value);
 188  9
                             status.setFirst(index == begin);
 189  9
                             status.setLast(index > end - step);
 190  
                         }
 191  369
                         invokeBody(output);
 192  
                     }
 193  
                 }
 194  
             }
 195  36
         }
 196  
         catch (BreakException e) {
 197  42
             if (log.isDebugEnabled()) {
 198  0
                 log.debug("loop terminated by break: " + e, e);
 199  
             }
 200  
         }
 201  78
     }
 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  9
         this.items = items;
 213  9
     }
 214  
 
 215  
     /** Sets the variable name to export for the item being iterated over
 216  
      */
 217  
     public void setVar(String var) {
 218  78
         this.var = class="keyword">var;
 219  78
     }
 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  72
         this.begin = begin;
 231  72
     }
 232  
 
 233  
     /** Sets the ending index value
 234  
      */
 235  
     public void setEnd(int end) {
 236  72
         this.end = end;
 237  72
     }
 238  
 
 239  
     /** Sets the index increment step
 240  
      */
 241  
     public void setStep(int step) {
 242  6
         this.step = step;
 243  6
     }
 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  6
         this.statusVar = var;
 261  6
     }
 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.