SWF-991, SWF-1413 - Add ajax-driven flow attribute and redirect-in-same-view-state flow execution attribute
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2004-2008 the original author or authors.
|
||||
* Copyright 2004-2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -30,6 +30,7 @@ import org.springframework.webflow.execution.RequestContextHolder;
|
||||
* Custom {@link StateManager} that manages the JSF component state in web flow's view scope.
|
||||
*
|
||||
* @author Jeremy Grelle
|
||||
* @author Rossen Stoyanchev
|
||||
*/
|
||||
public class FlowViewStateManager extends StateManager {
|
||||
|
||||
@@ -150,31 +151,35 @@ public class FlowViewStateManager extends StateManager {
|
||||
/**
|
||||
* <p>
|
||||
* JSF 1.2 (or higher) version of state saving.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* In JSF 2 where a partial state saving algorithm is used, this method merely delegates to the next
|
||||
* ViewStateManager. Thus partial state saving is handled by the JSF 2 runtime. However, a
|
||||
* {@link FlowViewResponseStateManager} plugged in via {@link FlowRenderKit} will ensure the state is saved in a Web
|
||||
* Flow view-scoped variable.
|
||||
* </p>
|
||||
* In JSF 2, if partial state saving is enabled this method delegates in order to obtain the serialized view state.
|
||||
* During rendering JSF calls this method to prepare the state and then calls {@link FlowViewResponseStateManager}
|
||||
* which writes it to Web Flow's view scope.
|
||||
*
|
||||
* <p>
|
||||
* Nevertheless this method always writes the serialized state to Web Flow's view scope to ensure it is up-to-date
|
||||
* for cases outside of rendering (e.g. ViewState.updateHistory()) or when the render phase doesn't call
|
||||
* {@link FlowViewResponseStateManager} such as when processing a partial request.
|
||||
*/
|
||||
public Object saveView(FacesContext context) {
|
||||
if (context.getViewRoot().isTransient()) {
|
||||
return null;
|
||||
}
|
||||
FlowSerializedView view = null;
|
||||
if ((!JsfUtils.isFlowRequest()) || JsfRuntimeInformation.isPartialStateSavingSupported()) {
|
||||
return delegate.saveView(context);
|
||||
Object[] state = (Object[]) delegate.saveView(context);
|
||||
view = new FlowSerializedView(context.getViewRoot().getViewId(), state[0], state[1]);
|
||||
} else {
|
||||
RequestContext requestContext = RequestContextHolder.getRequestContext();
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Saving view root '" + context.getViewRoot().getViewId() + "' in view scope");
|
||||
}
|
||||
FlowSerializedView view = new FlowSerializedView(context.getViewRoot().getViewId(),
|
||||
getTreeStructureToSave(context), getComponentStateToSave(context));
|
||||
requestContext.getViewScope().put(SERIALIZED_VIEW_STATE, view);
|
||||
return view;
|
||||
view = new FlowSerializedView(context.getViewRoot().getViewId(), getTreeStructureToSave(context),
|
||||
getComponentStateToSave(context));
|
||||
}
|
||||
RequestContext requestContext = RequestContextHolder.getRequestContext();
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Saving view root '" + context.getViewRoot().getViewId() + "' in view scope");
|
||||
}
|
||||
requestContext.getViewScope().put(SERIALIZED_VIEW_STATE, view);
|
||||
return view;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2004-2008 the original author or authors.
|
||||
* Copyright 2004-2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -88,6 +88,13 @@ public class JsfView implements View {
|
||||
try {
|
||||
logger.debug("Asking faces lifecycle to render");
|
||||
facesLifecycle.render(facesContext);
|
||||
|
||||
/* Ensure serialized view state is always updated even if JSF didn't call StateManager.writeState(). */
|
||||
if (JsfRuntimeInformation.isAtLeastJsf20()) {
|
||||
if (requestContext.getExternalContext().isAjaxRequest()) {
|
||||
saveState();
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
logger.debug("View rendering complete");
|
||||
facesContext.responseComplete();
|
||||
@@ -134,9 +141,10 @@ public class JsfView implements View {
|
||||
// Set the temporary UIViewRoot state so that it will be available across the redirect
|
||||
return new ViewRootHolder(getViewRoot());
|
||||
} else {
|
||||
// In JSF 2 the partial state saving algorithm attaches a system event listener to the UIViewRoot with
|
||||
// a reference to the FacesContext instance. The FacesContext instance is released at end of each request.
|
||||
// Hence, keeping the UIViewRoot across the redirect is not feasible.
|
||||
// In JSF 2 the partial state saving algorithm attaches a system event listener to the UIViewRoot which
|
||||
// holds on to a reference to the FacesContext instance. The FacesContext instance is released at end of
|
||||
// each request. Hence, keeping the UIViewRoot across the redirect is not feasible.
|
||||
// @see com.sun.faces.context.StateContext$AddRemoveListener
|
||||
logger.debug("User event state requested but not saved.");
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -1,12 +1,16 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beansProjectDescription>
|
||||
<version>1</version>
|
||||
<pluginVersion><![CDATA[2.0.5.v200805032123]]></pluginVersion>
|
||||
<pluginVersion><![CDATA[2.5.2.201101081000-RELEASE]]></pluginVersion>
|
||||
<configSuffixes>
|
||||
<configSuffix><![CDATA[xml]]></configSuffix>
|
||||
</configSuffixes>
|
||||
<enableImports><![CDATA[true]]></enableImports>
|
||||
<configs>
|
||||
<config>src/main/webapp/WEB-INF/config/data-access-config.xml</config>
|
||||
<config>src/main/webapp/WEB-INF/config/security-config.xml</config>
|
||||
<config>src/main/webapp/WEB-INF/config/webflow-config.xml</config>
|
||||
<config>src/main/webapp/WEB-INF/config/webmvc-config.xml</config>
|
||||
</configs>
|
||||
<configSets>
|
||||
</configSets>
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
<!-- Spring -->
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context</artifactId>
|
||||
<artifactId>spring-webmvc</artifactId>
|
||||
<version>${org.springframework-version}</version>
|
||||
<exclusions>
|
||||
<!-- Exclude Commons Logging in favor of SLF4j -->
|
||||
@@ -37,11 +37,6 @@
|
||||
<artifactId>spring-orm</artifactId>
|
||||
<version>${org.springframework-version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-webmvc</artifactId>
|
||||
<version>${org.springframework-version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.webflow</groupId>
|
||||
<artifactId>spring-webflow</artifactId>
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<flow xmlns="http://www.springframework.org/schema/webflow"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/webflow http://www.springframework.org/schema/webflow/spring-webflow-2.0.xsd">
|
||||
|
||||
<secured attributes="ROLE_USER" />
|
||||
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/webflow http://www.springframework.org/schema/webflow/spring-webflow.xsd">
|
||||
|
||||
<secured attributes="ROLE_USER" />
|
||||
|
||||
<ajax-driven />
|
||||
|
||||
<input name="hotelId" required="true" />
|
||||
|
||||
|
||||
<on-start>
|
||||
<evaluate expression="bookingService.createBooking(hotelId, currentUser.name)" result="flowScope.booking" />
|
||||
</on-start>
|
||||
@@ -23,11 +25,17 @@
|
||||
<binding property="creditCardExpiryYear" />
|
||||
<binding property="amenities" />
|
||||
</binder>
|
||||
<on-render>
|
||||
<render fragments="body" />
|
||||
</on-render>
|
||||
<transition on="proceed" to="reviewBooking" />
|
||||
<transition on="cancel" to="cancel" bind="false" />
|
||||
</view-state>
|
||||
|
||||
<view-state id="reviewBooking" model="booking">
|
||||
<view-state id="reviewBooking" model="booking">
|
||||
<on-render>
|
||||
<render fragments="body" />
|
||||
</on-render>
|
||||
<transition on="confirm" to="bookingConfirmed">
|
||||
<evaluate expression="bookingService.persistBooking(booking)" />
|
||||
</transition>
|
||||
@@ -36,7 +44,7 @@
|
||||
</view-state>
|
||||
|
||||
<end-state id="bookingConfirmed"/>
|
||||
|
||||
|
||||
<end-state id="cancel" />
|
||||
|
||||
</flow>
|
||||
@@ -27,7 +27,7 @@
|
||||
</spring:bind>
|
||||
</div>
|
||||
</spring:hasBindErrors>
|
||||
<form:form modelAttribute="booking">
|
||||
<form:form modelAttribute="booking" action="${flowExecutionUrl}">
|
||||
<fieldset>
|
||||
<legend>Book Hotel</legend>
|
||||
<div>
|
||||
@@ -187,7 +187,7 @@
|
||||
</p>
|
||||
<script type="text/javascript">
|
||||
Spring.addDecoration(new Spring.ValidateAllDecoration({elementId:'proceed', event:'onclick'}));
|
||||
Spring.addDecoration(new Spring.AjaxEventDecoration({elementId:'proceed',event:'onclick',formId:'booking',params:{fragments:'body'}}));
|
||||
Spring.addDecoration(new Spring.AjaxEventDecoration({elementId:'proceed',event:'onclick',formId:'booking'}));
|
||||
</script>
|
||||
</div>
|
||||
</fieldset>
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
</address>
|
||||
</div>
|
||||
<div class="span-12 last">
|
||||
<form:form id="confirm" modelAttribute="booking">
|
||||
<form:form id="confirm" modelAttribute="booking" action="${flowExecutionUrl}">
|
||||
<fieldset>
|
||||
<legend>Confirm Booking Details</legend>
|
||||
<div>
|
||||
@@ -49,9 +49,14 @@
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<button type="submit" name="_eventId_confirm">Confirm</button>
|
||||
<button type="submit" name="_eventId_revise">Revise</button>
|
||||
<button type="submit" name="_eventId_cancel">Cancel</button>
|
||||
<p>
|
||||
<button type="submit" name="_eventId_confirm">Confirm</button>
|
||||
<button type="submit" name="_eventId_revise" id="revise">Revise</button>
|
||||
<button type="submit" name="_eventId_cancel">Cancel</button>
|
||||
</p>
|
||||
<script type="text/javascript">
|
||||
Spring.addDecoration(new Spring.AjaxEventDecoration({elementId:'revise',event:'onclick',formId:'confirm'}));
|
||||
</script>
|
||||
</div>
|
||||
</fieldset>
|
||||
</form:form>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2004-2008 the original author or authors.
|
||||
* Copyright 2004-2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -89,16 +89,22 @@ class FlowExecutorBeanDefinitionParser extends AbstractSingleBeanDefinitionParse
|
||||
}
|
||||
}
|
||||
|
||||
private Set parseFlowExecutionAttributes(Element element) {
|
||||
private Set<Object> parseFlowExecutionAttributes(Element element) {
|
||||
Element executionAttributesElement = DomUtils.getChildElementByTagName(element, "flow-execution-attributes");
|
||||
if (executionAttributesElement != null) {
|
||||
HashSet attributes = new HashSet();
|
||||
HashSet<Object> attributes = new HashSet<Object>();
|
||||
Element redirectElement = DomUtils.getChildElementByTagName(executionAttributesElement,
|
||||
"always-redirect-on-pause");
|
||||
if (redirectElement != null) {
|
||||
String value = redirectElement.getAttribute("value");
|
||||
attributes.add(new FlowElementAttribute("alwaysRedirectOnPause", value, "boolean"));
|
||||
}
|
||||
Element redirectInSameStateElement = DomUtils.getChildElementByTagName(executionAttributesElement,
|
||||
"redirect-in-same-state");
|
||||
if (redirectInSameStateElement != null) {
|
||||
String value = redirectInSameStateElement.getAttribute("value");
|
||||
attributes.add(new FlowElementAttribute("redirectInSameState", value, "boolean"));
|
||||
}
|
||||
List attributeElements = DomUtils.getChildElementsByTagName(executionAttributesElement, "attribute");
|
||||
for (Iterator it = attributeElements.iterator(); it.hasNext();) {
|
||||
Element attributeElement = (Element) it.next();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2004-2008 the original author or authors.
|
||||
* Copyright 2004-2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -62,6 +62,8 @@ class FlowExecutorFactoryBean implements FactoryBean, ApplicationContextAware, B
|
||||
|
||||
private static final String ALWAYS_REDIRECT_ON_PAUSE = "alwaysRedirectOnPause";
|
||||
|
||||
private static final String REDIRECT_IN_SAME_STATE = "redirectInSameState";
|
||||
|
||||
private FlowDefinitionLocator flowDefinitionLocator;
|
||||
|
||||
private Integer maxFlowExecutions;
|
||||
@@ -185,11 +187,12 @@ class FlowExecutorFactoryBean implements FactoryBean, ApplicationContextAware, B
|
||||
|
||||
private void putDefaultFlowExecutionAttributes(LocalAttributeMap executionAttributes) {
|
||||
if (!executionAttributes.contains(ALWAYS_REDIRECT_ON_PAUSE)) {
|
||||
if (environment == MvcEnvironment.PORTLET) {
|
||||
executionAttributes.put(ALWAYS_REDIRECT_ON_PAUSE, Boolean.FALSE);
|
||||
} else {
|
||||
executionAttributes.put(ALWAYS_REDIRECT_ON_PAUSE, Boolean.TRUE);
|
||||
}
|
||||
boolean redirect = (environment == MvcEnvironment.PORTLET) ? Boolean.FALSE : Boolean.TRUE;
|
||||
executionAttributes.put(ALWAYS_REDIRECT_ON_PAUSE, redirect);
|
||||
}
|
||||
if (!executionAttributes.contains(REDIRECT_IN_SAME_STATE)) {
|
||||
boolean redirect = (environment == MvcEnvironment.PORTLET) ? Boolean.FALSE : Boolean.TRUE;
|
||||
executionAttributes.put(REDIRECT_IN_SAME_STATE, redirect);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -392,6 +392,16 @@ Example: 'flow1,flow2,flow3'.
|
||||
<xsd:documentation>
|
||||
<![CDATA[
|
||||
Determines if flow executions always redirect after they pause.
|
||||
]]>
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:element>
|
||||
<xsd:element name="redirect-in-same-state" type="redirectInSameStateType" minOccurs="0" maxOccurs="1">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
<![CDATA[
|
||||
Determines if flow executions redirect after they pause for transitions that remain in the same view state.
|
||||
This attribute effectively overrides the value of the "always-redirect-on-pause" attribute in same state tranisitions.
|
||||
]]>
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
@@ -420,6 +430,19 @@ true = always redirect on pause; false = do not, only redirect when explicitly i
|
||||
</xsd:attribute>
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:complexType name="redirectInSameStateType">
|
||||
<xsd:attribute name="value" type="xsd:boolean" use="required">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
<![CDATA[
|
||||
true = redirect on pause for transitions that remain in the same view state;
|
||||
false = do not redirect for transitions that remain in the same view state.
|
||||
]]>
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:complexType name="flowDefinitionAttributesType">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="attribute" type="attributeType" minOccurs="0" maxOccurs="unbounded">
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2004-2008 the original author or authors.
|
||||
* Copyright 2004-2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -150,4 +150,11 @@ public interface RequestControlContext extends RequestContext {
|
||||
*/
|
||||
public boolean getRedirectOnPause();
|
||||
|
||||
/**
|
||||
* Returns the value of the 'redirect in same state' flow execution attribute if set or otherwise it falls back on
|
||||
* the value returned by {@link #getRedirectOnPause()}.
|
||||
* @return true or false
|
||||
*/
|
||||
public boolean getRedirectInSameState();
|
||||
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2004-2008 the original author or authors.
|
||||
* Copyright 2004-2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -41,6 +41,11 @@ import org.springframework.webflow.execution.ViewFactory;
|
||||
*/
|
||||
public class ViewState extends TransitionableState {
|
||||
|
||||
/**
|
||||
* The name of the attribute indicating an Ajax-driven Flow Definition.
|
||||
*/
|
||||
private static final String AJAX_DRIVEN_ATTRIBUTE_NAME = "ajaxDriven";
|
||||
|
||||
/**
|
||||
* The list of actions to be executed before the view is rendered.
|
||||
*/
|
||||
@@ -61,12 +66,6 @@ public class ViewState extends TransitionableState {
|
||||
*/
|
||||
private Boolean redirect;
|
||||
|
||||
/**
|
||||
* Whether or not a redirect should occur when the state is not exited (e.g. invalid form submission, a transition
|
||||
* without a "to" attribute).
|
||||
*/
|
||||
private Boolean redirectInSameState = Boolean.FALSE;
|
||||
|
||||
/**
|
||||
* Whether or not the view should render as a popup.
|
||||
*/
|
||||
@@ -139,22 +138,6 @@ public class ViewState extends TransitionableState {
|
||||
this.redirect = redirect;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this view state should request a flow execution redirect when the state hasn't been exited.
|
||||
*/
|
||||
public boolean getRedirectInSameState() {
|
||||
return (redirectInSameState != null) ? redirectInSameState.booleanValue() : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether this view state should requests a flow execution redirect when entered when processing is done but
|
||||
* the state hasn't been exited (e.g. invalid form submissions).
|
||||
* @param redirectInSameState the redirect flag
|
||||
*/
|
||||
public void setRedirectInSameState(Boolean redirectInSameState) {
|
||||
this.redirectInSameState = redirectInSameState;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this view state should render as a popup.
|
||||
*/
|
||||
@@ -289,17 +272,29 @@ public class ViewState extends TransitionableState {
|
||||
private boolean shouldRedirect(RequestControlContext context) {
|
||||
if (redirect != null) {
|
||||
return redirect.booleanValue();
|
||||
} else {
|
||||
return context.getRedirectOnPause();
|
||||
}
|
||||
if (getAjaxDriven(context) != null) {
|
||||
if (context.getExternalContext().isAjaxRequest()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return context.getRedirectOnPause();
|
||||
}
|
||||
|
||||
private boolean shouldRedirectInSameState(RequestControlContext context) {
|
||||
if (redirectInSameState != null) {
|
||||
return redirectInSameState.booleanValue();
|
||||
} else {
|
||||
return shouldRedirect(context);
|
||||
if (redirect != null) {
|
||||
return redirect.booleanValue();
|
||||
}
|
||||
if (getAjaxDriven(context) != null) {
|
||||
if (context.getExternalContext().isAjaxRequest()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return context.getRedirectInSameState();
|
||||
}
|
||||
|
||||
private Boolean getAjaxDriven(RequestControlContext context) {
|
||||
return context.getActiveFlow().getAttributes().getBoolean(AJAX_DRIVEN_ATTRIBUTE_NAME);
|
||||
}
|
||||
|
||||
private void render(RequestControlContext context, View view) throws ViewRenderingException {
|
||||
@@ -367,8 +362,8 @@ public class ViewState extends TransitionableState {
|
||||
|
||||
protected void appendToString(ToStringCreator creator) {
|
||||
super.appendToString(creator);
|
||||
creator.append("viewFactory", viewFactory).append("variables", variables).append("redirect", redirect).append(
|
||||
"popup", popup);
|
||||
creator.append("viewFactory", viewFactory).append("variables", variables).append("redirect", redirect)
|
||||
.append("popup", popup);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2004-2008 the original author or authors.
|
||||
* Copyright 2004-2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -86,7 +86,6 @@ public class FlowArtifactFactory {
|
||||
ViewState viewState = new ViewState(flow, id, viewFactory);
|
||||
viewState.addVariables(variables);
|
||||
viewState.setRedirect(redirect);
|
||||
viewState.setRedirectInSameState(Boolean.FALSE);
|
||||
viewState.setPopup(popup);
|
||||
viewState.getRenderActionList().addAll(renderActions);
|
||||
configureCommonProperties(viewState, entryActions, transitions, exceptionHandlers, exitActions, attributes);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2004-2008 the original author or authors.
|
||||
* Copyright 2004-2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -76,6 +76,7 @@ import org.springframework.webflow.engine.model.AbstractActionModel;
|
||||
import org.springframework.webflow.engine.model.AbstractMappingModel;
|
||||
import org.springframework.webflow.engine.model.AbstractStateModel;
|
||||
import org.springframework.webflow.engine.model.ActionStateModel;
|
||||
import org.springframework.webflow.engine.model.AjaxDrivenModel;
|
||||
import org.springframework.webflow.engine.model.AttributeModel;
|
||||
import org.springframework.webflow.engine.model.BeanImportModel;
|
||||
import org.springframework.webflow.engine.model.BinderModel;
|
||||
@@ -382,6 +383,7 @@ public class FlowModelFlowBuilder extends AbstractFlowBuilder {
|
||||
MutableAttributeMap flowAttributes = parseMetaAttributes(flow.getAttributes());
|
||||
parseAndPutPersistenceContext(flow.getPersistenceContext(), flowAttributes);
|
||||
parseAndPutSecured(flow.getSecured(), flowAttributes);
|
||||
parseAndPutAjaxDriven(flow.getAjaxDriven(), flowAttributes);
|
||||
return flowAttributes;
|
||||
}
|
||||
|
||||
@@ -927,6 +929,12 @@ public class FlowModelFlowBuilder extends AbstractFlowBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
private void parseAndPutAjaxDriven(AjaxDrivenModel ajaxDrivenModel, MutableAttributeMap attributes) {
|
||||
if (ajaxDrivenModel != null) {
|
||||
attributes.put("ajaxDriven", Boolean.TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
private void parseAndPutSecured(SecuredModel secured, MutableAttributeMap attributes) {
|
||||
if (secured != null) {
|
||||
SecurityRule rule = new SecurityRule();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2004-2008 the original author or authors.
|
||||
* Copyright 2004-2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -246,10 +246,22 @@ class RequestControlContextImpl implements RequestControlContext {
|
||||
return redirectOnPause != null ? redirectOnPause.booleanValue() : false;
|
||||
}
|
||||
|
||||
public boolean getRedirectInSameState() {
|
||||
if (!getExternalContext().isResponseAllowed()) {
|
||||
return true;
|
||||
}
|
||||
Boolean redirectInSameState = flowExecution.getAttributes().getBoolean("redirectInSameState");
|
||||
if (redirectInSameState != null) {
|
||||
return redirectInSameState.booleanValue();
|
||||
} else {
|
||||
return getRedirectOnPause();
|
||||
}
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return new ToStringCreator(this).append("externalContext", externalContext)
|
||||
.append("currentEvent", currentEvent).append("requestScope", requestScope).append("attributes",
|
||||
attributes).append("messageContext", messageContext).append("flowExecution", flowExecution)
|
||||
.toString();
|
||||
.append("currentEvent", currentEvent).append("requestScope", requestScope)
|
||||
.append("attributes", attributes).append("messageContext", messageContext)
|
||||
.append("flowExecution", flowExecution).toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright 2004-2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.webflow.engine.model;
|
||||
|
||||
/**
|
||||
* Model support for the ajax-driven element.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 2.3
|
||||
*/
|
||||
public class AjaxDrivenModel extends AbstractModel {
|
||||
|
||||
public AjaxDrivenModel() {
|
||||
}
|
||||
|
||||
public boolean isMergeableWith(Model model) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public void merge(Model model) {
|
||||
|
||||
}
|
||||
|
||||
public Model createCopy() {
|
||||
return new AjaxDrivenModel();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2004-2008 the original author or authors.
|
||||
* Copyright 2004-2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -58,6 +58,8 @@ public class FlowModel extends AbstractModel {
|
||||
|
||||
private PersistenceContextModel persistenceContext;
|
||||
|
||||
private AjaxDrivenModel ajaxDriven;
|
||||
|
||||
private LinkedList vars;
|
||||
|
||||
private LinkedList inputs;
|
||||
@@ -224,6 +226,20 @@ public class FlowModel extends AbstractModel {
|
||||
this.persistenceContext = persistenceContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the ajaxDriven model
|
||||
*/
|
||||
public AjaxDrivenModel getAjaxDriven() {
|
||||
return ajaxDriven;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ajaxDriven the ajaxDriven model to set
|
||||
*/
|
||||
public void setAjaxDriven(AjaxDrivenModel ajaxDriven) {
|
||||
this.ajaxDriven = ajaxDriven;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the vars
|
||||
*/
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2004-2008 the original author or authors.
|
||||
* Copyright 2004-2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -24,7 +24,7 @@ import org.xml.sax.InputSource;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
/**
|
||||
* EntityResolver implementation for the Spring Web Flow 2.0 XML Schema. This will load the XSD from the classpath.
|
||||
* EntityResolver implementation for the Spring Web Flow XML Schema. This will load the XSD from the classpath.
|
||||
* <p>
|
||||
* The xmlns of the XSD expected to be resolved:
|
||||
*
|
||||
@@ -33,7 +33,7 @@ import org.xml.sax.SAXException;
|
||||
* <flow xmlns="http://www.springframework.org/schema/webflow"
|
||||
* xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
* xsi:schemaLocation="http://www.springframework.org/schema/webflow
|
||||
* http://www.springframework.org/schema/webflow/spring-webflow-2.0.xsd">
|
||||
* http://www.springframework.org/schema/webflow/spring-webflow.xsd">
|
||||
* </pre>
|
||||
*
|
||||
* @author Erwin Vervaet
|
||||
@@ -41,22 +41,32 @@ import org.xml.sax.SAXException;
|
||||
*/
|
||||
class WebFlowEntityResolver implements EntityResolver {
|
||||
|
||||
private static final String WEBFLOW_ELEMENT = "spring-webflow-2.0";
|
||||
private static final String[] WEBFLOW_VERSIONS = new String[] { "spring-webflow-2.3", "spring-webflow-2.0" };
|
||||
|
||||
public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException {
|
||||
if (systemId != null && systemId.indexOf(WEBFLOW_ELEMENT) > systemId.lastIndexOf("/")) {
|
||||
String filename = systemId.substring(systemId.indexOf(WEBFLOW_ELEMENT));
|
||||
try {
|
||||
Resource resource = new ClassPathResource(filename, getClass());
|
||||
InputSource source = new InputSource(resource.getInputStream());
|
||||
source.setPublicId(publicId);
|
||||
source.setSystemId(systemId);
|
||||
return source;
|
||||
} catch (IOException ex) {
|
||||
// fall through below
|
||||
if (systemId != null && systemId.indexOf("spring-webflow.xsd") > -1) {
|
||||
return createInputSource(publicId, systemId, WEBFLOW_VERSIONS[0] + ".xsd");
|
||||
}
|
||||
for (int i = 0; i < WEBFLOW_VERSIONS.length; i++) {
|
||||
if (systemId != null && systemId.indexOf(WEBFLOW_VERSIONS[i]) > systemId.lastIndexOf("/")) {
|
||||
String fileName = systemId.substring(systemId.indexOf(WEBFLOW_VERSIONS[i]));
|
||||
return createInputSource(publicId, systemId, fileName);
|
||||
}
|
||||
}
|
||||
// let the parser handle it
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private InputSource createInputSource(String publicId, String systemId, String fileName) {
|
||||
try {
|
||||
Resource resource = new ClassPathResource(fileName, getClass());
|
||||
InputSource source = new InputSource(resource.getInputStream());
|
||||
source.setPublicId(publicId);
|
||||
source.setSystemId(systemId);
|
||||
return source;
|
||||
} catch (IOException ex) {
|
||||
// fall through below
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2004-2008 the original author or authors.
|
||||
* Copyright 2004-2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -31,6 +31,7 @@ import org.springframework.util.xml.DomUtils;
|
||||
import org.springframework.webflow.engine.model.AbstractActionModel;
|
||||
import org.springframework.webflow.engine.model.AbstractStateModel;
|
||||
import org.springframework.webflow.engine.model.ActionStateModel;
|
||||
import org.springframework.webflow.engine.model.AjaxDrivenModel;
|
||||
import org.springframework.webflow.engine.model.AttributeModel;
|
||||
import org.springframework.webflow.engine.model.BeanImportModel;
|
||||
import org.springframework.webflow.engine.model.BinderModel;
|
||||
@@ -201,6 +202,7 @@ public class XmlFlowModelBuilder implements FlowModelBuilder {
|
||||
flow.setAttributes(parseAttributes(element));
|
||||
flow.setSecured(parseSecured(element));
|
||||
flow.setPersistenceContext(parsePersistenceContext(element));
|
||||
flow.setAjaxDriven(parseAjaxDriven(element));
|
||||
flow.setVars(parseVars(element));
|
||||
flow.setInputs(parseInputs(element));
|
||||
flow.setOnStartActions(parseOnStartActions(element));
|
||||
@@ -410,6 +412,15 @@ public class XmlFlowModelBuilder implements FlowModelBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
private AjaxDrivenModel parseAjaxDriven(Element element) {
|
||||
element = DomUtils.getChildElementByTagName(element, "ajax-driven");
|
||||
if (element == null) {
|
||||
return null;
|
||||
} else {
|
||||
return new AjaxDrivenModel();
|
||||
}
|
||||
}
|
||||
|
||||
private VarModel parseVar(Element element) {
|
||||
return new VarModel(element.getAttribute("name"), element.getAttribute("class"));
|
||||
}
|
||||
@@ -507,8 +518,8 @@ public class XmlFlowModelBuilder implements FlowModelBuilder {
|
||||
}
|
||||
|
||||
private BindingModel parseBinding(Element element) {
|
||||
return new BindingModel(element.getAttribute("property"), element.getAttribute("converter"), element
|
||||
.getAttribute("required"));
|
||||
return new BindingModel(element.getAttribute("property"), element.getAttribute("converter"),
|
||||
element.getAttribute("required"));
|
||||
}
|
||||
|
||||
private LinkedList parseOnExitActions(Element element) {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -125,6 +125,18 @@ public class MockRequestControlContext extends MockRequestContext implements Req
|
||||
return redirectOnPause != null ? redirectOnPause.booleanValue() : false;
|
||||
}
|
||||
|
||||
public boolean getRedirectInSameState() {
|
||||
if (!getExternalContext().isResponseAllowed()) {
|
||||
return true;
|
||||
}
|
||||
Boolean redirectInSameState = getMockFlowExecutionContext().getAttributes().getBoolean("redirectInSameState");
|
||||
if (redirectInSameState != null) {
|
||||
return redirectInSameState.booleanValue();
|
||||
} else {
|
||||
return getRedirectOnPause();
|
||||
}
|
||||
}
|
||||
|
||||
// implementation specific accessors for testing
|
||||
|
||||
public void setAlwaysRedirectOnPause(boolean alwaysRedirectOnPause) {
|
||||
@@ -132,4 +144,9 @@ public class MockRequestControlContext extends MockRequestContext implements Req
|
||||
Boolean.valueOf(alwaysRedirectOnPause));
|
||||
}
|
||||
|
||||
public void setRedirectInSameState(boolean redirectInSameState) {
|
||||
getMockFlowExecutionContext().getAttributeMap()
|
||||
.put("redirectInSameState", Boolean.valueOf(redirectInSameState));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -40,9 +40,11 @@ public class FlowExecutorBeanDefinitionParserTests extends TestCase {
|
||||
|
||||
public static class ConfigurationListener extends FlowExecutionListenerAdapter {
|
||||
public void sessionCreating(RequestContext context, FlowDefinition definition) {
|
||||
assertEquals(3, context.getFlowExecutionContext().getAttributes().size());
|
||||
assertEquals(4, context.getFlowExecutionContext().getAttributes().size());
|
||||
assertEquals(Boolean.FALSE,
|
||||
context.getFlowExecutionContext().getAttributes().getBoolean("alwaysRedirectOnPause"));
|
||||
assertEquals(Boolean.TRUE,
|
||||
context.getFlowExecutionContext().getAttributes().getBoolean("redirectInSameState"));
|
||||
assertEquals("bar", context.getFlowExecutionContext().getAttributes().get("foo"));
|
||||
assertEquals(new Integer(2), context.getFlowExecutionContext().getAttributes().get("bar"));
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
<webflow:flow-execution-repository max-executions="1" max-execution-snapshots="2" conversation-manager="conversationManager" />
|
||||
<webflow:flow-execution-attributes>
|
||||
<webflow:always-redirect-on-pause value="false"/>
|
||||
<webflow:redirect-in-same-state value="true"/>
|
||||
<webflow:attribute name="foo" value="bar"/>
|
||||
<webflow:attribute name="bar" value="2" type="integer"/>
|
||||
</webflow:flow-execution-attributes>
|
||||
|
||||
@@ -297,7 +297,6 @@ public class ViewStateTests extends TestCase {
|
||||
Flow flow = new Flow("myFlow");
|
||||
StubViewFactory viewFactory = new StubViewFactory();
|
||||
ViewState state = new ViewState(flow, "viewState", viewFactory);
|
||||
state.setRedirectInSameState(Boolean.TRUE);
|
||||
Transition t = new Transition(on("submit"), null);
|
||||
state.getTransitionSet().add(t);
|
||||
MockRequestControlContext context = new MockRequestControlContext(flow);
|
||||
@@ -320,7 +319,6 @@ public class ViewStateTests extends TestCase {
|
||||
Flow flow = new Flow("myFlow");
|
||||
StubViewFactory viewFactory = new StubViewFactory();
|
||||
ViewState state = new ViewState(flow, "viewState", viewFactory);
|
||||
state.setRedirectInSameState(Boolean.TRUE);
|
||||
Transition t = new Transition(on("submit"), null);
|
||||
TestAction action = new TestAction();
|
||||
t.setExecutionCriteria(new ActionTransitionCriteria(action));
|
||||
@@ -428,6 +426,62 @@ public class ViewStateTests extends TestCase {
|
||||
assertEquals(StubViewFactory.USER_EVENT_STATE, context.getFlashScope().get(View.USER_EVENT_STATE_ATTRIBUTE));
|
||||
}
|
||||
|
||||
public void testRedirectInSameStateOverridesAlwaysRedirectOnPause() {
|
||||
Flow flow = new Flow("myFlow");
|
||||
StubViewFactory viewFactory = new StubViewFactory();
|
||||
ViewState state = new ViewState(flow, "viewState", viewFactory);
|
||||
Transition t = new Transition(on("submit"), null);
|
||||
state.getTransitionSet().add(t);
|
||||
MockRequestControlContext context = new MockRequestControlContext(flow);
|
||||
state.enter(context);
|
||||
context = new MockRequestControlContext(context.getFlowExecutionContext());
|
||||
context.setAlwaysRedirectOnPause(false);
|
||||
context.setRedirectInSameState(true);
|
||||
context.getFlowScope().remove("renderCalled");
|
||||
context.putRequestParameter("_eventId", "submit");
|
||||
state.resume(context);
|
||||
assertTrue(context.getMockExternalContext().getFlowExecutionRedirectRequested());
|
||||
}
|
||||
|
||||
public void testAjaxDrivenAttributeOverridesRedirectInSameState() {
|
||||
Flow flow = new Flow("myFlow");
|
||||
flow.getAttributes().put("ajaxDriven", Boolean.TRUE);
|
||||
StubViewFactory viewFactory = new StubViewFactory();
|
||||
ViewState state = new ViewState(flow, "viewState", viewFactory);
|
||||
Transition t = new Transition(on("submit"), null);
|
||||
state.getTransitionSet().add(t);
|
||||
MockRequestControlContext context = new MockRequestControlContext(flow);
|
||||
state.enter(context);
|
||||
context = new MockRequestControlContext(context.getFlowExecutionContext());
|
||||
context.getMockExternalContext().setAjaxRequest(true);
|
||||
context.setAlwaysRedirectOnPause(true);
|
||||
context.setRedirectInSameState(true);
|
||||
context.getFlowScope().remove("renderCalled");
|
||||
context.putRequestParameter("_eventId", "submit");
|
||||
state.resume(context);
|
||||
assertFalse(context.getMockExternalContext().getFlowExecutionRedirectRequested());
|
||||
}
|
||||
|
||||
public void testViewStateRedirectOverridesAjaxDrivenAttribute() {
|
||||
Flow flow = new Flow("myFlow");
|
||||
flow.getAttributes().put("ajaxDriven", Boolean.TRUE);
|
||||
StubViewFactory viewFactory = new StubViewFactory();
|
||||
ViewState state = new ViewState(flow, "viewState", viewFactory);
|
||||
state.setRedirect(false);
|
||||
Transition t = new Transition(on("submit"), null);
|
||||
state.getTransitionSet().add(t);
|
||||
MockRequestControlContext context = new MockRequestControlContext(flow);
|
||||
state.enter(context);
|
||||
context = new MockRequestControlContext(context.getFlowExecutionContext());
|
||||
context.getMockExternalContext().setAjaxRequest(true);
|
||||
context.setAlwaysRedirectOnPause(true);
|
||||
context.setRedirectInSameState(true);
|
||||
context.getFlowScope().remove("renderCalled");
|
||||
context.putRequestParameter("_eventId", "submit");
|
||||
state.resume(context);
|
||||
assertFalse(context.getMockExternalContext().getFlowExecutionRedirectRequested());
|
||||
}
|
||||
|
||||
public void testResumeViewStateForEventDestroyVariables() {
|
||||
Flow flow = new Flow("myFlow");
|
||||
StubViewFactory viewFactory = new StubViewFactory();
|
||||
|
||||
@@ -18,6 +18,7 @@ import org.springframework.webflow.engine.ViewState;
|
||||
import org.springframework.webflow.engine.builder.FlowAssembler;
|
||||
import org.springframework.webflow.engine.builder.FlowBuilderException;
|
||||
import org.springframework.webflow.engine.impl.FlowExecutionImplFactory;
|
||||
import org.springframework.webflow.engine.model.AjaxDrivenModel;
|
||||
import org.springframework.webflow.engine.model.AttributeModel;
|
||||
import org.springframework.webflow.engine.model.EndStateModel;
|
||||
import org.springframework.webflow.engine.model.EvaluateModel;
|
||||
@@ -129,6 +130,14 @@ public class FlowModelFlowBuilderTests extends TestCase {
|
||||
assertTrue(((Boolean) flow.getAttributes().get("persistenceContext")).booleanValue());
|
||||
}
|
||||
|
||||
public void testAjaxDrivenFlow() {
|
||||
model.setAjaxDriven(new AjaxDrivenModel());
|
||||
model.setStates(singleList(new EndStateModel("end")));
|
||||
Flow flow = getFlow(model);
|
||||
assertNotNull(flow.getAttributes().get("ajaxDriven"));
|
||||
assertTrue(((Boolean) flow.getAttributes().get("ajaxDriven")).booleanValue());
|
||||
}
|
||||
|
||||
public void testFlowInputOutputMapping() {
|
||||
InputModel input1 = new InputModel("foo", "flowScope.foo");
|
||||
InputModel input2 = new InputModel("foo", "flowScope.bar");
|
||||
@@ -190,8 +199,8 @@ public class FlowModelFlowBuilderTests extends TestCase {
|
||||
end.setSecured(new SecuredModel("ROLE_USER"));
|
||||
model.setStates(singleList(end));
|
||||
Flow flow = getFlow(model);
|
||||
SecurityRule rule = (SecurityRule) flow.getState("end").getAttributes().get(
|
||||
SecurityRule.SECURITY_ATTRIBUTE_NAME);
|
||||
SecurityRule rule = (SecurityRule) flow.getState("end").getAttributes()
|
||||
.get(SecurityRule.SECURITY_ATTRIBUTE_NAME);
|
||||
assertNotNull(rule);
|
||||
assertEquals(SecurityRule.COMPARISON_ANY, rule.getComparisonType());
|
||||
assertEquals(1, rule.getAttributes().size());
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
package org.springframework.webflow.engine.model.builder.xml;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.xml.sax.InputSource;
|
||||
|
||||
public class WebFlowEntityResolverTests extends TestCase {
|
||||
|
||||
private static final String PUBLIC_ID = "http://www.springframework.org/schema/webflow";
|
||||
|
||||
public void testResolve23() throws Exception {
|
||||
WebFlowEntityResolver resolver = new WebFlowEntityResolver();
|
||||
InputSource source = resolver.resolveEntity(PUBLIC_ID,
|
||||
"http://www.springframework.org/schema/webflow/spring-webflow-2.3.xsd");
|
||||
assertNotNull(source);
|
||||
}
|
||||
|
||||
public void testResolve20() throws Exception {
|
||||
WebFlowEntityResolver resolver = new WebFlowEntityResolver();
|
||||
InputSource source = resolver.resolveEntity(PUBLIC_ID,
|
||||
"http://www.springframework.org/schema/webflow/spring-webflow-2.0.xsd");
|
||||
assertNotNull(source);
|
||||
}
|
||||
|
||||
public void testResolveLatest() throws Exception {
|
||||
WebFlowEntityResolver resolver = new WebFlowEntityResolver();
|
||||
InputSource source = resolver.resolveEntity(PUBLIC_ID,
|
||||
"http://www.springframework.org/schema/webflow/spring-webflow.xsd");
|
||||
assertNotNull(source);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -13,6 +13,7 @@ import org.springframework.webflow.engine.builder.FlowAssembler;
|
||||
import org.springframework.webflow.engine.builder.model.FlowModelFlowBuilder;
|
||||
import org.springframework.webflow.engine.impl.FlowExecutionImplFactory;
|
||||
import org.springframework.webflow.engine.model.AbstractStateModel;
|
||||
import org.springframework.webflow.engine.model.AjaxDrivenModel;
|
||||
import org.springframework.webflow.engine.model.AttributeModel;
|
||||
import org.springframework.webflow.engine.model.BindingModel;
|
||||
import org.springframework.webflow.engine.model.ExceptionHandlerModel;
|
||||
@@ -103,6 +104,16 @@ public class XmlFlowModelBuilderTests extends TestCase {
|
||||
assertEquals("ROLE_USER", secured.getAttributes());
|
||||
}
|
||||
|
||||
public void testFlowAjaxDriven() {
|
||||
ClassPathResource resource = new ClassPathResource("flow-ajax-driven.xml", getClass());
|
||||
FlowModelBuilder builder = new XmlFlowModelBuilder(resource, registry);
|
||||
builder.init();
|
||||
builder.build();
|
||||
FlowModel flow = builder.getFlowModel();
|
||||
AjaxDrivenModel ajaxDriven = flow.getAjaxDriven();
|
||||
assertNotNull(ajaxDriven);
|
||||
}
|
||||
|
||||
public void testFlowSecuredState() {
|
||||
ClassPathResource resource = new ClassPathResource("flow-secured-state.xml", getClass());
|
||||
FlowModelBuilder builder = new XmlFlowModelBuilder(resource, registry);
|
||||
@@ -290,16 +301,16 @@ public class XmlFlowModelBuilderTests extends TestCase {
|
||||
DefaultFlowModelHolder holder = new DefaultFlowModelHolder(builder);
|
||||
FlowModel model = holder.getFlowModel();
|
||||
assertEquals("foo1", ((ExceptionHandlerModel) model.getExceptionHandlers().get(0)).getBean());
|
||||
assertEquals("foo2", ((ExceptionHandlerModel) model.getStateById("state1").getExceptionHandlers().get(0))
|
||||
.getBean());
|
||||
assertEquals("foo3", ((ExceptionHandlerModel) model.getStateById("state2").getExceptionHandlers().get(0))
|
||||
.getBean());
|
||||
assertEquals("foo4", ((ExceptionHandlerModel) model.getStateById("state3").getExceptionHandlers().get(0))
|
||||
.getBean());
|
||||
assertEquals("foo5", ((ExceptionHandlerModel) model.getStateById("state4").getExceptionHandlers().get(0))
|
||||
.getBean());
|
||||
assertEquals("foo6", ((ExceptionHandlerModel) model.getStateById("state5").getExceptionHandlers().get(0))
|
||||
.getBean());
|
||||
assertEquals("foo2",
|
||||
((ExceptionHandlerModel) model.getStateById("state1").getExceptionHandlers().get(0)).getBean());
|
||||
assertEquals("foo3",
|
||||
((ExceptionHandlerModel) model.getStateById("state2").getExceptionHandlers().get(0)).getBean());
|
||||
assertEquals("foo4",
|
||||
((ExceptionHandlerModel) model.getStateById("state3").getExceptionHandlers().get(0)).getBean());
|
||||
assertEquals("foo5",
|
||||
((ExceptionHandlerModel) model.getStateById("state4").getExceptionHandlers().get(0)).getBean());
|
||||
assertEquals("foo6",
|
||||
((ExceptionHandlerModel) model.getStateById("state5").getExceptionHandlers().get(0)).getBean());
|
||||
}
|
||||
|
||||
public void testFormActionValidatorMethod() {
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
<flow xmlns="http://www.springframework.org/schema/webflow"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/webflow http://www.springframework.org/schema/webflow/spring-webflow-2.3.xsd">
|
||||
|
||||
<ajax-driven/>
|
||||
|
||||
<end-state id="end"/>
|
||||
|
||||
</flow>
|
||||
Reference in New Issue
Block a user