Coverage Report - org.apache.myfaces.view.facelets.tag.jstl.core.LegacyForEachHandler
 
Classes in this File Line Coverage Branch Coverage Complexity
LegacyForEachHandler
0%
0/122
0%
0/94
5.267
LegacyForEachHandler$ArrayIterator
0%
0/8
0%
0/2
5.267
 
 1  
 /*
 2  
  * Licensed to the Apache Software Foundation (ASF) under one
 3  
  * or more contributor license agreements.  See the NOTICE file
 4  
  * distributed with this work for additional information
 5  
  * regarding copyright ownership.  The ASF licenses this file
 6  
  * to you under the Apache License, Version 2.0 (the
 7  
  * "License"); you may not use this file except in compliance
 8  
  * with the License.  You may obtain a copy of the License at
 9  
  *
 10  
  *   http://www.apache.org/licenses/LICENSE-2.0
 11  
  *
 12  
  * Unless required by applicable law or agreed to in writing,
 13  
  * software distributed under the License is distributed on an
 14  
  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 15  
  * KIND, either express or implied.  See the License for the
 16  
  * specific language governing permissions and limitations
 17  
  * under the License.
 18  
  */
 19  
 package org.apache.myfaces.view.facelets.tag.jstl.core;
 20  
 
 21  
 import java.io.IOException;
 22  
 import java.lang.reflect.Array;
 23  
 import java.util.Collection;
 24  
 import java.util.Iterator;
 25  
 import java.util.List;
 26  
 import java.util.Map;
 27  
 
 28  
 import javax.el.ELException;
 29  
 import javax.el.ValueExpression;
 30  
 import javax.faces.FacesException;
 31  
 import javax.faces.component.UIComponent;
 32  
 import javax.faces.view.facelets.FaceletContext;
 33  
 import javax.faces.view.facelets.FaceletException;
 34  
 import javax.faces.view.facelets.TagAttribute;
 35  
 import javax.faces.view.facelets.TagAttributeException;
 36  
 import javax.faces.view.facelets.TagConfig;
 37  
 import javax.faces.view.facelets.TagHandler;
 38  
 
 39  
 import org.apache.myfaces.view.facelets.AbstractFaceletContext;
 40  
 import org.apache.myfaces.view.facelets.FaceletCompositionContext;
 41  
 import org.apache.myfaces.view.facelets.PageContext;
 42  
 import org.apache.myfaces.view.facelets.tag.ComponentContainerHandler;
 43  
 import org.apache.myfaces.view.facelets.tag.jsf.ComponentSupport;
 44  
 
 45  
 /**
 46  
  * The basic iteration tag, accepting many different
 47  
  * collection types and supporting subsetting and other
 48  
  * functionality
 49  
  * 
 50  
  * NOTE: This implementation is provided for compatibility reasons and
 51  
  * it is considered faulty. It is enabled using
 52  
  * org.apache.myfaces.STRICT_JSF_2_FACELETS_COMPATIBILITY web config param.
 53  
  * Don't use it if EL expression caching is enabled.
 54  
  * 
 55  
  * @author Jacob Hookom
 56  
  * @author Andrew Robinson
 57  
  * @version $Id$
 58  
  */
 59  
 //@JSFFaceletTag(name="c:forEach")
 60  
 public final class LegacyForEachHandler extends TagHandler implements ComponentContainerHandler
 61  
 {
 62  
 
 63  
     private static class ArrayIterator implements Iterator<Object>
 64  
     {
 65  
 
 66  
         protected final Object array;
 67  
 
 68  
         protected int i;
 69  
 
 70  
         protected final int len;
 71  
 
 72  
         public ArrayIterator(Object src)
 73  0
         {
 74  0
             this.i = 0;
 75  0
             this.array = src;
 76  0
             this.len = Array.getLength(src);
 77  0
         }
 78  
 
 79  
         public boolean hasNext()
 80  
         {
 81  0
             return this.i < this.len;
 82  
         }
 83  
 
 84  
         public Object next()
 85  
         {
 86  0
             return Array.get(this.array, this.i++);
 87  
         }
 88  
 
 89  
         public void remove()
 90  
         {
 91  0
             throw new UnsupportedOperationException();
 92  
         }
 93  
     }
 94  
 
 95  
     /**
 96  
      * If items specified:
 97  
      * Iteration begins at the item located at the
 98  
      * specified index. First item of the collection has
 99  
      * index 0.
 100  
      * If items not specified:
 101  
      * Iteration begins with index set at the value
 102  
      * specified.
 103  
      */
 104  
     //@JSFFaceletAttribute(className="int")
 105  
     private final TagAttribute begin;
 106  
 
 107  
     /**
 108  
      * If items specified:
 109  
      * Iteration ends at the item located at the
 110  
      * specified index (inclusive).
 111  
      * If items not specified:
 112  
      * Iteration ends when index reaches the value
 113  
      * specified.
 114  
      */
 115  
     //@JSFFaceletAttribute(className="int")
 116  
     private final TagAttribute end;
 117  
 
 118  
     /**
 119  
      * Collection of items to iterate over.
 120  
      */
 121  
     //@JSFFaceletAttribute(className="javax.el.ValueExpression")
 122  
     private final TagAttribute items;
 123  
 
 124  
     /**
 125  
      * Iteration will only process every step items of
 126  
      * the collection, starting with the first one.
 127  
      */
 128  
     //@JSFFaceletAttribute(className="int")
 129  
     private final TagAttribute step;
 130  
 
 131  
     private final TagAttribute tranzient;
 132  
 
 133  
     /**
 134  
      * Name of the exported scoped variable for the
 135  
      * current item of the iteration. This scoped
 136  
      * variable has nested visibility. Its type depends
 137  
      * on the object of the underlying collection.
 138  
      */
 139  
     //@JSFFaceletAttribute(className="java.lang.String")
 140  
     private final TagAttribute var;
 141  
 
 142  
     /**
 143  
      * Name of the exported scoped variable for the
 144  
      * status of the iteration. 
 145  
      */
 146  
     //@JSFFaceletAttribute(className="java.lang.String")
 147  
     private final TagAttribute varStatus;
 148  
 
 149  
     /**
 150  
      * @param config
 151  
      */
 152  
     public LegacyForEachHandler(TagConfig config)
 153  
     {
 154  0
         super(config);
 155  0
         this.items = this.getAttribute("items");
 156  0
         this.var = this.getAttribute("var");
 157  0
         this.begin = this.getAttribute("begin");
 158  0
         this.end = this.getAttribute("end");
 159  0
         this.step = this.getAttribute("step");
 160  0
         this.varStatus = this.getAttribute("varStatus");
 161  0
         this.tranzient = this.getAttribute("transient");
 162  
 
 163  0
         if (this.items == null && this.begin != null && this.end == null)
 164  
         {
 165  0
             throw new TagAttributeException(this.tag, this.begin,
 166  
                                             "If the 'items' attribute is not specified, but the 'begin' attribute is, "
 167  
                                             + "then the 'end' attribute is required");
 168  
         }
 169  0
     }
 170  
 
 171  
     public void apply(FaceletContext ctx, UIComponent parent) throws IOException, FacesException, FaceletException,
 172  
             ELException
 173  
     {
 174  
 
 175  0
         int s = this.getBegin(ctx);
 176  0
         int e = this.getEnd(ctx);
 177  0
         int m = this.getStep(ctx);
 178  0
         Integer sO = this.begin != null ? Integer.valueOf(s) : null;
 179  0
         Integer eO = this.end != null ? Integer.valueOf(e) : null;
 180  0
         Integer mO = this.step != null ? Integer.valueOf(m) : null;
 181  
 
 182  0
         boolean t = this.getTransient(ctx);
 183  0
         Object src = null;
 184  0
         ValueExpression srcVE = null;
 185  0
         if (this.items != null)
 186  
         {
 187  0
             srcVE = this.items.getValueExpression(ctx, Object.class);
 188  0
             src = srcVE.getValue(ctx);
 189  
         }
 190  
         else
 191  
         {
 192  0
             byte[] b = new byte[e + 1];
 193  0
             for (int i = 0; i < b.length; i++)
 194  
             {
 195  0
                 b[i] = (byte) i;
 196  
             }
 197  0
             src = b;
 198  
         }
 199  0
         FaceletCompositionContext fcc = FaceletCompositionContext.getCurrentInstance(ctx);
 200  0
         if (src != null)
 201  
         {
 202  
             try
 203  
             {
 204  0
                 fcc.startComponentUniqueIdSection();
 205  0
                 AbstractFaceletContext actx = (AbstractFaceletContext) ctx;
 206  0
                 PageContext pctx = actx.getPageContext();
 207  0
                 Iterator<?> itr = this.toIterator(src);
 208  0
                 if (itr != null)
 209  
                 {
 210  0
                     int i = 0;
 211  
 
 212  
                     // move to start
 213  0
                     while (i < s && itr.hasNext())
 214  
                     {
 215  0
                         itr.next();
 216  0
                         i++;
 217  
                     }
 218  
 
 219  0
                     String v = this.getVarName(ctx);
 220  0
                     String vs = this.getVarStatusName(ctx);
 221  0
                     ValueExpression ve = null;
 222  0
                     ValueExpression vO = this.capture(v, pctx);
 223  0
                     ValueExpression vsO = this.capture(vs, pctx);
 224  0
                     int mi = 0;
 225  0
                     Object value = null;
 226  
                     try
 227  
                     {
 228  0
                         boolean first = true;
 229  0
                         while (i <= e && itr.hasNext())
 230  
                         {
 231  0
                             value = itr.next();
 232  
 
 233  
                             // set the var
 234  0
                             if (v != null)
 235  
                             {
 236  0
                                 if (t || srcVE == null)
 237  
                                 {
 238  0
                                     if (value == null)
 239  
                                     {
 240  0
                                         pctx.getAttributes().put(v, null);
 241  
                                     }
 242  
                                     else
 243  
                                     {
 244  0
                                         pctx.getAttributes().put(v, 
 245  
                                                 ctx.getExpressionFactory().createValueExpression(
 246  
                                                     value, Object.class));
 247  
                                     }
 248  
                                 }
 249  
                                 else
 250  
                                 {
 251  0
                                     ve = this.getVarExpr(srcVE, src, value, i);
 252  0
                                     pctx.getAttributes().put(v, ve);
 253  
                                 }
 254  
                             }
 255  
 
 256  
                             // set the varStatus
 257  0
                             if (vs != null)
 258  
                             {
 259  0
                                 IterationStatus itrS = new IterationStatus(first, !itr.hasNext(), i, sO, eO, mO, value);
 260  0
                                 if (t || srcVE == null)
 261  
                                 {
 262  0
                                     if (srcVE == null)
 263  
                                     {
 264  0
                                         pctx.getAttributes().put(vs, null);
 265  
                                     }
 266  
                                     else
 267  
                                     {
 268  0
                                         pctx.getAttributes().put(vs, 
 269  
                                                 ctx.getExpressionFactory().createValueExpression(
 270  
                                                     itrS, Object.class));
 271  
                                     }
 272  
                                 }
 273  
                                 else
 274  
                                 {
 275  0
                                     ve = new IterationStatusExpression(itrS);
 276  0
                                     pctx.getAttributes().put(vs, ve);
 277  
                                 }
 278  
                             }
 279  
 
 280  
                             // execute body
 281  0
                             this.nextHandler.apply(ctx, parent);
 282  
 
 283  
                             // increment steps
 284  0
                             mi = 1;
 285  0
                             while (mi < m && itr.hasNext())
 286  
                             {
 287  0
                                 itr.next();
 288  0
                                 mi++;
 289  0
                                 i++;
 290  
                             }
 291  0
                             i++;
 292  
 
 293  0
                             first = false;
 294  
                         }
 295  
                     }
 296  
                     finally
 297  
                     {
 298  
                         //Remove them from PageContext
 299  0
                         if (v != null)
 300  
                         {
 301  0
                             pctx.getAttributes().put(v, vO);
 302  
                         }
 303  
                         else
 304  
                         {
 305  0
                             pctx.getAttributes().remove(v);
 306  
                         }
 307  0
                         if (vs != null)
 308  
                         {
 309  0
                             pctx.getAttributes().put(vs, vsO);
 310  
                         }
 311  
                         else
 312  
                         {
 313  0
                             pctx.getAttributes().remove(vs);
 314  
                         }
 315  0
                     }
 316  
                 }
 317  
             }
 318  
             finally
 319  
             {
 320  0
                 fcc.endComponentUniqueIdSection();
 321  0
             }
 322  
         }
 323  
 
 324  0
         if (fcc.isUsingPSSOnThisView() && fcc.isRefreshTransientBuildOnPSS() && !fcc.isRefreshingTransientBuild())
 325  
         {
 326  
             //Mark the parent component to be saved and restored fully.
 327  0
             ComponentSupport.markComponentToRestoreFully(ctx.getFacesContext(), parent);
 328  
         }
 329  0
         if (fcc.isDynamicComponentSection())
 330  
         {
 331  0
             ComponentSupport.markComponentToRefreshDynamically(ctx.getFacesContext(), parent);
 332  
         }
 333  0
     }
 334  
 
 335  
     private final ValueExpression capture(String name, PageContext pctx)
 336  
     {
 337  0
         if (name != null)
 338  
         {
 339  0
             return pctx.getAttributes().put(name, null);
 340  
         }
 341  0
         return null;
 342  
     }
 343  
 
 344  
     private final int getBegin(FaceletContext ctx)
 345  
     {
 346  0
         if (this.begin != null)
 347  
         {
 348  0
             return this.begin.getInt(ctx);
 349  
         }
 350  0
         return 0;
 351  
     }
 352  
 
 353  
     private final int getEnd(FaceletContext ctx)
 354  
     {
 355  0
         if (this.end != null)
 356  
         {
 357  0
             return this.end.getInt(ctx);
 358  
         }
 359  0
         return Integer.MAX_VALUE - 1; // hotspot bug in the JVM
 360  
     }
 361  
 
 362  
     private final int getStep(FaceletContext ctx)
 363  
     {
 364  0
         if (this.step != null)
 365  
         {
 366  0
             return this.step.getInt(ctx);
 367  
         }
 368  0
         return 1;
 369  
     }
 370  
 
 371  
     private final boolean getTransient(FaceletContext ctx)
 372  
     {
 373  0
         if (this.tranzient != null)
 374  
         {
 375  0
             return this.tranzient.getBoolean(ctx);
 376  
         }
 377  0
         return false;
 378  
     }
 379  
 
 380  
     private final ValueExpression getVarExpr(ValueExpression ve, Object src, Object value, int i)
 381  
     {
 382  0
         if (src instanceof List || src.getClass().isArray())
 383  
         {
 384  0
             return new IndexedValueExpression(ve, i);
 385  
         }
 386  0
         else if (src instanceof Map && value instanceof Map.Entry)
 387  
         {
 388  0
             return new MappedValueExpression(ve, (Map.Entry) value);
 389  
         }
 390  0
         else if (src instanceof Collection)
 391  
         {
 392  0
             return new IteratedValueExpression(ve, value);
 393  
         }
 394  0
         throw new IllegalStateException("Cannot create VE for: " + src);
 395  
     }
 396  
 
 397  
     private final String getVarName(FaceletContext ctx)
 398  
     {
 399  0
         if (this.var != null)
 400  
         {
 401  0
             return this.var.getValue(ctx);
 402  
         }
 403  0
         return null;
 404  
     }
 405  
 
 406  
     private final String getVarStatusName(FaceletContext ctx)
 407  
     {
 408  0
         if (this.varStatus != null)
 409  
         {
 410  0
             return this.varStatus.getValue(ctx);
 411  
         }
 412  0
         return null;
 413  
     }
 414  
 
 415  
     private final Iterator<?> toIterator(Object src)
 416  
     {
 417  0
         if (src == null)
 418  
         {
 419  0
             return null;
 420  
         }
 421  0
         else if (src instanceof Collection)
 422  
         {
 423  0
             return ((Collection<?>) src).iterator();
 424  
         }
 425  0
         else if (src instanceof Map)
 426  
         {
 427  0
             return ((Map<?, ?>) src).entrySet().iterator();
 428  
         }
 429  0
         else if (src.getClass().isArray())
 430  
         {
 431  0
             return new ArrayIterator(src);
 432  
         }
 433  
         else
 434  
         {
 435  0
             throw new TagAttributeException(this.tag, this.items,
 436  
                     "Must evaluate to a Collection, Map, Array, or null.");
 437  
         }
 438  
     }
 439  
 
 440  
 }