Initial state wrongly entered with entry point

- Fix case where submachine entry via entrypoint wrongly
  caused its initial state to get activated before
  entering transition target leading out from entrypoint.
- Fixes #577
This commit is contained in:
Janne Valkealahti
2018-07-17 07:39:48 +01:00
parent 594b8ef563
commit 61e762763f
2 changed files with 70 additions and 0 deletions

View File

@@ -216,6 +216,16 @@ public class StateMachineState<S, E> extends AbstractState<S, E> {
getSubmachine().getStateMachineAccessor().doWithRegion(
new StateMachineFunction<StateMachineAccess<S, E>>() {
@Override
public void apply(StateMachineAccess<S, E> function) {
function.setInitialEnabled(false);
}
});
}
if (immediateDeepParent == null && getSubmachine().getStates().contains(target) && isEntry(target)) {
getSubmachine().getStateMachineAccessor().doWithRegion(
new StateMachineFunction<StateMachineAccess<S, E>>() {
@Override
public void apply(StateMachineAccess<S, E> function) {
function.setInitialEnabled(false);
@@ -230,6 +240,10 @@ public class StateMachineState<S, E> extends AbstractState<S, E> {
return state.getPseudoState() != null && state.getPseudoState().getKind() == PseudoStateKind.INITIAL;
}
private boolean isEntry(State<S, E> state) {
return state.getPseudoState() != null && state.getPseudoState().getKind() == PseudoStateKind.ENTRY;
}
private State<S, E> findDeepParent(Collection<State<S, E>> states, State<S, E> state) {
for (State<S, E> s : states) {
if (s.getStates().contains(state)) {

View File

@@ -19,6 +19,9 @@ import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.notNullValue;
import static org.junit.Assert.assertThat;
import java.util.ArrayList;
import java.util.List;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Configuration;
@@ -29,6 +32,7 @@ import org.springframework.statemachine.config.EnableStateMachine;
import org.springframework.statemachine.config.StateMachineConfigurerAdapter;
import org.springframework.statemachine.config.builders.StateMachineStateConfigurer;
import org.springframework.statemachine.config.builders.StateMachineTransitionConfigurer;
import org.springframework.statemachine.listener.StateMachineListenerAdapter;
public class ExitEntryStateTests extends AbstractStateMachineTests {
@@ -40,14 +44,38 @@ public class ExitEntryStateTests extends AbstractStateMachineTests {
StateMachine<String, String> machine =
context.getBean(StateMachineSystemConstants.DEFAULT_ID_STATEMACHINE, StateMachine.class);
assertThat(machine, notNullValue());
TestStateEntryExitListener listener = new TestStateEntryExitListener();
machine.addStateListener(listener);
machine.start();
assertThat(machine.getState().getIds(), contains("S1"));
listener.reset();
machine.sendEvent("ENTRY1");
assertThat(machine.getState().getIds(), contains("S2", "S22"));
assertThat(listener.exited, contains("S1"));
assertThat(listener.entered, contains("S2", "S22"));
machine.sendEvent("EXIT1");
assertThat(machine.getState().getIds(), contains("S4"));
}
@SuppressWarnings("unchecked")
@Test
public void testSimpleEntryToInitial() {
context.register(Config1.class);
context.refresh();
StateMachine<String, String> machine =
context.getBean(StateMachineSystemConstants.DEFAULT_ID_STATEMACHINE, StateMachine.class);
assertThat(machine, notNullValue());
TestStateEntryExitListener listener = new TestStateEntryExitListener();
machine.addStateListener(listener);
machine.start();
assertThat(machine.getState().getIds(), contains("S1"));
listener.reset();
machine.sendEvent("ENTRY3");
assertThat(machine.getState().getIds(), contains("S2", "S21"));
assertThat(listener.exited, contains("S1"));
assertThat(listener.entered, contains("S2", "S21"));
}
@SuppressWarnings("unchecked")
@Test
public void testMultipleExitsToSameState() {
@@ -92,6 +120,7 @@ public class ExitEntryStateTests extends AbstractStateMachineTests {
.initial("S21")
.entry("S2ENTRY1")
.entry("S2ENTRY2")
.entry("S2ENTRY3")
.exit("S2EXIT1")
.exit("S2EXIT2")
.state("S22")
@@ -117,6 +146,10 @@ public class ExitEntryStateTests extends AbstractStateMachineTests {
.source("S1").target("S2ENTRY2")
.event("ENTRY2")
.and()
.withExternal()
.source("S1").target("S2ENTRY3")
.event("ENTRY3")
.and()
.withExternal()
.source("S22").target("S2EXIT1")
.event("EXIT1")
@@ -131,6 +164,9 @@ public class ExitEntryStateTests extends AbstractStateMachineTests {
.withEntry()
.source("S2ENTRY2").target("S23")
.and()
.withEntry()
.source("S2ENTRY3").target("S21")
.and()
.withExit()
.source("S2EXIT1").target("S4")
.and()
@@ -197,6 +233,26 @@ public class ExitEntryStateTests extends AbstractStateMachineTests {
}
}
private static class TestStateEntryExitListener extends StateMachineListenerAdapter<String, String> {
List<String> entered = new ArrayList<>();
List<String> exited = new ArrayList<>();
@Override
public void stateEntered(State<String, String> state) {
entered.add(state.getId());
}
@Override
public void stateExited(State<String, String> state) {
exited.add(state.getId());
}
public void reset() {
entered.clear();
exited.clear();
}
}
@Override
protected AnnotationConfigApplicationContext buildContext() {