You are viewing a plain text version of this content. The canonical link for it is here.
Posted to adffaces-commits@incubator.apache.org by aw...@apache.org on 2006/10/05 23:25:56 UTC

svn commit: r453425 - in /incubator/adffaces/branches/faces-1_2/trinidad: ./ trinidad-api/src/main/java-templates/org/apache/myfaces/trinidad/component/ trinidad-api/src/site/xdoc/tagdoc/ trinidad-demo/src/main/webapp/surveydemo/ trinidad-impl/ trinida...

Author: awiner
Date: Thu Oct  5 16:25:55 2006
New Revision: 453425

URL: http://svn.apache.org/viewvc?view=rev&rev=453425
Log:
- Re-add <tr:forEach> tag, reimplemented for JSP 2.1 VariableMapper API and ValueExpressions.  Turns out we do need it, because c:forEach doesn't support varStatus with JSF, just var.  Grrr....  <tr:forEach> supports varStatus too.
- Change UIXEditableValue code from ValueBindings over to ValueExpressions

Added:
    incubator/adffaces/branches/faces-1_2/trinidad/trinidad-api/src/site/xdoc/tagdoc/tr_forEach.xml
    incubator/adffaces/branches/faces-1_2/trinidad/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/taglib/ForEachTag.java
Modified:
    incubator/adffaces/branches/faces-1_2/trinidad/pom.xml
    incubator/adffaces/branches/faces-1_2/trinidad/trinidad-api/src/main/java-templates/org/apache/myfaces/trinidad/component/UIXEditableValueTemplate.java
    incubator/adffaces/branches/faces-1_2/trinidad/trinidad-demo/src/main/webapp/surveydemo/surveyPage1.jspx
    incubator/adffaces/branches/faces-1_2/trinidad/trinidad-impl/pom.xml
    incubator/adffaces/branches/faces-1_2/trinidad/trinidad-impl/src/main/conf/META-INF/tr-base.tld

Modified: incubator/adffaces/branches/faces-1_2/trinidad/pom.xml
URL: http://svn.apache.org/viewvc/incubator/adffaces/branches/faces-1_2/trinidad/pom.xml?view=diff&rev=453425&r1=453424&r2=453425
==============================================================================
--- incubator/adffaces/branches/faces-1_2/trinidad/pom.xml (original)
+++ incubator/adffaces/branches/faces-1_2/trinidad/pom.xml Thu Oct  5 16:25:55 2006
@@ -430,6 +430,13 @@
         <scope>provided</scope>
       </dependency>
 
+      <dependency>
+        <groupId>jstl</groupId>
+        <artifactId>jstl</artifactId>
+        <version>1.2</version>
+        <scope>provided</scope>
+      </dependency>
+
 
       <dependency>
         <groupId>com.sun.facelets</groupId>

Modified: incubator/adffaces/branches/faces-1_2/trinidad/trinidad-api/src/main/java-templates/org/apache/myfaces/trinidad/component/UIXEditableValueTemplate.java
URL: http://svn.apache.org/viewvc/incubator/adffaces/branches/faces-1_2/trinidad/trinidad-api/src/main/java-templates/org/apache/myfaces/trinidad/component/UIXEditableValueTemplate.java?view=diff&rev=453425&r1=453424&r2=453425
==============================================================================
--- incubator/adffaces/branches/faces-1_2/trinidad/trinidad-api/src/main/java-templates/org/apache/myfaces/trinidad/component/UIXEditableValueTemplate.java (original)
+++ incubator/adffaces/branches/faces-1_2/trinidad/trinidad-api/src/main/java-templates/org/apache/myfaces/trinidad/component/UIXEditableValueTemplate.java Thu Oct  5 16:25:55 2006
@@ -17,6 +17,8 @@
 
 import java.util.Iterator;
 
+import javax.el.ValueExpression;
+
 import javax.faces.application.Application;
 import javax.faces.application.FacesMessage;
 import javax.faces.component.EditableValueHolder;
@@ -25,7 +27,6 @@
 import javax.faces.convert.ConverterException;
 import javax.faces.el.EvaluationException;
 import javax.faces.el.MethodBinding;
-import javax.faces.el.ValueBinding;
 import javax.faces.event.AbortProcessingException;
 import javax.faces.event.FacesEvent;
 import javax.faces.event.ValueChangeEvent;
@@ -111,6 +112,7 @@
 
     // Submitted value == null means "the component was not submitted
     // at all";  validation should not continue
+
     Object submittedValue = getSubmittedValue();
     if (submittedValue == null)
       return;
@@ -239,21 +241,21 @@
     if (!isValid() || !isLocalValueSet())
       return;
 
-    ValueBinding binding = getFacesBean().getValueBinding(VALUE_KEY);
-    if (binding == null)
+    ValueExpression expression = getFacesBean().getValueExpression(VALUE_KEY);
+    if (expression == null)
       return;
 
     try
     {
       Object localValue = getLocalValue();
-      binding.setValue(context, localValue);
+      expression.setValue(context.getELContext(), localValue);
       setValue(null);
       setLocalValueSet(false);
       if (_LOG.isFiner())
       {
         _LOG.finer("Wrote value {0} to model {1} in component {2}",
                    new Object[]{localValue,
-                                binding.getExpressionString(),
+                                expression.getExpressionString(),
                                 this});
       }
     }
@@ -263,8 +265,8 @@
       // bean attribute level validation:
       if (_LOG.isFine())
       {
-        _LOG.fine("Error updating binding ({0})",
-                    binding.getExpressionString());
+        _LOG.fine("Error updating expression ({0})",
+                    expression.getExpressionString());
         _LOG.fine(e);
       }
 
@@ -381,7 +383,6 @@
     {
       newValue = renderer.getConvertedValue(context, this,
                                             submittedValue);
-
       if (_LOG.isFine())
       {
         _LOG.fine("Renderer " + renderer + " returned value " + newValue + "(" +
@@ -466,7 +467,7 @@
   {
     Object o = getAttributes().get("label");
     if (o == null)
-      o = getValueBinding("label");
+      o = getValueExpression("label");
 
     return o;
   }
@@ -475,7 +476,7 @@
   {
     Object o = getAttributes().get("requiredMessageDetail");
       if (o == null)
-       o = getValueBinding("requiredMessageDetail");
+       o = getValueExpression("requiredMessageDetail");
 
     return o;
   }
@@ -527,13 +528,13 @@
       return converter;
     }
 
-    ValueBinding valueBinding = getValueBinding("value");
-    if (valueBinding == null)
+    ValueExpression valueExpression = getValueExpression("value");
+    if (valueExpression == null)
     {
       return null;
     }
 
-    Class<?> converterType = valueBinding.getType(context);
+    Class<?> converterType = valueExpression.getType(context.getELContext());
     // if converterType is null, String, or Object, assume
     // no conversion is needed
     if (converterType == null ||

Added: incubator/adffaces/branches/faces-1_2/trinidad/trinidad-api/src/site/xdoc/tagdoc/tr_forEach.xml
URL: http://svn.apache.org/viewvc/incubator/adffaces/branches/faces-1_2/trinidad/trinidad-api/src/site/xdoc/tagdoc/tr_forEach.xml?view=auto&rev=453425
==============================================================================
--- incubator/adffaces/branches/faces-1_2/trinidad/trinidad-api/src/site/xdoc/tagdoc/tr_forEach.xml (added)
+++ incubator/adffaces/branches/faces-1_2/trinidad/trinidad-api/src/site/xdoc/tagdoc/tr_forEach.xml Thu Oct  5 16:25:55 2006
@@ -0,0 +1,98 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Copyright 2006 The Apache Software Foundation.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<document>
+ <properties>
+  <title>tr:forEach</title>
+ </properties>
+ <body>
+ <section name="Summary">
+ <p>
+   <b>Tag name:</b> &lt;tr:forEach&gt;
+   <br/>
+<p>
+        The forEach tag is a replacement for the JSTL
+&lt;c:forEach&gt; tag.  Though as of JSF 1.2/JSP 2.1/JSTL 1.2,
+&lt;c:forEach&gt; can be used with any JSF components or tags,
+it does not support "varStatus".  This tag adds support for varStatus
+(other than "current" which is not supported).
+(<b>Note</b>: this tag is not supported in Facelets, because c:forEach
+is fully functional in Facelets.)  Unlike the old Trinidad tr:forEach
+built with JSF 1.1, however, this tag can be used with any JSP 2.1-based
+tag, JSF or non-JSF.  This tag also has a limitation not found in &lt;c:forEach&gt;:  &lt;tr:forEach&gt; does not currently support arbitrary
+java.util.Collections; it can only iterate over java.util.Lists or
+arrays.</p>
+<h4>Example:</h4><source>
+            &lt;tr:selectOneListbox value="#{someValue}"&gt;
+              &lt;tr:forEach var="item" items="#{model.listOfItems}"&gt;
+                &lt;tr:selectItem value="#{item.value}" text="#{item.text}"/&gt;
+              &lt;/tr:forEach&gt;
+            &lt;/tr:selectOneListbox&gt;</source><source>
+            &lt;tr:forEach varStatus="vs" begin="1" end="5"&gt;
+              &lt;tr:outputText id="ot2" value="#{vs.index} #{vs.count} #{vs.begin} #{vs.current}"/&gt;
+            &lt;/tr:forEach&gt;</source>
+ </p>
+ </section>
+ <section name="Attributes">
+<table>
+<tr>
+<th>Name</th>
+<th>Type</th>
+<th>Supports EL?</th>
+<th>Description</th>
+</tr>
+<tr>
+<td>begin</td><td>int</td><td>No</td><td>
+
+          index at which iteration begins
+        </td>
+</tr>
+<tr>
+<td>end</td><td>int</td><td>No</td><td>
+
+          index at which iteration ends
+        </td>
+</tr>
+<tr>
+<td>items</td><td>Object</td><td>Only EL</td><td>
+
+          the collection to iterate over
+        </td>
+</tr>
+<tr>
+<td>step</td><td>int</td><td>No</td><td>
+
+          number to increment on each iteration
+        </td>
+</tr>
+<tr>
+<td>var</td><td>String</td><td>No</td><td>
+
+          name of the variable exposed when iterating
+        </td>
+</tr>
+<tr>
+<td>varStatus</td><td>String</td><td>No</td><td>
+
+          name of the loop status exposed when iterating. The properties
+		'index','count','begin','end','step','first','last'
+		are available through this
+        </td>
+</tr>
+</table>
+ </section>
+ </body>
+</document>

Modified: incubator/adffaces/branches/faces-1_2/trinidad/trinidad-demo/src/main/webapp/surveydemo/surveyPage1.jspx
URL: http://svn.apache.org/viewvc/incubator/adffaces/branches/faces-1_2/trinidad/trinidad-demo/src/main/webapp/surveydemo/surveyPage1.jspx?view=diff&rev=453425&r1=453424&r2=453425
==============================================================================
--- incubator/adffaces/branches/faces-1_2/trinidad/trinidad-demo/src/main/webapp/surveydemo/surveyPage1.jspx (original)
+++ incubator/adffaces/branches/faces-1_2/trinidad/trinidad-demo/src/main/webapp/surveydemo/surveyPage1.jspx Thu Oct  5 16:25:55 2006
@@ -25,17 +25,17 @@
        
         <tr:panelPage>
       
-        <tr:panelHeader text="Question 5 of 5">
+        <tr:panelHeader text="Question 1 of 5">
           <tr:panelFormLayout>
           
             <tr:selectOneRadio label="#{survey.q0.prompt}" 
                                   required="true"
                                   value="#{survey.a0}" >
-              <c:forEach var="item" varStatus="iter"
+              <tr:forEach var="item" varStatus="iter"
                           items="#{survey.q0.answerStrings}">
                 <!-- The strange EL syntax for "value" forces it to be a string -->
                 <tr:selectItem label="#{item}" value="#{''}#{iter.index}"/>
-              </c:forEach>
+              </tr:forEach>
             </tr:selectOneRadio >
           
           </tr:panelFormLayout>

Modified: incubator/adffaces/branches/faces-1_2/trinidad/trinidad-impl/pom.xml
URL: http://svn.apache.org/viewvc/incubator/adffaces/branches/faces-1_2/trinidad/trinidad-impl/pom.xml?view=diff&rev=453425&r1=453424&r2=453425
==============================================================================
--- incubator/adffaces/branches/faces-1_2/trinidad/trinidad-impl/pom.xml (original)
+++ incubator/adffaces/branches/faces-1_2/trinidad/trinidad-impl/pom.xml Thu Oct  5 16:25:55 2006
@@ -170,6 +170,11 @@
     </dependency>
 
     <dependency>
+      <groupId>jstl</groupId>
+      <artifactId>jstl</artifactId>
+    </dependency>
+
+    <dependency>
       <groupId>org.apache.myfaces.trinidad</groupId>
       <artifactId>trinidad-build</artifactId>
     </dependency>

Modified: incubator/adffaces/branches/faces-1_2/trinidad/trinidad-impl/src/main/conf/META-INF/tr-base.tld
URL: http://svn.apache.org/viewvc/incubator/adffaces/branches/faces-1_2/trinidad/trinidad-impl/src/main/conf/META-INF/tr-base.tld?view=diff&rev=453425&r1=453424&r2=453425
==============================================================================
--- incubator/adffaces/branches/faces-1_2/trinidad/trinidad-impl/src/main/conf/META-INF/tr-base.tld (original)
+++ incubator/adffaces/branches/faces-1_2/trinidad/trinidad-impl/src/main/conf/META-INF/tr-base.tld Thu Oct  5 16:25:55 2006
@@ -26,6 +26,68 @@
   <uri>http://myfaces.apache.org/trinidad</uri>
         
    <tag>
+      <name>forEach</name>
+      <tag-class>org.apache.myfaces.trinidadinternal.taglib.ForEachTag</tag-class>
+      <description>
+The forEach tag is a replacement for the JSTL &amp;lt;c:forEach&amp;gt; tag. 
+As of JSF 1.2/JSP 2.1/JSTL 1.2, the regular &amp;lt;c:forEach&amp;gt; tag
+does work with JSF components.  However, it does not support varStatus
+with JSF!  (Unlike c:forEach, tr:forEach doesn't currently support anything
+for "items" other than arrays and lists.)
+      </description>
+
+      <attribute>
+        <description>
+          the items over which iteration takes place 
+        </description>
+        <name>items</name>
+        <deferred-value/>
+      </attribute>
+
+      <attribute>
+        <description>
+          the name of the variable to expose
+        </description>
+        <name>var</name>
+        <rtexprvalue>false</rtexprvalue>
+      </attribute>
+
+      <attribute>
+        <description>
+          Name of the exported scoped variable for the
+          status of the iteration.
+        </description>
+        <name>varStatus</name>
+        <rtexprvalue>false</rtexprvalue>
+      </attribute>
+
+      <attribute>
+        <description>
+          the beginning index 
+        </description>
+        <name>begin</name>
+        <rtexprvalue>false</rtexprvalue>
+      </attribute>
+
+      <attribute>
+        <description>
+          the ending index 
+        </description>
+        <name>end</name>
+        <rtexprvalue>false</rtexprvalue>
+      </attribute>
+
+      <attribute>
+        <description>
+          the number of steps per iteration
+        </description>
+        <name>step</name>
+        <rtexprvalue>false</rtexprvalue>
+      </attribute>
+
+   </tag>
+
+   <tag>
       <description>
         The setActionListener tag provides a declarative syntax for assigning values before an action fires
       </description>

Added: incubator/adffaces/branches/faces-1_2/trinidad/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/taglib/ForEachTag.java
URL: http://svn.apache.org/viewvc/incubator/adffaces/branches/faces-1_2/trinidad/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/taglib/ForEachTag.java?view=auto&rev=453425
==============================================================================
--- incubator/adffaces/branches/faces-1_2/trinidad/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/taglib/ForEachTag.java (added)
+++ incubator/adffaces/branches/faces-1_2/trinidad/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/taglib/ForEachTag.java Thu Oct  5 16:25:55 2006
@@ -0,0 +1,403 @@
+/*
+ * Copyright  2003-2006 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.myfaces.trinidadinternal.taglib;
+
+import java.io.Serializable;
+
+import java.lang.reflect.Array;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.el.ELContext;
+import javax.el.PropertyNotWritableException;
+import javax.el.ValueExpression;
+import javax.el.VariableMapper;
+
+import javax.faces.context.FacesContext;
+import javax.faces.webapp.UIComponentTag;
+
+import javax.servlet.jsp.JspException;
+import javax.servlet.jsp.JspTagException;
+import javax.servlet.jsp.tagext.TagSupport;
+import javax.servlet.jsp.jstl.core.IndexedValueExpression;
+
+import org.apache.myfaces.trinidad.logging.TrinidadLogger;
+import org.apache.myfaces.trinidad.webapp.ELContextTag;
+import org.apache.myfaces.trinidadinternal.el.Tokenizer;
+import org.apache.myfaces.trinidadinternal.el.Tokenizer.Token;
+
+//JSTL Core Library - <c:forEach> Tag
+//===================================
+//Syntax 1: Iterate over a collection of objects
+//
+//<c:forEach [var="varName "] items="collection"
+//  [varStatus="varStatusName"]
+//  [begin="begin"] [end="end"] [step=" step"]>
+//  body content
+//</c:forEach>
+//
+//Syntax 2: Iterate a fixed number of times
+//
+//<c:forEach [var="varName"]
+//  [varStatus="varStatusName"]
+//  begin=" begin" end="end" [step="step"]>
+//  body content
+//</c:forEach>
+
+/**
+ *
+ * @author The Oracle ADF Faces Team
+ */
+public class ForEachTag extends TagSupport
+{
+  public void setItems(ValueExpression items)
+  {
+    if (items.isLiteralText())
+      throw new IllegalArgumentException(
+        "\"items\" must be an EL expression");
+    _items = items;
+  }
+
+  public void setBegin(Integer begin)
+  {
+    _begin = begin;
+  }
+
+  public void setEnd(Integer end)
+  {
+    _end = end;
+  }
+
+  public void setStep(Integer step)
+  {
+    _step = step;
+  }
+
+  public void setVar(String var)
+  {
+    _var = var;
+  }
+
+  public void setVarStatus(String varStatus)
+  {
+    _varStatus = varStatus;
+  }
+
+  @Override
+  public int doStartTag() throws JspException
+  {
+    _validateAttributes();
+
+    FacesContext context = FacesContext.getCurrentInstance();
+    _currentBegin = (_begin == null) ? 0 : _begin.intValue();
+    int length;
+
+    if (null != _items)
+    {
+      Object items = _items.getValue(pageContext.getELContext());
+
+      //pu: If items is specified and resolves to null, it is treated as an
+      //  empty collection, i.e., no iteration is performed.
+      if (items == null)
+      {
+        if (_LOG.isFine())
+          _LOG.fine("Items expression " + _items + " resolved to null.");
+        return SKIP_BODY;
+      }
+
+      _itemsValue = items;
+      // =-=AEW <c:forEach> supports arbitrary collections;  but
+      // JSF only supports List in its EL.
+      if (items instanceof List)
+        length = ((List) items).size();
+      else if (items.getClass().isArray())
+        length = Array.getLength(items);
+      else
+        throw new JspException("\"items\" must point to a List or array");
+      if (length == 0)
+      {
+        if (_LOG.isFine())
+          _LOG.fine("Items found at " + _items + " is empty.");
+        return SKIP_BODY;
+      }
+      //pu: If valid 'items' was specified, and so was 'begin', get out if size
+      //  of collection were to be less than the begin. A mimic of c:forEach.
+      if (length < _currentBegin)
+      {
+        if (_LOG.isFine())
+          _LOG.fine("Size of 'items' is less than 'begin'");
+        return SKIP_BODY;
+      }
+
+      _currentEnd = (_end == null) ? length - 1 : _end.intValue();
+      //pu: If 'end' were specified, but is beyond the size of collection, limit
+      //  the iteration to where the collection ends. A mimic of c:forEach and
+      //  fix for bug 4029853.
+      if (length < _currentEnd)
+        _currentEnd = length - 1;
+    }
+    else
+    {
+      _currentEnd = (_end == null) ? 0 : _end.intValue();
+    }
+    _currentIndex = _currentBegin;
+    _currentStep = (_step == null) ? 1 : _step.intValue();
+    //pu: Now check the valid relation between 'begin','end' and validity of 'step'
+    _validateRangeAndStep();
+    // If we can bail, do it now
+    if (_currentEnd < _currentIndex)
+      return SKIP_BODY;
+
+    // Save off the previous deferred variables
+    VariableMapper vm = 
+      pageContext.getELContext().getVariableMapper();
+    if (_var != null)
+      _previousDeferredVar = vm.resolveVariable(_var);
+
+    if (null != _varStatus)
+    {
+      _previousDeferredVarStatus = vm.resolveVariable(_varStatus);
+      _propertyReplacementMap = new HashMap<String, Object>(9, 1);
+      _propertyReplacementMap.put("begin", _currentBegin);
+      _propertyReplacementMap.put("end", _currentEnd);
+      _propertyReplacementMap.put("step", _currentStep);
+      _propertyReplacementMap.put("count", _currentCount);
+      _propertyReplacementMap.put("index", _currentIndex);
+      // FIXME: Can we support "current" efficiently?
+      //      _propertyReplacementMap.put("current", _varReplacement);
+      _propertyReplacementMap.put("first", _isFirst);
+      _propertyReplacementMap.put("last", _isLast);
+    }
+
+    if (_LOG.isFiner())
+    {
+      _LOG.finer("Iterating from " + _currentIndex + " to " + _currentEnd +
+                 " by " + _currentStep);
+    }
+
+    // Update the variables
+    _updateVars();
+
+    return EVAL_BODY_INCLUDE;
+  }
+
+  @Override
+  public int doAfterBody()
+  {
+    _currentIndex += _currentStep;
+
+    //pu: if there is no varStatus set, no point in keeping loop status
+    //  variables updated.
+    if (null != _varStatus)
+    {
+      //pu: _isFirst is not yet updated after first iteration
+      boolean isSecondIteration = (_isFirst)? true:false;
+      if (isSecondIteration)
+      {
+        _propertyReplacementMap.put("first", _isFirst);
+      }
+      if (_isLast)
+      {
+        _propertyReplacementMap.put("last", _isLast);
+      }
+      _propertyReplacementMap.put("count", _currentCount);
+      _propertyReplacementMap.put("index", _currentIndex);
+      // FIXME Can we support "current" efficiently?
+      //      _propertyReplacementMap.put("current", _varReplacement);
+    }
+
+    // If we're at the end, bail
+    if (_currentEnd < _currentIndex)
+    {
+      // Restore EL state
+      VariableMapper vm = 
+        pageContext.getELContext().getVariableMapper();
+      if (_var != null)
+        vm.setVariable(_var, _previousDeferredVar);
+      if (_varStatus != null)
+        vm.setVariable(_varStatus, _previousDeferredVarStatus);
+
+      return SKIP_BODY;
+    }
+    
+    // Otherwise, update the variables and go again
+    _updateVars();
+
+    return EVAL_BODY_AGAIN;
+  }
+
+  /**
+   * Release state.
+   */
+  @Override
+  public void release()
+  {
+    super.release();
+    _begin = null;
+    _end = null;
+    _step = null;
+    _items = null;
+    _itemsValue = null;
+    _var = null;
+    _varStatus = null;
+    _propertyReplacementMap = null;
+    _previousDeferredVar = null;
+    _previousDeferredVarStatus = null;
+  }
+
+  // Push new values into the VariableMapper and the pageContext
+  private void _updateVars()
+  {
+    VariableMapper vm = 
+      pageContext.getELContext().getVariableMapper();
+    if (_var != null)
+    {
+      ValueExpression iterated = new IndexedValueExpression(_items,
+                                                            _currentIndex);
+      vm.setVariable(_var, iterated);
+      
+      Object items = _itemsValue;
+      Object item;
+      if (items instanceof List)
+        item = ((List) items).get(_currentIndex);
+      else
+        item = Array.get(items, _currentIndex);
+
+      pageContext.setAttribute(_var, item);
+    }
+    
+    if (_varStatus != null)
+    {
+      pageContext.setAttribute(_varStatus, _propertyReplacementMap);
+      ValueExpression constant = new Constants(
+                                      new HashMap(_propertyReplacementMap));
+      vm.setVariable(_varStatus, constant);
+    }
+  }
+
+  private void _validateAttributes() throws JspTagException
+  {
+    if (null == _items)
+    {
+      if (null == _begin || null == _end)
+      {
+        throw new JspTagException(
+          "'begin' and 'end' should be specified if 'items' is not specified");
+      }
+    }
+    //pu: This is our own check - c:forEach behavior un-defined & unpredictable.
+    if (_var == _varStatus)
+    {
+      throw new JspTagException(
+        "'var' and 'varStatus' must not have same value");
+    }
+  }
+
+  private void _validateRangeAndStep() throws JspTagException
+  {
+    if (_currentBegin < 0)
+      throw new JspTagException("'begin' < 0");
+    if (_currentStep < 1)
+      throw new JspTagException("'step' < 1");
+  }
+
+  // Basic ValueExpression that always returns a constant object
+  static private class Constants extends ValueExpression
+                                 implements Serializable
+  {
+    public Constants(Object o)
+    {
+      _o = o;
+    }
+
+    public Object getValue(ELContext context)
+    {
+      return _o;
+    }
+
+    public void setValue(ELContext context, Object value)
+    {
+      throw new PropertyNotWritableException();
+    }
+
+    public boolean isReadOnly(ELContext context)
+    {
+      return true;
+    }
+
+    public Class getType(ELContext context)
+    {
+      return _o.getClass();
+    }
+
+    public Class getExpectedType()
+    {
+      return _o.getClass();
+    }
+
+    public String getExpressionString()
+    {
+      return null;
+    }
+
+    public boolean equals(Object obj)
+    {
+      return obj == this;
+    }
+
+    public int hashCode()
+    {
+      return _o.hashCode();
+    }
+
+    public boolean isLiteralText()
+    {
+      return true;
+    }
+
+    private Object _o;
+  }
+
+  private int _currentBegin;
+  private int _currentIndex;
+  private int _currentEnd;
+  private int _currentStep;
+  private int _currentCount;
+  private boolean _isFirst;
+  private boolean _isLast;
+
+
+  private ValueExpression _items;
+  private Object          _itemsValue;
+
+  private Integer _begin;
+  private Integer _end;
+  private Integer _step;
+  private String _var;
+  private String _varStatus;
+  
+  // Saved values on the VariableMapper
+  private ValueExpression _previousDeferredVar;
+  private ValueExpression _previousDeferredVarStatus;
+
+  // Map for properties referred off from 'varStatus' and their replacements
+  private Map<String, Object> _propertyReplacementMap;
+
+  private static final TrinidadLogger _LOG = TrinidadLogger.createTrinidadLogger(ForEachTag.class);
+
+}