Add source to event not accepted stage

- It makes sense to give source state when
  event is not accepted.
- Polish
- Relates #150
This commit is contained in:
Janne Valkealahti
2016-01-23 10:13:37 +00:00
parent e28caf1164
commit f6079c8a94
3 changed files with 60 additions and 7 deletions

View File

@@ -107,7 +107,7 @@ public interface StateContext<S, E> {
State<S,E> getSource(); State<S,E> 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 * is where a state machine going to which may be different
* than what the transition target is. * than what the transition target is.
* *

View File

@@ -177,7 +177,7 @@ public abstract class AbstractStateMachine<S, E> extends StateMachineObjectSuppo
public boolean sendEvent(Message<E> event) { public boolean sendEvent(Message<E> event) {
if (hasStateMachineError()) { if (hasStateMachineError()) {
// TODO: should we throw exception? // 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; return false;
} }
@@ -185,18 +185,18 @@ public abstract class AbstractStateMachine<S, E> extends StateMachineObjectSuppo
event = getStateMachineInterceptors().preEvent(event, this); event = getStateMachineInterceptors().preEvent(event, this);
} catch (Exception e) { } catch (Exception e) {
log.info("Event " + event + " threw exception in interceptors, not accepting event"); 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; return false;
} }
if (isComplete() || !isRunning()) { 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; return false;
} }
boolean accepted = acceptEvent(event); boolean accepted = acceptEvent(event);
stateMachineExecutor.execute(); stateMachineExecutor.execute();
if (!accepted) { if (!accepted) {
notifyEventNotAccepted(buildStateContext(Stage.EVENT_NOT_ACCEPTED, event, null, getRelayStateMachine())); notifyEventNotAccepted(buildStateContext(Stage.EVENT_NOT_ACCEPTED, event, null, getRelayStateMachine(), getState(), null));
} }
return accepted; return accepted;
} }

View File

@@ -23,6 +23,7 @@ import static org.hamcrest.Matchers.hasSize;
import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.notNullValue; import static org.hamcrest.Matchers.notNullValue;
import static org.hamcrest.Matchers.nullValue; import static org.hamcrest.Matchers.nullValue;
import static org.hamcrest.Matchers.sameInstance;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Map; import java.util.Map;
@@ -150,6 +151,55 @@ public class StateContextTests extends AbstractStateMachineTests {
assertThat(listener.contexts.get(18).getTransition(), notNullValue()); assertThat(listener.contexts.get(18).getTransition(), notNullValue());
} }
@SuppressWarnings("unchecked")
@Test
public void testEventNotAccepted() throws Exception {
context.register(Config1.class);
context.refresh();
StateMachine<States, Events> 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<States, Events> { static class TestStateMachineListener extends StateMachineListenerAdapter<States, Events> {
ArrayList<StateContext<States, Events>> contexts = new ArrayList<>(); ArrayList<StateContext<States, Events>> contexts = new ArrayList<>();
@@ -269,7 +319,10 @@ public class StateContextTests extends AbstractStateMachineTests {
.source(States.S211).target(States.S212).event(Events.I) .source(States.S211).target(States.S212).event(Events.I)
.and() .and()
.withExternal() .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 { 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<States, Events> { private static class FooAction implements Action<States, Events> {