/*
* Copyright 2004-2012 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.webflow.engine.support;
import junit.framework.TestCase;
import org.springframework.webflow.TestException;
import org.springframework.webflow.action.AbstractAction;
import org.springframework.webflow.core.collection.MutableAttributeMap;
import org.springframework.webflow.engine.EndState;
import org.springframework.webflow.engine.Flow;
import org.springframework.webflow.engine.RequestControlContext;
import org.springframework.webflow.engine.State;
import org.springframework.webflow.engine.TargetStateResolver;
import org.springframework.webflow.engine.Transition;
import org.springframework.webflow.engine.TransitionableState;
import org.springframework.webflow.engine.builder.FlowAssembler;
import org.springframework.webflow.engine.builder.FlowBuilder;
import org.springframework.webflow.engine.builder.FlowBuilderException;
import org.springframework.webflow.engine.builder.support.AbstractFlowBuilder;
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.FlowExecutionListener;
import org.springframework.webflow.execution.FlowExecutionListenerAdapter;
import org.springframework.webflow.execution.FlowSession;
import org.springframework.webflow.execution.RequestContext;
import org.springframework.webflow.execution.factory.StaticFlowExecutionListenerLoader;
import org.springframework.webflow.test.MockExternalContext;
import org.springframework.webflow.test.MockFlowBuilderContext;
public class TransitionExecutingFlowExecutionExceptionHandlerTests extends TestCase {
Flow flow;
TransitionableState state;
protected void setUp() {
flow = new Flow("myFlow");
state = new TransitionableState(flow, "state1") {
protected void doEnter(RequestControlContext context) {
throw new FlowExecutionException(getFlow().getId(), getId(), "Oops!", new TestException());
}
};
state.getTransitionSet().add(new Transition(toState("end")));
}
public void testTransitionExecutorHandlesExceptionExactMatch() {
TransitionExecutingFlowExecutionExceptionHandler handler = new TransitionExecutingFlowExecutionExceptionHandler();
handler.add(TestException.class, "state");
FlowExecutionException e = new FlowExecutionException(state.getOwner().getId(), state.getId(), "Oops",
new TestException());
assertTrue("Doesn't handle state exception", handler.canHandle(e));
e = new FlowExecutionException(state.getOwner().getId(), state.getId(), "Oops", new Exception());
assertFalse("Shouldn't handle exception", handler.canHandle(e));
}
public void testTransitionExecutorHandlesExceptionSuperclassMatch() {
TransitionExecutingFlowExecutionExceptionHandler handler = new TransitionExecutingFlowExecutionExceptionHandler();
handler.add(Exception.class, "state");
FlowExecutionException e = new FlowExecutionException(state.getOwner().getId(), state.getId(), "Oops",
new TestException());
assertTrue("Doesn't handle state exception", handler.canHandle(e));
e = new FlowExecutionException(state.getOwner().getId(), state.getId(), "Oops", new RuntimeException());
assertTrue("Doesn't handle state exception", handler.canHandle(e));
}
public void testFlowStateExceptionHandlingTransition() {
new EndState(flow, "end");
TransitionExecutingFlowExecutionExceptionHandler handler = new TransitionExecutingFlowExecutionExceptionHandler();
handler.add(TestException.class, "end");
flow.getExceptionHandlerSet().add(handler);
FlowExecutionListener listener = new FlowExecutionListenerAdapter() {
@SuppressWarnings("unused")
public void sessionEnding(RequestContext context, FlowSession session, MutableAttributeMap<?> output) {
assertTrue(context.getFlashScope().contains("flowExecutionException"));
assertTrue(context.getFlashScope().contains("rootCauseException"));
assertTrue(context.getFlashScope().get("rootCauseException") instanceof TestException);
}
};
FlowExecutionImplFactory factory = new FlowExecutionImplFactory();
factory.setExecutionListenerLoader(new StaticFlowExecutionListenerLoader(listener));
FlowExecution execution = factory.createFlowExecution(flow);
execution.start(null, new MockExternalContext());
assertTrue("Should have ended", !execution.isActive());
}
public void testStateExceptionHandlingTransitionNoSuchState() {
TransitionExecutingFlowExecutionExceptionHandler handler = new TransitionExecutingFlowExecutionExceptionHandler();
handler.add(TestException.class, "end");
flow.getExceptionHandlerSet().add(handler);
FlowExecution execution = new FlowExecutionImplFactory().createFlowExecution(flow);
try {
execution.start(null, new MockExternalContext());
fail("Should have failed no such state");
} catch (IllegalArgumentException e) {
}
}
public void testStateExceptionHandlingRethrow() {
FlowExecution execution = new FlowExecutionImplFactory().createFlowExecution(flow);
try {
execution.start(null, new MockExternalContext());
fail("Should have rethrown");
} catch (FlowExecutionException e) {
// expected
}
}
public void testStateExceptionHandlingExceptionInEndState() {
FlowBuilder builder = new AbstractFlowBuilder() {
public void buildStates() throws FlowBuilderException {
State state = new EndState(getFlow(), "end");
state.getEntryActionList().add(new AbstractAction() {
protected Event doExecute(RequestContext context) throws Exception {
throw new NullPointerException("failing");
}
});
new TransitionableState(getFlow(), "showError") {
protected void doEnter(RequestControlContext context) throws FlowExecutionException {
}
};
}
public void buildExceptionHandlers() throws FlowBuilderException {
getFlow().getExceptionHandlerSet().add(
new TransitionExecutingFlowExecutionExceptionHandler().add(Exception.class, "showError"));
}
public Flow createFlow() throws FlowBuilderException {
return Flow.create(getContext().getFlowId(), getContext().getFlowAttributes());
}
};
Flow flow = new FlowAssembler(builder, new MockFlowBuilderContext("flow")).assembleFlow();
FlowExecution execution = new FlowExecutionImplFactory().createFlowExecution(flow);
execution.start(null, new MockExternalContext());
assertTrue(execution.isActive());
}
protected TargetStateResolver toState(String stateId) {
return new DefaultTargetStateResolver(stateId);
}
}