From f6079c8a94271e2bb48ff2164e1997ec515bd02b Mon Sep 17 00:00:00 2001 From: Janne Valkealahti Date: Sat, 23 Jan 2016 10:13:37 +0000 Subject: [PATCH] Add source to event not accepted stage - It makes sense to give source state when event is not accepted. - Polish - Relates #150 --- .../statemachine/StateContext.java | 2 +- .../support/AbstractStateMachine.java | 8 +-- .../statemachine/StateContextTests.java | 57 ++++++++++++++++++- 3 files changed, 60 insertions(+), 7 deletions(-) diff --git a/spring-statemachine-core/src/main/java/org/springframework/statemachine/StateContext.java b/spring-statemachine-core/src/main/java/org/springframework/statemachine/StateContext.java index a1dc7407..5b92e3f7 100644 --- a/spring-statemachine-core/src/main/java/org/springframework/statemachine/StateContext.java +++ b/spring-statemachine-core/src/main/java/org/springframework/statemachine/StateContext.java @@ -107,7 +107,7 @@ public interface StateContext { State getSource(); /** - * Gets the tarter state of this context. Generally target + * Gets the target state of this context. Generally target * is where a state machine going to which may be different * than what the transition target is. * diff --git a/spring-statemachine-core/src/main/java/org/springframework/statemachine/support/AbstractStateMachine.java b/spring-statemachine-core/src/main/java/org/springframework/statemachine/support/AbstractStateMachine.java index bc58320d..38b52801 100644 --- a/spring-statemachine-core/src/main/java/org/springframework/statemachine/support/AbstractStateMachine.java +++ b/spring-statemachine-core/src/main/java/org/springframework/statemachine/support/AbstractStateMachine.java @@ -177,7 +177,7 @@ public abstract class AbstractStateMachine extends StateMachineObjectSuppo public boolean sendEvent(Message event) { if (hasStateMachineError()) { // TODO: should we throw exception? - notifyEventNotAccepted(buildStateContext(Stage.EVENT_NOT_ACCEPTED, event, null, getRelayStateMachine())); + notifyEventNotAccepted(buildStateContext(Stage.EVENT_NOT_ACCEPTED, event, null, getRelayStateMachine(), getState(), null)); return false; } @@ -185,18 +185,18 @@ public abstract class AbstractStateMachine extends StateMachineObjectSuppo event = getStateMachineInterceptors().preEvent(event, this); } catch (Exception e) { log.info("Event " + event + " threw exception in interceptors, not accepting event"); - notifyEventNotAccepted(buildStateContext(Stage.EVENT_NOT_ACCEPTED, event, null, getRelayStateMachine())); + notifyEventNotAccepted(buildStateContext(Stage.EVENT_NOT_ACCEPTED, event, null, getRelayStateMachine(), getState(), null)); return false; } if (isComplete() || !isRunning()) { - notifyEventNotAccepted(buildStateContext(Stage.EVENT_NOT_ACCEPTED, event, null, getRelayStateMachine())); + notifyEventNotAccepted(buildStateContext(Stage.EVENT_NOT_ACCEPTED, event, null, getRelayStateMachine(), getState(), null)); return false; } boolean accepted = acceptEvent(event); stateMachineExecutor.execute(); if (!accepted) { - notifyEventNotAccepted(buildStateContext(Stage.EVENT_NOT_ACCEPTED, event, null, getRelayStateMachine())); + notifyEventNotAccepted(buildStateContext(Stage.EVENT_NOT_ACCEPTED, event, null, getRelayStateMachine(), getState(), null)); } return accepted; } diff --git a/spring-statemachine-core/src/test/java/org/springframework/statemachine/StateContextTests.java b/spring-statemachine-core/src/test/java/org/springframework/statemachine/StateContextTests.java index a59ffcd9..bddf1516 100644 --- a/spring-statemachine-core/src/test/java/org/springframework/statemachine/StateContextTests.java +++ b/spring-statemachine-core/src/test/java/org/springframework/statemachine/StateContextTests.java @@ -23,6 +23,7 @@ import static org.hamcrest.Matchers.hasSize; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.notNullValue; import static org.hamcrest.Matchers.nullValue; +import static org.hamcrest.Matchers.sameInstance; import java.util.ArrayList; import java.util.Map; @@ -150,6 +151,55 @@ public class StateContextTests extends AbstractStateMachineTests { assertThat(listener.contexts.get(18).getTransition(), notNullValue()); } + @SuppressWarnings("unchecked") + @Test + public void testEventNotAccepted() throws Exception { + context.register(Config1.class); + context.refresh(); + StateMachine machine = context.getBean(StateMachineSystemConstants.DEFAULT_ID_STATEMACHINE, StateMachine.class); + + TestStateMachineListener listener = new TestStateMachineListener(); + machine.addStateListener(listener); + + machine.start(); + listener.contexts.clear(); + + machine.sendEvent(Events.J); + + // all nested machines sends these + assertThat(listener.contexts, contains( + hasStage(Stage.EVENT_NOT_ACCEPTED), + hasStage(Stage.EVENT_NOT_ACCEPTED), + hasStage(Stage.EVENT_NOT_ACCEPTED) + )); + + + assertThat(listener.contexts.get(0).getStage(), is(Stage.EVENT_NOT_ACCEPTED)); + assertThat(listener.contexts.get(0).getTransition(), nullValue()); + assertThat(listener.contexts.get(0).getEvent(), is(Events.J)); + assertThat(listener.contexts.get(0).getSource(), notNullValue()); + assertThat(listener.contexts.get(0).getSource().getId(), is(States.S11)); + assertThat(listener.contexts.get(0).getTarget(), nullValue()); + + assertThat(listener.contexts.get(1).getStage(), is(Stage.EVENT_NOT_ACCEPTED)); + assertThat(listener.contexts.get(1).getTransition(), nullValue()); + assertThat(listener.contexts.get(1).getEvent(), is(Events.J)); + assertThat(listener.contexts.get(1).getSource(), notNullValue()); + assertThat(listener.contexts.get(1).getSource().getId(), is(States.S1)); + assertThat(listener.contexts.get(1).getTarget(), nullValue()); + + assertThat(listener.contexts.get(2).getStage(), is(Stage.EVENT_NOT_ACCEPTED)); + assertThat(listener.contexts.get(2).getTransition(), nullValue()); + assertThat(listener.contexts.get(2).getEvent(), is(Events.J)); + assertThat(listener.contexts.get(2).getSource(), notNullValue()); + assertThat(listener.contexts.get(2).getSource().getId(), is(States.S0)); + assertThat(listener.contexts.get(2).getTarget(), nullValue()); + + // TODO: I wonder if these should be different machines + assertThat(listener.contexts.get(0).getStateMachine(), sameInstance(listener.contexts.get(1).getStateMachine())); + assertThat(listener.contexts.get(0).getStateMachine(), sameInstance(listener.contexts.get(2).getStateMachine())); + } + static class TestStateMachineListener extends StateMachineListenerAdapter { ArrayList> contexts = new ArrayList<>(); @@ -269,7 +319,10 @@ public class StateContextTests extends AbstractStateMachineTests { .source(States.S211).target(States.S212).event(Events.I) .and() .withExternal() - .source(States.S12).target(States.S212).event(Events.I); + .source(States.S12).target(States.S212).event(Events.I) + .and() + .withExternal() + .source(States.S212).target(States.S211).event(Events.J); } @@ -295,7 +348,7 @@ public class StateContextTests extends AbstractStateMachineTests { } public static enum Events { - A, B, C, D, E, F, G, H, I + A, B, C, D, E, F, G, H, I, J } private static class FooAction implements Action {