flow outcome modeling

flow possible outcomes
This commit is contained in:
Keith Donald
2008-04-22 22:13:04 +00:00
parent 9db8910b0a
commit 5486b2c8d7
35 changed files with 260 additions and 192 deletions

View File

@@ -63,6 +63,12 @@ public interface FlowDefinition extends Annotated {
*/
public StateDefinition getState(String id) throws IllegalArgumentException;
/**
* Returns the outcomes that are possible for this flow to reach.
* @return the possible outcomes
*/
public String[] getPossibleOutcomes();
/**
* Returns a reference to application context hosting application objects and services needed by this flow
* definition.

View File

@@ -20,7 +20,6 @@ import org.springframework.binding.mapping.MappingResults;
import org.springframework.core.style.ToStringCreator;
import org.springframework.webflow.core.collection.LocalAttributeMap;
import org.springframework.webflow.execution.Action;
import org.springframework.webflow.execution.Event;
import org.springframework.webflow.execution.FlowExecutionException;
import org.springframework.webflow.execution.FlowSession;
import org.springframework.webflow.execution.RequestContext;
@@ -99,12 +98,11 @@ public class EndState extends State {
if (finalResponseAction != null && context.getExternalContext().isResponseAllowed()) {
ActionExecutor.execute(finalResponseAction, context);
}
context.endActiveFlowSession(createSessionOutput(context));
context.endActiveFlowSession(getId(), createSessionOutput(context));
} else {
// there is a parent flow that will resume (this flow is a subflow)
LocalAttributeMap sessionOutput = createSessionOutput(context);
context.endActiveFlowSession(sessionOutput);
context.handleEvent(new Event(this, getId(), sessionOutput));
context.endActiveFlowSession(getId(), sessionOutput);
}
}

View File

@@ -15,9 +15,11 @@
*/
package org.springframework.webflow.engine;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -76,16 +78,17 @@ import org.springframework.webflow.execution.RequestContext;
* implementations but may also be directly instantiated.
* <p>
* This class and the rest of the Spring Web Flow (SWF) engine have been designed with minimal dependencies on other
* libraries. Spring Web Flow is usable in a standalone fashion (as well as in the context of other frameworks like
* Spring MVC, Struts, or JSF, for example). The engine system is fully usable outside an HTTP servlet environment, for
* example in portlets, tests, or standalone applications. One of the major architectural benefits of Spring Web Flow is
* the ability to design reusable, high-level controller modules that may be executed in <i>any</i> environment.
* libraries. Spring Web Flow is usable in a standalone fashion. The engine system is fully usable outside an HTTP
* servlet environment, for example in portlets, tests, or standalone applications. One of the major architectural
* benefits of Spring Web Flow is the ability to design reusable, high-level controller modules that may be executed in
* <i>any</i> environment.
* <p>
* Note: flows are singleton definition objects so they should be thread-safe. You can think a flow definition as
* analogous to a Java class, defining all the behavior of an application module. The core behaviors
* {@link #start(RequestControlContext, MutableAttributeMap) start}, {@link #resume(RequestControlContext)},
* {@link #handleEvent(RequestControlContext) on event}, {@link #end(RequestControlContext, MutableAttributeMap) end},
* and {@link #handleException(FlowExecutionException, RequestControlContext)}. Each method accepts a
* {@link #handleEvent(RequestControlContext) on event},
* {@link #end(RequestControlContext, String, MutableAttributeMap) end}, and
* {@link #handleException(FlowExecutionException, RequestControlContext)}. Each method accepts a
* {@link RequestContext request context} that allows for this flow to access execution state in a thread safe manner. A
* flow execution is what models a running instance of this flow definition, somewhat analogous to a java object that is
* an instance of a class.
@@ -210,6 +213,17 @@ public class Flow extends AnnotatedObject implements FlowDefinition {
return getStateInstance(stateId);
}
public String[] getPossibleOutcomes() {
List possibleOutcomes = new ArrayList();
for (Iterator it = states.iterator(); it.hasNext();) {
State state = (State) it.next();
if (state instanceof EndState) {
possibleOutcomes.add(state.getId());
}
}
return (String[]) possibleOutcomes.toArray(new String[possibleOutcomes.size()]);
}
public ApplicationContext getApplicationContext() {
return applicationContext;
}
@@ -541,10 +555,13 @@ public class Flow extends AnnotatedObject implements FlowDefinition {
* mapper ({@link #setOutputMapper(Mapper)}).</li>
* </ol>
* @param context the flow execution control context
* @param outcome the logical flow outcome that will be returned by the session, generally the id of the terminating
* end state
* @param output initial output produced by the session that is eligible for modification by this method
* @throws FlowExecutionException when an exception occurs ending this flow
*/
public void end(RequestControlContext context, MutableAttributeMap output) throws FlowExecutionException {
public void end(RequestControlContext context, String outcome, MutableAttributeMap output)
throws FlowExecutionException {
endActionList.execute(context);
if (outputMapper != null) {
MappingResults results = outputMapper.map(context, output);
@@ -584,7 +601,7 @@ public class Flow extends AnnotatedObject implements FlowDefinition {
}
}
private void restoreVariables(RequestContext context) {
public void restoreVariables(RequestContext context) {
Iterator it = variables.values().iterator();
while (it.hasNext()) {
FlowVariable variable = (FlowVariable) it.next();

View File

@@ -20,7 +20,6 @@ import org.springframework.webflow.execution.Event;
import org.springframework.webflow.execution.FlowExecutionContext;
import org.springframework.webflow.execution.FlowExecutionException;
import org.springframework.webflow.execution.FlowExecutionKey;
import org.springframework.webflow.execution.FlowSession;
import org.springframework.webflow.execution.RequestContext;
import org.springframework.webflow.execution.View;
@@ -132,12 +131,12 @@ public interface RequestControlContext extends RequestContext {
* End the active flow session of the current flow execution. This method should be called by clients that terminate
* flows, such as end states. The <code>end()</code> method of the flow involved in the flow execution will be
* called.
* @param output output produced by the session that is eligible for mapping by a resuming parent flow
* @return the ended session
* @param outcome the logical outcome the ending session should return
* @param output output the ending session should return
* @throws IllegalStateException when the flow execution is not active
* @see Flow#end(RequestControlContext, MutableAttributeMap)
* @see Flow#end(RequestControlContext, String, MutableAttributeMap)
*/
public FlowSession endActiveFlowSession(MutableAttributeMap output) throws IllegalStateException;
public void endActiveFlowSession(String outcome, MutableAttributeMap output) throws IllegalStateException;
/**
* Returns true if the 'always redirect pause' flow execution attribute is set to true, false otherwise.

View File

@@ -46,6 +46,7 @@ import org.springframework.webflow.execution.FlowExecutionException;
import org.springframework.webflow.execution.FlowExecutionKey;
import org.springframework.webflow.execution.FlowExecutionKeyFactory;
import org.springframework.webflow.execution.FlowExecutionListener;
import org.springframework.webflow.execution.FlowExecutionOutcome;
import org.springframework.webflow.execution.FlowSession;
import org.springframework.webflow.execution.RequestContext;
import org.springframework.webflow.execution.RequestContextHolder;
@@ -134,9 +135,9 @@ public class FlowExecutionImpl implements FlowExecution, Externalizable {
private String flowId;
/**
* The flow execution outcome event.
* The outcome reached by this flow execution when it ends.
*/
private transient Event outcome;
private transient FlowExecutionOutcome outcome;
/**
* Default constructor required for externalizable serialization. Should NOT be called programmatically.
@@ -195,7 +196,7 @@ public class FlowExecutionImpl implements FlowExecution, Externalizable {
return hasStarted() && !isActive();
}
public Event getOutcome() {
public FlowExecutionOutcome getOutcome() {
return outcome;
}
@@ -383,16 +384,23 @@ public class FlowExecutionImpl implements FlowExecution, Externalizable {
return transition.execute(getCurrentState(), context);
}
FlowSession endActiveFlowSession(MutableAttributeMap output, RequestControlContext context) {
void endActiveFlowSession(String outcome, MutableAttributeMap output, RequestControlContext context) {
FlowSessionImpl session = getActiveSessionInternal();
listeners.fireSessionEnding(context, session, output);
session.getFlow().end(context, output);
listeners.fireSessionEnding(context, session, outcome, output);
session.getFlow().end(context, outcome, output);
flowSessions.removeLast();
listeners.fireSessionEnded(context, session, output);
if (hasEnded()) {
outcome = new Event(this, session.getState().getId(), output);
boolean executionEnded = hasEnded();
if (executionEnded) {
// set the root flow execution outcome for external clients to use
this.outcome = new FlowExecutionOutcome(outcome, output);
}
listeners.fireSessionEnded(context, session, outcome, output);
if (!executionEnded) {
// restore any variables that may have transient references
getActiveSessionInternal().getFlow().restoreVariables(context);
// treat the outcome as an event against the current state of the new active flow
context.handleEvent(new Event(session.getState(), outcome, output));
}
return session;
}
FlowExecutionKey assignKey() {

View File

@@ -202,18 +202,19 @@ class FlowExecutionListeners {
/**
* Notify all interested listeners that the active flow execution session is ending.
*/
public void fireSessionEnding(RequestContext context, FlowSession session, MutableAttributeMap output) {
public void fireSessionEnding(RequestContext context, FlowSession session, String outcomeId,
MutableAttributeMap output) {
for (int i = 0; i < listeners.length; i++) {
listeners[i].sessionEnding(context, session, output);
listeners[i].sessionEnding(context, session, outcomeId, output);
}
}
/**
* Notify all interested listeners that a flow execution session has ended.
*/
public void fireSessionEnded(RequestContext context, FlowSession session, AttributeMap output) {
public void fireSessionEnded(RequestContext context, FlowSession session, String outcomeId, AttributeMap output) {
for (int i = 0; i < listeners.length; i++) {
listeners[i].sessionEnded(context, session, output);
listeners[i].sessionEnded(context, session, outcomeId, output);
}
}

View File

@@ -32,7 +32,6 @@ import org.springframework.webflow.execution.Event;
import org.springframework.webflow.execution.FlowExecutionContext;
import org.springframework.webflow.execution.FlowExecutionException;
import org.springframework.webflow.execution.FlowExecutionKey;
import org.springframework.webflow.execution.FlowSession;
import org.springframework.webflow.execution.View;
/**
@@ -218,8 +217,8 @@ class RequestControlContextImpl implements RequestControlContext {
flowExecution.start(flow, input, this);
}
public FlowSession endActiveFlowSession(MutableAttributeMap output) throws IllegalStateException {
return flowExecution.endActiveFlowSession(output, this);
public void endActiveFlowSession(String outcome, MutableAttributeMap output) throws IllegalStateException {
flowExecution.endActiveFlowSession(outcome, output, this);
}
public boolean getAlwaysRedirectOnPause() {

View File

@@ -84,10 +84,10 @@ public interface FlowExecutionContext {
public boolean hasEnded();
/**
* Returns the ending outcome event of this execution, or null if this execution has not yet ended.
* @return the outcome event
* Returns the outcome reached by this execution, or null if this execution has not yet ended.
* @return the outcome, or <code>null</code> if this execution has not yet ended
*/
public Event getOutcome();
public FlowExecutionOutcome getOutcome();
/**
* Returns the active flow session of this flow execution. The active flow session is the currently executing

View File

@@ -153,19 +153,21 @@ public interface FlowExecutionListener {
* Called when the active flow execution session has been asked to end but before it has ended.
* @param context the current flow request context
* @param session the current active session that is ending
* @param outcome the outcome reached by the ending session, generally the id of the terminating end-state
* @param output the flow output produced by the ending session, this map may be modified by this listener to affect
* the output returned
*/
public void sessionEnding(RequestContext context, FlowSession session, MutableAttributeMap output);
public void sessionEnding(RequestContext context, FlowSession session, String outcome, MutableAttributeMap output);
/**
* Called when a flow execution session ends. If the ended session was the root session of the flow execution, the
* entire flow execution also ends.
* @param context the current flow request context
* @param session ending flow session
* @param output final, unmodifiable output returned by the ended session
* @param outcome the outcome reached by the ended session, generally the id of the terminating end-state
* @param output the flow output returned by the ending session
*/
public void sessionEnded(RequestContext context, FlowSession session, AttributeMap output);
public void sessionEnded(RequestContext context, FlowSession session, String outcome, AttributeMap output);
/**
* Called when an exception is thrown during a flow execution, before the exception is handled by any registered

View File

@@ -70,10 +70,10 @@ public abstract class FlowExecutionListenerAdapter implements FlowExecutionListe
public void resuming(RequestContext context) {
}
public void sessionEnding(RequestContext context, FlowSession session, MutableAttributeMap output) {
public void sessionEnding(RequestContext context, FlowSession session, String outcome, MutableAttributeMap output) {
}
public void sessionEnded(RequestContext context, FlowSession session, AttributeMap output) {
public void sessionEnded(RequestContext context, FlowSession session, String outcome, AttributeMap output) {
}
public void exceptionThrown(RequestContext context, FlowExecutionException exception) {

View File

@@ -0,0 +1,49 @@
package org.springframework.webflow.execution;
import org.springframework.core.style.ToStringCreator;
import org.springframework.webflow.core.collection.AttributeMap;
import org.springframework.webflow.core.collection.CollectionUtils;
/**
* An outcome returned by a flow execution when it ends.
*
* @author Keith Donald
*/
public class FlowExecutionOutcome {
private String id;
private AttributeMap output;
/**
* Creates a new flow execution outcome
* @param id the outcome id
* @param output the output returned by the execution
*/
public FlowExecutionOutcome(String id, AttributeMap output) {
super();
this.id = id;
this.output = (output != null ? output : CollectionUtils.EMPTY_ATTRIBUTE_MAP);
}
/**
* Return the outcome identifier.
* @return the outcome that was reached by the flow execution
*/
public String getId() {
return id;
}
/**
* Returns the output returned by the flow execution.
* @return the output that was returned
*/
public AttributeMap getOutput() {
return output;
}
public String toString() {
return new ToStringCreator(this).append("id", id).append("output", output).toString();
}
}

View File

@@ -15,8 +15,7 @@
*/
package org.springframework.webflow.executor;
import org.springframework.webflow.core.collection.AttributeMap;
import org.springframework.webflow.execution.Event;
import org.springframework.webflow.execution.FlowExecutionOutcome;
/**
* A value object providing information about the result of a flow execution request.
@@ -29,15 +28,12 @@ public class FlowExecutionResult {
private String flowExecutionKey;
private String outcome;
private FlowExecutionOutcome outcome;
private AttributeMap output;
private FlowExecutionResult(String flowId, String flowExecutionKey, String outcome, AttributeMap output) {
private FlowExecutionResult(String flowId, String flowExecutionKey, FlowExecutionOutcome outcome) {
this.flowId = flowId;
this.flowExecutionKey = flowExecutionKey;
this.outcome = outcome;
this.output = output;
}
/**
@@ -48,7 +44,7 @@ public class FlowExecutionResult {
* @return the result
*/
public static FlowExecutionResult createPausedResult(String flowId, String flowExecutionKey) {
return new FlowExecutionResult(flowId, flowExecutionKey, null, null);
return new FlowExecutionResult(flowId, flowExecutionKey, null);
}
/**
@@ -57,8 +53,8 @@ public class FlowExecutionResult {
* @param outcome the ending execution outcome
* @return the result
*/
public static FlowExecutionResult createEndedResult(String flowId, Event outcome) {
return new FlowExecutionResult(flowId, null, outcome.getId(), outcome.getAttributes());
public static FlowExecutionResult createEndedResult(String flowId, FlowExecutionOutcome outcome) {
return new FlowExecutionResult(flowId, null, outcome);
}
/**
@@ -95,21 +91,12 @@ public class FlowExecutionResult {
}
/**
* Returns the flow execution outcome when ab ended result.
* Returns the flow execution outcome when an ended result.
* @see #ended()
* @return the ended outcome
* @return the ended outcome, or <code>null</code> if this is not an ended result
*/
public String getEndedOutcome() {
public FlowExecutionOutcome getOutcome() {
return outcome;
}
/**
* Returns the output returned from the flow execution when an ended result.
* @see #ended()
* @return the ended output
*/
public AttributeMap getEndedOutput() {
return output;
}
}

View File

@@ -21,8 +21,8 @@ import javax.portlet.RenderResponse;
import org.springframework.web.portlet.ModelAndView;
import org.springframework.webflow.core.FlowException;
import org.springframework.webflow.core.collection.AttributeMap;
import org.springframework.webflow.core.collection.MutableAttributeMap;
import org.springframework.webflow.execution.FlowExecutionOutcome;
/**
* Trivial flow handler base class that simply returns null for all operations. Subclasses should extend and override
@@ -44,7 +44,7 @@ public class AbstractFlowHandler implements FlowHandler {
return null;
}
public String handleFlowOutcome(String outcome, AttributeMap output, RenderRequest request, RenderResponse response) {
public String handleFlowOutcome(FlowExecutionOutcome outcome, RenderRequest request, RenderResponse response) {
return null;
}

View File

@@ -21,8 +21,8 @@ import javax.portlet.RenderResponse;
import org.springframework.web.portlet.ModelAndView;
import org.springframework.webflow.core.FlowException;
import org.springframework.webflow.core.collection.AttributeMap;
import org.springframework.webflow.core.collection.MutableAttributeMap;
import org.springframework.webflow.execution.FlowExecutionOutcome;
/**
* A controller helper used for customizing access to a <i>single</i> flow definition. This helper is used to:
@@ -55,13 +55,12 @@ public interface FlowHandler {
/**
* Handles a specific flow execution outcome. Used to select a new view to render after the flow ends.
* @param outcome the outcome that was reached
* @param output the output returned by the flow execution
* @param request the current render request
* @param response the current render response
* @return the id of the flow to start after handling the outcome, or null if the outcome should be handled by the
* caller
*/
public String handleFlowOutcome(String outcome, AttributeMap output, RenderRequest request, RenderResponse response);
public String handleFlowOutcome(FlowExecutionOutcome outcome, RenderRequest request, RenderResponse response);
/**
* Handles a flow exception that was not handled by the Web Flow system. Used by a Controller to handle a specific

View File

@@ -34,9 +34,9 @@ import org.springframework.webflow.context.portlet.DefaultFlowUrlHandler;
import org.springframework.webflow.context.portlet.FlowUrlHandler;
import org.springframework.webflow.context.portlet.PortletExternalContext;
import org.springframework.webflow.core.FlowException;
import org.springframework.webflow.core.collection.AttributeMap;
import org.springframework.webflow.core.collection.LocalAttributeMap;
import org.springframework.webflow.core.collection.MutableAttributeMap;
import org.springframework.webflow.execution.FlowExecutionOutcome;
import org.springframework.webflow.execution.repository.NoSuchFlowExecutionException;
import org.springframework.webflow.executor.FlowExecutionResult;
import org.springframework.webflow.executor.FlowExecutor;
@@ -88,10 +88,8 @@ public class FlowHandlerAdapter extends PortletApplicationObjectSupport implemen
.getAttribute(FLOW_EXECUTION_RESULT_ATTRIBUTE);
if (result != null) {
session.removeAttribute(FLOW_EXECUTION_RESULT_ATTRIBUTE);
String outcome = result.getEndedOutcome();
AttributeMap output = result.getEndedOutput();
String flowId = flowHandler.handleFlowOutcome(outcome, output, request, response);
return defaultHandleFlowOutcome(flowHandler, outcome, output, flowId, request, response);
String flowId = flowHandler.handleFlowOutcome(result.getOutcome(), request, response);
return defaultHandleFlowOutcome(flowHandler, result.getOutcome(), flowId, request, response);
} else {
return startFlow(request, response, flowHandler);
}
@@ -145,7 +143,7 @@ public class FlowHandlerAdapter extends PortletApplicationObjectSupport implemen
return inputMap;
}
protected ModelAndView defaultHandleFlowOutcome(FlowHandler flowHandler, String outcome, AttributeMap output,
protected ModelAndView defaultHandleFlowOutcome(FlowHandler flowHandler, FlowExecutionOutcome outcome,
String nextFlowId, RenderRequest request, RenderResponse response) throws IOException {
if (nextFlowId == null) {
nextFlowId = flowHandler.getFlowId();
@@ -154,7 +152,7 @@ public class FlowHandlerAdapter extends PortletApplicationObjectSupport implemen
logger.debug("Starting a new execution of flow '" + nextFlowId + "'");
}
PortletExternalContext context = createPortletExternalContext(request, response);
flowExecutor.launchExecution(nextFlowId, new LocalAttributeMap(output.asMap()), context);
flowExecutor.launchExecution(nextFlowId, new LocalAttributeMap(outcome.getOutput().asMap()), context);
return null;
}

View File

@@ -19,8 +19,8 @@ import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.webflow.core.FlowException;
import org.springframework.webflow.core.collection.AttributeMap;
import org.springframework.webflow.core.collection.MutableAttributeMap;
import org.springframework.webflow.execution.FlowExecutionOutcome;
/**
* Trivial flow handler base class that simply returns null for all operations. Subclasses should extend and override
@@ -38,7 +38,7 @@ public class AbstractFlowHandler implements FlowHandler {
return null;
}
public String handleExecutionOutcome(String outcome, AttributeMap output, HttpServletRequest request,
public String handleExecutionOutcome(FlowExecutionOutcome outcome, HttpServletRequest request,
HttpServletResponse response) {
return null;
}

View File

@@ -35,6 +35,7 @@ import org.springframework.webflow.core.FlowException;
import org.springframework.webflow.core.collection.AttributeMap;
import org.springframework.webflow.core.collection.LocalAttributeMap;
import org.springframework.webflow.core.collection.MutableAttributeMap;
import org.springframework.webflow.execution.FlowExecutionOutcome;
import org.springframework.webflow.execution.repository.NoSuchFlowExecutionException;
import org.springframework.webflow.executor.FlowExecutionResult;
import org.springframework.webflow.executor.FlowExecutor;
@@ -195,14 +196,14 @@ public class FlowController extends AbstractController {
return inputMap;
}
protected ModelAndView defaultHandleFlowOutcome(String flowId, String outcome, AttributeMap endedOutput,
protected ModelAndView defaultHandleFlowOutcome(String flowId, FlowExecutionOutcome outcome,
HttpServletRequest request, HttpServletResponse response) throws IOException {
if (!response.isCommitted()) {
// by default, just start the flow over passing the output as input
if (logger.isDebugEnabled()) {
logger.debug("Restarting a new execution of ended flow '" + flowId + "'");
}
response.sendRedirect(urlHandler.createFlowDefinitionUrl(flowId, endedOutput, request));
response.sendRedirect(urlHandler.createFlowDefinitionUrl(flowId, outcome.getOutput(), request));
}
return null;
}
@@ -269,8 +270,7 @@ public class FlowController extends AbstractController {
sendRedirect(context, request, response, context.getExternalRedirectUrl());
return null;
} else {
return handleFlowOutcome(result.getFlowId(), result.getEndedOutcome(), result.getEndedOutput(),
request, response);
return handleFlowOutcome(result.getFlowId(), result.getOutcome(), request, response);
}
} else {
throw new IllegalStateException("Execution result should have been one of [paused] or [ended]");
@@ -295,15 +295,15 @@ public class FlowController extends AbstractController {
}
}
private ModelAndView handleFlowOutcome(String flowId, String outcome, AttributeMap endedOutput,
HttpServletRequest request, HttpServletResponse response) throws IOException {
private ModelAndView handleFlowOutcome(String flowId, FlowExecutionOutcome outcome, HttpServletRequest request,
HttpServletResponse response) throws IOException {
FlowHandler handler = getFlowHandler(flowId);
if (handler != null) {
String location = handler.handleExecutionOutcome(outcome, endedOutput, request, response);
String location = handler.handleExecutionOutcome(outcome, request, response);
return location != null ? createRedirectView(location, request) : defaultHandleFlowOutcome(flowId, outcome,
endedOutput, request, response);
request, response);
} else {
return defaultHandleFlowOutcome(flowId, outcome, endedOutput, request, response);
return defaultHandleFlowOutcome(flowId, outcome, request, response);
}
}

View File

@@ -19,8 +19,8 @@ import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.webflow.core.FlowException;
import org.springframework.webflow.core.collection.AttributeMap;
import org.springframework.webflow.core.collection.MutableAttributeMap;
import org.springframework.webflow.execution.FlowExecutionOutcome;
/**
* A controller helper used for customizing access to a <i>single</i> flow definition. This helper is used to:
@@ -59,13 +59,12 @@ public interface FlowHandler {
* to the current servlet path.
*
* @param outcome the outcome that was reached
* @param output the output returned by the flow execution
* @param request the current request
* @param response the current response
* @return the location of the new resource to redirect to, or null if the execution outcome was not handled and
* should be handled by the caller
*/
public String handleExecutionOutcome(String outcome, AttributeMap output, HttpServletRequest request,
public String handleExecutionOutcome(FlowExecutionOutcome outcome, HttpServletRequest request,
HttpServletResponse response);
/**

View File

@@ -35,6 +35,7 @@ import org.springframework.webflow.core.FlowException;
import org.springframework.webflow.core.collection.AttributeMap;
import org.springframework.webflow.core.collection.LocalAttributeMap;
import org.springframework.webflow.core.collection.MutableAttributeMap;
import org.springframework.webflow.execution.FlowExecutionOutcome;
import org.springframework.webflow.execution.repository.NoSuchFlowExecutionException;
import org.springframework.webflow.executor.FlowExecutionResult;
import org.springframework.webflow.executor.FlowExecutor;
@@ -159,14 +160,14 @@ public class FlowHandlerAdapter extends WebApplicationObjectSupport implements H
return inputMap;
}
protected ModelAndView defaultHandleFlowOutcome(String flowId, String outcome, AttributeMap endedOutput,
protected ModelAndView defaultHandleFlowOutcome(String flowId, FlowExecutionOutcome outcome,
HttpServletRequest request, HttpServletResponse response) throws IOException {
if (!response.isCommitted()) {
// by default, just start the flow over passing the output as input
if (logger.isDebugEnabled()) {
logger.debug("Restarting a new execution of ended flow '" + flowId + "'");
}
response.sendRedirect(urlHandler.createFlowDefinitionUrl(flowId, endedOutput, request));
response.sendRedirect(urlHandler.createFlowDefinitionUrl(flowId, outcome.getOutput(), request));
}
return null;
}
@@ -225,10 +226,9 @@ public class FlowHandlerAdapter extends WebApplicationObjectSupport implements H
sendRedirect(context, request, response, context.getExternalRedirectUrl());
return null;
} else {
String location = handler.handleExecutionOutcome(result.getEndedOutcome(), result.getEndedOutput(),
request, response);
String location = handler.handleExecutionOutcome(result.getOutcome(), request, response);
return location != null ? createRedirectView(location, request) : defaultHandleFlowOutcome(result
.getFlowId(), result.getEndedOutcome(), result.getEndedOutput(), request, response);
.getFlowId(), result.getOutcome(), request, response);
}
} else {
throw new IllegalStateException("Execution result should have been one of [paused] or [ended]");

View File

@@ -131,7 +131,7 @@ public class HibernateFlowExecutionListener extends FlowExecutionListenerAdapter
}
}
public void sessionEnded(RequestContext context, FlowSession session, AttributeMap output) {
public void sessionEnded(RequestContext context, FlowSession session, String outcome, AttributeMap output) {
if (isPersistenceContext(session.getDefinition())) {
final Session hibernateSession = (Session) session.getScope().remove(HIBERNATE_SESSION_ATTRIBUTE);
Boolean commitStatus = session.getState().getAttributes().getBoolean("commit");

View File

@@ -119,7 +119,7 @@ public class JpaFlowExecutionListener extends FlowExecutionListenerAdapter {
}
}
public void sessionEnded(RequestContext context, FlowSession session, AttributeMap output) {
public void sessionEnded(RequestContext context, FlowSession session, String outcome, AttributeMap output) {
if (isPersistenceContext(session.getDefinition())) {
final EntityManager em = (EntityManager) session.getScope().remove(ENTITY_MANAGER_ATTRIBUTE);
Boolean commitStatus = session.getState().getAttributes().getBoolean("commit");

View File

@@ -42,11 +42,24 @@ import org.springframework.webflow.execution.RequestContext;
*/
public class SecurityFlowExecutionListener extends FlowExecutionListenerAdapter {
AccessDecisionManager accessDecisionManager;
private AccessDecisionManager accessDecisionManager;
/**
* Check security authorization when flow session starts
* Get the access decision manager that makes flow authorization decisions.
* @return the decision manager
*/
public AccessDecisionManager getAccessDecisionManager() {
return accessDecisionManager;
}
/**
* Set the access decision manager that makes flow authorization decisions.
* @param accessDecisionManager the decision manager to user
*/
public void setAccessDecisionManager(AccessDecisionManager accessDecisionManager) {
this.accessDecisionManager = accessDecisionManager;
}
public void sessionCreating(RequestContext context, FlowDefinition definition) {
SecurityRule rule = (SecurityRule) definition.getAttributes().get(SecurityRule.SECURITY_ATTRIBUTE_NAME);
if (rule != null) {
@@ -54,9 +67,6 @@ public class SecurityFlowExecutionListener extends FlowExecutionListenerAdapter
}
}
/**
* Check security authorization when entering state
*/
public void stateEntering(RequestContext context, StateDefinition state) throws EnterStateVetoException {
SecurityRule rule = (SecurityRule) state.getAttributes().get(SecurityRule.SECURITY_ATTRIBUTE_NAME);
if (rule != null) {
@@ -64,9 +74,6 @@ public class SecurityFlowExecutionListener extends FlowExecutionListenerAdapter
}
}
/**
* Check security authorization on transition
*/
public void transitionExecuting(RequestContext context, TransitionDefinition transition) {
SecurityRule rule = (SecurityRule) transition.getAttributes().get(SecurityRule.SECURITY_ATTRIBUTE_NAME);
if (rule != null) {
@@ -81,7 +88,7 @@ public class SecurityFlowExecutionListener extends FlowExecutionListenerAdapter
* @param rule the rule to base the decision
* @param object the execution listener phase
*/
public void decide(SecurityRule rule, Object object) {
protected void decide(SecurityRule rule, Object object) {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
ConfigAttributeDefinition config = new ConfigAttributeDefinition(getConfigAttributes(rule));
if (accessDecisionManager != null) {
@@ -115,21 +122,4 @@ public class SecurityFlowExecutionListener extends FlowExecutionListenerAdapter
}
return configAttributes;
}
/**
* Get decision manager
* @return the decision manager
*/
public AccessDecisionManager getAccessDecisionManager() {
return accessDecisionManager;
}
/**
* Set decision manager
* @param accessDecisionManager the decision manager to user
*/
public void setAccessDecisionManager(AccessDecisionManager accessDecisionManager) {
this.accessDecisionManager = accessDecisionManager;
}
}

View File

@@ -20,9 +20,9 @@ import org.springframework.webflow.core.collection.LocalAttributeMap;
import org.springframework.webflow.core.collection.MutableAttributeMap;
import org.springframework.webflow.definition.FlowDefinition;
import org.springframework.webflow.engine.Flow;
import org.springframework.webflow.execution.Event;
import org.springframework.webflow.execution.FlowExecutionContext;
import org.springframework.webflow.execution.FlowExecutionKey;
import org.springframework.webflow.execution.FlowExecutionOutcome;
import org.springframework.webflow.execution.FlowSession;
/**
@@ -34,6 +34,8 @@ import org.springframework.webflow.execution.FlowSession;
*/
public class MockFlowExecutionContext implements FlowExecutionContext {
private boolean started;
private FlowExecutionKey key;
private FlowDefinition flow;
@@ -46,14 +48,14 @@ public class MockFlowExecutionContext implements FlowExecutionContext {
private MutableAttributeMap attributes = new LocalAttributeMap();
private Event outcome;
private FlowExecutionOutcome outcome;
/**
* Creates a new mock flow execution context -- automatically installs a root flow definition and active flow
* session.
*/
public MockFlowExecutionContext() {
activeSession = new MockFlowSession();
setActiveSession(new MockFlowSession());
this.flow = activeSession.getDefinition();
}
@@ -68,8 +70,8 @@ public class MockFlowExecutionContext implements FlowExecutionContext {
* Creates a new mock flow execution context for the specified active flow session.
*/
public MockFlowExecutionContext(FlowSession flowSession) {
setActiveSession(flowSession);
this.flow = flowSession.getDefinition();
this.activeSession = flowSession;
}
public FlowExecutionKey getKey() {
@@ -87,7 +89,7 @@ public class MockFlowExecutionContext implements FlowExecutionContext {
}
public boolean hasStarted() {
return isActive();
return started;
}
public boolean isActive() {
@@ -117,7 +119,7 @@ public class MockFlowExecutionContext implements FlowExecutionContext {
return attributes;
}
public Event getOutcome() {
public FlowExecutionOutcome getOutcome() {
return outcome;
}
@@ -148,6 +150,9 @@ public class MockFlowExecutionContext implements FlowExecutionContext {
*/
public void setActiveSession(FlowSession activeSession) {
this.activeSession = activeSession;
if (!started && activeSession != null) {
started = true;
}
}
/**
@@ -166,9 +171,9 @@ public class MockFlowExecutionContext implements FlowExecutionContext {
/**
* Sets the result of this flow ending.
* @param outcome the ending outcome event.
* @param outcome the ended outcome
*/
public void setOutcome(Event outcome) {
public void setOutcome(FlowExecutionOutcome outcome) {
this.outcome = outcome;
}

View File

@@ -24,7 +24,6 @@ import org.springframework.webflow.engine.TransitionableState;
import org.springframework.webflow.execution.Event;
import org.springframework.webflow.execution.FlowExecutionContext;
import org.springframework.webflow.execution.FlowExecutionKey;
import org.springframework.webflow.execution.FlowSession;
import org.springframework.webflow.execution.View;
/**
@@ -113,11 +112,13 @@ public class MockRequestControlContext extends MockRequestContext implements Req
flow.start(this, input);
}
public FlowSession endActiveFlowSession(MutableAttributeMap output) throws IllegalStateException {
public void endActiveFlowSession(String outcome, MutableAttributeMap output) throws IllegalStateException {
MockFlowSession endingSession = getMockFlowExecutionContext().getMockActiveSession();
endingSession.getDefinitionInternal().end(this, output);
endingSession.getDefinitionInternal().end(this, outcome, output);
getMockFlowExecutionContext().setActiveSession(endingSession.getParent());
return endingSession;
if (!getMockFlowExecutionContext().hasEnded()) {
handleEvent(new Event(endingSession.getState(), outcome, output));
}
}
public boolean getAlwaysRedirectOnPause() {

View File

@@ -23,10 +23,10 @@ import org.springframework.webflow.core.collection.MutableAttributeMap;
import org.springframework.webflow.definition.FlowDefinition;
import org.springframework.webflow.engine.impl.FlowExecutionImpl;
import org.springframework.webflow.engine.impl.FlowExecutionImplFactory;
import org.springframework.webflow.execution.Event;
import org.springframework.webflow.execution.FlowExecution;
import org.springframework.webflow.execution.FlowExecutionException;
import org.springframework.webflow.execution.FlowExecutionFactory;
import org.springframework.webflow.execution.FlowExecutionOutcome;
import org.springframework.webflow.test.MockExternalContext;
/**
@@ -70,7 +70,7 @@ public abstract class AbstractFlowExecutionTests extends TestCase {
/**
* The outcome that was reached when the flow ends; initially null.
*/
private Event flowExecutionOutcome;
private FlowExecutionOutcome flowExecutionOutcome;
/**
* Constructs a default flow execution test.
@@ -168,7 +168,7 @@ public abstract class AbstractFlowExecutionTests extends TestCase {
* Returns the flow execution outcome that was reached.
* @return the flow execution outcome, or null if the flow execution has not ended
*/
protected Event getFlowExecutionOutcome() {
protected FlowExecutionOutcome getFlowExecutionOutcome() {
return flowExecutionOutcome;
}

View File

@@ -110,6 +110,10 @@ public class FlowDefinitionRegistryImplTests extends TestCase {
return null;
}
public String[] getPossibleOutcomes() {
return null;
}
public ApplicationContext getApplicationContext() {
return null;
}
@@ -143,6 +147,10 @@ public class FlowDefinitionRegistryImplTests extends TestCase {
return null;
}
public String[] getPossibleOutcomes() {
return null;
}
public ApplicationContext getApplicationContext() {
return null;
}

View File

@@ -144,6 +144,14 @@ public class FlowTests extends TestCase {
}
}
public void testGetPossibleOutcomes() {
Flow flow = new Flow("myFlow");
new EndState(flow, "myState1");
new EndState(flow, "myState2");
assertEquals("myState1", flow.getPossibleOutcomes()[0]);
assertEquals("myState2", flow.getPossibleOutcomes()[1]);
}
public void testAddActions() {
flow.getStartActionList().add(new TestMultiAction());
flow.getStartActionList().add(new TestMultiAction());
@@ -299,7 +307,7 @@ public class FlowTests extends TestCase {
flow.getEndActionList().add(action);
MockRequestControlContext context = new MockRequestControlContext(flow);
LocalAttributeMap sessionOutput = new LocalAttributeMap();
flow.end(context, sessionOutput);
flow.end(context, "finish", sessionOutput);
assertEquals(1, action.getExecutionCount());
}
@@ -314,7 +322,7 @@ public class FlowTests extends TestCase {
MockRequestControlContext context = new MockRequestControlContext(flow);
context.getFlowScope().put("attr", "foo");
LocalAttributeMap sessionOutput = new LocalAttributeMap();
flow.end(context, sessionOutput);
flow.end(context, "finish", sessionOutput);
assertEquals("foo", sessionOutput.get("attr"));
}

View File

@@ -35,9 +35,9 @@ import org.springframework.webflow.engine.model.registry.DefaultFlowModelHolder;
import org.springframework.webflow.engine.model.registry.FlowModelHolder;
import org.springframework.webflow.engine.model.registry.FlowModelRegistryImpl;
import org.springframework.webflow.engine.support.ActionExecutingViewFactory;
import org.springframework.webflow.execution.Event;
import org.springframework.webflow.execution.FlowExecution;
import org.springframework.webflow.execution.FlowExecutionException;
import org.springframework.webflow.execution.FlowExecutionOutcome;
import org.springframework.webflow.execution.ViewFactory;
import org.springframework.webflow.security.SecurityRule;
import org.springframework.webflow.test.MockExternalContext;
@@ -137,14 +137,14 @@ public class FlowModelFlowBuilderTests extends TestCase {
map.put("number", "3");
map.put("required", "9");
execution.start(map, context);
Event outcome = execution.getOutcome();
FlowExecutionOutcome outcome = execution.getOutcome();
assertEquals("end", outcome.getId());
assertEquals("bar", outcome.getAttributes().get("foo"));
assertEquals("bar", outcome.getAttributes().get("differentName"));
assertEquals(new Integer(3), outcome.getAttributes().get("number"));
assertEquals(new Integer(3), outcome.getAttributes().get("required"));
assertEquals("a literal", outcome.getAttributes().get("literal"));
assertNull(outcome.getAttributes().get("notReached"));
assertEquals("bar", outcome.getOutput().get("foo"));
assertEquals("bar", outcome.getOutput().get("differentName"));
assertEquals(new Integer(3), outcome.getOutput().get("number"));
assertEquals(new Integer(3), outcome.getOutput().get("required"));
assertEquals("a literal", outcome.getOutput().get("literal"));
assertNull(outcome.getOutput().get("notReached"));
}
public void testFlowRequiredInputMapping() {

View File

@@ -273,13 +273,13 @@ public class MockFlowExecutionListener extends FlowExecutionListenerAdapter {
resumingCount++;
}
public void sessionEnding(RequestContext context, FlowSession session, MutableAttributeMap output) {
public void sessionEnding(RequestContext context, FlowSession session, String outcome, MutableAttributeMap output) {
sessionEnding = true;
sessionEndingCount++;
flowNestingLevel--;
}
public void sessionEnded(RequestContext context, FlowSession session, AttributeMap output) {
public void sessionEnded(RequestContext context, FlowSession session, String outcome, AttributeMap output) {
assertStarted();
Assert.state(sessionEnding, "Should have been ending");
sessionEnding = false;

View File

@@ -8,10 +8,10 @@ import org.springframework.webflow.core.collection.LocalAttributeMap;
import org.springframework.webflow.core.collection.MutableAttributeMap;
import org.springframework.webflow.definition.FlowDefinition;
import org.springframework.webflow.definition.registry.FlowDefinitionLocator;
import org.springframework.webflow.execution.Event;
import org.springframework.webflow.execution.FlowExecution;
import org.springframework.webflow.execution.FlowExecutionFactory;
import org.springframework.webflow.execution.FlowExecutionKey;
import org.springframework.webflow.execution.FlowExecutionOutcome;
import org.springframework.webflow.execution.repository.FlowExecutionLock;
import org.springframework.webflow.execution.repository.FlowExecutionRepository;
import org.springframework.webflow.test.GeneratedFlowExecutionKey;
@@ -65,8 +65,7 @@ public class FlowExecutorImplTests extends TestCase {
assertTrue(result.paused());
assertEquals("12345", result.getPausedKey());
assertFalse(result.ended());
assertNull(result.getEndedOutcome());
assertNull(result.getEndedOutput());
assertNull(result.getOutcome());
assertNull(ExternalContextHolder.getExternalContext());
verifyMocks();
}
@@ -86,14 +85,14 @@ public class FlowExecutorImplTests extends TestCase {
EasyMock.expect(execution.getDefinition()).andReturn(definition);
EasyMock.expect(definition.getId()).andReturn("foo");
EasyMock.expect(execution.getOutcome()).andReturn(new Event(execution, "finish", null));
EasyMock.expect(execution.getOutcome()).andReturn(new FlowExecutionOutcome("finish", null));
replayMocks();
FlowExecutionResult result = flowExecutor.launchExecution("foo", null, context);
assertTrue(result.ended());
assertEquals("finish", result.getEndedOutcome());
assertTrue(result.getEndedOutput().isEmpty());
assertEquals("finish", result.getOutcome().getId());
assertTrue(result.getOutcome().getOutput().isEmpty());
assertFalse(result.paused());
assertNull(result.getPausedKey());
assertNull(ExternalContextHolder.getExternalContext());
@@ -131,8 +130,7 @@ public class FlowExecutorImplTests extends TestCase {
assertTrue(result.paused());
assertEquals("12345", result.getPausedKey());
assertFalse(result.ended());
assertNull(result.getEndedOutcome());
assertNull(result.getEndedOutput());
assertNull(result.getOutcome());
assertNull(ExternalContextHolder.getExternalContext());
verifyMocks();
@@ -159,7 +157,7 @@ public class FlowExecutorImplTests extends TestCase {
LocalAttributeMap output = new LocalAttributeMap();
output.put("foo", "bar");
EasyMock.expect(execution.getOutcome()).andReturn(new Event(execution, "finish", output));
EasyMock.expect(execution.getOutcome()).andReturn(new FlowExecutionOutcome("finish", output));
repository.removeFlowExecution(execution);
@@ -169,8 +167,8 @@ public class FlowExecutorImplTests extends TestCase {
FlowExecutionResult result = flowExecutor.resumeExecution(flowExecutionKey, context);
assertTrue(result.ended());
assertEquals("finish", result.getEndedOutcome());
assertEquals(output, result.getEndedOutput());
assertEquals("finish", result.getOutcome().getId());
assertEquals(output, result.getOutcome().getOutput());
assertFalse(result.paused());
assertNull(result.getPausedKey());
assertNull(ExternalContextHolder.getExternalContext());

View File

@@ -20,10 +20,9 @@ import org.springframework.web.portlet.ModelAndView;
import org.springframework.webflow.context.portlet.DefaultFlowUrlHandler;
import org.springframework.webflow.context.portlet.PortletExternalContext;
import org.springframework.webflow.core.FlowException;
import org.springframework.webflow.core.collection.AttributeMap;
import org.springframework.webflow.core.collection.LocalAttributeMap;
import org.springframework.webflow.core.collection.MutableAttributeMap;
import org.springframework.webflow.execution.Event;
import org.springframework.webflow.execution.FlowExecutionOutcome;
import org.springframework.webflow.execution.repository.NoSuchFlowExecutionException;
import org.springframework.webflow.executor.FlowExecutionResult;
import org.springframework.webflow.executor.FlowExecutor;
@@ -85,8 +84,7 @@ public class FlowHandlerAdapterTests extends TestCase {
}
}
public String handleFlowOutcome(String outcome, AttributeMap output, RenderRequest request,
RenderResponse response) {
public String handleFlowOutcome(FlowExecutionOutcome outcome, RenderRequest request, RenderResponse response) {
if (handleExecutionOutcome) {
return "home";
} else {
@@ -174,7 +172,7 @@ public class FlowHandlerAdapterTests extends TestCase {
renderRequest.setContextPath("/springtravel");
LocalAttributeMap output = new LocalAttributeMap();
output.put("bar", "baz");
Event outcome = new Event(this, "finish", output);
FlowExecutionOutcome outcome = new FlowExecutionOutcome("finish", output);
FlowExecutionResult result = FlowExecutionResult.createEndedResult("foo", outcome);
PortletSession session = renderRequest.getPortletSession();
session.setAttribute("flowExecutionResult", result);

View File

@@ -16,10 +16,9 @@ import org.springframework.web.context.support.StaticWebApplicationContext;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.webflow.context.servlet.ServletExternalContext;
import org.springframework.webflow.core.FlowException;
import org.springframework.webflow.core.collection.AttributeMap;
import org.springframework.webflow.core.collection.LocalAttributeMap;
import org.springframework.webflow.core.collection.MutableAttributeMap;
import org.springframework.webflow.execution.Event;
import org.springframework.webflow.execution.FlowExecutionOutcome;
import org.springframework.webflow.execution.repository.NoSuchFlowExecutionException;
import org.springframework.webflow.executor.FlowExecutionResult;
import org.springframework.webflow.executor.FlowExecutor;
@@ -77,7 +76,7 @@ public class FlowControllerTests extends TestCase {
executor.launchExecution("foo", new LocalAttributeMap(parameters), context);
LocalAttributeMap output = new LocalAttributeMap();
output.put("bar", "baz");
Event outcome = new Event(this, "finish", output);
FlowExecutionOutcome outcome = new FlowExecutionOutcome("finish", output);
FlowExecutionResult result = FlowExecutionResult.createEndedResult("foo", outcome);
EasyMock.expectLastCall().andReturn(result);
EasyMock.replay(new Object[] { executor });
@@ -117,7 +116,7 @@ public class FlowControllerTests extends TestCase {
executor.resumeExecution("12345", context);
LocalAttributeMap output = new LocalAttributeMap();
output.put("bar", "baz");
Event outcome = new Event(this, "finish", output);
FlowExecutionOutcome outcome = new FlowExecutionOutcome("finish", output);
FlowExecutionResult result = FlowExecutionResult.createEndedResult("foo", outcome);
EasyMock.expectLastCall().andReturn(result);
EasyMock.replay(new Object[] { executor });
@@ -207,7 +206,7 @@ public class FlowControllerTests extends TestCase {
executor.launchExecution("foo", new LocalAttributeMap(parameters), context);
LocalAttributeMap output = new LocalAttributeMap();
output.put("bar", "baz");
Event outcome = new Event(this, "finish", output);
FlowExecutionOutcome outcome = new FlowExecutionOutcome("finish", output);
FlowExecutionResult result = FlowExecutionResult.createEndedResult("foo", outcome);
EasyMock.expectLastCall().andReturn(result);
EasyMock.replay(new Object[] { executor });
@@ -289,7 +288,7 @@ public class FlowControllerTests extends TestCase {
return input;
}
public String handleExecutionOutcome(String outcome, AttributeMap output, HttpServletRequest request,
public String handleExecutionOutcome(FlowExecutionOutcome outcome, HttpServletRequest request,
HttpServletResponse response) {
return null;
}
@@ -324,10 +323,10 @@ public class FlowControllerTests extends TestCase {
return input;
}
public String handleExecutionOutcome(String outcome, AttributeMap output, HttpServletRequest request,
public String handleExecutionOutcome(FlowExecutionOutcome outcome, HttpServletRequest request,
HttpServletResponse response) {
assertEquals("finish", outcome);
assertEquals("baz", output.get("bar"));
assertEquals("finish", outcome.getId());
assertEquals("baz", outcome.getOutput().get("bar"));
assertEquals(FlowControllerTests.this.request, request);
assertEquals(FlowControllerTests.this.response, response);
return null;
@@ -345,7 +344,7 @@ public class FlowControllerTests extends TestCase {
executor.launchExecution("foo", input, context);
LocalAttributeMap output = new LocalAttributeMap();
output.put("bar", "baz");
Event outcome = new Event(this, "finish", output);
FlowExecutionOutcome outcome = new FlowExecutionOutcome("finish", output);
FlowExecutionResult result = FlowExecutionResult.createEndedResult("foo", outcome);
EasyMock.expectLastCall().andReturn(result);
EasyMock.replay(new Object[] { executor });
@@ -368,7 +367,7 @@ public class FlowControllerTests extends TestCase {
return null;
}
public String handleExecutionOutcome(String outcome, AttributeMap output, HttpServletRequest request,
public String handleExecutionOutcome(FlowExecutionOutcome outcome, HttpServletRequest request,
HttpServletResponse response) {
return null;
}

View File

@@ -16,10 +16,9 @@ import org.springframework.web.context.support.StaticWebApplicationContext;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.webflow.context.servlet.ServletExternalContext;
import org.springframework.webflow.core.FlowException;
import org.springframework.webflow.core.collection.AttributeMap;
import org.springframework.webflow.core.collection.LocalAttributeMap;
import org.springframework.webflow.core.collection.MutableAttributeMap;
import org.springframework.webflow.execution.Event;
import org.springframework.webflow.execution.FlowExecutionOutcome;
import org.springframework.webflow.execution.repository.NoSuchFlowExecutionException;
import org.springframework.webflow.executor.FlowExecutionResult;
import org.springframework.webflow.executor.FlowExecutor;
@@ -61,7 +60,7 @@ public class FlowHandlerAdapterTests extends TestCase {
return "foo";
}
public String handleExecutionOutcome(String outcome, AttributeMap output, HttpServletRequest request,
public String handleExecutionOutcome(FlowExecutionOutcome outcome, HttpServletRequest request,
HttpServletResponse response) {
if (handleExecutionOutcome) {
return "/home";
@@ -107,7 +106,7 @@ public class FlowHandlerAdapterTests extends TestCase {
executor.launchExecution("foo", flowInput, context);
LocalAttributeMap output = new LocalAttributeMap();
output.put("bar", "baz");
Event outcome = new Event(this, "finish", output);
FlowExecutionOutcome outcome = new FlowExecutionOutcome("finish", output);
FlowExecutionResult result = FlowExecutionResult.createEndedResult("foo", outcome);
EasyMock.expectLastCall().andReturn(result);
EasyMock.replay(new Object[] { executor });
@@ -147,7 +146,7 @@ public class FlowHandlerAdapterTests extends TestCase {
executor.resumeExecution("12345", context);
LocalAttributeMap output = new LocalAttributeMap();
output.put("bar", "baz");
Event outcome = new Event(this, "finish", output);
FlowExecutionOutcome outcome = new FlowExecutionOutcome("finish", output);
FlowExecutionResult result = FlowExecutionResult.createEndedResult("foo", outcome);
EasyMock.expectLastCall().andReturn(result);
EasyMock.replay(new Object[] { executor });
@@ -191,7 +190,7 @@ public class FlowHandlerAdapterTests extends TestCase {
executor.launchExecution("foo", flowInput, context);
LocalAttributeMap output = new LocalAttributeMap();
output.put("bar", "baz");
Event outcome = new Event(this, "finish", output);
FlowExecutionOutcome outcome = new FlowExecutionOutcome("finish", output);
FlowExecutionResult result = FlowExecutionResult.createEndedResult("foo", outcome);
EasyMock.expectLastCall().andReturn(result);
EasyMock.replay(new Object[] { executor });
@@ -271,7 +270,7 @@ public class FlowHandlerAdapterTests extends TestCase {
executor.launchExecution("foo", flowInput, context);
LocalAttributeMap output = new LocalAttributeMap();
output.put("bar", "baz");
Event outcome = new Event(this, "finish", output);
FlowExecutionOutcome outcome = new FlowExecutionOutcome("finish", output);
FlowExecutionResult result = FlowExecutionResult.createEndedResult("foo", outcome);
EasyMock.expectLastCall().andReturn(result);
EasyMock.replay(new Object[] { executor });

View File

@@ -118,7 +118,7 @@ public class HibernateFlowExecutionListenerTests extends TestCase {
endState.getAttributes().put("commit", Boolean.TRUE);
flowSession.setState(endState);
hibernateListener.sessionEnded(context, flowSession, null);
hibernateListener.sessionEnded(context, flowSession, "success", null);
assertEquals("Table should only have two rows", 2, jdbcTemplate.queryForInt("select count(*) from T_BEAN"));
assertSessionNotBound();
assertFalse(flowSession.getScope().contains("hibernate.session"));
@@ -149,7 +149,7 @@ public class HibernateFlowExecutionListenerTests extends TestCase {
endState.getAttributes().put("commit", Boolean.TRUE);
flowSession.setState(endState);
hibernateListener.sessionEnded(context, flowSession, null);
hibernateListener.sessionEnded(context, flowSession, "success", null);
assertEquals("Table should only have three rows", 3, jdbcTemplate.queryForInt("select count(*) from T_BEAN"));
assertFalse(flowSession.getScope().contains("hibernate.session"));
@@ -174,7 +174,7 @@ public class HibernateFlowExecutionListenerTests extends TestCase {
EndState endState = new EndState(flowSession.getDefinitionInternal(), "cancel");
endState.getAttributes().put("commit", Boolean.FALSE);
flowSession.setState(endState);
hibernateListener.sessionEnded(context, flowSession, null);
hibernateListener.sessionEnded(context, flowSession, "cancel", null);
assertEquals("Table should only have two rows", 1, jdbcTemplate.queryForInt("select count(*) from T_BEAN"));
assertSessionNotBound();
assertFalse(flowSession.getScope().contains("hibernate.session"));
@@ -192,7 +192,7 @@ public class HibernateFlowExecutionListenerTests extends TestCase {
EndState endState = new EndState(flowSession.getDefinitionInternal(), "cancel");
flowSession.setState(endState);
hibernateListener.sessionEnded(context, flowSession, null);
hibernateListener.sessionEnded(context, flowSession, "cancel", null);
assertEquals("Table should only have three rows", 1, jdbcTemplate.queryForInt("select count(*) from T_BEAN"));
assertFalse(flowSession.getScope().contains("hibernate.session"));

View File

@@ -68,7 +68,7 @@ public class JpaFlowExecutionListenerTests extends TestCase {
endState.getAttributes().put("commit", Boolean.TRUE);
flowSession.setState(endState);
jpaListener.sessionEnded(context, flowSession, null);
jpaListener.sessionEnded(context, flowSession, "success", null);
assertEquals("Table should only have two rows", 2, jdbcTemplate.queryForInt("select count(*) from T_BEAN"));
assertSessionNotBound();
assertFalse(flowSession.getScope().contains("hibernate.session"));
@@ -99,7 +99,7 @@ public class JpaFlowExecutionListenerTests extends TestCase {
endState.getAttributes().put("commit", Boolean.TRUE);
flowSession.setState(endState);
jpaListener.sessionEnded(context, flowSession, null);
jpaListener.sessionEnded(context, flowSession, "success", null);
assertEquals("Table should only have three rows", 3, jdbcTemplate.queryForInt("select count(*) from T_BEAN"));
assertFalse(flowSession.getScope().contains("hibernate.session"));
@@ -123,7 +123,7 @@ public class JpaFlowExecutionListenerTests extends TestCase {
EndState endState = new EndState(flowSession.getDefinitionInternal(), "cancel");
endState.getAttributes().put("commit", Boolean.FALSE);
flowSession.setState(endState);
jpaListener.sessionEnded(context, flowSession, null);
jpaListener.sessionEnded(context, flowSession, "cancel", null);
assertEquals("Table should only have two rows", 1, jdbcTemplate.queryForInt("select count(*) from T_BEAN"));
assertSessionNotBound();
assertFalse(flowSession.getScope().contains("hibernate.session"));
@@ -141,7 +141,7 @@ public class JpaFlowExecutionListenerTests extends TestCase {
EndState endState = new EndState(flowSession.getDefinitionInternal(), "cancel");
flowSession.setState(endState);
jpaListener.sessionEnded(context, flowSession, null);
jpaListener.sessionEnded(context, flowSession, "cancel", null);
assertEquals("Table should only have three rows", 1, jdbcTemplate.queryForInt("select count(*) from T_BEAN"));
assertFalse(flowSession.getScope().contains("hibernate.session"));