SWF-333 review
This commit is contained in:
@@ -192,11 +192,8 @@ public class FlowExecutionImpl implements FlowExecution, Externalizable {
|
||||
catch (FlowExecutionException e) {
|
||||
return pause(context, handleException(e, context));
|
||||
} catch (Exception e) {
|
||||
String flowId = context.getActiveFlow().getId();
|
||||
String stateId = null;
|
||||
if(context.getCurrentState() != null) {
|
||||
stateId = context.getCurrentState().getId();
|
||||
}
|
||||
String flowId = getCurrentFlow().getId();
|
||||
String stateId = getCurrentStateId();
|
||||
FlowExecutionException flowException = new FlowExecutionException(flowId, stateId,
|
||||
"Exception thrown in state '" + stateId + "' of flow '" + flowId + "'", e);
|
||||
return pause(context, handleException(flowException, context));
|
||||
@@ -226,8 +223,8 @@ public class FlowExecutionImpl implements FlowExecution, Externalizable {
|
||||
catch (FlowExecutionException e) {
|
||||
return pause(context, handleException(e, context));
|
||||
} catch (Exception e) {
|
||||
String flowId = context.getActiveFlow().getId();
|
||||
String stateId = context.getCurrentState().getId();
|
||||
String flowId = getCurrentFlow().getId();
|
||||
String stateId = getCurrentStateId();
|
||||
FlowExecutionException flowException = new FlowExecutionException(flowId, stateId,
|
||||
"Exception thrown in state '" + stateId + "' of flow '" + flowId + "'", e);
|
||||
return pause(context, handleException(flowException, context));
|
||||
@@ -259,8 +256,8 @@ public class FlowExecutionImpl implements FlowExecution, Externalizable {
|
||||
catch (FlowExecutionException e) {
|
||||
return pause(context, handleException(e, context));
|
||||
} catch (Exception e) {
|
||||
String flowId = context.getActiveFlow().getId();
|
||||
String stateId = context.getCurrentState().getId();
|
||||
String flowId = getCurrentFlow().getId();
|
||||
String stateId = getCurrentStateId();
|
||||
FlowExecutionException flowException = new FlowExecutionException(flowId, stateId,
|
||||
"Exception thrown in state '" + stateId + "' of flow '" + flowId + "'", e);
|
||||
return pause(context, handleException(flowException, context));
|
||||
@@ -332,16 +329,29 @@ public class FlowExecutionImpl implements FlowExecution, Externalizable {
|
||||
// the state could be null if the flow was attempting a start operation
|
||||
ViewSelection selectedView = tryStateHandlers(exception, context);
|
||||
if (selectedView != null) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("State '" + exception.getStateId() + "' handled exception");
|
||||
}
|
||||
return selectedView;
|
||||
}
|
||||
selectedView = tryFlowHandlers(exception, context);
|
||||
if (selectedView != null) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Flow '" + flow.getId() + "' handled exception");
|
||||
}
|
||||
return selectedView;
|
||||
}
|
||||
}
|
||||
catch (FlowExecutionException newException) {
|
||||
// exception handling resulted in a new FlowExecutionException, try to handle it
|
||||
return handleException(newException, context);
|
||||
} catch (Exception e) {
|
||||
// a lower-level exception occured, wrap it in a flow execution exception and try to handle it
|
||||
String flowId = getCurrentFlow().getId();
|
||||
String stateId = getCurrentStateId();
|
||||
FlowExecutionException flowException = new FlowExecutionException(flowId, stateId,
|
||||
"Exception thrown in state '" + stateId + "' of flow '" + flowId + "'", e);
|
||||
return handleException(flowException, context);
|
||||
}
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Rethrowing unhandled flow execution exception");
|
||||
@@ -354,16 +364,11 @@ public class FlowExecutionImpl implements FlowExecution, Externalizable {
|
||||
* at the state level. Returns null if no handler handled the exception.
|
||||
*/
|
||||
private ViewSelection tryStateHandlers(FlowExecutionException exception, RequestControlContext context) {
|
||||
ViewSelection selectedView = null;
|
||||
if (exception.getStateId() != null) {
|
||||
selectedView = getActiveFlow().getStateInstance(exception.getStateId()).handleException(exception, context);
|
||||
if (selectedView != null) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("State '" + exception.getStateId() + "' handled exception");
|
||||
}
|
||||
}
|
||||
if (isActive() && exception.getStateId() != null) {
|
||||
return getActiveFlow().getStateInstance(exception.getStateId()).handleException(exception, context);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
return selectedView;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -371,13 +376,7 @@ public class FlowExecutionImpl implements FlowExecution, Externalizable {
|
||||
* at the flow level. Returns null if no handler handled the exception.
|
||||
*/
|
||||
private ViewSelection tryFlowHandlers(FlowExecutionException exception, RequestControlContext context) {
|
||||
ViewSelection selectedView = getActiveFlow().handleException(exception, context);
|
||||
if (selectedView != null) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Flow '" + exception.getFlowId() + "' handled exception");
|
||||
}
|
||||
}
|
||||
return selectedView;
|
||||
return getCurrentFlow().handleException(exception, context);
|
||||
}
|
||||
|
||||
// internal helpers
|
||||
@@ -476,17 +475,41 @@ public class FlowExecutionImpl implements FlowExecution, Externalizable {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the "current flow": which is the active flow if this execution is active, else the top-level flow definition.
|
||||
*/
|
||||
private Flow getCurrentFlow() {
|
||||
return isActive() ? getActiveFlow() : this.flow;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the id of the "current" state: a valid state identifier if the flow is active and in a state; null if the flow
|
||||
* is not active or has not yet entered a state.
|
||||
*/
|
||||
private String getCurrentStateId() {
|
||||
if (isActive()) {
|
||||
State state = getCurrentState();
|
||||
if (state != null) {
|
||||
return state.getId();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the currently active flow.
|
||||
*/
|
||||
private Flow getActiveFlow() {
|
||||
private Flow getActiveFlow() throws IllegalStateException {
|
||||
return (Flow)getActiveSessionInternal().getDefinition();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current state of this flow execution.
|
||||
*/
|
||||
private State getCurrentState() {
|
||||
private State getCurrentState() throws IllegalStateException {
|
||||
return (State)getActiveSessionInternal().getState();
|
||||
}
|
||||
|
||||
|
||||
@@ -24,6 +24,8 @@ import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.webflow.action.AbstractAction;
|
||||
import org.springframework.webflow.core.DefaultExpressionParserFactory;
|
||||
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.ActionState;
|
||||
import org.springframework.webflow.engine.EndState;
|
||||
import org.springframework.webflow.engine.Flow;
|
||||
@@ -253,6 +255,24 @@ public class FlowExecutionImplTests extends TestCase {
|
||||
execution.signalEvent("view", context);
|
||||
}
|
||||
|
||||
public void testUnhandledExceptionThrownBeforeSessionStartup() {
|
||||
FlowBuilder flowBuilder = new XmlFlowBuilder(new ClassPathResource("runtime-exception.xml",
|
||||
getClass()));
|
||||
Flow flow = new FlowAssembler("runtime-exception", flowBuilder).assembleFlow();
|
||||
FlowExecutionListener listener = new FlowExecutionListenerAdapter() {
|
||||
public void sessionStarting(RequestContext context, FlowDefinition definition, MutableAttributeMap input) {
|
||||
throw new IllegalStateException("Cannot proceed");
|
||||
}
|
||||
};
|
||||
FlowExecutionImpl flowExecution = new FlowExecutionImpl(flow);
|
||||
flowExecution.setListeners(new FlowExecutionListeners(new FlowExecutionListener[] { listener }));
|
||||
try {
|
||||
flowExecution.start(new LocalAttributeMap(), new MockExternalContext());
|
||||
fail("Should have thrown a FlowExecutionException, not any other type");
|
||||
} catch (FlowExecutionException e) {
|
||||
}
|
||||
}
|
||||
|
||||
public void testExceptionFromInputMapper() {
|
||||
FlowBuilder flowBuilder = new XmlFlowBuilder(new ClassPathResource("runtime-exception.xml",
|
||||
getClass()));
|
||||
|
||||
@@ -17,9 +17,27 @@
|
||||
<action bean="testAction">
|
||||
<attribute name="exceptionType" value="java.sql.SQLException"/>
|
||||
</action>
|
||||
<transition on-exception="java.sql.SQLException" to="failed"/>
|
||||
<transition on-exception="java.sql.SQLException" to="thirdTry"/>
|
||||
</action-state>
|
||||
|
||||
<end-state id="failed" view="failed"/>
|
||||
|
||||
<action-state id="thirdTry">
|
||||
<action bean="testAction">
|
||||
<attribute name="exceptionType" value="java.sql.SQLException"/>
|
||||
</action>
|
||||
<transition on-exception="java.sql.SQLException" to="failed"/>
|
||||
</action-state>
|
||||
|
||||
<end-state id="failed" view="failed">
|
||||
<output-mapper>
|
||||
<!-- will generate an exception as foo doesn't exist -->
|
||||
<mapping source="flowScope.foo" target="foo" required="true"/>
|
||||
</output-mapper>
|
||||
</end-state>
|
||||
|
||||
<end-state id="reallyFailed" view="failed"/>
|
||||
|
||||
<global-transitions>
|
||||
<transition on-exception="org.springframework.binding.mapping.RequiredMappingException" to="reallyFailed"/>
|
||||
</global-transitions>
|
||||
|
||||
</flow>
|
||||
Reference in New Issue
Block a user