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/20 16:48:01 UTC
svn commit: r466196 - in
/incubator/adffaces/branches/faces-1_2-second/trinidad:
trinidad-api/src/site/xdoc/tagdoc/tr_forEach.xml
trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/taglib/ForEachTag.java
Author: awiner
Date: Fri Oct 20 09:47:59 2006
New Revision: 466196
URL: http://svn.apache.org/viewvc?view=rev&rev=466196
Log:
Merge final two files back into branch. Seems svn - at least my version - was deeply unhappy with merging from a branch when that branch had removed and re-added a file; these are those files
Modified:
incubator/adffaces/branches/faces-1_2-second/trinidad/trinidad-api/src/site/xdoc/tagdoc/tr_forEach.xml
incubator/adffaces/branches/faces-1_2-second/trinidad/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/taglib/ForEachTag.java
Modified: incubator/adffaces/branches/faces-1_2-second/trinidad/trinidad-api/src/site/xdoc/tagdoc/tr_forEach.xml
URL: http://svn.apache.org/viewvc/incubator/adffaces/branches/faces-1_2-second/trinidad/trinidad-api/src/site/xdoc/tagdoc/tr_forEach.xml?view=diff&rev=466196&r1=466195&r2=466196
==============================================================================
--- incubator/adffaces/branches/faces-1_2-second/trinidad/trinidad-api/src/site/xdoc/tagdoc/tr_forEach.xml (original)
+++ incubator/adffaces/branches/faces-1_2-second/trinidad/trinidad-api/src/site/xdoc/tagdoc/tr_forEach.xml Fri Oct 20 09:47:59 2006
@@ -25,34 +25,17 @@
<br/>
<p>
The forEach tag is a replacement for the JSTL
-<c:forEach> tag that works with ADF Faces components. In JSF
-1.1, <c:forEach> cannot be used with any JSF components or tags.
+<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 functional in Facelets. It will also be removed in JSF 1.2/JSP
-2.1, because c:forEach will become functional there too.) This tag
-brings that functionality to JSF, but it is limited to ADF Faces tags.
-This tag also has several limitations not found in <c:forEach>:
-
-<ul>
-
-<li><tr:forEach> does not currently support scenarios where the
-size of the "items" list or array changes from one request to the
-next. It may be possible to work around this in specific scenarios by
-manually deleting all children of the parent component
-(<tr:selectOneListbox> in the above example), but this has not
-yet been tested.</li>
-
-<li><tr:forEach> does not support arbitrary
+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.</li>
-
-<li><tr:forEach> executes at the time the JSP tag executes. So
-it does not have access to any EL variables that are created by JSF
-components. For example, the <tr:table> creates an EL variable
-using the value of the "var" attribute. However, this EL variable is
-not available to <tr:forEach></li>
-
-</ul></p><h4>Example:</h4><source>
+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}"/>
@@ -105,7 +88,7 @@
<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','current','first','last'
+ 'index','count','begin','end','step','first','last'
are available through this
</td>
</tr>
Modified: incubator/adffaces/branches/faces-1_2-second/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-second/trinidad/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/taglib/ForEachTag.java?view=diff&rev=466196&r1=466195&r2=466196
==============================================================================
--- incubator/adffaces/branches/faces-1_2-second/trinidad/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/taglib/ForEachTag.java (original)
+++ incubator/adffaces/branches/faces-1_2-second/trinidad/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/taglib/ForEachTag.java Fri Oct 20 09:47:59 2006
@@ -15,19 +15,26 @@
*/
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.el.ValueBinding;
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;
@@ -56,45 +63,38 @@
*
* @author The Oracle ADF Faces Team
*/
-public class ForEachTag extends TagSupport implements ELContextTag
+public class ForEachTag extends TagSupport
{
- public void setItems(String items)
+ public void setItems(ValueExpression items)
{
- if (!items.startsWith("#{") ||
- !items.endsWith("}"))
+ if (items.isLiteralText())
throw new IllegalArgumentException(
- "\"items\" must be a simple JSF EL expression");
+ "\"items\" must be an EL expression");
_items = items;
}
- public void setBegin(String begin)
+ public void setBegin(Integer begin)
{
_begin = begin;
}
- public void setEnd(String end)
+ public void setEnd(Integer end)
{
_end = end;
}
- public void setStep(String step)
+ public void setStep(Integer step)
{
_step = step;
}
public void setVar(String var)
{
- if (UIComponentTag.isValueReference(var))
- throw new IllegalArgumentException("\"var\" cannot be an expression");
-
_var = var;
}
public void setVarStatus(String varStatus)
{
- if (UIComponentTag.isValueReference(varStatus))
- throw new IllegalArgumentException("\"varStatus\" cannot be an expression");
-
_varStatus = varStatus;
}
@@ -104,13 +104,13 @@
_validateAttributes();
FacesContext context = FacesContext.getCurrentInstance();
- _parentELContext = (ELContextTag)
- findAncestorWithClass(this, ELContextTag.class);
- _currentBegin = _resolveInteger(context, _begin, 0);
+ _currentBegin = (_begin == null) ? 0 : _begin.intValue();
int length;
+
if (null != _items)
{
- Object items = _resolveObject(context, _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)
@@ -119,6 +119,8 @@
_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)
@@ -141,7 +143,8 @@
_LOG.fine("Size of 'items' is less than 'begin'");
return SKIP_BODY;
}
- _currentEnd = _resolveInteger(context, _end, length - 1);
+
+ _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.
@@ -150,41 +153,35 @@
}
else
{
- _currentEnd = _resolveInteger(context, _end, 0);
+ _currentEnd = (_end == null) ? 0 : _end.intValue();
}
_currentIndex = _currentBegin;
- _currentStep = _resolveInteger(context, _step, 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;
- if (null != _var || null != _varStatus)
- {
- //pu: If items not defined (syntax 2), the return type of 'var' is an
- // int according to JSTL specs, and apache impl returns index. Mimic.
- _varReplacement = (null == _items)?
- String.valueOf(_currentIndex):
- _items.substring(2, _items.length() - 1) + "[" + _currentIndex + "]";
- }
- //pu: If there is no varStatus set, no point in keeping loop status
- // variables updated.
+ // Save off the previous deferred variables
+ VariableMapper vm =
+ pageContext.getELContext().getVariableMapper();
+ if (_var != null)
+ _previousDeferredVar = vm.resolveVariable(_var);
+
if (null != _varStatus)
{
- _updateLoopStatus();
+ _previousDeferredVarStatus = vm.resolveVariable(_varStatus);
_propertyReplacementMap = new HashMap<String, Object>(9, 1);
- _propertyReplacementMap.put("begin", new Integer(_currentBegin));
- _propertyReplacementMap.put("end", new Integer(_currentEnd));
- _propertyReplacementMap.put("step", new Integer(_currentStep));
- _propertyReplacementMap.put("count", new Integer(_currentCount));
- _propertyReplacementMap.put("index", new Integer(_currentIndex));
- _propertyReplacementMap.put("current", _varReplacement);
- _propertyReplacementMap.put(
- "first",
- (_isFirst)? Boolean.TRUE:Boolean.FALSE);
- _propertyReplacementMap.put(
- "last",
- (_isLast)? Boolean.TRUE:Boolean.FALSE);
+ _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())
@@ -192,6 +189,10 @@
_LOG.finer("Iterating from " + _currentIndex + " to " + _currentEnd +
" by " + _currentStep);
}
+
+ // Update the variables
+ _updateVars();
+
return EVAL_BODY_INCLUDE;
}
@@ -200,102 +201,46 @@
{
_currentIndex += _currentStep;
- if (null != _var || null != _varStatus)
- {
- //pu: If items not defined (syntax 2), the return type of 'var' is an
- // int according to JSTL specs, and apache impl returns index. Mimic.
- _varReplacement = (null == _items)?
- String.valueOf(_currentIndex):
- _items.substring(2, _items.length() - 1) + "[" + _currentIndex + "]";
- }
-
//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;
- _updateLoopStatus();
if (isSecondIteration)
{
- _propertyReplacementMap.put(
- "first",
- (_isFirst)? Boolean.TRUE:Boolean.FALSE);
+ _propertyReplacementMap.put("first", _isFirst);
}
if (_isLast)
{
- _propertyReplacementMap.put(
- "last",
- (_isLast)? Boolean.TRUE:Boolean.FALSE);
+ _propertyReplacementMap.put("last", _isLast);
}
- _propertyReplacementMap.put("count", new Integer(_currentCount));
- _propertyReplacementMap.put("index", new Integer(_currentIndex));
- _propertyReplacementMap.put("current", _varReplacement);
+ _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)
- return SKIP_BODY;
- return EVAL_BODY_AGAIN;
- }
-
- public String transformId(String id)
- {
- if (_parentELContext != null)
- id = _parentELContext.transformId(id);
-
- // SEPARATOR_CHAR would be nice; but JSF does not allow
- // the separator char in an ID - just in client IDs.
- // return id + NamingContainer.SEPARATOR_CHAR + _currentIndex;
- return id + '_' + _currentIndex;
- }
- static String __transformExpression(
- String expression,
- String var,
- String subst)
- {
- String varDot = var + ".";
- Tokenizer tokens = new Tokenizer(expression);
- StringBuffer buf = new StringBuffer(expression.length());
- while(tokens.hasNext())
- {
- Token tok = tokens.next();
- String exp = tok.getText();
- if (tok.type == Tokenizer.VAR_TYPE)
- {
- if (var.equals(exp) || exp.startsWith(varDot))
- {
- buf.append(subst);
- buf.append(exp.substring(var.length()));
- continue;
- }
- }
-
- buf.append(exp);
- }
- return buf.toString();
- }
- public String transformExpression(String expression)
- {
- if (expression != null)
{
- String transformedExp = expression;
- int expressionStart = expression.indexOf("#{");
- if (expressionStart >= 0)
- {
- transformedExp = _transformExpression(expression);
+ // Restore EL state
+ VariableMapper vm =
+ pageContext.getELContext().getVariableMapper();
+ if (_var != null)
+ vm.setVariable(_var, _previousDeferredVar);
+ if (_varStatus != null)
+ vm.setVariable(_varStatus, _previousDeferredVarStatus);
- if (_parentELContext != null)
- transformedExp = _parentELContext.transformExpression(transformedExp);
- }
-
- if (_LOG.isFiner())
- _LOG.finer("Transformed expression:{0} to:{1}",
- new String[] {expression, transformedExp});
- return transformedExp;
+ return SKIP_BODY;
}
+
+ // Otherwise, update the variables and go again
+ _updateVars();
- return null;
+ return EVAL_BODY_AGAIN;
}
+
/**
* Release state.
*/
@@ -303,25 +248,46 @@
public void release()
{
super.release();
- //=-=pu: Does only the properties that has setters need to be released ?
- // What about variables like _propertyReplacementMap/_varReplacement etc. ?
_begin = null;
_end = null;
- _end = null;
- _items = null;
_step = null;
+ _items = null;
+ _itemsValue = null;
_var = null;
_varStatus = null;
- }
-
- protected ValueBinding createValueBinding(
- FacesContext context,
- String expression)
- {
- if (_parentELContext != null)
- expression = _parentELContext.transformExpression(expression);
+ _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);
- return context.getApplication().createValueBinding(expression);
+ 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
@@ -349,154 +315,62 @@
if (_currentStep < 1)
throw new JspTagException("'step' < 1");
}
-
- private String _transformExpression(String expression)
+
+ // Basic ValueExpression that always returns a constant object
+ static private class Constants extends ValueExpression
+ implements Serializable
{
- boolean doVar = (_var != null);
- boolean doVarStatus = (_varStatus != null);
- if (!(doVar || doVarStatus))
- return expression;
- StringBuffer buf = new StringBuffer(expression.length());
- // ACW: see bug 3754666:
- Tokenizer tokens = new Tokenizer(expression);
- String varDot = _var+".";
- String varStatusDot = _varStatus+".";
- while(tokens.hasNext())
- {
- Token tok = tokens.next();
- String text = tok.getText();
- if (tok.type == Tokenizer.VAR_TYPE)
- {
- if (doVar && (_var.equals(text) || text.startsWith(varDot)))
- {
- text = _replaceVariableAndPropertiesInExpression(
- text, _var, _varReplacement, null);
- }
- else if (doVarStatus && (_varStatus.equals(text) || text.startsWith(varStatusDot)))
- {
- text = _replaceVariableAndPropertiesInExpression(
- text, _varStatus, null, _propertyReplacementMap);
- }
- }
- buf.append(text);
+ public Constants(Object o)
+ {
+ _o = o;
}
- return buf.toString();
- }
- /**
- * Replaces all occurance of 'variable' and the property (the key in map)
- * with the property replacement (value in the map).
- * If propertyReplacementMap were to be null, then all the occurance of
- * 'variable' will be replaced by 'variableReplacement'.
- * Returns a string modified thus.
- */
- private String _replaceVariableAndPropertiesInExpression(
- String subExpression,
- String variable,
- String variableReplacement,
- Map<String, Object> propertyReplacementMap)
- {
- int variableLength = variable.length();
- //pu: Now check whether the variable is followed by any property from
- // the supplied map.
- if (null != propertyReplacementMap)
- {
- String property;
- String propertyReplacement;
- for(Map.Entry<String, Object> entry : propertyReplacementMap.entrySet())
- {
- property = entry.getKey();
- String expressionAfterVar = subExpression.substring(variableLength);
- if (expressionAfterVar.startsWith("."+property))
- {
- int propertyLength = property.length();
- //pu: We found our property, but it could be followed
- // by an alphanumeric in which case we ignore and move on because
- // we just found it as a substring
- int endOfReplacement = propertyLength + 1;
- if (expressionAfterVar.length() > endOfReplacement)
- {
- if (Character.isLetterOrDigit(
- expressionAfterVar.charAt(endOfReplacement)))
- {
- continue;
- }
- }
- propertyReplacement = entry.getValue().toString();
- //pu: Replace both the variable plus the property following it.
- subExpression = _replaceSubString(
- subExpression,
- 0,
- variableLength + propertyLength + 1,
- propertyReplacement);
- //pu: If we handled atleast one property, break out from here.
- break;
- }
- }
+
+ public Object getValue(ELContext context)
+ {
+ return _o;
}
- //pu: If there were no properties to be replaced, replace the variable itself
- else
+
+ public void setValue(ELContext context, Object value)
{
- subExpression = _replaceSubString(subExpression, 0, variableLength, variableReplacement);
+ throw new PropertyNotWritableException();
}
+ public boolean isReadOnly(ELContext context)
+ {
+ return true;
+ }
- return subExpression;
- }
- /**
- * Given the 'str', replaces a substring starting from 'beginIndex'
- * of 'noOfChars' length with the string in 'replacement', returns the
- * string modified thus.
- */
- private String _replaceSubString(
- String str,
- int beginIndex,
- int noOfChars,
- String replacement)
- {
- StringBuffer buffer = new StringBuffer(str.length() +
- replacement.length() -
- noOfChars);
- buffer.append(str.substring(0, beginIndex));
- buffer.append(replacement);
- buffer.append(str.substring(beginIndex + noOfChars));
- return buffer.toString();
- }
- /**
- * Update the loop status variables.
- */
- private void _updateLoopStatus()
- {
- _currentCount = ((_currentIndex - _currentBegin)/_currentStep) + 1;
- _isFirst = (_currentIndex == _currentBegin);
- _isLast = (_currentIndex + _currentStep) > _currentEnd;
- }
+ public Class getType(ELContext context)
+ {
+ return _o.getClass();
+ }
+ public Class getExpectedType()
+ {
+ return _o.getClass();
+ }
- private Object _resolveObject(FacesContext context, String expression)
- {
- ValueBinding vb = createValueBinding(context, expression);
- return vb.getValue(context);
- }
+ public String getExpressionString()
+ {
+ return null;
+ }
- private int _resolveInteger(
- FacesContext context,
- String expression,
- int defaultValue)
- {
- if (expression == null)
- return defaultValue;
+ public boolean equals(Object obj)
+ {
+ return obj == this;
+ }
- if (UIComponentTag.isValueReference(expression))
+ public int hashCode()
{
- Object o = _resolveObject(context, expression);
- if (o instanceof Number)
- return ((Number) o).intValue();
- if (o == null)
- return defaultValue;
+ return _o.hashCode();
+ }
- expression = o.toString();
+ public boolean isLiteralText()
+ {
+ return true;
}
- return Integer.parseInt(expression);
+
+ private Object _o;
}
private int _currentBegin;
@@ -506,18 +380,23 @@
private int _currentCount;
private boolean _isFirst;
private boolean _isLast;
- private ELContextTag _parentELContext;
- private String _items;
- private String _begin;
- private String _end;
- private String _step;
+
+ private ValueExpression _items;
+ private Object _itemsValue;
+
+ private Integer _begin;
+ private Integer _end;
+ private Integer _step;
private String _var;
private String _varStatus;
- //pu: Map for properties referred off from 'varStatus' and their replacements
+
+ // 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;
- //pu: Represents replacement for 'var' upon every iteration
- private String _varReplacement;
private static final TrinidadLogger _LOG = TrinidadLogger.createTrinidadLogger(ForEachTag.class);