From 214f8a45e38ba2df25b5d324a57d5ab7ead6d632 Mon Sep 17 00:00:00 2001 From: Janne Valkealahti Date: Sat, 9 May 2015 17:45:42 +0100 Subject: [PATCH] Triggerless transition doesn't work from initial to terminate - Fix correct handling in this case. - Tune lifecycle so that recursive calls to start() in a same thread doesn't cause multiple calls to doStart(). --- .../support/AbstractStateMachine.java | 2 +- .../support/LifecycleObjectSupport.java | 2 +- .../transition/TransitionTests.java | 72 +++++++++++++++++++ 3 files changed, 74 insertions(+), 2 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 1e44de11..90710b66 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 @@ -371,7 +371,7 @@ public abstract class AbstractStateMachine extends StateMachineObjectSuppo } } } - + private State findStateWithPseudoState(PseudoState pseudoState) { for (State s : states) { if (s.getPseudoState() == pseudoState) { diff --git a/spring-statemachine-core/src/main/java/org/springframework/statemachine/support/LifecycleObjectSupport.java b/spring-statemachine-core/src/main/java/org/springframework/statemachine/support/LifecycleObjectSupport.java index ea4987c6..1dde7fca 100644 --- a/spring-statemachine-core/src/main/java/org/springframework/statemachine/support/LifecycleObjectSupport.java +++ b/spring-statemachine-core/src/main/java/org/springframework/statemachine/support/LifecycleObjectSupport.java @@ -101,8 +101,8 @@ public abstract class LifecycleObjectSupport implements InitializingBean, SmartL this.lifecycleLock.lock(); try { if (!this.running) { - this.doStart(); this.running = true; + this.doStart(); if (log.isInfoEnabled()) { log.info("started " + this); } else { diff --git a/spring-statemachine-core/src/test/java/org/springframework/statemachine/transition/TransitionTests.java b/spring-statemachine-core/src/test/java/org/springframework/statemachine/transition/TransitionTests.java index 03d8a370..8431bdb6 100644 --- a/spring-statemachine-core/src/test/java/org/springframework/statemachine/transition/TransitionTests.java +++ b/spring-statemachine-core/src/test/java/org/springframework/statemachine/transition/TransitionTests.java @@ -17,6 +17,7 @@ package org.springframework.statemachine.transition; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.Matchers.contains; +import static org.hamcrest.Matchers.nullValue; import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; @@ -59,7 +60,33 @@ public class TransitionTests extends AbstractStateMachineTests { machine.sendEvent(MessageBuilder.withPayload(TestEvents.E1).build()); assertThat(machine.getState().getIds(), contains(TestStates.S3)); ctx.close(); + } + @SuppressWarnings({ "unchecked" }) + @Test + public void testTriggerlessTransitionFromInitial() throws Exception { + AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(BaseConfig.class, Config3.class); + assertTrue(ctx.containsBean(StateMachineSystemConstants.DEFAULT_ID_STATEMACHINE)); + EnumStateMachine machine = + ctx.getBean(StateMachineSystemConstants.DEFAULT_ID_STATEMACHINE, EnumStateMachine.class); + machine.start(); + assertThat(machine.getState().getIds(), contains(TestStates.S2)); + ctx.close(); + } + + @SuppressWarnings({ "unchecked" }) + @Test + public void testTriggerlessTransitionFromInitialToEnd() throws Exception { + AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(BaseConfig.class, Config4.class); + assertTrue(ctx.containsBean(StateMachineSystemConstants.DEFAULT_ID_STATEMACHINE)); + EnumStateMachine machine = + ctx.getBean(StateMachineSystemConstants.DEFAULT_ID_STATEMACHINE, EnumStateMachine.class); + machine.start(); + // end state terminates sm so state is null + assertThat(machine.getState(), nullValue()); + assertThat(machine.isComplete(), is(true)); + assertThat(machine.isRunning(), is(false)); + ctx.close(); } @SuppressWarnings({ "unchecked" }) @@ -174,4 +201,49 @@ public class TransitionTests extends AbstractStateMachineTests { } + @Configuration + @EnableStateMachine + public static class Config3 extends EnumStateMachineConfigurerAdapter { + + @Override + public void configure(StateMachineStateConfigurer states) throws Exception { + states + .withStates() + .initial(TestStates.S1) + .states(EnumSet.allOf(TestStates.class)); + } + + @Override + public void configure(StateMachineTransitionConfigurer transitions) throws Exception { + transitions + .withExternal() + .source(TestStates.S1) + .target(TestStates.S2); + } + + } + + @Configuration + @EnableStateMachine + public static class Config4 extends EnumStateMachineConfigurerAdapter { + + @Override + public void configure(StateMachineStateConfigurer states) throws Exception { + states + .withStates() + .initial(TestStates.S1) + .state(TestStates.SF) + .end(TestStates.SF); + } + + @Override + public void configure(StateMachineTransitionConfigurer transitions) throws Exception { + transitions + .withExternal() + .source(TestStates.S1) + .target(TestStates.SF); + } + + } + }