Add support for default history state

- Add mechanism for transition into a default
  state vertex in cases where i.e. substate has
  never been entered, thus meaning there is no
  history. Without default vertex, submachine now
  does default entry logic to that region.
- Fixes #204
This commit is contained in:
Janne Valkealahti
2016-04-22 07:46:17 +01:00
parent 9339f6c742
commit 1adca702f6
16 changed files with 723 additions and 22 deletions

View File

@@ -73,23 +73,23 @@ public abstract class AbstractStateMachineTests {
}
public enum TestEvents {
E1,E2,E3,E4,EF
E1,E2,E3,E4,EF,EH
}
public static enum TestStates2 {
BUSY, PLAYING, PAUSED,
IDLE, CLOSED, OPEN,
PAUSED1, PAUSED2
BUSY, PLAYING, PAUSED,
IDLE, CLOSED, OPEN,
PAUSED1, PAUSED2
}
public static enum TestStates3 {
READY,
FORK, JOIN,
TASKS, T1, T1E, T2, T2E, T3, T3E
READY,
FORK, JOIN,
TASKS, T1, T1E, T2, T2E, T3, T3E
}
public static enum TestEvents2 {
PLAY, STOP, PAUSE, EJECT, LOAD
PLAY, STOP, PAUSE, EJECT, LOAD
}
@Configuration

View File

@@ -77,7 +77,7 @@ public class StateMachineModelTests {
Map<String, List<JunctionData<String, String>>> junctions = new HashMap<>();
Map<String, List<String>> forks = new HashMap<>();
Map<String, List<String>> joins = new HashMap<>();
TransitionsData<String, String> transitionsData = new TransitionsData<>(transitions, choices, junctions, forks, joins, null, null);
TransitionsData<String, String> transitionsData = new TransitionsData<>(transitions, choices, junctions, forks, joins, null, null, null);
StateMachineModel<String, String> stateMachineModel = new DefaultStateMachineModel<>(configurationData, statesData, transitionsData);
ObjectStateMachineFactory<String, String> factory = new ObjectStateMachineFactory<>(stateMachineModel);

View File

@@ -55,6 +55,20 @@ public class HistoryStateTests extends AbstractStateMachineTests {
assertThat(machine.getState().getIds(), contains(TestStates.S2, TestStates.S21));
}
@Test
@SuppressWarnings("unchecked")
public void testShallowNoHistoryDefaultsNormalEntry() {
context.register(BaseConfig.class, Config1.class);
context.refresh();
ObjectStateMachine<TestStates,TestEvents> machine =
context.getBean(StateMachineSystemConstants.DEFAULT_ID_STATEMACHINE, ObjectStateMachine.class);
assertThat(machine, notNullValue());
machine.start();
machine.sendEvent(TestEvents.E4);
assertThat(machine.getState().getIds(), contains(TestStates.S2, TestStates.S20));
}
@Test
@SuppressWarnings("unchecked")
public void testDeep() {
@@ -88,6 +102,40 @@ public class HistoryStateTests extends AbstractStateMachineTests {
assertThat(machine.getState().getIds(), contains(TestStates.S2, TestStates.S21, TestStates.S211));
}
@Test
@SuppressWarnings("unchecked")
public void testDefaultNotEntered() {
context.register(BaseConfig.class, Config4.class);
context.refresh();
ObjectStateMachine<TestStates,TestEvents> machine =
context.getBean(StateMachineSystemConstants.DEFAULT_ID_STATEMACHINE, ObjectStateMachine.class);
assertThat(machine, notNullValue());
machine.start();
assertThat(machine.getState().getIds(), contains(TestStates.S1));
machine.sendEvent(TestEvents.EH);
assertThat(machine.getState().getIds(), contains(TestStates.S3, TestStates.S33));
}
@Test
@SuppressWarnings("unchecked")
public void testDefaultHistoryIsFinal() {
context.register(BaseConfig.class, Config4.class);
context.refresh();
ObjectStateMachine<TestStates,TestEvents> machine =
context.getBean(StateMachineSystemConstants.DEFAULT_ID_STATEMACHINE, ObjectStateMachine.class);
assertThat(machine, notNullValue());
machine.start();
assertThat(machine.getState().getIds(), contains(TestStates.S1));
machine.sendEvent(TestEvents.E1);
assertThat(machine.getState().getIds(), contains(TestStates.S3, TestStates.S30));
machine.sendEvent(TestEvents.EF);
assertThat(machine.getState().getIds(), contains(TestStates.S3, TestStates.SF));
machine.sendEvent(TestEvents.E4);
assertThat(machine.getState().getIds(), contains(TestStates.S1));
machine.sendEvent(TestEvents.EH);
assertThat(machine.getState().getIds(), contains(TestStates.S3, TestStates.S33));
}
@Configuration
@EnableStateMachine
static class Config1 extends EnumStateMachineConfigurerAdapter<TestStates, TestEvents> {
@@ -106,7 +154,6 @@ public class HistoryStateTests extends AbstractStateMachineTests {
.state(TestStates.S20)
.state(TestStates.S21)
.history(TestStates.SH, History.SHALLOW);
}
@Override
@@ -239,4 +286,64 @@ public class HistoryStateTests extends AbstractStateMachineTests {
}
@Configuration
@EnableStateMachine
static class Config4 extends EnumStateMachineConfigurerAdapter<TestStates, TestEvents> {
@Override
public void configure(StateMachineStateConfigurer<TestStates, TestEvents> states) throws Exception {
states
.withStates()
.initial(TestStates.S1)
.state(TestStates.S1)
.state(TestStates.S3)
.and()
.withStates()
.parent(TestStates.S3)
.initial(TestStates.S30)
.state(TestStates.S31)
.state(TestStates.S32)
.state(TestStates.S33)
.end(TestStates.SF)
.history(TestStates.SH, History.SHALLOW);
}
@Override
public void configure(StateMachineTransitionConfigurer<TestStates, TestEvents> transitions) throws Exception {
transitions
.withExternal()
.source(TestStates.S1)
.target(TestStates.S3)
.event(TestEvents.E1)
.and()
.withExternal()
.source(TestStates.S30)
.target(TestStates.S31)
.event(TestEvents.E2)
.and()
.withExternal()
.source(TestStates.S31)
.target(TestStates.S32)
.event(TestEvents.E3)
.and()
.withExternal()
.source(TestStates.S30)
.target(TestStates.SF)
.event(TestEvents.EF)
.and()
.withExternal()
.source(TestStates.S3)
.target(TestStates.S1)
.event(TestEvents.E4)
.and()
.withExternal()
.source(TestStates.S1)
.target(TestStates.SH)
.event(TestEvents.EH)
.and()
.withHistory()
.source(TestStates.SH)
.target(TestStates.S33);
}
}
}