Author: dan.j.allen
Date: 2008-09-21 02:38:44 -0400 (Sun, 21 Sep 2008)
New Revision: 9070
Modified:
trunk/src/main/org/jboss/seam/navigation/Action.java
trunk/src/main/org/jboss/seam/navigation/Page.java
trunk/src/main/org/jboss/seam/navigation/Pages.java
trunk/src/main/org/jboss/seam/pages-2.1.xsd
trunk/src/test/unit/META-INF/pagesForPageActionsTest.xml
trunk/src/test/unit/org/jboss/seam/test/unit/PageActionsTest.java
Log:
JBSEAM-2469
Modified: trunk/src/main/org/jboss/seam/navigation/Action.java
===================================================================
--- trunk/src/main/org/jboss/seam/navigation/Action.java 2008-09-21 06:32:13 UTC (rev
9069)
+++ trunk/src/main/org/jboss/seam/navigation/Action.java 2008-09-21 06:38:44 UTC (rev
9070)
@@ -14,11 +14,12 @@
private MethodExpression methodExpression;
private ValueExpression valueExpression;
private String outcome;
+ private boolean onPostback = true;
- public boolean isExecutable()
+ public boolean isExecutable(boolean postback)
{
- return valueExpression==null ||
- Boolean.TRUE.equals( valueExpression.getValue() );
+ return (!postback || (postback && onPostback)) &&
+ (valueExpression == null || Boolean.TRUE.equals( valueExpression.getValue()));
}
public MethodExpression getMethodExpression()
@@ -47,4 +48,14 @@
{
this.outcome = outcome;
}
+
+ public boolean isOnPostback()
+ {
+ return onPostback;
+ }
+
+ public void setOnPostback(boolean onPostback)
+ {
+ this.onPostback = onPostback;
+ }
}
Modified: trunk/src/main/org/jboss/seam/navigation/Page.java
===================================================================
--- trunk/src/main/org/jboss/seam/navigation/Page.java 2008-09-21 06:32:13 UTC (rev 9069)
+++ trunk/src/main/org/jboss/seam/navigation/Page.java 2008-09-21 06:38:44 UTC (rev 9070)
@@ -276,7 +276,7 @@
for ( Action action: getActions() )
{
- if ( action.isExecutable() )
+ if (
action.isExecutable(facesContext.getRenderKit().getResponseStateManager().isPostback(facesContext))
)
{
String outcome = action.getOutcome();
String fromAction = outcome;
Modified: trunk/src/main/org/jboss/seam/navigation/Pages.java
===================================================================
--- trunk/src/main/org/jboss/seam/navigation/Pages.java 2008-09-21 06:32:13 UTC (rev
9069)
+++ trunk/src/main/org/jboss/seam/navigation/Pages.java 2008-09-21 06:38:44 UTC (rev
9070)
@@ -1209,12 +1209,12 @@
page.setEventType( eventElement.attributeValue("type") );
}
- Action action = parseAction(element, "action");
+ Action action = parseAction(element, "action", false);
if (action!=null) page.getActions().add(action);
List<Element> childElements = element.elements("action");
for (Element childElement: childElements)
{
- page.getActions().add( parseAction(childElement, "execute") );
+ page.getActions().add( parseAction(childElement, "execute", true) );
}
String bundle = element.attributeValue("bundle");
@@ -1239,7 +1239,7 @@
return page;
}
- private static Action parseAction(Element element, String actionAtt)
+ private static Action parseAction(Element element, String actionAtt, boolean
conditionalsAllowed)
{
Action action = new Action();
String methodExpression = element.attributeValue(actionAtt);
@@ -1252,10 +1252,15 @@
{
action.setOutcome(methodExpression);
}
- String expression = element.attributeValue("if");
- if (expression!=null)
+
+ if (conditionalsAllowed)
{
- action.setValueExpression(
Expressions.instance().createValueExpression(expression) );
+ String expression = element.attributeValue("if");
+ if (expression!=null)
+ {
+ action.setValueExpression(
Expressions.instance().createValueExpression(expression) );
+ }
+
action.setOnPostback(!"false".equals(element.attributeValue("on-postback")));
}
return action;
}
Modified: trunk/src/main/org/jboss/seam/pages-2.1.xsd
===================================================================
--- trunk/src/main/org/jboss/seam/pages-2.1.xsd 2008-09-21 06:32:13 UTC (rev 9069)
+++ trunk/src/main/org/jboss/seam/pages-2.1.xsd 2008-09-21 06:38:44 UTC (rev 9070)
@@ -179,6 +179,7 @@
</xs:element>
<xs:attributeGroup name="attlist.action">
<xs:attribute name="if"
type="pages:boolean-value-expression" />
+ <xs:attribute name="on-postback" default="true"
type="pages:tf-boolean"/>
<xs:attribute name="execute" use="required"
type="pages:method-expression" />
</xs:attributeGroup>
Modified: trunk/src/test/unit/META-INF/pagesForPageActionsTest.xml
===================================================================
--- trunk/src/test/unit/META-INF/pagesForPageActionsTest.xml 2008-09-21 06:32:13 UTC (rev
9069)
+++ trunk/src/test/unit/META-INF/pagesForPageActionsTest.xml 2008-09-21 06:38:44 UTC (rev
9070)
@@ -84,8 +84,13 @@
</rule>
</navigation>
</page>
+
+ <page view-id="/action-test06.xhtml">
+ <action execute="#{testActions.nonNullActionA}"/>
+ <action execute="#{testActions.nonNullActionB}"
on-postback="false"/>
+ </page>
- <!-- The next two page nodes (action-test05*) demonstrate the old
+ <!-- The next two page nodes (action-test99*) demonstrate the old
behavior, where successive actions could trigger navigations on
different page nodes because the viewId changes mid-run -->
<page view-id="/action-test99a.xhtml">
Modified: trunk/src/test/unit/org/jboss/seam/test/unit/PageActionsTest.java
===================================================================
--- trunk/src/test/unit/org/jboss/seam/test/unit/PageActionsTest.java 2008-09-21 06:32:13
UTC (rev 9069)
+++ trunk/src/test/unit/org/jboss/seam/test/unit/PageActionsTest.java 2008-09-21 06:38:44
UTC (rev 9070)
@@ -7,11 +7,13 @@
import org.jboss.seam.annotations.intercept.BypassInterceptors;
import org.jboss.seam.contexts.Contexts;
import org.jboss.seam.faces.FacesManager;
+import org.jboss.seam.mock.MockHttpServletRequest;
import org.jboss.seam.navigation.Pages;
import org.jboss.seam.test.unit.component.TestActions;
import org.testng.annotations.Test;
import javax.faces.context.FacesContext;
+import javax.faces.render.ResponseStateManager;
import java.util.List;
import java.util.Map;
@@ -66,6 +68,11 @@
assertActionCalls(testActions, new String[] { "nonNullActionA",
"nonNullActionB" });
}
+ /**
+ * This test verifies that an action method with a null return can still match
+ * a navigation rule and short-circuit the remaining actions. The key is that
+ * a navigation rule is matched, not what the return value is.
+ */
@Test(enabled = true)
public void testShortCircuitOnNullOutcome()
{
@@ -83,7 +90,7 @@
* will short circuit the action calls.
*/
@Test(enabled = true)
- public void testShortCircuitOnFirstNonNullOutcome()
+ public void testShortCircuitOnNonNullOutcomeToSamePage()
{
FacesContext facesContext = FacesContext.getCurrentInstance();
TestActions testActions = TestActions.instance();
@@ -112,6 +119,23 @@
"Expecting a redirect to /pageA.xhtml but redirected to " +
Contexts.getEventContext().get("lastRedirectViewId");
assert facesContext.getResponseComplete() == true : "The response should have
been marked as complete";
}
+
+ /**
+ * Verify that only those actions without on-postback="false" are executed
when the
+ * magic postback parameter (javax.faces.ViewState) is present in the request map.
+ */
+ @Test(enabled = true)
+ public void testPostbackConditionOnPageAction()
+ {
+ FacesContext facesContext = FacesContext.getCurrentInstance();
+ simulatePostback(facesContext);
+ TestActions testActions = TestActions.instance();
+
+ facesContext.getViewRoot().setViewId("/action-test06.xhtml");
+ Pages.instance().preRender(facesContext);
+ assertViewId(facesContext, "/action-test06.xhtml");
+ assertActionCalls(testActions, new String[] { "nonNullActionA" });
+ }
/**
* This test is here (and disabled) to demonstrate the old behavior. All page
@@ -168,6 +192,13 @@
Contexts.getEventContext().remove(Component.getComponentName(TestActions.class));
}
+ private void simulatePostback(FacesContext facesContext)
+ {
+ MockHttpServletRequest request = (MockHttpServletRequest)
facesContext.getExternalContext().getRequest();
+ request.getParameters().put(ResponseStateManager.VIEW_STATE_PARAM, new String[] {
"true" });
+ assert
facesContext.getRenderKit().getResponseStateManager().isPostback(facesContext) == true;
+ }
+
@Scope(ScopeType.EVENT)
@Name("org.jboss.seam.core.manager")
@BypassInterceptors