You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by lu...@apache.org on 2013/11/10 01:12:41 UTC
svn commit: r1540431 - in /myfaces/core/trunk/impl/src:
main/java/org/apache/myfaces/view/facelets/
main/java/org/apache/myfaces/view/facelets/impl/
main/java/org/apache/myfaces/view/facelets/tag/jsf/
main/java/org/apache/myfaces/view/facelets/tag/jstl...
Author: lu4242
Date: Sun Nov 10 00:12:40 2013
New Revision: 1540431
URL: http://svn.apache.org/r1540431
Log:
MYFACES-3811 Fix c:forEach behavior once for all
Added:
myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/tag/jstl/core/IterationState.java (with props)
myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/tag/jstl/core/LegacyForEachHandler.java
- copied, changed from r1539924, myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/tag/jstl/core/ForEachHandler.java
myfaces/core/trunk/impl/src/test/java/org/apache/myfaces/view/facelets/pss/acid/managed/ForEachBean.java (with props)
myfaces/core/trunk/impl/src/test/resources/org/apache/myfaces/view/facelets/pss/acid/forEach1.xhtml
- copied, changed from r1539924, myfaces/core/trunk/impl/src/test/resources/org/apache/myfaces/view/facelets/pss/acid/componentBinding1.xhtml
Modified:
myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/FaceletCompositionContext.java
myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/impl/FaceletCompositionContextImpl.java
myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/impl/SectionUniqueIdCounter.java
myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/tag/jsf/ComponentSupport.java
myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/tag/jstl/core/ForEachHandler.java
myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/tag/jstl/core/LegacyJstlCoreLibrary.java
myfaces/core/trunk/impl/src/test/java/org/apache/myfaces/mc/test/core/AbstractMyFacesTestCase.java
myfaces/core/trunk/impl/src/test/java/org/apache/myfaces/view/facelets/pss/acid/AcidMyFacesRequestTestCase.java
Modified: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/FaceletCompositionContext.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/FaceletCompositionContext.java?rev=1540431&r1=1540430&r2=1540431&view=diff
==============================================================================
--- myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/FaceletCompositionContext.java (original)
+++ myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/FaceletCompositionContext.java Sun Nov 10 00:12:40 2013
@@ -451,6 +451,27 @@ abstract public class FaceletComposition
}
/**
+ * Start a new unique id section, which means a new counter is used to
+ * generate unique ids to components, but appending a base to the
+ * new counter.
+ *
+ * @since 2.2.0
+ * @return
+ */
+ public String startComponentUniqueIdSection(String base)
+ {
+ return null;
+ }
+
+ /**
+ * @since 2.2.0
+ * @param base
+ */
+ public void endComponentUniqueIdSection(String base)
+ {
+ }
+
+ /**
* Generate a unique id that will be used later to derive a unique id per tag
* by FaceletContext.generateUniqueId(). This generator ensures uniqueness per
* view but FaceletContext.generateUniqueId() ensures uniqueness per view and
Modified: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/impl/FaceletCompositionContextImpl.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/impl/FaceletCompositionContextImpl.java?rev=1540431&r1=1540430&r2=1540431&view=diff
==============================================================================
--- myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/impl/FaceletCompositionContextImpl.java (original)
+++ myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/impl/FaceletCompositionContextImpl.java Sun Nov 10 00:12:40 2013
@@ -1015,6 +1015,13 @@ public class FaceletCompositionContextIm
_sectionUniqueComponentIdCounter.startUniqueIdSection();
return _sectionUniqueIdCounter.startUniqueIdSection();
}
+
+ public String startComponentUniqueIdSection(String base)
+ {
+ _level++;
+ _sectionUniqueComponentIdCounter.startUniqueIdSection(base);
+ return _sectionUniqueIdCounter.startUniqueIdSection(base);
+ }
@Override
public void incrementUniqueId()
@@ -1053,6 +1060,13 @@ public class FaceletCompositionContextIm
_sectionUniqueComponentIdCounter.endUniqueIdSection();
}
+ public void endComponentUniqueIdSection(String base)
+ {
+ _level--;
+ _sectionUniqueIdCounter.endUniqueIdSection(base);
+ _sectionUniqueComponentIdCounter.endUniqueIdSection(base);
+ }
+
@Override
public void startMetadataSection()
{
Modified: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/impl/SectionUniqueIdCounter.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/impl/SectionUniqueIdCounter.java?rev=1540431&r1=1540430&r2=1540431&view=diff
==============================================================================
--- myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/impl/SectionUniqueIdCounter.java (original)
+++ myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/impl/SectionUniqueIdCounter.java Sun Nov 10 00:12:40 2013
@@ -202,6 +202,19 @@ public class SectionUniqueIdCounter
}
}
+ public void endUniqueIdSection(String base)
+ {
+ if (_activeSection <= 0)
+ {
+ return;
+ }
+ else
+ {
+ _counterStack.remove(_activeSection);
+ _activeSection--;
+ }
+ }
+
private static class Section
{
Modified: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/tag/jsf/ComponentSupport.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/tag/jsf/ComponentSupport.java?rev=1540431&r1=1540430&r2=1540431&view=diff
==============================================================================
--- myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/tag/jsf/ComponentSupport.java (original)
+++ myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/tag/jsf/ComponentSupport.java Sun Nov 10 00:12:40 2013
@@ -785,6 +785,18 @@ public final class ComponentSupport
}
}
+ public static FaceletState getFaceletState(FaceletContext ctx, UIComponent parent, boolean create)
+ {
+ UIViewRoot root = getViewRoot(ctx, parent);
+ FaceletState map = (FaceletState) root.getAttributes().get(FACELET_STATE_INSTANCE);
+ if (map == null && create)
+ {
+ map = new FaceletState();
+ root.getAttributes().put(FACELET_STATE_INSTANCE, map);
+ }
+ return map;
+ }
+
public static void setCachedFacesContext(UIComponent component,
FacesContext context)
{
Modified: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/tag/jstl/core/ForEachHandler.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/tag/jstl/core/ForEachHandler.java?rev=1540431&r1=1540430&r2=1540431&view=diff
==============================================================================
--- myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/tag/jstl/core/ForEachHandler.java (original)
+++ myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/tag/jstl/core/ForEachHandler.java Sun Nov 10 00:12:40 2013
@@ -19,6 +19,7 @@
package org.apache.myfaces.view.facelets.tag.jstl.core;
import java.io.IOException;
+import java.io.Serializable;
import java.lang.reflect.Array;
import java.util.Collection;
import java.util.Iterator;
@@ -28,7 +29,9 @@ import java.util.Map;
import javax.el.ELException;
import javax.el.ValueExpression;
import javax.faces.FacesException;
+import javax.faces.application.StateManager;
import javax.faces.component.UIComponent;
+import javax.faces.event.PhaseId;
import javax.faces.view.facelets.FaceletContext;
import javax.faces.view.facelets.FaceletException;
import javax.faces.view.facelets.TagAttribute;
@@ -43,6 +46,7 @@ import org.apache.myfaces.view.facelets.
import org.apache.myfaces.view.facelets.PageContext;
import org.apache.myfaces.view.facelets.tag.ComponentContainerHandler;
import org.apache.myfaces.view.facelets.tag.jsf.ComponentSupport;
+import org.apache.myfaces.view.facelets.tag.jsf.FaceletState;
/**
* The basic iteration tag, accepting many different
@@ -168,15 +172,7 @@ public final class ForEachHandler extend
public void apply(FaceletContext ctx, UIComponent parent) throws IOException, FacesException, FaceletException,
ELException
{
-
- int s = this.getBegin(ctx);
int e = this.getEnd(ctx);
- int m = this.getStep(ctx);
- Integer sO = this.begin != null ? Integer.valueOf(s) : null;
- Integer eO = this.end != null ? Integer.valueOf(e) : null;
- Integer mO = this.step != null ? Integer.valueOf(m) : null;
-
- boolean t = this.getTransient(ctx);
Object src = null;
ValueExpression srcVE = null;
if (this.items != null)
@@ -194,132 +190,446 @@ public final class ForEachHandler extend
src = b;
}
FaceletCompositionContext fcc = FaceletCompositionContext.getCurrentInstance(ctx);
+ // Just increment one number to ensure the prefix doesn't conflict later if two
+ // c:forEach are close between each other. Note c:forEach is different from
+ // c:if tag and doesn't require a section because c:forEach requires to provide
+ // multiple sections starting with a specified "base" related to the element
+ // position and value in the collection.
+ fcc.incrementUniqueComponentId();
+ String uniqueId = fcc.generateUniqueId();
if (src != null)
{
- fcc.startComponentUniqueIdSection();
AbstractFaceletContext actx = (AbstractFaceletContext) ctx;
PageContext pctx = actx.getPageContext();
- Iterator<?> itr = this.toIterator(src);
- if (itr != null)
+ // c:forEach is special because it requires FaceletState even if no pss is used.
+ FaceletState restoredFaceletState = ComponentSupport.getFaceletState(ctx, parent, false);
+ IterationState restoredSavedOption = (restoredFaceletState == null) ? null :
+ (IterationState) restoredFaceletState.getState(uniqueId);
+
+ if (restoredSavedOption != null)
+ {
+ if (!PhaseId.RESTORE_VIEW.equals(ctx.getFacesContext().getCurrentPhaseId()))
+ {
+ // Refresh, evaluate and synchronize state
+ applyOnRefresh(ctx, fcc, pctx, parent, uniqueId, src, srcVE, restoredSavedOption);
+ }
+ else
+ {
+ // restore view, don't record iteration, use the saved value
+ applyOnRestore(ctx, fcc, pctx, parent, uniqueId, src, srcVE, restoredSavedOption);
+ }
+ }
+ else
{
- int i = 0;
+ // First time
+ applyFirstTime(ctx, fcc, pctx, parent, uniqueId, src, srcVE);
+ }
+ }
- // move to start
- while (i < s && itr.hasNext())
+ if (fcc.isUsingPSSOnThisView() && fcc.isRefreshTransientBuildOnPSS() && !fcc.isRefreshingTransientBuild())
+ {
+ //Mark the parent component to be saved and restored fully.
+ ComponentSupport.markComponentToRestoreFully(ctx.getFacesContext(), parent);
+ }
+ if (fcc.isDynamicComponentSection())
+ {
+ ComponentSupport.markComponentToRefreshDynamically(ctx.getFacesContext(), parent);
+ }
+ }
+
+ private void setVar(FaceletContext ctx, PageContext pctx, boolean t, Object src,
+ ValueExpression srcVE, Object value, String v, int i)
+ {
+ // set the var
+ if (v != null)
+ {
+ if (t || srcVE == null)
+ {
+ if (value == null)
{
- itr.next();
- i++;
+ pctx.getAttributes().put(v, null);
}
+ else
+ {
+ pctx.getAttributes().put(v,
+ ctx.getExpressionFactory().createValueExpression(
+ value, Object.class));
+ }
+ }
+ else
+ {
+ ValueExpression ve = this.getVarExpr(srcVE, src, value, i);
+ pctx.getAttributes().put(v, ve);
+ }
+ }
+ }
+
+ private void applyFirstTime(FaceletContext ctx, FaceletCompositionContext fcc, PageContext pctx,
+ UIComponent parent, String uniqueId, Object src, ValueExpression srcVE) throws IOException
+ {
+ int s = this.getBegin(ctx);
+ int e = this.getEnd(ctx);
+ int m = this.getStep(ctx);
+ Integer sO = this.begin != null ? Integer.valueOf(s) : null;
+ Integer eO = this.end != null ? Integer.valueOf(e) : null;
+ Integer mO = this.step != null ? Integer.valueOf(m) : null;
+ boolean t = this.getTransient(ctx);
+ IterationState iterationState = new IterationState();
+
+ boolean serializableValues = true;
+ Iterator<?> itr = this.toIterator(src);
+ if (itr != null)
+ {
+ int i = 0;
+
+ // move to start
+ while (i < s && itr.hasNext())
+ {
+ itr.next();
+ i++;
+ }
- String v = this.getVarName(ctx);
- String vs = this.getVarStatusName(ctx);
- ValueExpression ve = null;
- ValueExpression vO = this.capture(v, pctx);
- ValueExpression vsO = this.capture(vs, pctx);
- int mi = 0;
- Object value = null;
- try
+ String v = this.getVarName(ctx);
+ String vs = this.getVarStatusName(ctx);
+ ValueExpression vO = this.capture(v, pctx);
+ ValueExpression vsO = this.capture(vs, pctx);
+ int mi = 0;
+ Object value = null;
+ try
+ {
+ boolean first = true;
+ while (i <= e && itr.hasNext())
{
- boolean first = true;
- while (i <= e && itr.hasNext())
+ value = itr.next();
+
+ // first time, use the counter
+ Integer count = iterationState.getCounter();
+ String base = count.toString();
+ iterationState.setCounter(count+1);
+
+ if (value instanceof Serializable)
+ {
+ iterationState.getValueList().add(
+ new Object[]{base, value, i});
+ }
+ else
{
- value = itr.next();
+ serializableValues = false;
+ }
+
+ fcc.startComponentUniqueIdSection(base);
- // set the var
- if (v != null)
+ setVar(ctx, pctx, t, src, srcVE, value, v, i);
+ boolean last = !itr.hasNext();
+ // set the varStatus
+ if (vs != null)
+ {
+ IterationStatus itrS = new IterationStatus(first, last, i, sO, eO, mO, value);
+ if (t || srcVE == null)
{
- if (t || srcVE == null)
+ if (srcVE == null)
{
- if (value == null)
- {
- pctx.getAttributes().put(v, null);
- }
- else
- {
- pctx.getAttributes().put(v,
- ctx.getExpressionFactory().createValueExpression(
- value, Object.class));
- }
+ pctx.getAttributes().put(vs, null);
}
else
{
- ve = this.getVarExpr(srcVE, src, value, i);
- pctx.getAttributes().put(v, ve);
+ pctx.getAttributes().put(vs,
+ ctx.getExpressionFactory().createValueExpression(
+ itrS, Object.class));
}
}
-
- // set the varStatus
- if (vs != null)
+ else
{
- IterationStatus itrS = new IterationStatus(first, !itr.hasNext(), i, sO, eO, mO, value);
- if (t || srcVE == null)
- {
- if (srcVE == null)
- {
- pctx.getAttributes().put(vs, null);
- }
- else
- {
- pctx.getAttributes().put(vs,
- ctx.getExpressionFactory().createValueExpression(
- itrS, Object.class));
- }
- }
- else
- {
- ve = new IterationStatusExpression(itrS);
- pctx.getAttributes().put(vs, ve);
- }
+ ValueExpression ve = new IterationStatusExpression(itrS);
+ pctx.getAttributes().put(vs, ve);
}
+ }
- // execute body
- this.nextHandler.apply(ctx, parent);
+ // execute body
+ this.nextHandler.apply(ctx, parent);
- // increment steps
- mi = 1;
- while (mi < m && itr.hasNext())
- {
- itr.next();
- mi++;
- i++;
- }
+ fcc.endComponentUniqueIdSection(base);
+
+ // increment steps
+ mi = 1;
+ while (mi < m && itr.hasNext())
+ {
+ itr.next();
+ mi++;
i++;
+ }
+ i++;
+
+ first = false;
+ }
+ }
+ finally
+ {
+ removeVarAndVarStatus(pctx, v, vO, vs, vsO);
+ }
+ }
+ if (serializableValues)
+ {
+ FaceletState faceletState = ComponentSupport.getFaceletState(ctx, parent, true);
+ faceletState.putState(uniqueId, iterationState);
+ }
+ }
+
+ private void applyOnRestore(FaceletContext ctx, FaceletCompositionContext fcc, PageContext pctx,
+ UIComponent parent, String uniqueId, Object src, ValueExpression srcVE, IterationState restoredSavedOption)
+ throws IOException
+ {
+ int s = this.getBegin(ctx);
+ int e = this.getEnd(ctx);
+ int m = this.getStep(ctx);
+ Integer sO = this.begin != null ? Integer.valueOf(s) : null;
+ Integer eO = this.end != null ? Integer.valueOf(e) : null;
+ Integer mO = this.step != null ? Integer.valueOf(m) : null;
+ boolean t = this.getTransient(ctx);
- first = false;
+ // restore view, don't record iteration, use the saved value
+ String v = this.getVarName(ctx);
+ String vs = this.getVarStatusName(ctx);
+ ValueExpression vO = this.capture(v, pctx);
+ ValueExpression vsO = this.capture(vs, pctx);
+ Object value = null;
+ try
+ {
+ int size = restoredSavedOption.getValueList().size();
+ for (int si = 0; si < size; si++)
+ {
+ Object[] stateValue = restoredSavedOption.getValueList().get(si);
+ value = stateValue[1];
+ String base = (String) stateValue[0];
+
+ fcc.startComponentUniqueIdSection(base);
+
+ setVar(ctx, pctx, t, src, srcVE, value, v, (Integer) stateValue[2]);
+
+ boolean first = (si == 0);
+ boolean last = (si == size-1);
+ int i = (Integer)stateValue[2];
+ // set the varStatus
+ if (vs != null)
+ {
+ IterationStatus itrS = new IterationStatus(first, last, i, sO, eO, mO, value);
+ if (t || srcVE == null)
+ {
+ if (srcVE == null)
+ {
+ pctx.getAttributes().put(vs, null);
+ }
+ else
+ {
+ pctx.getAttributes().put(vs,
+ ctx.getExpressionFactory().createValueExpression(
+ itrS, Object.class));
+ }
+ }
+ else
+ {
+ ValueExpression ve = new IterationStatusExpression(itrS);
+ pctx.getAttributes().put(vs, ve);
}
}
- finally
+
+ // execute body
+ this.nextHandler.apply(ctx, parent);
+
+ fcc.endComponentUniqueIdSection(base);
+ }
+ }
+ finally
+ {
+ removeVarAndVarStatus(pctx, v, vO, vs, vsO);
+ }
+ }
+
+ private void applyOnRefresh(FaceletContext ctx, FaceletCompositionContext fcc, PageContext pctx,
+ UIComponent parent, String uniqueId, Object src, ValueExpression srcVE, IterationState restoredSavedOption)
+ throws IOException
+ {
+ int s = this.getBegin(ctx);
+ int e = this.getEnd(ctx);
+ int m = this.getStep(ctx);
+ Integer sO = this.begin != null ? Integer.valueOf(s) : null;
+ Integer eO = this.end != null ? Integer.valueOf(e) : null;
+ Integer mO = this.step != null ? Integer.valueOf(m) : null;
+ boolean t = this.getTransient(ctx);
+
+ // Refresh, evaluate and synchronize state
+ Iterator<?> itr = this.toIterator(src);
+ IterationState iterationState = new IterationState();
+ iterationState.setCounter(restoredSavedOption.getCounter());
+ if (itr != null)
+ {
+ int i = 0;
+
+ // move to start
+ while (i < s && itr.hasNext())
+ {
+ itr.next();
+ i++;
+ }
+
+ String v = this.getVarName(ctx);
+ String vs = this.getVarStatusName(ctx);
+ ValueExpression vO = this.capture(v, pctx);
+ ValueExpression vsO = this.capture(vs, pctx);
+ int mi = 0;
+ Object value = null;
+ int stateIndex = 0;
+ try
+ {
+ boolean first = true;
+ while (i <= e && itr.hasNext())
{
- //Remove them from PageContext
- if (v != null)
+ value = itr.next();
+ Object[] stateValue = null; /*restoredSavedOption.getValueList().get(stateIndex);*/
+ String base = null;
+ boolean found = false;
+
+ // The important thing here is use the same base for the generated component ids
+ // for each element in the iteration that was used on the restore. To do that
+ //
+ int stateIndexCheck = stateIndex;
+ for (; stateIndexCheck < restoredSavedOption.getValueList().size(); stateIndexCheck++)
+ {
+ stateValue = restoredSavedOption.getValueList().get(stateIndexCheck);
+ if (value.equals(stateValue[1]))
+ {
+ found = true;
+ break;
+ }
+ }
+ if (found)
{
- pctx.getAttributes().put(v, vO);
+ stateIndex = stateIndexCheck;
+ base = (String) stateValue[0];
+ stateIndex++;
}
else
{
- pctx.getAttributes().remove(v);
+ // No state, added item, create new count
+ Integer count = iterationState.getCounter();
+ base = count.toString();
+ iterationState.setCounter(count+1);
+ stateValue = null;
+ }
+
+ if (value instanceof Serializable)
+ {
+ iterationState.getValueList().add(
+ new Object[]{base, value, i});
}
+
+ fcc.startComponentUniqueIdSection(base);
+
+ setVar(ctx, pctx, t, src, srcVE, value, v, i);
+
+ boolean last = !itr.hasNext();
+ // set the varStatus
if (vs != null)
{
- pctx.getAttributes().put(vs, vsO);
+ IterationStatus itrS = new IterationStatus(first, last, i, sO, eO, mO, value);
+ if (t || srcVE == null)
+ {
+ if (srcVE == null)
+ {
+ pctx.getAttributes().put(vs, null);
+ }
+ else
+ {
+ pctx.getAttributes().put(vs,
+ ctx.getExpressionFactory().createValueExpression(
+ itrS, Object.class));
+ }
+ }
+ else
+ {
+ ValueExpression ve = new IterationStatusExpression(itrS);
+ pctx.getAttributes().put(vs, ve);
+ }
}
- else
+ //setVarStatus(ctx, pctx, t, sO, eO, mO, srcVE, value, vs, first, !itr.hasNext(), i);
+
+ // execute body
+ boolean markInitialState = (stateValue == null);// !restoredSavedOption.equals(i)
+ boolean oldMarkInitialState = false;
+ Boolean isBuildingInitialState = null;
+ try
+ {
+ if (markInitialState && fcc.isUsingPSSOnThisView())
+ {
+ //set markInitialState flag
+ oldMarkInitialState = fcc.isMarkInitialState();
+ fcc.setMarkInitialState(true);
+ isBuildingInitialState = (Boolean) ctx.getFacesContext().getAttributes().put(
+ StateManager.IS_BUILDING_INITIAL_STATE, Boolean.TRUE);
+ }
+ this.nextHandler.apply(ctx, parent);
+ }
+ finally
+ {
+ if (markInitialState && fcc.isUsingPSSOnThisView())
+ {
+ //unset markInitialState flag
+ if (isBuildingInitialState == null)
+ {
+ ctx.getFacesContext().getAttributes().remove(
+ StateManager.IS_BUILDING_INITIAL_STATE);
+ }
+ else
+ {
+ ctx.getFacesContext().getAttributes().put(
+ StateManager.IS_BUILDING_INITIAL_STATE, isBuildingInitialState);
+ }
+ fcc.setMarkInitialState(oldMarkInitialState);
+ }
+ }
+
+ fcc.endComponentUniqueIdSection(base);
+
+ // increment steps
+ mi = 1;
+ while (mi < m && itr.hasNext())
{
- pctx.getAttributes().remove(vs);
+ itr.next();
+ mi++;
+ i++;
}
+ i++;
+
+ first = false;
}
}
- fcc.endComponentUniqueIdSection();
+ finally
+ {
+ removeVarAndVarStatus(pctx, v, vO, vs, vsO);
+ }
}
-
- if (fcc.isUsingPSSOnThisView() && fcc.isRefreshTransientBuildOnPSS() && !fcc.isRefreshingTransientBuild())
+ FaceletState faceletState = ComponentSupport.getFaceletState(ctx, parent, true);
+ faceletState.putState(uniqueId, iterationState);
+ }
+
+ private void removeVarAndVarStatus(PageContext pctx, String v, ValueExpression vO, String vs, ValueExpression vsO)
+ {
+ //Remove them from PageContext
+ if (v != null)
{
- //Mark the parent component to be saved and restored fully.
- ComponentSupport.markComponentToRestoreFully(ctx.getFacesContext(), parent);
+ pctx.getAttributes().put(v, vO);
}
- if (fcc.isDynamicComponentSection())
+ else
{
- ComponentSupport.markComponentToRefreshDynamically(ctx.getFacesContext(), parent);
+ pctx.getAttributes().remove(v);
+ }
+ if (vs != null)
+ {
+ pctx.getAttributes().put(vs, vsO);
+ }
+ else
+ {
+ pctx.getAttributes().remove(vs);
}
}
@@ -372,7 +682,8 @@ public final class ForEachHandler extend
{
if (src instanceof List || src.getClass().isArray())
{
- return new IndexedValueExpression(ve, i);
+ //return new IndexedValueExpression(ve, i);
+ return new IteratedValueExpression(ve, value);
}
else if (src instanceof Map && value instanceof Map.Entry)
{
Added: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/tag/jstl/core/IterationState.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/tag/jstl/core/IterationState.java?rev=1540431&view=auto
==============================================================================
--- myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/tag/jstl/core/IterationState.java (added)
+++ myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/tag/jstl/core/IterationState.java Sun Nov 10 00:12:40 2013
@@ -0,0 +1,109 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * 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
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.myfaces.view.facelets.tag.jstl.core;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * Holds the iteration state generated by c:forEach tag.
+ */
+public class IterationState implements Serializable
+{
+ /**
+ * This counter is used to generate an unique base per element
+ * in the collection that will be used later in the id
+ * generation algorithm.
+ */
+ private int counter;
+
+ private List<Object[]> valueList;
+
+ public IterationState()
+ {
+ this.valueList = new ArrayList<Object[]>();
+ }
+
+ /**
+ * @return the valueList
+ */
+ public List<Object[]> getValueList()
+ {
+ return valueList;
+ }
+
+ /**
+ * @param valueList the valueList to set
+ */
+ public void setValueList(List<Object[]> valueList)
+ {
+ this.valueList = valueList;
+ }
+
+ /**
+ * @return the counter
+ */
+ public int getCounter()
+ {
+ return counter;
+ }
+
+ /**
+ * @param counter the counter to set
+ */
+ public void setCounter(int counter)
+ {
+ this.counter = counter;
+ }
+
+ public Iterator getIterator()
+ {
+ return new IteratorWrapper(valueList.iterator());
+ }
+
+ private static class IteratorWrapper implements Iterator
+ {
+ private Iterator<Object[]> delegate;
+
+ public IteratorWrapper(Iterator<Object[]> delegate)
+ {
+ this.delegate = delegate;
+ }
+
+ @Override
+ public boolean hasNext()
+ {
+ return delegate.hasNext();
+ }
+
+ @Override
+ public Object next()
+ {
+ return delegate.next()[1];
+ }
+
+ @Override
+ public void remove()
+ {
+ delegate.remove();
+ }
+ }
+}
Propchange: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/tag/jstl/core/IterationState.java
------------------------------------------------------------------------------
svn:eol-style = native
Copied: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/tag/jstl/core/LegacyForEachHandler.java (from r1539924, myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/tag/jstl/core/ForEachHandler.java)
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/tag/jstl/core/LegacyForEachHandler.java?p2=myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/tag/jstl/core/LegacyForEachHandler.java&p1=myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/tag/jstl/core/ForEachHandler.java&r1=1539924&r2=1540431&rev=1540431&view=diff
==============================================================================
--- myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/tag/jstl/core/ForEachHandler.java (original)
+++ myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/tag/jstl/core/LegacyForEachHandler.java Sun Nov 10 00:12:40 2013
@@ -36,8 +36,6 @@ import javax.faces.view.facelets.TagAttr
import javax.faces.view.facelets.TagConfig;
import javax.faces.view.facelets.TagHandler;
-import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFFaceletAttribute;
-import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFFaceletTag;
import org.apache.myfaces.view.facelets.AbstractFaceletContext;
import org.apache.myfaces.view.facelets.FaceletCompositionContext;
import org.apache.myfaces.view.facelets.PageContext;
@@ -49,12 +47,17 @@ import org.apache.myfaces.view.facelets.
* collection types and supporting subsetting and other
* functionality
*
+ * NOTE: This implementation is provided for compatibility reasons and
+ * it is considered faulty. It is enabled using
+ * org.apache.myfaces.STRICT_JSF_2_FACELETS_COMPATIBILITY web config param.
+ * Don't use it if EL expression caching is enabled.
+ *
* @author Jacob Hookom
* @author Andrew Robinson
* @version $Id$
*/
-@JSFFaceletTag(name="c:forEach")
-public final class ForEachHandler extends TagHandler implements ComponentContainerHandler
+//@JSFFaceletTag(name="c:forEach")
+public final class LegacyForEachHandler extends TagHandler implements ComponentContainerHandler
{
private static class ArrayIterator implements Iterator<Object>
@@ -98,7 +101,7 @@ public final class ForEachHandler extend
* Iteration begins with index set at the value
* specified.
*/
- @JSFFaceletAttribute(className="int")
+ //@JSFFaceletAttribute(className="int")
private final TagAttribute begin;
/**
@@ -109,20 +112,20 @@ public final class ForEachHandler extend
* Iteration ends when index reaches the value
* specified.
*/
- @JSFFaceletAttribute(className="int")
+ //@JSFFaceletAttribute(className="int")
private final TagAttribute end;
/**
* Collection of items to iterate over.
*/
- @JSFFaceletAttribute(className="javax.el.ValueExpression")
+ //@JSFFaceletAttribute(className="javax.el.ValueExpression")
private final TagAttribute items;
/**
* Iteration will only process every step items of
* the collection, starting with the first one.
*/
- @JSFFaceletAttribute(className="int")
+ //@JSFFaceletAttribute(className="int")
private final TagAttribute step;
private final TagAttribute tranzient;
@@ -133,20 +136,20 @@ public final class ForEachHandler extend
* variable has nested visibility. Its type depends
* on the object of the underlying collection.
*/
- @JSFFaceletAttribute(className="java.lang.String")
+ //@JSFFaceletAttribute(className="java.lang.String")
private final TagAttribute var;
/**
* Name of the exported scoped variable for the
* status of the iteration.
*/
- @JSFFaceletAttribute(className="java.lang.String")
+ //@JSFFaceletAttribute(className="java.lang.String")
private final TagAttribute varStatus;
/**
* @param config
*/
- public ForEachHandler(TagConfig config)
+ public LegacyForEachHandler(TagConfig config)
{
super(config);
this.items = this.getAttribute("items");
Modified: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/tag/jstl/core/LegacyJstlCoreLibrary.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/tag/jstl/core/LegacyJstlCoreLibrary.java?rev=1540431&r1=1540430&r2=1540431&view=diff
==============================================================================
--- myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/tag/jstl/core/LegacyJstlCoreLibrary.java (original)
+++ myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/tag/jstl/core/LegacyJstlCoreLibrary.java Sun Nov 10 00:12:40 2013
@@ -49,7 +49,7 @@ public final class LegacyJstlCoreLibrary
this.addTagHandler("if", IfHandler.class);
- this.addTagHandler("forEach", ForEachHandler.class);
+ this.addTagHandler("forEach", LegacyForEachHandler.class);
this.addTagHandler("catch", CatchHandler.class);
@@ -68,7 +68,7 @@ public final class LegacyJstlCoreLibrary
this.addTagHandler("if", IfHandler.class);
- this.addTagHandler("forEach", ForEachHandler.class);
+ this.addTagHandler("forEach", LegacyForEachHandler.class);
this.addTagHandler("catch", CatchHandler.class);
Modified: myfaces/core/trunk/impl/src/test/java/org/apache/myfaces/mc/test/core/AbstractMyFacesTestCase.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/test/java/org/apache/myfaces/mc/test/core/AbstractMyFacesTestCase.java?rev=1540431&r1=1540430&r2=1540431&view=diff
==============================================================================
--- myfaces/core/trunk/impl/src/test/java/org/apache/myfaces/mc/test/core/AbstractMyFacesTestCase.java (original)
+++ myfaces/core/trunk/impl/src/test/java/org/apache/myfaces/mc/test/core/AbstractMyFacesTestCase.java Sun Nov 10 00:12:40 2013
@@ -75,8 +75,6 @@ import org.apache.myfaces.test.el.MockEx
import org.apache.myfaces.test.mock.MockPrintWriter;
import org.apache.myfaces.test.mock.MockServletConfig;
import org.apache.myfaces.test.mock.MockServletContext;
-import org.apache.myfaces.util.DebugUtils;
-import org.apache.myfaces.view.facelets.FaceletViewDeclarationLanguage;
import org.apache.myfaces.webapp.AbstractFacesInitializer;
import org.apache.myfaces.webapp.StartupServletContextListener;
import org.junit.After;
Modified: myfaces/core/trunk/impl/src/test/java/org/apache/myfaces/view/facelets/pss/acid/AcidMyFacesRequestTestCase.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/test/java/org/apache/myfaces/view/facelets/pss/acid/AcidMyFacesRequestTestCase.java?rev=1540431&r1=1540430&r2=1540431&view=diff
==============================================================================
--- myfaces/core/trunk/impl/src/test/java/org/apache/myfaces/view/facelets/pss/acid/AcidMyFacesRequestTestCase.java (original)
+++ myfaces/core/trunk/impl/src/test/java/org/apache/myfaces/view/facelets/pss/acid/AcidMyFacesRequestTestCase.java Sun Nov 10 00:12:40 2013
@@ -23,6 +23,7 @@ import javax.faces.application.StateMana
import javax.faces.component.UICommand;
import javax.faces.component.UIComponent;
import javax.faces.component.UIInput;
+import javax.faces.component.UIOutput;
import javax.faces.component.UIPanel;
import javax.faces.component.html.HtmlDataTable;
@@ -31,6 +32,7 @@ import org.apache.myfaces.shared.config.
import org.apache.myfaces.test.mock.MockPrintWriter;
import org.apache.myfaces.view.facelets.pss.acid.managed.CheckActionEventBean;
import org.apache.myfaces.view.facelets.pss.acid.managed.CustomSessionBean;
+import org.apache.myfaces.view.facelets.pss.acid.managed.ForEachBean;
import org.apache.myfaces.view.facelets.pss.acid.managed.ResourceDependencyBean;
import org.junit.Assert;
import org.junit.Test;
@@ -1741,4 +1743,99 @@ public class AcidMyFacesRequestTestCase
tearDownRequest();
}
+ @Test
+ public void testCForEach1() throws Exception
+ {
+ setupRequest("/forEach1.xhtml");
+ processLifecycleExecute();
+
+ executeBeforeRender(facesContext);
+ executeBuildViewCycle(facesContext);
+
+ UIOutput itemA_1 = (UIOutput) facesContext.getViewRoot().findComponent("mainForm:item_a");
+ Assert.assertNotNull(itemA_1);
+ Assert.assertEquals("a", itemA_1.getValue());
+ itemA_1.getAttributes().put("prop", "a");
+ UIOutput itemB_1 = (UIOutput) facesContext.getViewRoot().findComponent("mainForm:item_b");
+ Assert.assertNotNull(itemB_1);
+ Assert.assertEquals("b", itemB_1.getValue());
+ itemB_1.getAttributes().put("prop", "b");
+ UIOutput itemC_1 = (UIOutput) facesContext.getViewRoot().findComponent("mainForm:item_c");
+ Assert.assertNotNull(itemC_1);
+ Assert.assertEquals("c", itemC_1.getValue());
+ itemC_1.getAttributes().put("prop", "c");
+
+ executeViewHandlerRender(facesContext);
+
+ UICommand button = (UICommand) facesContext.getViewRoot().findComponent("mainForm:postback");
+ submit(button);
+
+ processLifecycleExecute();
+
+ UIOutput itemA_2 = (UIOutput) facesContext.getViewRoot().findComponent("mainForm:item_a");
+ Assert.assertNotNull(itemA_2);
+ Assert.assertEquals("a", itemA_2.getValue());
+ Assert.assertEquals("a", itemA_2.getAttributes().get("prop"));
+ UIOutput itemB_2 = (UIOutput) facesContext.getViewRoot().findComponent("mainForm:item_b");
+ Assert.assertNotNull(itemB_2);
+ Assert.assertEquals("b", itemB_2.getValue());
+ Assert.assertEquals("b", itemB_2.getAttributes().get("prop"));
+ UIOutput itemC_2 = (UIOutput) facesContext.getViewRoot().findComponent("mainForm:item_c");
+ Assert.assertNotNull(itemC_2);
+ Assert.assertEquals("c", itemC_2.getValue());
+ Assert.assertEquals("c", itemC_2.getAttributes().get("prop"));
+
+ ForEachBean bean = facesContext.getApplication().evaluateExpressionGet(facesContext, "#{forEachBean}",
+ ForEachBean.class);
+ bean.addFirst();
+ bean.addMiddle();
+ bean.removeLast();
+
+ executeBeforeRender(facesContext);
+ executeBuildViewCycle(facesContext);
+
+ UIOutput itemA_3 = (UIOutput) facesContext.getViewRoot().findComponent("mainForm:item_a");
+ Assert.assertNotNull(itemA_3);
+ Assert.assertEquals("a", itemA_3.getValue());
+ Assert.assertEquals("a", itemA_3.getAttributes().get("prop"));
+ UIOutput itemB_3 = (UIOutput) facesContext.getViewRoot().findComponent("mainForm:item_b");
+ Assert.assertNotNull(itemB_3);
+ Assert.assertEquals("b", itemB_3.getValue());
+ Assert.assertEquals("b", itemB_3.getAttributes().get("prop"));
+ UIOutput itemC_3 = (UIOutput) facesContext.getViewRoot().findComponent("mainForm:item_c");
+ Assert.assertNull(itemC_3);
+ UIOutput itemZ_3 = (UIOutput) facesContext.getViewRoot().findComponent("mainForm:item_z");
+ Assert.assertNotNull(itemZ_3);
+ Assert.assertEquals("z", itemZ_3.getValue());
+ Assert.assertNull(itemZ_3.getAttributes().get("prop"));
+ UIOutput itemX_3 = (UIOutput) facesContext.getViewRoot().findComponent("mainForm:item_x");
+ Assert.assertNotNull(itemX_3);
+ Assert.assertEquals("x", itemX_3.getValue());
+ Assert.assertNull(itemX_3.getAttributes().get("prop"));
+
+ executeViewHandlerRender(facesContext);
+
+ UICommand button2 = (UICommand) facesContext.getViewRoot().findComponent("mainForm:postback");
+ submit(button2);
+
+ processLifecycleExecute();
+
+ UIOutput itemA_4 = (UIOutput) facesContext.getViewRoot().findComponent("mainForm:item_a");
+ Assert.assertNotNull(itemA_4);
+ Assert.assertEquals("a", itemA_4.getValue());
+ UIOutput itemB_4 = (UIOutput) facesContext.getViewRoot().findComponent("mainForm:item_b");
+ Assert.assertNotNull(itemB_4);
+ Assert.assertEquals("b", itemB_4.getValue());
+ UIOutput itemC_4 = (UIOutput) facesContext.getViewRoot().findComponent("mainForm:item_c");
+ Assert.assertNull(itemC_4);
+ UIOutput itemZ_4 = (UIOutput) facesContext.getViewRoot().findComponent("mainForm:item_z");
+ Assert.assertNotNull(itemZ_4);
+ Assert.assertEquals("z", itemZ_4.getValue());
+ UIOutput itemX_4 = (UIOutput) facesContext.getViewRoot().findComponent("mainForm:item_x");
+ Assert.assertNotNull(itemX_4);
+ Assert.assertEquals("x", itemX_4.getValue());
+
+ tearDownRequest();
+ }
+
}
Added: myfaces/core/trunk/impl/src/test/java/org/apache/myfaces/view/facelets/pss/acid/managed/ForEachBean.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/test/java/org/apache/myfaces/view/facelets/pss/acid/managed/ForEachBean.java?rev=1540431&view=auto
==============================================================================
--- myfaces/core/trunk/impl/src/test/java/org/apache/myfaces/view/facelets/pss/acid/managed/ForEachBean.java (added)
+++ myfaces/core/trunk/impl/src/test/java/org/apache/myfaces/view/facelets/pss/acid/managed/ForEachBean.java Sun Nov 10 00:12:40 2013
@@ -0,0 +1,66 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * 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
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.myfaces.view.facelets.pss.acid.managed;
+
+import java.util.ArrayList;
+import java.util.List;
+import javax.annotation.PostConstruct;
+import javax.faces.bean.ManagedBean;
+import javax.faces.bean.SessionScoped;
+
+/**
+ *
+ */
+@ManagedBean(name="forEachBean")
+@SessionScoped
+public class ForEachBean
+{
+ private List<String> items1;
+
+ public ForEachBean()
+ {
+ items1 = new ArrayList<String>();
+ items1.add("a");
+ items1.add("b");
+ items1.add("c");
+ }
+
+ /**
+ * @return the items1
+ */
+ public List<String> getItems1()
+ {
+ return items1;
+ }
+
+ public void addFirst()
+ {
+ items1.add(0, "z");
+ }
+
+ public void addMiddle()
+ {
+ items1.add(2, "x");
+ }
+
+ public void removeLast()
+ {
+ items1.remove(items1.size()-1);
+ }
+}
Propchange: myfaces/core/trunk/impl/src/test/java/org/apache/myfaces/view/facelets/pss/acid/managed/ForEachBean.java
------------------------------------------------------------------------------
svn:eol-style = native
Copied: myfaces/core/trunk/impl/src/test/resources/org/apache/myfaces/view/facelets/pss/acid/forEach1.xhtml (from r1539924, myfaces/core/trunk/impl/src/test/resources/org/apache/myfaces/view/facelets/pss/acid/componentBinding1.xhtml)
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/test/resources/org/apache/myfaces/view/facelets/pss/acid/forEach1.xhtml?p2=myfaces/core/trunk/impl/src/test/resources/org/apache/myfaces/view/facelets/pss/acid/forEach1.xhtml&p1=myfaces/core/trunk/impl/src/test/resources/org/apache/myfaces/view/facelets/pss/acid/componentBinding1.xhtml&r1=1539924&r2=1540431&rev=1540431&view=diff
==============================================================================
--- myfaces/core/trunk/impl/src/test/resources/org/apache/myfaces/view/facelets/pss/acid/componentBinding1.xhtml (original)
+++ myfaces/core/trunk/impl/src/test/resources/org/apache/myfaces/view/facelets/pss/acid/forEach1.xhtml Sun Nov 10 00:12:40 2013
@@ -15,13 +15,24 @@
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
- xmlns:ui="http://java.sun.com/jsf/facelets">
+ xmlns:ui="http://java.sun.com/jsf/facelets"
+ xmlns:c="http://java.sun.com/jsp/jstl/core">
<h:head>
</h:head>
<h:body>
- <h:panelGroup id="panel" binding="#{componentBindingBean.panel}"/>
<h:form id="mainForm">
- <h:commandButton id="postback" value="POSTBACK"/>
+ <c:if test="#{true}">
+ Start
+ </c:if>
+ <h:outputText value="Start"/>
+ <c:forEach items="#{forEachBean.items1}" var="item">
+ <p><h:outputText id="item_#{item}" value="#{item}"/></p>
+ </c:forEach>
+ <h:outputText value="End"/>
+ <c:if test="#{true}">
+ End
+ </c:if>
+ <h:commandButton id="postback" value="POSTBACK"/>
</h:form>
</h:body>
</html>