From 8c18dc86de4aab79919af37f056c6df6aec5da85 Mon Sep 17 00:00:00 2001 From: Janne Valkealahti Date: Sat, 8 Jul 2017 17:34:31 +0100 Subject: [PATCH] Change machine lifecycle with restore - Fixing machine lifecycle logic when machine is restored which effectively should not touch any lifecycle methods as start/stop is user level action. - Remove start/stop from restore and attempt to do same when root machine is started. This also needed some further changes as some functionality for restore was essentially broken - Fixes #386 --- .../support/AbstractStateMachine.java | 36 ++++++++++++------- .../persist/StateMachinePersistTests.java | 33 +++++++++++++++-- 2 files changed, 55 insertions(+), 14 deletions(-) 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 6952da65..ea95ef09 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 @@ -355,6 +355,15 @@ public abstract class AbstractStateMachine extends StateMachineObjectSuppo // dispatched via executor StateContext stateContext = buildStateContext(Stage.STATEMACHINE_START, null, null, getRelayStateMachine()); notifyStateMachineStarted(stateContext); + if (currentState != null && currentState.isSubmachineState()) { + StateMachine submachine = ((AbstractState)currentState).getSubmachine(); + submachine.start(); + } else if (currentState != null && currentState.isOrthogonal()) { + Collection> regions = ((AbstractState)currentState).getRegions(); + for (Region region : regions) { + region.start(); + } + } return; } registerPseudoStateListener(); @@ -613,7 +622,6 @@ public abstract class AbstractStateMachine extends StateMachineObjectSuppo } }); } - submachine.start(); } else if (s.isOrthogonal() && stateMachineContext.getChilds() != null) { Collection> regions = ((AbstractState)s).getRegions(); for (Region region : regions) { @@ -627,9 +635,6 @@ public abstract class AbstractStateMachine extends StateMachineObjectSuppo }); } } - for (Region region : regions) { - region.start(); - } } if (log.isDebugEnabled()) { @@ -652,8 +657,15 @@ public abstract class AbstractStateMachine extends StateMachineObjectSuppo }); } } - for (Region region : regions) { - region.start(); + } else { + for (final StateMachineContext child : stateMachineContext.getChilds()) { + S state2 = child.getState(); + if (state2 != null && ss.getIds().contains(state2)) { + currentState = s; + lastState = currentState; + stateSet = true; + break; + } } } } @@ -951,23 +963,23 @@ public abstract class AbstractStateMachine extends StateMachineObjectSuppo } State notifyFrom = currentState; currentState = state; - if (!isRunning()) { - start(); - } entryToState(state, message, transition, stateMachine); notifyStateChanged(buildStateContext(Stage.STATE_CHANGED, message, null, getRelayStateMachine(), notifyFrom, state)); nonDeepStatePresent = true; + if (!isRunning() && !isComplete()) { + start(); + } } else if (currentState == null && StateMachineUtils.isSubstate(findDeep, state)) { if (exit) { exitCurrentState(findDeep, message, transition, stateMachine, sources, targets); } State notifyFrom = currentState; currentState = findDeep; - if (!isRunning()) { - start(); - } entryToState(findDeep, message, transition, stateMachine); notifyStateChanged(buildStateContext(Stage.STATE_CHANGED, message, null, getRelayStateMachine(), notifyFrom, findDeep)); + if (!isRunning() && !isComplete()) { + start(); + } } if (currentState != null && !nonDeepStatePresent) { diff --git a/spring-statemachine-core/src/test/java/org/springframework/statemachine/persist/StateMachinePersistTests.java b/spring-statemachine-core/src/test/java/org/springframework/statemachine/persist/StateMachinePersistTests.java index 9a3c8005..52483ca5 100644 --- a/spring-statemachine-core/src/test/java/org/springframework/statemachine/persist/StateMachinePersistTests.java +++ b/spring-statemachine-core/src/test/java/org/springframework/statemachine/persist/StateMachinePersistTests.java @@ -177,7 +177,7 @@ public class StateMachinePersistTests extends AbstractStateMachineTests { @SuppressWarnings("unchecked") @Test - public void testSubsInRegions() throws Exception { + public void testSubsInRegions1() throws Exception { context.register(Config51.class, Config52.class); context.refresh(); @@ -208,6 +208,30 @@ public class StateMachinePersistTests extends AbstractStateMachineTests { assertThat(stateMachine2.getState().getIds(), containsInAnyOrder("S12", "S22", "S221")); } + @SuppressWarnings("unchecked") + @Test + public void testSubsInRegions2() throws Exception { + context.register(Config51.class, Config52.class); + context.refresh(); + + InMemoryStateMachinePersist1 stateMachinePersist = new InMemoryStateMachinePersist1(); + StateMachinePersister persister = new DefaultStateMachinePersister<>(stateMachinePersist); + + StateMachine stateMachine1 = context.getBean("machine1", StateMachine.class); + StateMachine stateMachine2 = context.getBean("machine2", StateMachine.class); + stateMachine1.start(); + + stateMachine1.sendEvent("E1"); + assertThat(stateMachine1.getState().getIds(), containsInAnyOrder("S12", "S21")); + stateMachine1.sendEvent("E2"); + assertThat(stateMachine1.getState().getIds(), containsInAnyOrder("S12", "S22", "S221")); + stateMachine1.sendEvent("E3"); + assertThat(stateMachine1.getState().getIds(), containsInAnyOrder("S12", "S22", "S222")); + persister.persist(stateMachine1, "xxx"); + stateMachine2 = persister.restore(stateMachine2, "xxx"); + assertThat(stateMachine2.getState().getIds(), containsInAnyOrder("S12", "S22", "S222")); + } + @SuppressWarnings("unchecked") @Test public void testHistoryFlatShallow() throws Exception { @@ -553,7 +577,12 @@ public class StateMachinePersistTests extends AbstractStateMachineTests { .withExternal() .source("S21") .target("S22") - .event("E2"); + .event("E2") + .and() + .withExternal() + .source("S221") + .target("S222") + .event("E3"); } }