diff --git a/spring-webflow/src/main/java/org/springframework/webflow/action/FlowDefinitionRedirectAction.java b/spring-webflow/src/main/java/org/springframework/webflow/action/FlowDefinitionRedirectAction.java index 61c825f8..2774031f 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/action/FlowDefinitionRedirectAction.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/action/FlowDefinitionRedirectAction.java @@ -46,7 +46,6 @@ public class FlowDefinitionRedirectAction extends AbstractAction { } public static FlowDefinitionRedirectAction create(String encodedFlowRedirect) { - // TODO - return null; + throw new UnsupportedOperationException("Not yet implemented"); } } diff --git a/spring-webflow/src/main/java/org/springframework/webflow/engine/Flow.java b/spring-webflow/src/main/java/org/springframework/webflow/engine/Flow.java index b642f8df..2e6738b3 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/engine/Flow.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/engine/Flow.java @@ -16,7 +16,9 @@ package org.springframework.webflow.engine; import java.util.Iterator; +import java.util.LinkedHashMap; import java.util.LinkedHashSet; +import java.util.Map; import java.util.Set; import org.apache.commons.logging.Log; @@ -129,7 +131,7 @@ public class Flow extends AnnotatedObject implements FlowDefinition { /** * The set of flow variables created by this flow. */ - private Set variables = new LinkedHashSet(3); + private Map variables = new LinkedHashMap(); /** * The mapper to map flow input attributes. @@ -350,7 +352,7 @@ public class Flow extends AnnotatedObject implements FlowDefinition { * @param variable the variable */ public void addVariable(FlowVariable variable) { - variables.add(variable); + variables.put(variable.getName(), variable); } /** @@ -366,11 +368,19 @@ public class Flow extends AnnotatedObject implements FlowDefinition { } } + /** + * Returns the flow variable with the given name. + * @param name the name of the variable + */ + public FlowVariable getVariable(String name) { + return (FlowVariable) variables.get(name); + } + /** * Returns the flow variables. */ public FlowVariable[] getVariables() { - return (FlowVariable[]) variables.toArray(new FlowVariable[variables.size()]); + return (FlowVariable[]) variables.values().toArray(new FlowVariable[variables.size()]); } /** @@ -513,6 +523,7 @@ public class Flow extends AnnotatedObject implements FlowDefinition { * @throws FlowExecutionException when an exception occurs during the resume operation */ public void resume(RequestControlContext context) throws FlowExecutionException { + restoreVariables(context); getCurrentViewState(context).resume(context); } @@ -575,11 +586,8 @@ public class Flow extends AnnotatedObject implements FlowDefinition { } } - /** - * Create (setup) all known flow variables in flow scope. - */ private void createVariables(RequestContext context) { - Iterator it = variables.iterator(); + Iterator it = variables.values().iterator(); while (it.hasNext()) { FlowVariable variable = (FlowVariable) it.next(); if (logger.isDebugEnabled()) { @@ -589,9 +597,17 @@ public class Flow extends AnnotatedObject implements FlowDefinition { } } - /** - * Returns the current state and makes sure it is a view state. - */ + private void restoreVariables(RequestContext context) { + Iterator it = variables.values().iterator(); + while (it.hasNext()) { + FlowVariable variable = (FlowVariable) it.next(); + if (logger.isDebugEnabled()) { + logger.debug("Restoring " + variable); + } + variable.restore(context); + } + } + private ViewState getCurrentViewState(RequestControlContext context) { State currentState = (State) context.getCurrentState(); if (!(currentState instanceof ViewState)) { @@ -601,9 +617,6 @@ public class Flow extends AnnotatedObject implements FlowDefinition { return (ViewState) currentState; } - /** - * Returns the current state and makes sure it is transitionable. - */ private TransitionableState getCurrentTransitionableState(RequestControlContext context) { State currentState = (State) context.getCurrentState(); if (!(currentState instanceof TransitionableState)) { diff --git a/spring-webflow/src/main/java/org/springframework/webflow/engine/FlowVariable.java b/spring-webflow/src/main/java/org/springframework/webflow/engine/FlowVariable.java index c73268d8..6ba2bfab 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/engine/FlowVariable.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/engine/FlowVariable.java @@ -17,7 +17,6 @@ package org.springframework.webflow.engine; import org.springframework.core.style.ToStringCreator; import org.springframework.util.Assert; -import org.springframework.webflow.execution.FlowSession; import org.springframework.webflow.execution.RequestContext; /** @@ -85,10 +84,6 @@ public class FlowVariable extends AnnotatedObject { return name.hashCode() + valueFactory.hashCode() + local.hashCode(); } - /** - * Creates a new instance of this flow variable in the configured scope. - * @param context the flow execution request context - */ public final void create(RequestContext context) { Object value = valueFactory.createVariableValue(context); if (local == Boolean.TRUE) { @@ -98,10 +93,10 @@ public class FlowVariable extends AnnotatedObject { } } - public final Object restore(FlowSession session, RequestContext context) { + public final Object restore(RequestContext context) { Object value; if (local == Boolean.TRUE) { - value = session.getScope().get(name); + value = context.getFlowScope().get(name); } else { value = context.getConversationScope().get(name); } diff --git a/spring-webflow/src/main/java/org/springframework/webflow/engine/State.java b/spring-webflow/src/main/java/org/springframework/webflow/engine/State.java index ed2373fb..b9d7f305 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/engine/State.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/engine/State.java @@ -184,10 +184,21 @@ public abstract class State extends AnnotatedObject implements StateDefinition { logger.debug("Entering state '" + getId() + "' of flow '" + getFlow().getId() + "'"); } context.setCurrentState(this); + doPreEntryActions(context); entryActionList.execute(context); doEnter(context); } + /** + * Hook method to execute before running state entry actions upon state entry. Does nothing by default. Subclasses + * may override. + * @param context the request control context + * @throws FlowExecutionException if an exception occurs + */ + protected void doPreEntryActions(RequestControlContext context) throws FlowExecutionException { + + } + /** * Hook method to execute custom behavior as a result of entering this state. By implementing this method subclasses * specialize the behavior of the state. diff --git a/spring-webflow/src/main/java/org/springframework/webflow/engine/ViewState.java b/spring-webflow/src/main/java/org/springframework/webflow/engine/ViewState.java index e2be964b..4cf7751b 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/engine/ViewState.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/engine/ViewState.java @@ -15,10 +15,15 @@ */ package org.springframework.webflow.engine; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.Map; + import org.springframework.core.style.ToStringCreator; import org.springframework.util.Assert; import org.springframework.webflow.execution.Event; import org.springframework.webflow.execution.FlowExecutionException; +import org.springframework.webflow.execution.RequestContext; import org.springframework.webflow.execution.View; import org.springframework.webflow.execution.ViewFactory; @@ -33,25 +38,33 @@ import org.springframework.webflow.execution.ViewFactory; */ public class ViewState extends TransitionableState { - private static final String FLOW_MODAL_VIEW_HEADER = "Flow-Modal-View"; - - private static final String MODAL_ATTR = "modal"; + private static final String POPUP_VIEW_HEADER = "Flow-Modal-View"; /** * The list of actions to be executed when this state is entered. */ private ActionList renderActionList = new ActionList(); - /** - * Whether or not a redirect should occur before the view is rendered. - */ - private boolean redirect; - /** * A factory for creating and restoring the view rendered by this view state. */ private ViewFactory viewFactory; + /** + * The set of view variables created by this view state. + */ + private Map variables = new LinkedHashMap(); + + /** + * Whether or not a redirect should occur before the view is rendered. + */ + private Boolean redirect; + + /** + * Whether or not the view should render as a popup. + */ + private boolean popup; + /** * Create a new view state. * @param flow the owning flow @@ -65,12 +78,53 @@ public class ViewState extends TransitionableState { this.viewFactory = viewFactory; } + /** + * Adds a view variable. + * @param variable the variable + */ + public void addVariable(ViewVariable variable) { + variables.put(variable.getName(), variable); + } + + /** + * Adds a set of view variables. + * @param variables the variables + */ + public void addVariables(ViewVariable[] variables) { + for (int i = 0; i < variables.length; i++) { + addVariable(variables[i]); + } + } + + /** + * Returns the view variable with the given name. + * @param name the name of the variable + */ + public ViewVariable getVariable(String name) { + return (ViewVariable) variables.get(name); + } + + /** + * Returns the flow variables. + */ + public ViewVariable[] getVariables() { + return (ViewVariable[]) variables.values().toArray(new ViewVariable[variables.size()]); + } + /** * Sets whether this view state should send a flow execution redirect when entered. * @param redirect the redirect flag */ public void setRedirect(boolean redirect) { - this.redirect = redirect; + this.redirect = Boolean.valueOf(redirect); + } + + /** + * Sets whether this view state should render as a popup. + * @param popup the popup flag + */ + public void setPopup(boolean popup) { + this.popup = popup; } /** @@ -81,13 +135,16 @@ public class ViewState extends TransitionableState { return renderActionList; } + protected void doPreEntryActions(RequestControlContext context) throws FlowExecutionException { + createVariables(context); + } + protected void doEnter(RequestControlContext context) throws FlowExecutionException { context.assignFlowExecutionKey(); - if (context.getExternalContext().isAjaxRequest() - && Boolean.TRUE.equals(context.getCurrentState().getAttributes().getBoolean(MODAL_ATTR))) { - context.getExternalContext().setResponseHeader(FLOW_MODAL_VIEW_HEADER, "true"); - } if (shouldRedirect(context)) { + if (context.getExternalContext().isAjaxRequest() && popup) { + context.getExternalContext().setResponseHeader(POPUP_VIEW_HEADER, "true"); + } context.sendFlowExecutionRedirect(); } else { View view = viewFactory.getView(context); @@ -103,6 +160,7 @@ public class ViewState extends TransitionableState { public void resume(RequestControlContext context) { View view = viewFactory.getView(context); + restoreVariables(context); if (view.eventSignaled()) { Event event = view.getEvent(); if (logger.isDebugEnabled()) { @@ -120,12 +178,58 @@ public class ViewState extends TransitionableState { } } + public void exit(RequestControlContext context) { + destroyVariables(context); + super.exit(context); + } + + // internal helpers + private boolean shouldRedirect(RequestControlContext context) { - return redirect || context.getAlwaysRedirectOnPause(); + if (redirect != null) { + return redirect.booleanValue(); + } else { + return context.getAlwaysRedirectOnPause(); + } + } + + private void createVariables(RequestContext context) { + Iterator it = variables.values().iterator(); + while (it.hasNext()) { + ViewVariable variable = (ViewVariable) it.next(); + if (logger.isDebugEnabled()) { + logger.debug("Creating " + variable); + } + variable.create(context); + } + } + + private void restoreVariables(RequestContext context) { + Iterator it = variables.values().iterator(); + while (it.hasNext()) { + ViewVariable variable = (ViewVariable) it.next(); + if (logger.isDebugEnabled()) { + logger.debug("Destroying " + variable); + + } + variable.restore(context); + } + } + + private void destroyVariables(RequestContext context) { + Iterator it = variables.values().iterator(); + while (it.hasNext()) { + ViewVariable variable = (ViewVariable) it.next(); + if (logger.isDebugEnabled()) { + logger.debug("Destroying " + variable); + + } + variable.destroy(context); + } } protected void appendToString(ToStringCreator creator) { super.appendToString(creator); - creator.append("viewManager", viewFactory); + creator.append("viewFactory", viewFactory).append("variables", variables); } } \ No newline at end of file diff --git a/spring-webflow/src/main/java/org/springframework/webflow/engine/ViewVariable.java b/spring-webflow/src/main/java/org/springframework/webflow/engine/ViewVariable.java new file mode 100644 index 00000000..3f7dbdd7 --- /dev/null +++ b/spring-webflow/src/main/java/org/springframework/webflow/engine/ViewVariable.java @@ -0,0 +1,50 @@ +package org.springframework.webflow.engine; + +import org.springframework.webflow.execution.RequestContext; + +public class ViewVariable extends AnnotatedObject { + private String name; + + private VariableValueFactory valueFactory; + + public ViewVariable(String name, VariableValueFactory valueFactory) { + this.name = name; + this.valueFactory = valueFactory; + } + + public String getName() { + return name; + } + + public VariableValueFactory getValueFactory() { + return valueFactory; + } + + // name and scope based equality + + public boolean equals(Object o) { + if (!(o instanceof ViewVariable)) { + return false; + } + ViewVariable other = (ViewVariable) o; + return name.equals(other.name) && valueFactory.equals(other.valueFactory); + } + + public int hashCode() { + return name.hashCode() + valueFactory.hashCode(); + } + + public final void create(RequestContext context) { + Object value = valueFactory.createVariableValue(context); + context.getFlowScope().put(name, value); + } + + public final Object restore(RequestContext context) { + Object value = context.getFlowScope().get(name); + return valueFactory.restoreReferences(value, context); + } + + public final Object destroy(RequestContext context) { + return context.getFlowScope().remove(name); + } +} diff --git a/spring-webflow/src/main/java/org/springframework/webflow/engine/builder/FlowArtifactFactory.java b/spring-webflow/src/main/java/org/springframework/webflow/engine/builder/FlowArtifactFactory.java index 42477416..d7af8e78 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/engine/builder/FlowArtifactFactory.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/engine/builder/FlowArtifactFactory.java @@ -30,6 +30,7 @@ import org.springframework.webflow.engine.Transition; import org.springframework.webflow.engine.TransitionCriteria; import org.springframework.webflow.engine.TransitionableState; import org.springframework.webflow.engine.ViewState; +import org.springframework.webflow.engine.ViewVariable; import org.springframework.webflow.execution.Action; import org.springframework.webflow.execution.ViewFactory; @@ -38,7 +39,7 @@ import org.springframework.webflow.execution.ViewFactory; * {@link Transition transitions}. *
* This factory encapsulates the construction of each Flow implementation as well as each core artifact type. Subclasses
- * may customize how the core elements are created, useful for plugging in custom implementations.
+ * may customize how the core elements are created.
*
* @author Keith Donald
* @author Erwin Vervaet
@@ -69,6 +70,7 @@ public class FlowArtifactFactory {
* @param entryActions any state entry actions; may be null
* @param viewFactory the state view factory strategy
* @param redirect whether to send a flow execution redirect before rendering
+ * @param popup whether to display the view in a popup window
* @param renderActions any 'render actions' to execute on entry and refresh; may be null
* @param transitions any transitions (paths) out of this state; may be null
* @param exceptionHandlers any exception handlers; may be null
@@ -77,11 +79,13 @@ public class FlowArtifactFactory {
* null
* @return the fully initialized view state instance
*/
- public State createViewState(String id, Flow flow, Action[] entryActions, ViewFactory viewFactory,
- boolean redirect, Action[] renderActions, Transition[] transitions,
+ public State createViewState(String id, Flow flow, ViewVariable[] variables, Action[] entryActions,
+ ViewFactory viewFactory, boolean redirect, boolean popup, Action[] renderActions, Transition[] transitions,
FlowExecutionExceptionHandler[] exceptionHandlers, Action[] exitActions, AttributeMap attributes) {
ViewState viewState = new ViewState(flow, id, viewFactory);
+ viewState.addVariables(variables);
viewState.setRedirect(redirect);
+ viewState.setPopup(popup);
viewState.getRenderActionList().addAll(renderActions);
configureCommonProperties(viewState, entryActions, transitions, exceptionHandlers, exitActions, attributes);
return viewState;
diff --git a/spring-webflow/src/main/java/org/springframework/webflow/engine/builder/support/ActionExecutingViewFactory.java b/spring-webflow/src/main/java/org/springframework/webflow/engine/builder/support/ActionExecutingViewFactory.java
index 21a1ad47..588ea513 100644
--- a/spring-webflow/src/main/java/org/springframework/webflow/engine/builder/support/ActionExecutingViewFactory.java
+++ b/spring-webflow/src/main/java/org/springframework/webflow/engine/builder/support/ActionExecutingViewFactory.java
@@ -65,7 +65,9 @@ public class ActionExecutingViewFactory implements ViewFactory {
}
public void render() {
- ActionExecutor.execute(action, context);
+ if (action != null) {
+ ActionExecutor.execute(action, context);
+ }
}
}
diff --git a/spring-webflow/src/main/java/org/springframework/webflow/engine/builder/xml/XmlFlowBuilder.java b/spring-webflow/src/main/java/org/springframework/webflow/engine/builder/xml/XmlFlowBuilder.java
index e0885283..188ead31 100644
--- a/spring-webflow/src/main/java/org/springframework/webflow/engine/builder/xml/XmlFlowBuilder.java
+++ b/spring-webflow/src/main/java/org/springframework/webflow/engine/builder/xml/XmlFlowBuilder.java
@@ -16,6 +16,7 @@
package org.springframework.webflow.engine.builder.xml;
import java.io.IOException;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
@@ -43,6 +44,7 @@ import org.springframework.binding.method.MethodSignature;
import org.springframework.binding.method.Parameter;
import org.springframework.binding.method.Parameters;
import org.springframework.context.ApplicationContext;
+import org.springframework.context.annotation.AnnotationConfigUtils;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
@@ -70,6 +72,7 @@ import org.springframework.webflow.engine.TargetStateResolver;
import org.springframework.webflow.engine.Transition;
import org.springframework.webflow.engine.TransitionCriteria;
import org.springframework.webflow.engine.VariableValueFactory;
+import org.springframework.webflow.engine.ViewVariable;
import org.springframework.webflow.engine.builder.FlowArtifactFactory;
import org.springframework.webflow.engine.builder.FlowBuilderException;
import org.springframework.webflow.engine.builder.support.AbstractFlowBuilder;
@@ -435,7 +438,8 @@ public class XmlFlowBuilder extends AbstractFlowBuilder implements ResourceHolde
+ importElement.getAttribute(RESOURCE_ATTRIBUTE) + "'", e);
}
}
- this.localFlowBuilderContext = new LocalFlowBuilderContext(getContext(), createFlowApplicationContext(resources));
+ this.localFlowBuilderContext = new LocalFlowBuilderContext(getContext(),
+ createFlowApplicationContext(resources));
}
private GenericApplicationContext createFlowApplicationContext(Resource[] resources) {
@@ -459,6 +463,7 @@ public class XmlFlowBuilder extends AbstractFlowBuilder implements ResourceHolde
}
}
flowContext.setResourceLoader(new FlowRelativeResourceLoader(resource));
+ AnnotationConfigUtils.registerAnnotationConfigProcessors(flowContext);
new XmlBeanDefinitionReader(flowContext).loadBeanDefinitions(resources);
registerFlowBeans(flowContext.getDefaultListableBeanFactory());
flowContext.refresh();
@@ -561,14 +566,35 @@ public class XmlFlowBuilder extends AbstractFlowBuilder implements ResourceHolde
}
private void parseAndAddViewState(Element element, Flow flow) {
- ViewInfo viewInfo = parseViewInfo(element);
+ ViewFactory viewFactory = parseViewFactory(element);
boolean redirect = false;
- if (viewInfo.redirect != null) {
- redirect = viewInfo.redirect.booleanValue();
+ if (element.hasAttribute("redirect")) {
+ redirect = ((Boolean) fromStringTo(Boolean.class).execute(element.getAttribute("redirect"))).booleanValue();
}
- getFlowArtifactFactory().createViewState(parseId(element), flow, parseEntryActions(element),
- viewInfo.viewFactory, redirect, parseRenderActions(element), parseTransitions(element),
- parseExceptionHandlers(element), parseExitActions(element), parseAttributes(element));
+ boolean popup = false;
+ if (element.hasAttribute("popup")) {
+ popup = ((Boolean) fromStringTo(Boolean.class).execute(element.getAttribute("popup"))).booleanValue();
+ }
+ getFlowArtifactFactory().createViewState(parseId(element), flow, parseViewVariables(element),
+ parseEntryActions(element), viewFactory, redirect, popup, parseRenderActions(element),
+ parseTransitions(element), parseExceptionHandlers(element), parseExitActions(element),
+ parseAttributes(element));
+ }
+
+ private ViewVariable[] parseViewVariables(Element viewStateElement) {
+ List varElements = DomUtils.getChildElementsByTagName(viewStateElement, VAR_ELEMENT);
+ List variables = new ArrayList(varElements.size());
+ for (Iterator it = varElements.iterator(); it.hasNext();) {
+ variables.add(parseViewVariable((Element) it.next()));
+ }
+ return (ViewVariable[]) variables.toArray(new ViewVariable[variables.size()]);
+ }
+
+ private ViewVariable parseViewVariable(Element element) {
+ Class clazz = (Class) fromStringTo(Class.class).execute(element.getAttribute(CLASS_ATTRIBUTE));
+ VariableValueFactory valueFactory = new BeanFactoryVariableValueFactory(clazz,
+ (AutowireCapableBeanFactory) getFlow().getBeanFactory());
+ return new ViewVariable(element.getAttribute("name"), valueFactory);
}
private void parseAndAddDecisionState(Element element, Flow flow) {
@@ -602,41 +628,38 @@ public class XmlFlowBuilder extends AbstractFlowBuilder implements ResourceHolde
}
}
- private ViewInfo parseViewInfo(Element element) {
+ private ViewFactory parseViewFactory(Element element) {
String encodedView = element.getAttribute(VIEW_ATTRIBUTE);
- if (encodedView == null || encodedView.length() == 0) {
- // TODO what to do here?
- return null;
- } else if (encodedView.startsWith(REDIRECT_PREFIX)) {
- String encodedViewName = encodedView.substring(REDIRECT_PREFIX.length());
- Expression viewName = getExpressionParser().parseExpression(encodedViewName,
+ if (!StringUtils.hasText(encodedView)) {
+ encodedView = createViewId(element.getAttribute(ID_ATTRIBUTE));
+ Expression viewName = getExpressionParser().parseExpression(encodedView,
new ParserContextImpl().eval(RequestContext.class).expect(String.class));
- ViewFactory viewFactory = getLocalContext().getViewFactoryCreator().createViewFactory(viewName,
+ return getLocalContext().getViewFactoryCreator().createViewFactory(viewName,
getLocalContext().getResourceLoader());
- return new ViewInfo(viewFactory, Boolean.TRUE);
} else if (encodedView.startsWith(EXTERNAL_REDIRECT_PREFIX)) {
String encodedUrl = encodedView.substring(EXTERNAL_REDIRECT_PREFIX.length());
Expression externalUrl = getExpressionParser().parseExpression(encodedUrl,
new ParserContextImpl().eval(RequestContext.class).expect(String.class));
- ViewFactory viewFactory = new ActionExecutingViewFactory(new ExternalRedirectAction(externalUrl));
- return new ViewInfo(viewFactory, Boolean.FALSE);
+ return new ActionExecutingViewFactory(new ExternalRedirectAction(externalUrl));
} else if (encodedView.startsWith(FLOW_DEFINITION_REDIRECT_PREFIX)) {
String flowRedirect = encodedView.substring(FLOW_DEFINITION_REDIRECT_PREFIX.length());
- ViewFactory viewFactory = new ActionExecutingViewFactory(FlowDefinitionRedirectAction.create(flowRedirect));
- return new ViewInfo(viewFactory, Boolean.FALSE);
+ return new ActionExecutingViewFactory(FlowDefinitionRedirectAction.create(flowRedirect));
} else if (encodedView.startsWith(BEAN_PREFIX)) {
- ViewFactory viewFactory = (ViewFactory) getLocalContext().getBeanFactory().getBean(
+ return (ViewFactory) getLocalContext().getBeanFactory().getBean(
encodedView.substring(BEAN_PREFIX.length()), ViewFactory.class);
- return new ViewInfo(viewFactory, Boolean.FALSE);
} else {
Expression viewName = getExpressionParser().parseExpression(encodedView,
new ParserContextImpl().eval(RequestContext.class).expect(String.class));
- ViewFactory viewFactory = getLocalContext().getViewFactoryCreator().createViewFactory(viewName,
+ return getLocalContext().getViewFactoryCreator().createViewFactory(viewName,
getLocalContext().getResourceLoader());
- return new ViewInfo(viewFactory, null);
}
}
+ // TODO - make configurable
+ private String createViewId(String viewStateId) {
+ return viewStateId + ".html";
+ }
+
private Action parseFinalResponseAction(Element element) {
String encodedView = element.getAttribute(VIEW_ATTRIBUTE);
if (encodedView == null || encodedView.length() == 0) {
@@ -1123,12 +1146,14 @@ public class XmlFlowBuilder extends AbstractFlowBuilder implements ResourceHolde
private ViewFactory viewFactory;
- private Boolean redirect;
-
- public ViewInfo(ViewFactory viewFactory, Boolean redirect) {
+ public ViewInfo(ViewFactory viewFactory) {
this.viewFactory = viewFactory;
- this.redirect = redirect;
}
+
+ public ViewFactory getViewFactory() {
+ return viewFactory;
+ }
+
}
private static class FlowRelativeResourceLoader implements ResourceLoader {
diff --git a/spring-webflow/src/main/java/org/springframework/webflow/engine/builder/xml/spring-webflow-2.0.xsd b/spring-webflow/src/main/java/org/springframework/webflow/engine/builder/xml/spring-webflow-2.0.xsd
index 7e40f5f2..df534a93 100644
--- a/spring-webflow/src/main/java/org/springframework/webflow/engine/builder/xml/spring-webflow-2.0.xsd
+++ b/spring-webflow/src/main/java/org/springframework/webflow/engine/builder/xml/spring-webflow-2.0.xsd
@@ -1294,7 +1294,17 @@ An attribute describing this state.
]]>
-
+
+
${flowScope.view}
-Use of the "redirect:" prefix indicates this view state should trigger a redirect to a
-unique "flow execution URL". This causes the application view to render on the
-redirected request to that URL. This allows browsers to refresh a specific
-state of the conversation while it remains active:
-
- redirect:priceForm
-
Use of the "externalRedirect:" prefix indicates this view state should trigger a
redirect to an absolute external URL, typically to interface with an external system.
External redirect query parameters may be specified using ${expressions} that evaluate
@@ -1379,27 +1382,43 @@ against the request context:
externalRedirect:/someOtherSystem.htm?orderId=${flowScope.order.id}
-Use of the "flowRedirect:" prefix has this view state generate a redirect to a URL
-that launches a new flow execution of an identified flow:
+Use of the "flowRedirect:" prefix requests a redirect to a new execution of another flow:
- flowRedirect:editOrderFlow?orderId=${flowScope.order.id}
+ flowRedirect:myOtherFlow?someData=${flowScope.data}
-Use of the "bean:" prefix references a custom ViewSelector implementation you define,
+Use of the "bean:" prefix references a custom ViewFactory implementation you define,
exposed by id in either a flow-local context using the "import" element or in the parent
context.
- bean:myCustomViewSelector
+ bean:myCustomViewFactory
-The exact semantics regarding the interpretation of this value are determined by the
-installed TextToViewSelector converter.
-Note when no view name is provided, this view state will make a "null" view selection. A null
-view does not request the rendering of a view, it only pauses the flow and returns control
-the client. Use a null view when another state is expected to generate the response.
+Note when no view name is provided, the view to render will be determined by convention.
+The default convention is to treat the id of this view state as the view identifier.
]]>