From 714b8131ffc6e710ddad708efb5414c076db662c Mon Sep 17 00:00:00 2001 From: Janne Valkealahti Date: Sun, 22 Feb 2015 16:01:55 +0000 Subject: [PATCH] Submachine doesn't work with states on a same level - resolves #20 - create correct state type when substate mixed with normal states. --- .../config/EnumStateMachineFactory.java | 38 ++++++++++++++----- .../statemachine/SubStateMachineTests.java | 36 ++++++++++++++++++ 2 files changed, 65 insertions(+), 9 deletions(-) diff --git a/spring-statemachine-core/src/main/java/org/springframework/statemachine/config/EnumStateMachineFactory.java b/spring-statemachine-core/src/main/java/org/springframework/statemachine/config/EnumStateMachineFactory.java index a359bb19..13b6e91c 100644 --- a/spring-statemachine-core/src/main/java/org/springframework/statemachine/config/EnumStateMachineFactory.java +++ b/spring-statemachine-core/src/main/java/org/springframework/statemachine/config/EnumStateMachineFactory.java @@ -97,7 +97,7 @@ public class EnumStateMachineFactory, E extends Enum> exten }; // use two stack, first for states and second for machines - Stack> machineStack = new Stack>(); + Stack> machineStack = new Stack>(); Stack> stateStack = new Stack>(); Iterable>> postOrderTraversal = traverser.postOrderTraversal(tree.getRoot()); @@ -131,11 +131,11 @@ public class EnumStateMachineFactory, E extends Enum> exten if (machineStack.isEmpty()) { machine = buildSimpleMachine(stateMap, stateDatas, transitionsData, getBeanFactory()); - machineStack.push(machine); + machineStack.push(new MachineStackItem(machine, peek.getParent())); } else { - StateMachine pop = machineStack.pop(); + MachineStackItem pop = machineStack.pop(); machine = buildSubMachine(stateMap, pop, stateDatas, transitionsData, getBeanFactory()); - machineStack.push(machine); + machineStack.push(new MachineStackItem(machine, null)); } stateStack.push(stateData); } @@ -144,6 +144,19 @@ public class EnumStateMachineFactory, E extends Enum> exten return machine; } + private static class MachineStackItem { + + StateMachine machine; + Object parent; + + public MachineStackItem(StateMachine machine, Object parent) { + super(); + this.machine = machine; + this.parent = parent; + } + + } + private Collection> resolveTransitionData(Collection> in, Collection> stateDatas) { ArrayList> out = new ArrayList>(); @@ -222,14 +235,21 @@ public class EnumStateMachineFactory, E extends Enum> exten } private static , E extends Enum> StateMachine buildSubMachine( - Map> stateMap, StateMachine submachine, Collection> stateDatas, + Map> stateMap, MachineStackItem stackItem, Collection> stateDatas, Collection> transitionsData, BeanFactory beanFactory) { Collection> states = new ArrayList>(); State state = null; + State initialState = null; for (StateData stateData : stateDatas) { - state = new StateMachineState(stateData.getState(), submachine, stateData.getDeferred(), - stateData.getEntryActions(), stateData.getExitActions(), new DefaultPseudoState( - PseudoStateKind.INITIAL)); + if (stackItem.parent == null || stateData.getState().equals(stackItem.parent)) { + state = new StateMachineState(stateData.getState(), stackItem.machine, stateData.getDeferred(), + stateData.getEntryActions(), stateData.getExitActions(), new DefaultPseudoState( + PseudoStateKind.INITIAL)); + initialState = state; + } else { + state = new EnumState(stateData.getState(), stateData.getDeferred(), + stateData.getEntryActions(), stateData.getExitActions(), null); + } states.add(state); stateMap.put(stateData.getState(), state); } @@ -251,7 +271,7 @@ public class EnumStateMachineFactory, E extends Enum> exten } } - EnumStateMachine machine = new EnumStateMachine(states, transitions, state, null); + EnumStateMachine machine = new EnumStateMachine(states, transitions, initialState, null); machine.afterPropertiesSet(); if (beanFactory != null) { diff --git a/spring-statemachine-core/src/test/java/org/springframework/statemachine/SubStateMachineTests.java b/spring-statemachine-core/src/test/java/org/springframework/statemachine/SubStateMachineTests.java index 24b3d7e9..a313cb54 100644 --- a/spring-statemachine-core/src/test/java/org/springframework/statemachine/SubStateMachineTests.java +++ b/spring-statemachine-core/src/test/java/org/springframework/statemachine/SubStateMachineTests.java @@ -16,6 +16,8 @@ package org.springframework.statemachine; import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.Matchers.contains; +import static org.hamcrest.Matchers.notNullValue; import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; @@ -34,6 +36,7 @@ import org.springframework.statemachine.config.EnableStateMachine; import org.springframework.statemachine.config.EnumStateMachineConfigurerAdapter; import org.springframework.statemachine.config.builders.StateMachineStateConfigurer; import org.springframework.statemachine.config.builders.StateMachineTransitionConfigurer; +import org.springframework.statemachine.event.StateMachineEventPublisherConfiguration; import org.springframework.statemachine.state.DefaultPseudoState; import org.springframework.statemachine.state.EnumState; import org.springframework.statemachine.state.PseudoState; @@ -371,6 +374,19 @@ public class SubStateMachineTests extends AbstractStateMachineTests { } + @Test + public void testMixedStates() throws Exception { + context.register(BaseConfig.class, StateMachineEventPublisherConfiguration.class, Config2.class); + context.refresh(); + assertTrue(context.containsBean(StateMachineSystemConstants.DEFAULT_ID_STATEMACHINE)); + @SuppressWarnings("unchecked") + EnumStateMachine machine = + context.getBean(StateMachineSystemConstants.DEFAULT_ID_STATEMACHINE, EnumStateMachine.class); + machine.start(); + assertThat(machine, notNullValue()); + + assertThat(machine.getState().getIds(), contains(TestStates.S1, TestStates.S10)); + } @Configuration @EnableStateMachine @@ -436,4 +452,24 @@ public class SubStateMachineTests extends AbstractStateMachineTests { } + @Configuration + @EnableStateMachine + static class Config2 extends EnumStateMachineConfigurerAdapter { + + @Override + public void configure(StateMachineStateConfigurer states) throws Exception { + states + .withStates() + .initial(TestStates.S1) + .state(TestStates.S1) + .state(TestStates.S2) + .and() + .withStates() + .parent(TestStates.S1) + .initial(TestStates.S10) + .state(TestStates.S10); + } + + } + }