You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by ar...@apache.org on 2011/11/04 18:07:24 UTC
svn commit: r1197669 - in /myfaces/trinidad/branches/ar_1940: ./
trinidad-api/src/main/java/org/apache/myfaces/trinidad/webapp/
trinidad-examples/trinidad-demo/src/main/java/org/apache/myfaces/trinidaddemo/tagDemos/
trinidad-examples/trinidad-demo/src/...
Author: arobinson74
Date: Fri Nov 4 17:07:23 2011
New Revision: 1197669
URL: http://svn.apache.org/viewvc?rev=1197669&view=rev
Log:
Merge of r1042072
Added:
myfaces/trinidad/branches/ar_1940/trinidad-api/src/main/java/org/apache/myfaces/trinidad/webapp/ComponentIdSuffixStack.java
- copied unchanged from r1042072, myfaces/trinidad/branches/ar_TRINIDAD-1940/trinidad-api/src/main/java/org/apache/myfaces/trinidad/webapp/ComponentIdSuffixStack.java
myfaces/trinidad/branches/ar_1940/trinidad-api/src/main/java/org/apache/myfaces/trinidad/webapp/TagComponentBridge.java
- copied unchanged from r1042072, myfaces/trinidad/branches/ar_TRINIDAD-1940/trinidad-api/src/main/java/org/apache/myfaces/trinidad/webapp/TagComponentBridge.java
myfaces/trinidad/branches/ar_1940/trinidad-api/src/main/java/org/apache/myfaces/trinidad/webapp/TrinidadIterationTag.java
- copied unchanged from r1042072, myfaces/trinidad/branches/ar_TRINIDAD-1940/trinidad-api/src/main/java/org/apache/myfaces/trinidad/webapp/TrinidadIterationTag.java
myfaces/trinidad/branches/ar_1940/trinidad-examples/trinidad-demo/src/main/java/org/apache/myfaces/trinidaddemo/tagDemos/ForEachBean.java
- copied unchanged from r1042072, myfaces/trinidad/branches/ar_TRINIDAD-1940/trinidad-examples/trinidad-demo/src/main/java/org/apache/myfaces/trinidaddemo/tagDemos/ForEachBean.java
myfaces/trinidad/branches/ar_1940/trinidad-examples/trinidad-demo/src/main/webapp/demos/tags/forEach.jspx
- copied unchanged from r1042072, myfaces/trinidad/branches/ar_TRINIDAD-1940/trinidad-examples/trinidad-demo/src/main/webapp/demos/tags/forEach.jspx
Modified:
myfaces/trinidad/branches/ar_1940/ (props changed)
myfaces/trinidad/branches/ar_1940/trinidad-api/src/main/java/org/apache/myfaces/trinidad/webapp/UIXComponentELTag.java
myfaces/trinidad/branches/ar_1940/trinidad-examples/trinidad-demo/src/main/webapp/WEB-INF/faces-config.xml
myfaces/trinidad/branches/ar_1940/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/el/TrinidadELResolver.java
myfaces/trinidad/branches/ar_1940/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/taglib/ForEachTag.java
Propchange: myfaces/trinidad/branches/ar_1940/
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Fri Nov 4 17:07:23 2011
@@ -3,6 +3,7 @@
/myfaces/trinidad/branches/1.2.9.1-branch:697924,699406,699496
/myfaces/trinidad/branches/TRINIDAD-1402:745675
/myfaces/trinidad/branches/ar-1715:908782
+/myfaces/trinidad/branches/ar_TRINIDAD-1940:1042072
/myfaces/trinidad/branches/ar_clientBehaviors:881469-891464
/myfaces/trinidad/branches/jsf2_ajax.3:926625-936022
/myfaces/trinidad/branches/jwaldman_StyleMap:754977-770778
Modified: myfaces/trinidad/branches/ar_1940/trinidad-api/src/main/java/org/apache/myfaces/trinidad/webapp/UIXComponentELTag.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/branches/ar_1940/trinidad-api/src/main/java/org/apache/myfaces/trinidad/webapp/UIXComponentELTag.java?rev=1197669&r1=1197668&r2=1197669&view=diff
==============================================================================
--- myfaces/trinidad/branches/ar_1940/trinidad-api/src/main/java/org/apache/myfaces/trinidad/webapp/UIXComponentELTag.java (original)
+++ myfaces/trinidad/branches/ar_1940/trinidad-api/src/main/java/org/apache/myfaces/trinidad/webapp/UIXComponentELTag.java Fri Nov 4 17:07:23 2011
@@ -6,9 +6,9 @@
* to you 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
@@ -27,12 +27,14 @@ import java.util.Calendar;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
+import java.util.Map;
import java.util.Set;
import java.util.TimeZone;
import javax.el.MethodExpression;
import javax.el.ValueExpression;
+import javax.faces.component.NamingContainer;
import javax.faces.component.UIComponent;
import javax.faces.component.UIViewRoot;
import javax.faces.webapp.UIComponentELTag;
@@ -64,6 +66,11 @@ abstract public class UIXComponentELTag
@Override
public int doStartTag() throws JspException
{
+ ComponentIdSuffixStack suffixStack =
+ ComponentIdSuffixStack.getInstance(pageContext);
+
+ _suffixId(suffixStack);
+
int retVal = super.doStartTag();
//pu: There could have been some validation error during property setting
@@ -71,10 +78,70 @@ abstract public class UIXComponentELTag
if (_validationError != null)
throw new JspException(_validationError);
+ if (getComponentInstance() instanceof NamingContainer)
+ {
+ // If a naming container, do not carry component suffixes over from
+ // outside of the naming container.
+ suffixStack.suspend();
+ }
+
return retVal;
}
@Override
+ public int doEndTag() throws JspException
+ {
+ UIComponent component = getComponentInstance();
+
+ // Apply changes once we have a stable UIComponent subtree is completely
+ // created. End of document tag is a best bet.
+ if (component instanceof UIXDocument)
+ {
+ if (getCreated())
+ {
+ ExternalContext ec = FacesContext.getCurrentInstance().getExternalContext();
+ // Used by SessionChangeManager to confirm that the state was not restored.
+ ec.getRequestMap().put(DOCUMENT_CREATED_KEY, Boolean.TRUE);
+ }
+ ChangeManager cm = RequestContext.getCurrentInstance().getChangeManager();
+ cm.applyComponentChangesForCurrentView(FacesContext.getCurrentInstance());
+ }
+
+ if (getComponentInstance() instanceof NamingContainer)
+ {
+ ComponentIdSuffixStack suffixStack =
+ ComponentIdSuffixStack.getInstance(pageContext);
+ suffixStack.resume();
+ }
+
+ // In the case where this component has had a suffix appended to it,
+ // clear the suffix and revert back to the original ID
+ setId(_origId);
+ _origId = null;
+
+ TagComponentBridge bridge = TagComponentBridge
+ .getInstance(pageContext);
+ bridge.notifyAfterComponentProcessed(getComponentInstance());
+
+ return super.doEndTag();
+ }
+
+ @Override
+ protected UIComponent findComponent(FacesContext context)
+ throws JspException
+ {
+ UIComponent component = super.findComponent(context);
+
+ // Notify any listening tags that this component was found or
+ // created (this method actually does create the compnoent if it
+ // was not found, so it is a bit mis-named in JSF)
+ TagComponentBridge bridge = TagComponentBridge
+ .getInstance(pageContext);
+ bridge.notifyComponentProcessed(component);
+
+ return component;
+ }
+
protected final void setProperties(UIComponent component)
{
if (component instanceof UIViewRoot)
@@ -156,7 +223,7 @@ abstract public class UIXComponentELTag
if (expression.isLiteralText())
{
- bean.setProperty(key,
+ bean.setProperty(key,
_parseNameTokensAsList(expression.getValue(null)));
}
else
@@ -182,7 +249,7 @@ abstract public class UIXComponentELTag
if (expression.isLiteralText())
{
- bean.setProperty(key,
+ bean.setProperty(key,
_parseNameTokensAsSet(expression.getValue(null)));
}
else
@@ -209,7 +276,7 @@ abstract public class UIXComponentELTag
{
Object value = expression.getValue(null);
if (value != null)
- {
+ {
if (value instanceof Number)
{
bean.setProperty(key, value);
@@ -453,10 +520,55 @@ abstract public class UIXComponentELTag
if (list == null)
return null;
else
- return new HashSet(list);
+ return new HashSet<String>(list);
+ }
+
+ private void _suffixId(
+ ComponentIdSuffixStack suffixStack)
+ {
+ // Check to see if this component needs to have its ID suffixed.
+ // This will happen when the component is inside of a suffix
+ // supporting tag like the for each tag. This will allow iterating
+ // components to define how unique IDs will be generated
+ // for components without relying on the UIComponentClassicTagBase
+ // code, which in the Mojarra implementation of JSF appends "j_id_#"
+ // to each component beyond the first, but is not able to be used from
+ // code in a supported fashion.
+ String currentSuffix = suffixStack.getSuffix();
+ if (currentSuffix != null)
+ {
+ _origId = getId();
+ if (_origId == null)
+ {
+ // If the original ID is null, then we cannot suffix the ID correctly. We also cannot
+ // rely on the component ID generation of the UIComponentClassicTagBase is it prevents
+ // anyone from assigning an ID with the autogenerated prefix. As a result, we have to
+ // generate our own unique ID ourselves.
+ // This will ensure that component state will stick with Trinidad components with
+ // generated IDs if components are reordered.
+ Map<String, Object> viewAttrs = FacesContext.getCurrentInstance().getViewRoot()
+ .getAttributes();
+ Integer lastUniqueId = (Integer)viewAttrs.get(_UNIQUE_ID_KEY);
+ if (lastUniqueId == null)
+ {
+ lastUniqueId = 0;
+ }
+ else
+ {
+ ++lastUniqueId;
+ }
+
+ _origId = "tr_" + lastUniqueId;
+ viewAttrs.put(_UNIQUE_ID_KEY, lastUniqueId);
+
+ _origIdGenerated = true;
+ }
+
+ setId(_origId + currentSuffix);
+ }
}
- private static final TrinidadLogger _LOG =
+ private static final TrinidadLogger _LOG =
TrinidadLogger.createTrinidadLogger(UIXComponentELTag.class);
// We rely strictly on ISO 8601 formats
@@ -469,11 +581,11 @@ abstract public class UIXComponentELTag
return sdf;
}
- // No more used anywhere in Trinidad code, so deprecate since 2.0.x.
- @Deprecated
- public static final String DOCUMENT_CREATED_KEY = "org.apache.myfaces.trinidad.DOCUMENTCREATED";
+ private static final String _DOCUMENT_CREATED_KEY = "org.apache.myfaces.trinidad.DOCUMENTCREATED";
+ private final static String _UNIQUE_ID_KEY = UIXComponentELTag.class.getName() + ".ID";
private MethodExpression _attributeChangeListener;
private String _validationError;
-
+ private String _origId;
+ private boolean _origIdGenerated = false;
}
Modified: myfaces/trinidad/branches/ar_1940/trinidad-examples/trinidad-demo/src/main/webapp/WEB-INF/faces-config.xml
URL: http://svn.apache.org/viewvc/myfaces/trinidad/branches/ar_1940/trinidad-examples/trinidad-demo/src/main/webapp/WEB-INF/faces-config.xml?rev=1197669&r1=1197668&r2=1197669&view=diff
==============================================================================
--- myfaces/trinidad/branches/ar_1940/trinidad-examples/trinidad-demo/src/main/webapp/WEB-INF/faces-config.xml (original)
+++ myfaces/trinidad/branches/ar_1940/trinidad-examples/trinidad-demo/src/main/webapp/WEB-INF/faces-config.xml Fri Nov 4 17:07:23 2011
@@ -3139,4 +3139,10 @@
<managed-bean-class>org.apache.myfaces.trinidaddemo.SkinDirtyPhaseListener</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
</managed-bean>
+
+ <managed-bean>
+ <managed-bean-name>forEachBean</managed-bean-name>
+ <managed-bean-class>org.apache.myfaces.trinidaddemo.tagDemos.ForEachBean</managed-bean-class>
+ <managed-bean-scope>request</managed-bean-scope>
+ </managed-bean>
</faces-config>
Modified: myfaces/trinidad/branches/ar_1940/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/el/TrinidadELResolver.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/branches/ar_1940/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/el/TrinidadELResolver.java?rev=1197669&r1=1197668&r2=1197669&view=diff
==============================================================================
--- myfaces/trinidad/branches/ar_1940/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/el/TrinidadELResolver.java (original)
+++ myfaces/trinidad/branches/ar_1940/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/el/TrinidadELResolver.java Fri Nov 4 17:07:23 2011
@@ -6,9 +6,9 @@
* to you 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
@@ -23,7 +23,6 @@ import java.beans.FeatureDescriptor;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
-
import java.util.List;
import java.util.Map;
@@ -31,6 +30,8 @@ import javax.el.ELContext;
import javax.el.ELResolver;
import org.apache.myfaces.trinidad.context.RequestContext;
+import org.apache.myfaces.trinidad.model.CollectionModel;
+
/**
* ELResolver implementation for Trinidad. Serves up:
@@ -52,8 +53,10 @@ public class TrinidadELResolver
{
}
- public Object getValue(ELContext elContext, Object base,
- Object property)
+ public Object getValue(
+ ELContext elContext,
+ Object base,
+ Object property)
{
if (base == null)
{
@@ -71,12 +74,22 @@ public class TrinidadELResolver
return RequestContext.getCurrentInstance().getPageFlowScope();
}
}
-
+ else if (base != null && base instanceof CollectionModel)
+ {
+ elContext.setPropertyResolved(true);
+ CollectionModel model = (CollectionModel)base;
+ return (property instanceof Integer) ?
+ model.getRowData(((Integer)property).intValue()) :
+ model.getRowData(property);
+ }
+
return null;
}
- public Class<?> getType(ELContext elContext, Object base,
- Object property)
+ public Class<?> getType(
+ ELContext elContext,
+ Object base,
+ Object property)
{
if (base == null)
{
@@ -94,11 +107,16 @@ public class TrinidadELResolver
return Map.class;
}
}
-
+ else if (base != null && base instanceof CollectionModel)
+ {
+ elContext.setPropertyResolved(true);
+ return Object.class;
+ }
+
return null;
}
- public void setValue(ELContext elContext, Object base, Object property,
+ public void setValue(ELContext elContext, Object base, Object property,
Object value)
{
if (PAGE_FLOW_SCOPE_VARIABLE_NAME.equals(base) ||
@@ -110,13 +128,20 @@ public class TrinidadELResolver
}
}
- public boolean isReadOnly(ELContext elContext, Object base,
- Object property)
+ public boolean isReadOnly(
+ ELContext elContext,
+ Object base,
+ Object property)
{
+ if (base != null && base instanceof CollectionModel)
+ {
+ return true;
+ }
+
return false;
}
- public Iterator<FeatureDescriptor> getFeatureDescriptors(ELContext elContext,
+ public Iterator<FeatureDescriptor> getFeatureDescriptors(ELContext elContext,
Object base)
{
if (base == null)
@@ -125,15 +150,61 @@ public class TrinidadELResolver
_featureDescriptorList = _createFeatureDescriptorList();
return _featureDescriptorList.iterator();
}
-
+ else if (base != null && base instanceof CollectionModel)
+ {
+ CollectionModel model = (CollectionModel)base;
+ int rowCount = model.getRowCount();
+
+ List<FeatureDescriptor> list = rowCount == -1 ?
+ new ArrayList<FeatureDescriptor>() :
+ new ArrayList<FeatureDescriptor>(rowCount);
+
+ Object origRowKey = model.getRowKey();
+ try
+ {
+ for (int rowIndex = 0; model.isRowAvailable(rowIndex); ++rowIndex)
+ {
+ model.setRowIndex(rowIndex);
+
+ String name = Integer.toString(rowIndex);
+ FeatureDescriptor descriptor = new FeatureDescriptor();
+
+ descriptor.setName(name);
+ descriptor.setDisplayName(name);
+ descriptor.setShortDescription("");
+ descriptor.setExpert(false);
+ descriptor.setHidden(false);
+ descriptor.setPreferred(true);
+ descriptor.setValue("type", Integer.class);
+ descriptor.setValue("resolvableAtDesignTime", Boolean.TRUE);
+
+ list.add(descriptor);
+ }
+ }
+ finally
+ {
+ model.setRowKey(origRowKey);
+ }
+
+ return list.iterator();
+ }
+
return null;
}
- public Class<?> getCommonPropertyType(ELContext elContext, Object base)
+ public Class<?> getCommonPropertyType(
+ ELContext elContext,
+ Object base)
{
if (base == null)
+ {
return String.class;
-
+ }
+ else if (base != null && base instanceof CollectionModel)
+ {
+ return Object.class;
+ }
+
return null;
}
@@ -151,7 +222,7 @@ public class TrinidadELResolver
requestContext.setValue(ELResolver.RESOLVABLE_AT_DESIGN_TIME, false);
requestContext.setValue(ELResolver.TYPE, RequestContext.class);
list.add(requestContext);
-
+
// FeatureDescriptor for "pageFlowScope"
FeatureDescriptor pageFlowScope = new FeatureDescriptor();
pageFlowScope.setName(PAGE_FLOW_SCOPE_VARIABLE_NAME);
@@ -160,7 +231,7 @@ public class TrinidadELResolver
pageFlowScope.setValue(ELResolver.RESOLVABLE_AT_DESIGN_TIME, false);
pageFlowScope.setValue(ELResolver.TYPE, Map.class);
list.add(pageFlowScope);
-
+
// FeatureDescriptor for "processScope"
FeatureDescriptor processScope = new FeatureDescriptor();
processScope.setName(PAGE_FLOW_SCOPE_VARIABLE_NAME);
Modified: myfaces/trinidad/branches/ar_1940/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/taglib/ForEachTag.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/branches/ar_1940/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/taglib/ForEachTag.java?rev=1197669&r1=1197668&r2=1197669&view=diff
==============================================================================
--- myfaces/trinidad/branches/ar_1940/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/taglib/ForEachTag.java (original)
+++ myfaces/trinidad/branches/ar_1940/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/taglib/ForEachTag.java Fri Nov 4 17:07:23 2011
@@ -6,9 +6,9 @@
* to you 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
@@ -19,8 +19,11 @@
package org.apache.myfaces.trinidadinternal.taglib;
import java.io.Serializable;
+
import java.lang.reflect.Array;
+
import java.util.HashMap;
+import java.util.Iterator;
import java.util.List;
import java.util.Map;
@@ -28,13 +31,20 @@ import javax.el.ELContext;
import javax.el.PropertyNotWritableException;
import javax.el.ValueExpression;
import javax.el.VariableMapper;
+
+import javax.faces.component.UIComponent;
+import javax.faces.component.UIViewRoot;
import javax.faces.context.FacesContext;
+import javax.faces.webapp.UIComponentClassicTagBase;
+
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspTagException;
-import javax.servlet.jsp.jstl.core.IndexedValueExpression;
+import javax.servlet.jsp.tagext.JspIdConsumer;
import org.apache.myfaces.trinidad.logging.TrinidadLogger;
-import org.apache.myfaces.trinidad.webapp.TrinidadTagSupport;
+import org.apache.myfaces.trinidad.model.CollectionModel;
+import org.apache.myfaces.trinidad.webapp.TrinidadIterationTag;
+
//JSTL Core Library - <c:forEach> Tag
//===================================
@@ -55,10 +65,18 @@ import org.apache.myfaces.trinidad.webap
//</c:forEach>
/**
- *
+ * Trinidad JSP for each tag that is based on the JSTL c:forEach tag
+ * but provides additinal functionality.
*/
-public class ForEachTag extends TrinidadTagSupport
+public class ForEachTag
+ extends TrinidadIterationTag
+ implements JspIdConsumer
{
+ public ForEachTag()
+ {
+ System.out.println("ForEachTag created");
+ }
+
public void setItems(ValueExpression items)
{
if (items.isLiteralText())
@@ -93,14 +111,51 @@ public class ForEachTag extends Trinidad
}
@Override
- public int doStartTag() throws JspException
+ public void setJspId(String id)
{
+ System.out.println("setJspId: " + id);
+ // If the view attributes are null, then this is the first time this method has been called
+ // for this request.
+ if (_viewAttributes == null)
+ {
+ // The iteration map key is a key that will allow us to get the map for this tag instance,
+ // separated from other ForEachTags, that will map an iteration ID to the IterationMetaData
+ // instances. EL will use this map to get to the IterationMetaData and the indirection will
+ // allow the IterationMetaData to be updated without having to update the EL expressions.
+ _iterationMapKey = new StringBuilder(_VIEW_ATTR_KEY_LENGTH + id.length())
+ .append(_VIEW_ATTR_KEY)
+ .append(id)
+ .toString();
+
+ FacesContext facesContext = FacesContext.getCurrentInstance();
+
+ // store the map into the view attributes to put it in a location that the EL expressions
+ // can access for not only the remainder of this request, but also the next request.
+ UIViewRoot viewRoot = facesContext.getViewRoot();
+
+ // We can cache the view attributes in the tag as a JSP tag marked with JspIdConsumer
+ // is never reused.
+ _viewAttributes = viewRoot.getAttributes();
+
+ // Create a new iteration map per-request. This will ensure that values from the previous
+ // request are not kept.
+ _iterationMap = new HashMap<Integer, IterationMetaData>();
+ _viewAttributes.put(_iterationMapKey, _iterationMap);
+ }
+ }
+
+ @Override
+ protected int doStartTagImpl()
+ throws JspException
+ {
+ System.out.println("doStartTagImpl");
_validateAttributes();
- FacesContext context = FacesContext.getCurrentInstance();
+ FacesContext facesContext = FacesContext.getCurrentInstance();
+ int length;
+
_currentBegin = (_begin == null) ? 0 : _begin.intValue();
_isFirst = true;
- int length;
if (null != _items)
{
@@ -110,39 +165,32 @@ public class ForEachTag extends Trinidad
// to the JSF ELContext seems to resolve that. We certainly
// have to use the JSPs ELResolver for calling through
// to the VariableMapper
- Object items = _items.getValue(context.getELContext());//pageContext.getELContext());
+ Object items = _items.getValue(facesContext.getELContext());//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.");
+ _LOG.fine("Items expression {0} resolved to null.", _items);
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(_LOG.getMessage(
- "MUST_POINT_TO_LIST_OR_ARRAY"));
+ // Build a wrapper around the items so that a common API can be used to interact with
+ // the items regardless of the type.
+ _itemsWrapper = _buildItemsWrapper(items);
+ length = _itemsWrapper.getSize();
+
if (length == 0)
{
- if (_LOG.isFine())
- _LOG.fine("Items found at " + _items + " is empty.");
+ _LOG.fine("Items found at {0} is empty.", _items);
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'");
+ _LOG.fine("Size of 'items' is less than 'begin'");
return SKIP_BODY;
}
@@ -151,57 +199,49 @@ public class ForEachTag extends Trinidad
// 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;
_currentCount = 1;
_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;
+ }
_isLast = _currentIndex == _currentEnd;
// Save off the previous deferred variables
- VariableMapper vm =
+ VariableMapper vm =
pageContext.getELContext().getVariableMapper();
- if (_var != null)
- _previousDeferredVar = vm.resolveVariable(_var);
- if (null != _varStatus)
+ if (_var != null)
{
- _previousDeferredVarStatus = vm.resolveVariable(_varStatus);
- _propertyReplacementMap = new HashMap<String, Object>(9, 1);
- _propertyReplacementMap.put("begin", Integer.valueOf(_currentBegin));
- _propertyReplacementMap.put("end", Integer.valueOf(_currentEnd));
- _propertyReplacementMap.put("step", Integer.valueOf(_currentStep));
- _propertyReplacementMap.put("count", Integer.valueOf(_currentCount));
- _propertyReplacementMap.put("index", Integer.valueOf(_currentIndex));
- // FIXME: Can we support "current" efficiently?
- // _propertyReplacementMap.put("current", _varReplacement);
- _propertyReplacementMap.put(
- "first",
- (_isFirst)? Boolean.TRUE:Boolean.FALSE);
- _propertyReplacementMap.put(
- "last",
- (_isLast)? Boolean.TRUE:Boolean.FALSE);
+ // Store off the current variable so that it may be restored after tag processing
+ _previousDeferredVar = vm.resolveVariable(_var);
}
if (_LOG.isFiner())
{
- _LOG.finer("Iterating from " + _currentIndex + " to " + _currentEnd +
- " by " + _currentStep);
+ _LOG.finer("Iterating from {0} to {1} by {2}",
+ new Object[] { _currentIndex, _currentEnd, _currentStep });
}
- // Update the variables
- _updateVars();
+ _parentComponent = _getParentComponent();
+
+ _updateVars(true);
return EVAL_BODY_INCLUDE;
}
@@ -209,46 +249,34 @@ public class ForEachTag extends Trinidad
@Override
public int doAfterBody()
{
+ System.out.println("doAfterBody");
_currentIndex += _currentStep;
- _currentCount += 1;
-
- //pu: if there is no varStatus set, no point in keeping loop status
- // variables updated.
- if (null != _varStatus)
- {
- if (_isFirst)
- {
- _propertyReplacementMap.put("first", Boolean.FALSE);
- _isFirst = false;
- }
-
- _isLast = (_currentIndex == _currentEnd);
- if (_isLast)
- {
- _propertyReplacementMap.put("last", _isLast);
- }
- _propertyReplacementMap.put("count", Integer.valueOf(_currentCount));
- _propertyReplacementMap.put("index", Integer.valueOf(_currentIndex));
- // FIXME: Can we support "current" efficiently?
- // _propertyReplacementMap.put("current", _varReplacement);
- }
+ ++_currentCount;
+ _isFirst = false;
+ _isLast = _currentIndex == _currentEnd;
// If we're at the end, bail
if (_currentEnd < _currentIndex)
{
// Restore EL state
- VariableMapper vm =
+ VariableMapper vm =
pageContext.getELContext().getVariableMapper();
if (_var != null)
vm.setVariable(_var, _previousDeferredVar);
if (_varStatus != null)
vm.setVariable(_varStatus, _previousDeferredVarStatus);
+ if (_suffixPushed)
+ {
+ popComponentSuffix();
+ _suffixPushed = false;
+ }
+
return SKIP_BODY;
}
-
+
// Otherwise, update the variables and go again
- _updateVars();
+ _updateVars(true);
return EVAL_BODY_AGAIN;
}
@@ -264,52 +292,166 @@ public class ForEachTag extends Trinidad
_end = null;
_step = null;
_items = null;
- _itemsValue = null;
_var = null;
_varStatus = null;
- _propertyReplacementMap = null;
_previousDeferredVar = null;
_previousDeferredVarStatus = null;
+
+ System.out.println("release called");
+ _iterationId = null;
+ _iterationData = null;
+ _viewAttributes = null;
+ _iterationMapKey = null;
+ _iterationMap = null;
+ _itemsWrapper = null;
+
+ _parentComponent = null;
+
+ _suffixPushed = false;
+}
+
+ @Override
+ public final void childComponentProcessed(
+ UIComponent component)
+ {
+ // This code is called when a component is created or found, see which it is.
+ // We are only interested in components that are directly under our parent.
+ if (component.getParent() == _parentComponent)
+ {
+ Map<String, Object> compAttrs = component.getAttributes();
+ Integer iterationId = (Integer)compAttrs.get(_ITERATION_ID_KEY);
+ System.out.println("childComponentProcessed: " + component +
+ " Previous component iteration ID: " + iterationId);
+
+ if (iterationId == null)
+ {
+ // This is a new component, use the current iteration ID
+ compAttrs.put(_ITERATION_ID_KEY, _iterationId);
+
+ // Remember that the iteration ID was used
+ _iterationIdRequiresIncrement = true;
+ }
+ else
+ {
+ // This component has been seen before, register the old iteration ID with the iteration
+ // map so that the EL may look up the iteration data.
+ _iterationMap.put(iterationId, _iterationData);
+ }
+ }
+ }
+
+ @Override
+ public void afterChildComponentProcessed(
+ UIComponent component)
+ {
+ // This code is called when a component is created or found, see which it is.
+ // We are only interested in components that are directly under our parent.
+ if (component.getParent() == _parentComponent)
+ {
+ System.out.println("afterChildComponentProcessed: " + component);
+ // Store a unique iteration ID in each component. That way, if a component is ever moved
+ // from one iteration to another between requests, but not all the components, no problems
+ // will ensue. The use case is that ${} is used in the ID of one or more child components
+ // of a for each loop to pin the component to the item in the collection rather than the
+ // for each index.
+ if (_iterationIdRequiresIncrement)
+ {
+ _updateVars(false);
+ _iterationIdRequiresIncrement = false;
+ }
+ }
+ }
+
+ private UIComponent _getParentComponent()
+ {
+ UIComponentClassicTagBase tag = UIComponentClassicTagBase.getParentUIComponentClassicTagBase(
+ pageContext);
+ return tag == null ? null : tag.getComponentInstance();
}
// Push new values into the VariableMapper and the pageContext
- private void _updateVars()
+ private void _updateVars(
+ boolean createNewIterationData)
{
- VariableMapper vm =
+ VariableMapper vm =
pageContext.getELContext().getVariableMapper();
+
+ // Generate a new iteration ID
+ _updateIterationId();
+
if (_var != null)
{
// Catch programmer error where _var has been set but
// _items has not
if (_items != null)
{
- ValueExpression iterated = new IndexedValueExpression(_items,
- _currentIndex);
- vm.setVariable(_var, iterated);
+ // Determine if we need to use a key or an index based value expression
+ // for the current items.
+ ValueExpression expr;
+ if (_itemsWrapper.isKeyBased())
+ {
+ // Use a key to get the value
+ Serializable key = _asSerializable(_itemsWrapper.getKey(_currentIndex));
+ expr = new KeyedValueExpression(_items, key);
+ }
+ else
+ {
+ // Use indirection to get the index from the iteration data using the iteration ID
+ // so that the expression is not hard-coded to one index
+ expr = new IndexedValueExpression(_iterationId, _iterationMapKey, _items);
+ }
+
+ vm.setVariable(_var, expr);
}
-
+
// Ditto (though, technically, one check for
// _items is sufficient, because if _items evaluated
// to null, we'd skip the whole loop)
- Object items = _itemsValue;
- if (items != null)
+ if (_itemsWrapper != null)
{
- Object item;
- if (items instanceof List)
- item = ((List) items).get(_currentIndex);
- else
- item = Array.get(items, _currentIndex);
-
+ Object item = _itemsWrapper.getValue(_currentIndex);
pageContext.setAttribute(_var, item);
}
}
-
+
+ Object key = _itemsWrapper == null ?
+ _currentIndex : _itemsWrapper.getKey(_currentIndex);
+
+ if (!(key instanceof Serializable))
+ {
+ throw new IllegalStateException("For each loop keys must be serializable");
+ }
+
+ if (createNewIterationData || _iterationData == null)
+ {
+ _iterationData = new IterationMetaData((Serializable)key, _isFirst, _isLast,
+ _currentBegin, _currentCount, _currentIndex, _currentEnd);
+ }
+
+ // Store the iteration data into the view attributes to allow the EL expressions
+ // gain access to it
+ _iterationMap.put(_iterationId, _iterationData);
+
if (_varStatus != null)
{
- pageContext.setAttribute(_varStatus, _propertyReplacementMap);
- ValueExpression constant = new Constants(
- new HashMap(_propertyReplacementMap));
- vm.setVariable(_varStatus, constant);
+ _previousDeferredVarStatus = vm.resolveVariable(_varStatus);
+
+
+ // Store a new var status value expression into the variable mapper
+ vm.setVariable(_varStatus, new VarStatusValueExpression(_iterationId, _iterationMapKey));
+ }
+
+ if (_suffixPushed)
+ {
+ popComponentSuffix();
+ _suffixPushed = false;
+ }
+
+ // To do, support non-key pass-through
+ if (_itemsWrapper != null && _itemsWrapper.isIdSuffixSupported())
+ {
+ pushComponentSuffix("_" + key.toString());
+ _suffixPushed = true;
}
}
@@ -364,21 +506,84 @@ public class ForEachTag extends Trinidad
throw new JspTagException("'step' < 1");
}
- // Basic ValueExpression that always returns a constant object
- static private class Constants extends ValueExpression
- implements Serializable
+ private void _updateIterationId()
{
- public Constants(Object o)
+ Integer intObj = (Integer)_viewAttributes.get(_ITERATION_ID_KEY);
+
+ if (intObj == null)
{
- _o = o;
+ // By using MIN_VALUE, we can achive 4.2E9 requests for the current view (should
+ // be way more than we need)
+ _iterationId = new Integer(Integer.MIN_VALUE);
+ }
+ else
+ {
+ _iterationId = intObj + 1;
}
- public Object getValue(ELContext context)
+ System.out.println("Iteration ID is now " + _iterationId);
+ _viewAttributes.put(_ITERATION_ID_KEY, _iterationId);
+
+ if (_iterationData != null)
{
- return _o;
+ _iterationMap.put(_iterationId, _iterationData);
}
+ }
- public void setValue(ELContext context, Object value)
+ private Serializable _asSerializable(Object key)
+ {
+ if (key instanceof Serializable)
+ {
+ return (Serializable)key;
+ }
+ else
+ {
+ throw new IllegalStateException("The forEach tag only supports serializable keys for " +
+ "maps and collection models");
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ private static ItemsWrapper _buildItemsWrapper(
+ Object items)
+ {
+ if (items instanceof Array)
+ {
+ return new ArrayWrapper(items);
+ }
+ else if (items instanceof List)
+ {
+ return new ListWrapper((List<?>)items);
+ }
+ else if (items instanceof CollectionModel)
+ {
+ return new CollectionModelWrapper((CollectionModel)items);
+ }
+ else if (items instanceof Map)
+ {
+ return new MapWrapper((Map<?, ?>)items);
+ }
+ else
+ {
+ throw new IllegalArgumentException("Illegal items type: " + items.getClass());
+ }
+ }
+
+ private static abstract class ForEachBaseValueExpression
+ extends ValueExpression
+ implements Serializable
+ {
+ protected ForEachBaseValueExpression(
+ Integer iterationId,
+ String mapKey)
+ {
+ _iterationId = iterationId;
+ _mapKey = mapKey;
+ }
+
+ public void setValue(
+ ELContext context,
+ Object value)
{
throw new PropertyNotWritableException();
}
@@ -390,12 +595,7 @@ public class ForEachTag extends Trinidad
public Class getType(ELContext context)
{
- return _o.getClass();
- }
-
- public Class getExpectedType()
- {
- return _o.getClass();
+ return getExpectedType();
}
public String getExpressionString()
@@ -410,7 +610,7 @@ public class ForEachTag extends Trinidad
public int hashCode()
{
- return _o.hashCode();
+ return _iterationId.hashCode() | _mapKey.hashCode();
}
public boolean isLiteralText()
@@ -418,10 +618,488 @@ public class ForEachTag extends Trinidad
return true;
}
- private Object _o;
+ protected IterationMetaData getIterationMetaData()
+ {
+ // A value expression should ever only be used for one view root,
+ // so keep a transient reference to the view to increase performance
+ if (_viewAttributes == null)
+ {
+ FacesContext facesContext = FacesContext.getCurrentInstance();
+ UIViewRoot view = facesContext.getViewRoot();
+ _viewAttributes = view.getAttributes();
+ }
+
+ // Get the map from the view attributes created by the tag:
+ @SuppressWarnings("unchecked")
+ Map<Integer, IterationMetaData> map = (Map<Integer, IterationMetaData>)
+ _viewAttributes.get(_mapKey);
+
+ // The map will be null if, somehow, the component for a given for each loop execution
+ // is still around, but the for each loop did not match the component during this request
+ // (probably a temporary state until the unmatched component is removed).
+ return map == null ? null : map.get(_iterationId);
+ }
+
+ private final Integer _iterationId;
+ private final String _mapKey;
+ private transient Map<String, Object> _viewAttributes;
+
+ @SuppressWarnings("compatibility:29745293788177755")
+ private static final long serialVersionUID = 1L;
+ }
+
+ private static class KeyedValueExpression
+ extends ValueExpression
+ {
+ private KeyedValueExpression(
+ ValueExpression itemsExpression,
+ Serializable key)
+ {
+ _itemsExpression = itemsExpression;
+ _key = key;
+ }
+
+ public Object getValue(ELContext context)
+ {
+ Object items = _itemsExpression.getValue(context);
+
+ if (items == null)
+ {
+ return null;
+ }
+
+ context.setPropertyResolved(false);
+ return context.getELResolver().getValue(context, items, _key);
+ }
+
+ public void setValue(ELContext context, Object value)
+ {
+ Object items = _itemsExpression.getValue(context);
+
+ if (items != null)
+ {
+ context.setPropertyResolved(false);
+ context.getELResolver().setValue(context, items, _key, value);
+ }
+ }
+
+ public boolean isReadOnly(ELContext context)
+ {
+ Object items = _itemsExpression.getValue(context);
+ if (items == null)
+ {
+ return true;
+ }
+
+ return context.getELResolver().isReadOnly(context, items, _key);
+ }
+
+ public Class<?> getType(ELContext context)
+ {
+ return null;
+ }
+
+ public Class<?> getExpectedType()
+ {
+ return Object.class;
+ }
+
+ public String getExpressionString()
+ {
+ return _itemsExpression.getExpressionString();
+ }
+
+ public boolean isLiteralText()
+ {
+ return false;
+ }
+
+ @Override
+ public int hashCode()
+ {
+ return _itemsExpression.hashCode();
+ }
+
+ public boolean equals(Object obj)
+ {
+ return _itemsExpression.equals(obj);
+ }
+
+ private final ValueExpression _itemsExpression;
+ private final Serializable _key;
+
+ @SuppressWarnings("compatibility:-8374272730669095059")
+ private static final long serialVersionUID = 1L;
+ }
+
+ /**
+ * Value expression that looks up the var value using an index.
+ * This class is written in such a way that the index is dynamic, so that if a component is
+ * used in different iterations of the for each loop across requests, the correct variable
+ * is returned.
+ */
+ private static class IndexedValueExpression
+ extends ForEachBaseValueExpression
+ implements Serializable
+ {
+ private IndexedValueExpression(
+ Integer iterationId,
+ String mapKey,
+ ValueExpression itemsExpression)
+ {
+ super(iterationId, mapKey);
+ _itemsExpression = itemsExpression;
+ }
+
+ public Object getValue(ELContext context)
+ {
+ // By using a layer of indirection, we can ensure that the correct value is returned for
+ // users who pin their component ID to the varStatus so that the component is processed
+ // during a different index across requests. We can use the index from the varStatus
+ // to determine the correct index to use in the items collection.
+ IterationMetaData data = getIterationMetaData();
+ if (data == null)
+ {
+ return null;
+ }
+
+ Object items = _itemsExpression.getValue(context);
+ if (items == null)
+ {
+ return null;
+ }
+
+ context.setPropertyResolved(false);
+ return context.getELResolver().getValue(context, items, data.getIndex());
+ }
+
+ public Class<?> getExpectedType()
+ {
+ return Object.class;
+ }
+
+ @Override
+ public int hashCode()
+ {
+ return _itemsExpression.hashCode();
+ }
+
+ public boolean equals(Object obj)
+ {
+ return _itemsExpression.equals(obj);
+ }
+
+ private final ValueExpression _itemsExpression;
+
+ @SuppressWarnings("compatibility:1734834404228501647")
private static final long serialVersionUID = 1L;
}
+ /**
+ * Value Expression instance used to get an object containing the var status properties.
+ */
+ static private class VarStatusValueExpression
+ extends ForEachBaseValueExpression
+ implements Serializable
+ {
+ private VarStatusValueExpression(
+ Integer iterationId,
+ String mapKey)
+ {
+ super(iterationId, mapKey);
+ }
+
+ public Object getValue(ELContext context)
+ {
+ return super.getIterationMetaData();
+ }
+
+ public Class getExpectedType()
+ {
+ return IterationMetaData.class;
+ }
+
+ @SuppressWarnings("compatibility:-3014844132563306923")
+ private static final long serialVersionUID = 1L;
+ }
+
+ private abstract static class ItemsWrapper
+ {
+ public abstract Object getKey(int index);
+ public abstract Object getValue(int index);
+ public abstract int getSize();
+ public abstract boolean isIdSuffixSupported();
+ public abstract boolean isKeyBased();
+ }
+
+ private static class CollectionModelWrapper
+ extends ItemsWrapper
+ {
+ private CollectionModelWrapper(
+ CollectionModel collectionModel)
+ {
+ _collectionModel = collectionModel;
+ }
+
+ @Override
+ public Object getKey(int index)
+ {
+ Object oldRowKey = _collectionModel.getRowKey();
+ try
+ {
+ _collectionModel.setRowIndex(index);
+ return _collectionModel.getRowKey();
+ }
+ finally
+ {
+ _collectionModel.setRowKey(oldRowKey);
+ }
+ }
+
+ @Override
+ public Object getValue(int index)
+ {
+ return _collectionModel.getRowData(index);
+ }
+
+ @Override
+ public int getSize()
+ {
+ return _collectionModel.getRowCount();
+ }
+
+ public boolean isIdSuffixSupported()
+ {
+ return true;
+ }
+
+ public boolean isKeyBased()
+ {
+ return true;
+ }
+
+ private CollectionModel _collectionModel;
+ }
+
+ private static class MapWrapper
+ extends ItemsWrapper
+ {
+ private MapWrapper(
+ Map<?, ?> map)
+ {
+ _map = map;
+ }
+
+ @Override
+ public Object getKey(int index)
+ {
+ _moveToIndex(index);
+ return _currentEntry.getKey();
+ }
+
+ @Override
+ public Object getValue(int index)
+ {
+ _moveToIndex(index);
+ return _currentEntry.getValue();
+ }
+
+ @Override
+ public int getSize()
+ {
+ return _map.size();
+ }
+
+ private void _moveToIndex(int index)
+ {
+ if (index == _currentIndex)
+ {
+ return;
+ }
+
+ if (index < _currentIndex)
+ {
+ // Need to re-create the iterator
+ _iter = _map.entrySet().iterator();
+ _currentIndex = -1;
+ }
+
+ for (int i = _currentIndex; i < index; ++i)
+ {
+ _currentEntry = _iter.next();
+ }
+
+ _currentIndex = index;
+ }
+
+ public boolean isIdSuffixSupported()
+ {
+ return true;
+ }
+
+ public boolean isKeyBased()
+ {
+ return true;
+ }
+
+ private final Map<?, ?> _map;
+ private Iterator<? extends Map.Entry<?, ?>> _iter;
+ private Map.Entry<?, ?> _currentEntry;
+ private int _currentIndex = -1;
+ }
+
+ private static class ListWrapper
+ extends ItemsWrapper
+ {
+ private ListWrapper(
+ List<?> list)
+ {
+ _list = list;
+ }
+
+ @Override
+ public Object getKey(int index)
+ {
+ return index;
+ }
+
+ @Override
+ public Object getValue(int index)
+ {
+ return _list.get(index);
+ }
+
+ @Override
+ public int getSize()
+ {
+ return _list.size();
+ }
+
+ public boolean isIdSuffixSupported()
+ {
+ return false;
+ }
+
+ public boolean isKeyBased()
+ {
+ return false;
+ }
+
+ private final List<?> _list;
+ }
+
+ private static class ArrayWrapper
+ extends ItemsWrapper
+ {
+ private ArrayWrapper(
+ Object array)
+ {
+ _array = array;
+ }
+
+ @Override
+ public Object getKey(int index)
+ {
+ return index;
+ }
+
+ @Override
+ public Object getValue(int index)
+ {
+ return Array.get(_array, index);
+ }
+
+ @Override
+ public int getSize()
+ {
+ return Array.getLength(_array);
+ }
+
+ public boolean isIdSuffixSupported()
+ {
+ return false;
+ }
+
+ public boolean isKeyBased()
+ {
+ return false;
+ }
+
+ private final Object _array;
+ }
+
+ /**
+ * Data that is used for the children content of the tag. This contains
+ * the var status information.
+ */
+ public static class IterationMetaData
+ implements Serializable
+ {
+ private IterationMetaData(
+ Serializable key,
+ boolean first,
+ boolean last,
+ int begin,
+ int count,
+ int index,
+ int end)
+ {
+ super();
+ this._key = key;
+ this._first = first;
+ this._last = last;
+ this._begin = begin;
+ this._count = count;
+ this._index = index;
+ this._end = end;
+ }
+
+ public final boolean isLast()
+ {
+ return _last;
+ }
+
+ public final boolean isFirst()
+ {
+ return _first;
+ }
+
+ public final int getIndex()
+ {
+ return _index;
+ }
+
+ public final int getCount()
+ {
+ return _count;
+ }
+
+ public final int getBegin()
+ {
+ return _begin;
+ }
+
+ public final int getEnd()
+ {
+ return _end;
+ }
+
+ public final Serializable getKey()
+ {
+ return _key;
+ }
+
+ private boolean _last;
+ private boolean _first;
+ private int _begin;
+ private int _count;
+ private int _index;
+ private int _end;
+ private Serializable _key;
+
+ private static final long serialVersionUID = 0L;
+ }
+
private int _currentBegin;
private int _currentIndex;
private int _currentEnd;
@@ -429,11 +1107,9 @@ public class ForEachTag extends Trinidad
private int _currentCount;
private boolean _isFirst;
private boolean _isLast;
-
+ private boolean _iterationIdRequiresIncrement;
private ValueExpression _items;
- private Object _itemsValue;
-
private ValueExpression _beginVE;
private ValueExpression _endVE;
private ValueExpression _stepVE;
@@ -442,16 +1118,29 @@ public class ForEachTag extends Trinidad
private Integer _end;
private Integer _step;
+ private boolean _suffixPushed = false;
+
+ private UIComponent _parentComponent;
+
+ private Integer _iterationId;
+ private IterationMetaData _iterationData;
+ private Map<String, Object> _viewAttributes;
+
+ private String _iterationMapKey;
+ private Map<Integer, IterationMetaData> _iterationMap;
+ private ItemsWrapper _itemsWrapper;
+
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);
+ private static final String _VIEW_ATTR_KEY = ForEachTag.class.getName() + ".";
+ private static final int _VIEW_ATTR_KEY_LENGTH = _VIEW_ATTR_KEY.length();
+ private static final String _ITERATION_ID_KEY =
+ ForEachTag.class.getName() + ".ITER";
private static final long serialVersionUID = 1L;
}