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> <tr:forEach>
+ <br/>
+<p>
+ The forEach tag is a replacement for the JSTL
+<c:forEach> tag. Though as of JSF 1.2/JSP 2.1/JSTL 1.2,
+<c:forEach> 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 <c:forEach>: <tr:forEach> does not currently support arbitrary
+java.util.Collections; it can only iterate over java.util.Lists or
+arrays.</p>
+<h4>Example:</h4><source>
+ <tr:selectOneListbox value="#{someValue}">
+ <tr:forEach var="item" items="#{model.listOfItems}">
+ <tr:selectItem value="#{item.value}" text="#{item.text}"/>
+ </tr:forEach>
+ </tr:selectOneListbox></source><source>
+ <tr:forEach varStatus="vs" begin="1" end="5">
+ <tr:outputText id="ot2" value="#{vs.index} #{vs.count} #{vs.begin} #{vs.current}"/>
+ </tr:forEach></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 &lt;c:forEach&gt; tag.
+As of JSF 1.2/JSP 2.1/JSTL 1.2, the regular &lt;c:forEach&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);
+
+}