Persisting StateMachineContext for SM with nested regions and Fork/Join
- fixing issue when StateMachineContext is incorrectly persisted for SM with nested regions and Fork/Join configuration - Fixes #723
This commit is contained in:
committed by
Janne Valkealahti
parent
39ab4a0732
commit
bd2518cce9
@@ -88,7 +88,9 @@ public abstract class AbstractStateMachinePersister<S, E, T> implements StateMac
|
||||
S id = null;
|
||||
State<S, E> state = stateMachine.getState();
|
||||
if (state.isSubmachineState()) {
|
||||
id = getDeepState(state);
|
||||
StateMachine<S, E> submachine = ((AbstractState<S, E>) state).getSubmachine();
|
||||
id = submachine.getState().getId();
|
||||
childs.add(buildStateMachineContext(submachine));
|
||||
} else if (state.isOrthogonal()) {
|
||||
Collection<Region<S, E>> regions = ((AbstractState<S, E>)state).getRegions();
|
||||
for (Region<S, E> r : regions) {
|
||||
@@ -103,8 +105,8 @@ public abstract class AbstractStateMachinePersister<S, E, T> implements StateMac
|
||||
// building history state mappings
|
||||
Map<S, S> historyStates = new HashMap<S, S>();
|
||||
PseudoState<S, E> historyState = ((AbstractStateMachine<S, E>) stateMachine).getHistoryState();
|
||||
if (historyState != null) {
|
||||
historyStates.put(null, ((HistoryPseudoState<S, E>)historyState).getState().getId());
|
||||
if (historyState != null && ((HistoryPseudoState<S, E>)historyState).getState() != null) {
|
||||
historyStates.put(null, ((HistoryPseudoState<S, E>) historyState).getState().getId());
|
||||
}
|
||||
Collection<State<S, E>> states = stateMachine.getStates();
|
||||
for (State<S, E> ss : states) {
|
||||
@@ -121,12 +123,4 @@ public abstract class AbstractStateMachinePersister<S, E, T> implements StateMac
|
||||
}
|
||||
return new DefaultStateMachineContext<S, E>(childs, id, null, null, extendedState, historyStates, stateMachine.getId());
|
||||
}
|
||||
|
||||
private S getDeepState(State<S, E> state) {
|
||||
Collection<S> ids1 = state.getIds();
|
||||
@SuppressWarnings("unchecked")
|
||||
S[] ids2 = (S[]) ids1.toArray();
|
||||
// TODO: can this be empty as then we'd get error?
|
||||
return ids2[ids2.length-1];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,19 +73,19 @@ public class DefaultStateMachinePersisterTests {
|
||||
persister.persist(machine, "xxx");
|
||||
context = persist.contexts.get("xxx");
|
||||
assertThat(context.getState(), is("S1I"));
|
||||
assertThat(context.getChilds().isEmpty(), is(true));
|
||||
assertThat(context.getChilds().size(), is(1));
|
||||
|
||||
machine.sendEvent("E2");
|
||||
persister.persist(machine, "xxx");
|
||||
context = persist.contexts.get("xxx");
|
||||
assertThat(context.getState(), is("S11I"));
|
||||
assertThat(context.getChilds().isEmpty(), is(true));
|
||||
assertThat(context.getState(), is("S11"));
|
||||
assertThat(context.getChilds().size(), is(1));
|
||||
|
||||
machine.sendEvent("E3");
|
||||
persister.persist(machine, "xxx");
|
||||
context = persist.contexts.get("xxx");
|
||||
assertThat(context.getState(), is("S111"));
|
||||
assertThat(context.getChilds().isEmpty(), is(true));
|
||||
assertThat(context.getState(), is("S11"));
|
||||
assertThat(context.getChilds().size(), is(1));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -125,6 +125,53 @@ public class DefaultStateMachinePersisterTests {
|
||||
assertThat(context.getChilds().get(1).getState(), anyOf(is("S12"), is("S222")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeepNestedRegionsAndFork() throws Exception {
|
||||
StateMachine<String, String> machine = buildDeepNestedRegionsAndFork();
|
||||
|
||||
machine.start();
|
||||
InMemoryStateMachinePersist1 persist = new InMemoryStateMachinePersist1();
|
||||
StateMachinePersister<String, String, String> persister = new DefaultStateMachinePersister<>(persist);
|
||||
persister.persist(machine, "xxx");
|
||||
StateMachineContext<String, String> context = persist.contexts.get("xxx");
|
||||
assertThat(context.getState(), is("S2"));
|
||||
|
||||
machine.sendEvent("E1");
|
||||
persister.persist(machine, "xxx");
|
||||
context = persist.contexts.get("xxx");
|
||||
assertThat(context.getState(), is("S3"));
|
||||
assertThat(context.getChilds().size(), is(1));
|
||||
assertThat(context.getChilds().get(0).getChilds().size(), is(2));
|
||||
|
||||
machine.sendEvent("E2");
|
||||
persister.persist(machine, "xxx");
|
||||
context = persist.contexts.get("xxx");
|
||||
assertThat(context.getState(), is("S3"));
|
||||
assertThat(context.getChilds().size(), is(1));
|
||||
assertThat(context.getChilds().get(0).getChilds().size(), is(2));
|
||||
|
||||
machine.sendEvent("E3");
|
||||
persister.persist(machine, "xxx");
|
||||
context = persist.contexts.get("xxx");
|
||||
assertThat(context.getState(), is("S3"));
|
||||
assertThat(context.getChilds().size(), is(1));
|
||||
assertThat(context.getChilds().get(0).getChilds().size(), is(2));
|
||||
|
||||
machine.sendEvent("E4");
|
||||
persister.persist(machine, "xxx");
|
||||
context = persist.contexts.get("xxx");
|
||||
assertThat(context.getState(), is("S3"));
|
||||
assertThat(context.getChilds().size(), is(1));
|
||||
assertThat(context.getChilds().get(0).getChilds().size(), is(2));
|
||||
|
||||
machine.sendEvent("E5");
|
||||
persister.persist(machine, "xxx");
|
||||
context = persist.contexts.get("xxx");
|
||||
assertThat(context.getState(), is("END"));
|
||||
assertThat(context.getChilds().size(), is(1));
|
||||
assertThat(context.getChilds().get(0).getChilds().isEmpty(), is(true));
|
||||
}
|
||||
|
||||
private StateMachine<String, String> buildSimpleFlat() throws Exception {
|
||||
Builder<String, String> builder = StateMachineBuilder.builder();
|
||||
builder.configureStates()
|
||||
@@ -170,7 +217,6 @@ public class DefaultStateMachinePersisterTests {
|
||||
.source("S11I")
|
||||
.target("S111")
|
||||
.event("E3");
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
@@ -218,6 +264,78 @@ public class DefaultStateMachinePersisterTests {
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
private StateMachine<String, String> buildDeepNestedRegionsAndFork() throws Exception {
|
||||
Builder<String, String> builder = StateMachineBuilder.builder();
|
||||
builder.configureStates()
|
||||
.withStates()
|
||||
.initial("S1")
|
||||
.and()
|
||||
.withStates()
|
||||
.parent("S1")
|
||||
.initial("S2")
|
||||
.state("S22")
|
||||
.fork("F1")
|
||||
.state("S3")
|
||||
.join("J1")
|
||||
.end("END")
|
||||
.and()
|
||||
.withStates()
|
||||
.parent("S3")
|
||||
.initial("S4")
|
||||
.state("S41")
|
||||
.end("S4E")
|
||||
.and()
|
||||
.withStates()
|
||||
.parent("S3")
|
||||
.initial("S5")
|
||||
.state("S51")
|
||||
.end("S5E");
|
||||
|
||||
builder.configureTransitions()
|
||||
.withExternal()
|
||||
.source("S2")
|
||||
.target("S22")
|
||||
.event("E1")
|
||||
.and()
|
||||
.withExternal()
|
||||
.source("S22")
|
||||
.target("F1")
|
||||
.and()
|
||||
.withFork()
|
||||
.source("F1")
|
||||
.target("S3")
|
||||
.and()
|
||||
.withExternal()
|
||||
.source("S4")
|
||||
.target("S41")
|
||||
.event("E2")
|
||||
.and()
|
||||
.withExternal()
|
||||
.source("S41")
|
||||
.target("S4E")
|
||||
.event("E3")
|
||||
.and()
|
||||
.withExternal()
|
||||
.source("S5")
|
||||
.target("S51")
|
||||
.event("E4")
|
||||
.and()
|
||||
.withExternal()
|
||||
.source("S51")
|
||||
.target("S5E")
|
||||
.event("E5")
|
||||
.and()
|
||||
.withJoin()
|
||||
.source("S3")
|
||||
.target("J1")
|
||||
.and()
|
||||
.withExternal()
|
||||
.source("J1")
|
||||
.target("END");
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
static class InMemoryStateMachinePersist1 implements StateMachinePersist<String, String, String> {
|
||||
|
||||
public final HashMap<String, StateMachineContext<String, String>> contexts = new HashMap<>();
|
||||
|
||||
Reference in New Issue
Block a user