diff --git a/docs/src/reference/asciidoc/sm.adoc b/docs/src/reference/asciidoc/sm.adoc index 7be04a03..aaef7f6c 100644 --- a/docs/src/reference/asciidoc/sm.adoc +++ b/docs/src/reference/asciidoc/sm.adoc @@ -163,10 +163,11 @@ interface. Both of these have pros and cons which will be discussed later. === Application Context Events Application context events classes are _OnTransitionStartEvent_, _OnTransitionEvent_, _OnTransitionEndEvent_, _OnStateExitEvent_, -_OnStateEntryEvent_ and _OnStateChangedEvent_. There can be used as is -as spring typed _ApplicationListener_ class but all also share a -common class _StateMachineEvent_ which can be used to get events for -all. +_OnStateEntryEvent_, _OnStateChangedEvent_, _OnStateMachineStart_ and +_OnStateMachineStop_. These can be used as is with spring typed +_ApplicationListener_ class but they also share a common class +_StateMachineEvent_ which can be used to get statemachine related +events. [source,java,indent=0] ---- diff --git a/spring-statemachine-core/src/main/java/org/springframework/statemachine/EnumStateMachine.java b/spring-statemachine-core/src/main/java/org/springframework/statemachine/EnumStateMachine.java index c6509d92..ef3a898f 100644 --- a/spring-statemachine-core/src/main/java/org/springframework/statemachine/EnumStateMachine.java +++ b/spring-statemachine-core/src/main/java/org/springframework/statemachine/EnumStateMachine.java @@ -41,14 +41,24 @@ public class EnumStateMachine, E extends Enum> extends Abst * @param initialState the initial state */ public EnumStateMachine(Collection> states, Collection> transitions, - State initialState, State endState) { - super(states, transitions, initialState, endState); + State initialState) { + super(states, transitions, initialState); } + /** + * Instantiates a new enum state machine. + * + * @param states the states + * @param transitions the transitions + * @param initialState the initial state + * @param initialTransition the initial transition + * @param initialEvent the initial event + * @param extendedState the extended state + */ public EnumStateMachine(Collection> states, Collection> transitions, - State initialState, Transition initialTransition, State endState, + State initialState, Transition initialTransition, Message initialEvent, ExtendedState extendedState) { - super(states, transitions, initialState, initialTransition, endState, initialEvent, extendedState); + super(states, transitions, initialState, initialTransition, initialEvent, extendedState); } } 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 3f7be089..2202d7fd 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 @@ -191,7 +191,7 @@ public class EnumStateMachineFactory, E extends Enum> exten Collection> states = new ArrayList>(); states.add(rstate); EnumStateMachine m = new EnumStateMachine(states, null, rstate, - null, null, null, defaultExtendedState); + null, null, defaultExtendedState); if (contextEvents != null) { m.setContextEventsEnabled(contextEvents); } @@ -278,7 +278,6 @@ public class EnumStateMachineFactory, E extends Enum> exten State state = null; State initialState = null; Action initialAction = null; - State endState = null; Collection> states = new ArrayList>(); for (StateData stateData : stateDatas) { StateMachine stateMachine = machineMap.get(stateData.getState()); @@ -299,6 +298,8 @@ public class EnumStateMachineFactory, E extends Enum> exten PseudoState pseudoState = null; if (stateData.isInitial()) { pseudoState = new DefaultPseudoState(PseudoStateKind.INITIAL); + } else if (stateData.isEnd()) { + pseudoState = new DefaultPseudoState(PseudoStateKind.END); } state = new EnumState(stateData.getState(), stateData.getDeferred(), stateData.getEntryActions(), stateData.getExitActions(), pseudoState); @@ -306,9 +307,6 @@ public class EnumStateMachineFactory, E extends Enum> exten initialState = state; initialAction = stateData.getInitialAction(); } - if (stateData.isEnd()) { - endState = state; - } states.add(state); } @@ -355,7 +353,7 @@ public class EnumStateMachineFactory, E extends Enum> exten } EnumStateMachine machine = new EnumStateMachine(states, transitions, initialState, - initialTransition, endState, null, defaultExtendedState); + initialTransition, null, defaultExtendedState); if (contextEvents != null) { machine.setContextEventsEnabled(contextEvents); } diff --git a/spring-statemachine-core/src/main/java/org/springframework/statemachine/event/DefaultStateMachineEventPublisher.java b/spring-statemachine-core/src/main/java/org/springframework/statemachine/event/DefaultStateMachineEventPublisher.java index cf744869..f56a1dd9 100644 --- a/spring-statemachine-core/src/main/java/org/springframework/statemachine/event/DefaultStateMachineEventPublisher.java +++ b/spring-statemachine-core/src/main/java/org/springframework/statemachine/event/DefaultStateMachineEventPublisher.java @@ -17,6 +17,7 @@ package org.springframework.statemachine.event; import org.springframework.context.ApplicationEventPublisher; import org.springframework.context.ApplicationEventPublisherAware; +import org.springframework.statemachine.StateMachine; import org.springframework.statemachine.state.State; import org.springframework.statemachine.transition.Transition; @@ -92,4 +93,18 @@ public class DefaultStateMachineEventPublisher implements StateMachineEventPubli } } + @Override + public void publishStateMachineStart(Object source, StateMachine stateMachine) { + if (applicationEventPublisher != null) { + applicationEventPublisher.publishEvent(new OnStateMachineStart(source, stateMachine)); + } + } + + @Override + public void publishStateMachineStop(Object source, StateMachine stateMachine) { + if (applicationEventPublisher != null) { + applicationEventPublisher.publishEvent(new OnStateMachineStop(source, stateMachine)); + } + } + } diff --git a/spring-statemachine-core/src/main/java/org/springframework/statemachine/event/OnStateMachineStart.java b/spring-statemachine-core/src/main/java/org/springframework/statemachine/event/OnStateMachineStart.java new file mode 100644 index 00000000..9fa95241 --- /dev/null +++ b/spring-statemachine-core/src/main/java/org/springframework/statemachine/event/OnStateMachineStart.java @@ -0,0 +1,56 @@ +/* + * Copyright 2015 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.statemachine.event; + +import org.springframework.statemachine.StateMachine; + +/** + * Generic event representing that state machine has been started. + * + * @author Janne Valkealahti + * + */ +@SuppressWarnings("serial") +public class OnStateMachineStart extends StateMachineEvent { + + private final StateMachine stateMachine; + + /** + * Instantiates a new on state exit event. + * + * @param source the source + * @param stateMachine the statemachine + */ + public OnStateMachineStart(Object source, StateMachine stateMachine) { + super(source); + this.stateMachine = stateMachine; + } + + /** + * Gets the statemachine. + * + * @return the statemachine + */ + public StateMachine getStateMachine() { + return stateMachine; + } + + @Override + public String toString() { + return "OnStateMachineStart [stateMachine=" + stateMachine + "]"; + } + +} diff --git a/spring-statemachine-core/src/main/java/org/springframework/statemachine/event/OnStateMachineStop.java b/spring-statemachine-core/src/main/java/org/springframework/statemachine/event/OnStateMachineStop.java new file mode 100644 index 00000000..f062f28e --- /dev/null +++ b/spring-statemachine-core/src/main/java/org/springframework/statemachine/event/OnStateMachineStop.java @@ -0,0 +1,56 @@ +/* + * Copyright 2015 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.statemachine.event; + +import org.springframework.statemachine.StateMachine; + +/** + * Generic event representing that state machine has been stopped or terminated. + * + * @author Janne Valkealahti + * + */ +@SuppressWarnings("serial") +public class OnStateMachineStop extends StateMachineEvent { + + private final StateMachine stateMachine; + + /** + * Instantiates a new on state exit event. + * + * @param source the source + * @param stateMachine the statemachine + */ + public OnStateMachineStop(Object source, StateMachine stateMachine) { + super(source); + this.stateMachine = stateMachine; + } + + /** + * Gets the statemachine. + * + * @return the statemachine + */ + public StateMachine getStateMachine() { + return stateMachine; + } + + @Override + public String toString() { + return "OnStateMachineStart [stateMachine=" + stateMachine + "]"; + } + +} diff --git a/spring-statemachine-core/src/main/java/org/springframework/statemachine/event/StateMachineEventPublisher.java b/spring-statemachine-core/src/main/java/org/springframework/statemachine/event/StateMachineEventPublisher.java index b2f76ef7..670c27af 100644 --- a/spring-statemachine-core/src/main/java/org/springframework/statemachine/event/StateMachineEventPublisher.java +++ b/spring-statemachine-core/src/main/java/org/springframework/statemachine/event/StateMachineEventPublisher.java @@ -15,6 +15,7 @@ */ package org.springframework.statemachine.event; +import org.springframework.statemachine.StateMachine; import org.springframework.statemachine.state.State; import org.springframework.statemachine.transition.Transition; @@ -75,4 +76,20 @@ public interface StateMachineEventPublisher { */ void publishTransition(Object source, Transition transition); + /** + * Publish a statemachine start event. + * + * @param source the source + * @param stateMachine the statemachine + */ + void publishStateMachineStart(Object source, StateMachine stateMachine); + + /** + * Publish a statemachine stop event. + * + * @param source the source + * @param stateMachine the statemachine + */ + void publishStateMachineStop(Object source, StateMachine stateMachine); + } diff --git a/spring-statemachine-core/src/main/java/org/springframework/statemachine/listener/CompositeStateMachineListener.java b/spring-statemachine-core/src/main/java/org/springframework/statemachine/listener/CompositeStateMachineListener.java index be85e23c..b6e37bce 100644 --- a/spring-statemachine-core/src/main/java/org/springframework/statemachine/listener/CompositeStateMachineListener.java +++ b/spring-statemachine-core/src/main/java/org/springframework/statemachine/listener/CompositeStateMachineListener.java @@ -17,6 +17,7 @@ package org.springframework.statemachine.listener; import java.util.Iterator; +import org.springframework.statemachine.StateMachine; import org.springframework.statemachine.state.State; import org.springframework.statemachine.transition.Transition; @@ -79,4 +80,20 @@ public class CompositeStateMachineListener extends AbstractCompositeListene } } + @Override + public void stateMachineStarted(StateMachine stateMachine) { + for (Iterator> iterator = getListeners().reverse(); iterator.hasNext();) { + StateMachineListener listener = iterator.next(); + listener.stateMachineStarted(stateMachine); + } + } + + @Override + public void stateMachineStopped(StateMachine stateMachine) { + for (Iterator> iterator = getListeners().reverse(); iterator.hasNext();) { + StateMachineListener listener = iterator.next(); + listener.stateMachineStopped(stateMachine); + } + } + } diff --git a/spring-statemachine-core/src/main/java/org/springframework/statemachine/listener/StateMachineListener.java b/spring-statemachine-core/src/main/java/org/springframework/statemachine/listener/StateMachineListener.java index f1c940a7..74038adf 100644 --- a/spring-statemachine-core/src/main/java/org/springframework/statemachine/listener/StateMachineListener.java +++ b/spring-statemachine-core/src/main/java/org/springframework/statemachine/listener/StateMachineListener.java @@ -15,6 +15,7 @@ */ package org.springframework.statemachine.listener; +import org.springframework.statemachine.StateMachine; import org.springframework.statemachine.state.State; import org.springframework.statemachine.transition.Transition; @@ -71,4 +72,18 @@ public interface StateMachineListener { */ void transitionEnded(Transition transition); + /** + * Notified when statemachine starts + * + * @param stateMachine the statemachine + */ + void stateMachineStarted(StateMachine stateMachine); + + /** + * Notified when statemachine stops + * + * @param stateMachine the statemachine + */ + void stateMachineStopped(StateMachine stateMachine); + } diff --git a/spring-statemachine-core/src/main/java/org/springframework/statemachine/listener/StateMachineListenerAdapter.java b/spring-statemachine-core/src/main/java/org/springframework/statemachine/listener/StateMachineListenerAdapter.java index 11f7e40c..ba49ba3b 100644 --- a/spring-statemachine-core/src/main/java/org/springframework/statemachine/listener/StateMachineListenerAdapter.java +++ b/spring-statemachine-core/src/main/java/org/springframework/statemachine/listener/StateMachineListenerAdapter.java @@ -15,6 +15,7 @@ */ package org.springframework.statemachine.listener; +import org.springframework.statemachine.StateMachine; import org.springframework.statemachine.state.State; import org.springframework.statemachine.transition.Transition; @@ -53,4 +54,12 @@ public class StateMachineListenerAdapter implements StateMachineListener transition) { } + @Override + public void stateMachineStarted(StateMachine stateMachine) { + } + + @Override + public void stateMachineStopped(StateMachine stateMachine) { + } + } diff --git a/spring-statemachine-core/src/main/java/org/springframework/statemachine/state/PseudoStateKind.java b/spring-statemachine-core/src/main/java/org/springframework/statemachine/state/PseudoStateKind.java index f14bc4be..14d458e7 100644 --- a/spring-statemachine-core/src/main/java/org/springframework/statemachine/state/PseudoStateKind.java +++ b/spring-statemachine-core/src/main/java/org/springframework/statemachine/state/PseudoStateKind.java @@ -18,13 +18,16 @@ package org.springframework.statemachine.state; /** * Defines enumeration of a {@link PseudoState} kind. This is uses within a * transitive states indicating its kind. - * + * * @author Janne Valkealahti * */ public enum PseudoStateKind { /** Indicates an initial kind. */ - INITIAL - + INITIAL, + + /** End or terminate kind */ + END + } 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 44d4cdca..4eebe2fd 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 @@ -81,8 +81,6 @@ public abstract class AbstractStateMachine extends LifecycleObjectSupport private final Transition initialTransition; - private final State endState; - private final Message initialEvent; private final ExtendedState extendedState; @@ -119,19 +117,6 @@ public abstract class AbstractStateMachine extends LifecycleObjectSupport this(states, transitions, initialState, new DefaultExtendedState()); } - /** - * Instantiates a new abstract state machine. - * - * @param states the states - * @param transitions the transitions - * @param initialState the initial state - * @param endState the end state - */ - public AbstractStateMachine(Collection> states, Collection> transitions, - State initialState, State endState) { - this(states, transitions, initialState, null, endState, null, new DefaultExtendedState()); - } - /** * Instantiates a new abstract state machine. * @@ -142,7 +127,7 @@ public abstract class AbstractStateMachine extends LifecycleObjectSupport */ public AbstractStateMachine(Collection> states, Collection> transitions, State initialState, ExtendedState extendedState) { - this(states, transitions, initialState, null, null, null, extendedState); + this(states, transitions, initialState, null, null, extendedState); } /** @@ -151,18 +136,16 @@ public abstract class AbstractStateMachine extends LifecycleObjectSupport * @param states the states of this machine * @param transitions the transitions of this machine * @param initialState the initial state of this machine - * @param endState the final state of this machine * @param initialEvent the initial event of this machine * @param extendedState the extended state of this machine */ public AbstractStateMachine(Collection> states, Collection> transitions, - State initialState, Transition initialTransition, State endState, Message initialEvent, ExtendedState extendedState) { + State initialState, Transition initialTransition, Message initialEvent, ExtendedState extendedState) { super(); this.states = states; this.transitions = transitions; this.initialState = initialState; this.initialTransition = initialTransition; - this.endState = endState; this.initialEvent = initialEvent; this.extendedState = extendedState != null ? extendedState : new DefaultExtendedState(); } @@ -222,6 +205,7 @@ public abstract class AbstractStateMachine extends LifecycleObjectSupport @Override protected void doStart() { super.doStart(); + notifyStateMachineStarted(this); registerTriggerListener(); switchToState(initialState, initialEvent, null, this); // TODO: for now execute outside of switchToState @@ -235,6 +219,7 @@ public abstract class AbstractStateMachine extends LifecycleObjectSupport @Override protected void doStop() { super.doStop(); + notifyStateMachineStopped(this); currentState = null; } @@ -245,7 +230,12 @@ public abstract class AbstractStateMachine extends LifecycleObjectSupport @Override public boolean isComplete() { - return (endState != null && endState.equals(currentState)); + if (currentState == null) { + return !isRunning(); + } else { + return currentState != null && currentState.getPseudoState() != null + && currentState.getPseudoState().getKind() == PseudoStateKind.END; + } } /** @@ -333,7 +323,9 @@ public abstract class AbstractStateMachine extends LifecycleObjectSupport switchToState(target, event, t, stateMachine); } } - + if (isComplete()) { + stop(); + } } private State findDeepParent(State state) { @@ -777,6 +769,26 @@ public abstract class AbstractStateMachine extends LifecycleObjectSupport } } + private void notifyStateMachineStarted(StateMachine stateMachine) { + stateListener.stateMachineStarted(stateMachine); + if (contextEventsEnabled) { + StateMachineEventPublisher eventPublisher = getStateMachineEventPublisher(); + if (eventPublisher != null) { + eventPublisher.publishStateMachineStart(this, stateMachine); + } + } + } + + private void notifyStateMachineStopped(StateMachine stateMachine) { + stateListener.stateMachineStopped(stateMachine); + if (contextEventsEnabled) { + StateMachineEventPublisher eventPublisher = getStateMachineEventPublisher(); + if (eventPublisher != null) { + eventPublisher.publishStateMachineStop(this, stateMachine); + } + } + } + private class TriggerQueueItem { Trigger trigger; Message message; @@ -823,6 +835,16 @@ public abstract class AbstractStateMachine extends LifecycleObjectSupport stateListener.transitionEnded(transition); } + @Override + public void stateMachineStarted(StateMachine stateMachine) { + stateListener.stateMachineStarted(stateMachine); + } + + @Override + public void stateMachineStopped(StateMachine stateMachine) { + stateListener.stateMachineStopped(stateMachine); + } + } } diff --git a/spring-statemachine-core/src/test/java/org/springframework/statemachine/EnumStateMachineTests.java b/spring-statemachine-core/src/test/java/org/springframework/statemachine/EnumStateMachineTests.java index a9f6c2ee..88e7d1a7 100644 --- a/spring-statemachine-core/src/test/java/org/springframework/statemachine/EnumStateMachineTests.java +++ b/spring-statemachine-core/src/test/java/org/springframework/statemachine/EnumStateMachineTests.java @@ -75,7 +75,7 @@ public class EnumStateMachineTests extends AbstractStateMachineTests { transitions.add(transitionFromS2ToS3); SyncTaskExecutor taskExecutor = new SyncTaskExecutor(); - EnumStateMachine machine = new EnumStateMachine(states, transitions, stateSI, null); + EnumStateMachine machine = new EnumStateMachine(states, transitions, stateSI); machine.setTaskExecutor(taskExecutor); machine.afterPropertiesSet(); machine.start(); @@ -148,7 +148,7 @@ public class EnumStateMachineTests extends AbstractStateMachineTests { // create machine SyncTaskExecutor taskExecutor = new SyncTaskExecutor(); - EnumStateMachine machine = new EnumStateMachine(states, transitions, stateSI, null); + EnumStateMachine machine = new EnumStateMachine(states, transitions, stateSI); machine.setTaskExecutor(taskExecutor); machine.afterPropertiesSet(); machine.start(); @@ -188,7 +188,7 @@ public class EnumStateMachineTests extends AbstractStateMachineTests { transitions.add(transitionInternalSI); SyncTaskExecutor taskExecutor = new SyncTaskExecutor(); - EnumStateMachine machine = new EnumStateMachine(states, transitions, stateSI, null); + EnumStateMachine machine = new EnumStateMachine(states, transitions, stateSI); machine.setTaskExecutor(taskExecutor); machine.start(); diff --git a/spring-statemachine-core/src/test/java/org/springframework/statemachine/RegionMachineTests.java b/spring-statemachine-core/src/test/java/org/springframework/statemachine/RegionMachineTests.java index 1338f245..0cd1bb88 100644 --- a/spring-statemachine-core/src/test/java/org/springframework/statemachine/RegionMachineTests.java +++ b/spring-statemachine-core/src/test/java/org/springframework/statemachine/RegionMachineTests.java @@ -87,7 +87,7 @@ public class RegionMachineTests { transitions.add(transitionFromS2ToS3); SyncTaskExecutor taskExecutor = new SyncTaskExecutor(); - EnumStateMachine machine = new EnumStateMachine(states, transitions, stateSI, null); + EnumStateMachine machine = new EnumStateMachine(states, transitions, stateSI); machine.setTaskExecutor(taskExecutor); machine.afterPropertiesSet(); machine.start(); @@ -150,7 +150,7 @@ public class RegionMachineTests { DefaultExternalTransition transitionFromS111ToS112 = new DefaultExternalTransition(stateS111, stateS112, null, TestEvents.E2, null, new EventTrigger(TestEvents.E2)); transitions11.add(transitionFromS111ToS112); - EnumStateMachine machine11 = new EnumStateMachine(states11, transitions11, stateS111, null); + EnumStateMachine machine11 = new EnumStateMachine(states11, transitions11, stateS111); machine11.setTaskExecutor(taskExecutor); machine11.afterPropertiesSet(); @@ -161,7 +161,7 @@ public class RegionMachineTests { DefaultExternalTransition transitionFromSIToS121 = new DefaultExternalTransition(stateSI, stateS111, null, TestEvents.E3, null, new EventTrigger(TestEvents.E3)); transitions12.add(transitionFromSIToS121); - EnumStateMachine machine12 = new EnumStateMachine(states12, transitions12, stateS121, null); + EnumStateMachine machine12 = new EnumStateMachine(states12, transitions12, stateS121); machine12.setTaskExecutor(taskExecutor); machine12.afterPropertiesSet(); @@ -176,7 +176,7 @@ public class RegionMachineTests { DefaultExternalTransition transitionFromSIToRegionstate = new DefaultExternalTransition(stateSI, stateR, null, TestEvents.E1, null, new EventTrigger(TestEvents.E1)); transitions.add(transitionFromSIToRegionstate); - EnumStateMachine machine = new EnumStateMachine(states, transitions, stateR, null); + EnumStateMachine machine = new EnumStateMachine(states, transitions, stateR); machine.setTaskExecutor(taskExecutor); machine.afterPropertiesSet(); 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 589e3107..42eb7b59 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 @@ -94,7 +94,7 @@ public class SubStateMachineTests extends AbstractStateMachineTests { Collection> substates111 = new ArrayList>(); substates111.add(stateS111); Collection> subtransitions111 = new ArrayList>(); - EnumStateMachine submachine11 = new EnumStateMachine(substates111, subtransitions111, stateS111, null); + EnumStateMachine submachine11 = new EnumStateMachine(substates111, subtransitions111, stateS111); // submachine 1 TestEntryAction entryActionS11 = new TestEntryAction("S11"); @@ -108,7 +108,7 @@ public class SubStateMachineTests extends AbstractStateMachineTests { Collection> substates11 = new ArrayList>(); substates11.add(stateS11); Collection> subtransitions11 = new ArrayList>(); - EnumStateMachine submachine1 = new EnumStateMachine(substates11, subtransitions11, stateS11, null); + EnumStateMachine submachine1 = new EnumStateMachine(substates11, subtransitions11, stateS11); // machine TestEntryAction entryActionS1 = new TestEntryAction("S1"); @@ -125,7 +125,7 @@ public class SubStateMachineTests extends AbstractStateMachineTests { DefaultExternalTransition transitionFromS111ToS1 = new DefaultExternalTransition(stateS111, stateS1, null, TestEvents.E1, null, new EventTrigger(TestEvents.E1)); transitions.add(transitionFromS111ToS1); - EnumStateMachine machine = new EnumStateMachine(states, transitions, stateS1, null); + EnumStateMachine machine = new EnumStateMachine(states, transitions, stateS1); SyncTaskExecutor taskExecutor = new SyncTaskExecutor(); @@ -198,7 +198,7 @@ public class SubStateMachineTests extends AbstractStateMachineTests { substates11.add(stateS111); substates11.add(stateS112); Collection> subtransitions11 = new ArrayList>(); - EnumStateMachine submachine11 = new EnumStateMachine(substates11, subtransitions11, stateS111, null); + EnumStateMachine submachine11 = new EnumStateMachine(substates11, subtransitions11, stateS111); // machine TestEntryAction entryActionS1 = new TestEntryAction("S1"); @@ -215,7 +215,7 @@ public class SubStateMachineTests extends AbstractStateMachineTests { DefaultExternalTransition transitionFromS111ToS112 = new DefaultExternalTransition(stateS111, stateS112, null, TestEvents.E1, null, new EventTrigger(TestEvents.E1)); transitions.add(transitionFromS111ToS112); - EnumStateMachine machine = new EnumStateMachine(states, transitions, stateS1, null); + EnumStateMachine machine = new EnumStateMachine(states, transitions, stateS1); SyncTaskExecutor taskExecutor = new SyncTaskExecutor(); @@ -281,7 +281,7 @@ public class SubStateMachineTests extends AbstractStateMachineTests { Collection> substates111 = new ArrayList>(); substates111.add(stateS111); Collection> subtransitions111 = new ArrayList>(); - EnumStateMachine submachine11 = new EnumStateMachine(substates111, subtransitions111, stateS111, null); + EnumStateMachine submachine11 = new EnumStateMachine(substates111, subtransitions111, stateS111); // submachine 1 TestEntryAction entryActionS11 = new TestEntryAction("S11"); @@ -295,7 +295,7 @@ public class SubStateMachineTests extends AbstractStateMachineTests { Collection> substates11 = new ArrayList>(); substates11.add(stateS11); Collection> subtransitions11 = new ArrayList>(); - EnumStateMachine submachine1 = new EnumStateMachine(substates11, subtransitions11, stateS11, null); + EnumStateMachine submachine1 = new EnumStateMachine(substates11, subtransitions11, stateS11); // machine TestEntryAction entryActionS1 = new TestEntryAction("S1"); @@ -312,7 +312,7 @@ public class SubStateMachineTests extends AbstractStateMachineTests { DefaultLocalTransition transitionFromS11ToS1 = new DefaultLocalTransition(stateS111, stateS1, null, TestEvents.E1, null, new EventTrigger(TestEvents.E1)); transitions.add(transitionFromS11ToS1); - EnumStateMachine machine = new EnumStateMachine(states, transitions, stateS1, null); + EnumStateMachine machine = new EnumStateMachine(states, transitions, stateS1); SyncTaskExecutor taskExecutor = new SyncTaskExecutor(); diff --git a/spring-statemachine-core/src/test/java/org/springframework/statemachine/config/ConfigurationTests.java b/spring-statemachine-core/src/test/java/org/springframework/statemachine/config/ConfigurationTests.java index 3575b56a..bae7d1e5 100644 --- a/spring-statemachine-core/src/test/java/org/springframework/statemachine/config/ConfigurationTests.java +++ b/spring-statemachine-core/src/test/java/org/springframework/statemachine/config/ConfigurationTests.java @@ -33,7 +33,6 @@ import org.springframework.core.task.TaskExecutor; import org.springframework.statemachine.AbstractStateMachineTests; import org.springframework.statemachine.EnumStateMachine; import org.springframework.statemachine.StateMachineSystemConstants; -import org.springframework.statemachine.TestUtils; import org.springframework.statemachine.action.Action; import org.springframework.statemachine.config.builders.StateMachineStateConfigurer; import org.springframework.statemachine.config.builders.StateMachineTransitionConfigurer; @@ -66,20 +65,6 @@ public class ConfigurationTests extends AbstractStateMachineTests { assertThat(testGuard, notNullValue()); } - - @SuppressWarnings({ "unchecked" }) - @Test - public void testEndState() throws Exception { - context.register(Config3.class); - context.refresh(); - assertTrue(context.containsBean(StateMachineSystemConstants.DEFAULT_ID_STATEMACHINE)); - EnumStateMachine machine = - context.getBean(StateMachineSystemConstants.DEFAULT_ID_STATEMACHINE, EnumStateMachine.class); - assertThat(machine, notNullValue()); - Object endState = TestUtils.readField("endState", machine); - assertThat(endState, notNullValue()); - } - @SuppressWarnings({ "unchecked" }) @Test public void testSimpleSubmachine() throws Exception { diff --git a/spring-statemachine-core/src/test/java/org/springframework/statemachine/docs/DocsConfigurationSampleTests.java b/spring-statemachine-core/src/test/java/org/springframework/statemachine/docs/DocsConfigurationSampleTests.java index c473c14d..8a690b03 100644 --- a/spring-statemachine-core/src/test/java/org/springframework/statemachine/docs/DocsConfigurationSampleTests.java +++ b/spring-statemachine-core/src/test/java/org/springframework/statemachine/docs/DocsConfigurationSampleTests.java @@ -31,7 +31,6 @@ import org.springframework.statemachine.AbstractStateMachineTests; import org.springframework.statemachine.StateContext; import org.springframework.statemachine.StateMachine; import org.springframework.statemachine.action.Action; -import org.springframework.statemachine.annotation.AnnoStates; import org.springframework.statemachine.annotation.OnTransition; import org.springframework.statemachine.annotation.WithStateMachine; import org.springframework.statemachine.config.EnableStateMachine; @@ -240,6 +239,14 @@ public class DocsConfigurationSampleTests extends AbstractStateMachineTests { @Override public void transitionEnded(Transition transition) { } + + @Override + public void stateMachineStarted(StateMachine stateMachine) { + } + + @Override + public void stateMachineStopped(StateMachine stateMachine) { + } } // end::snippetH[] @@ -315,16 +322,16 @@ public class DocsConfigurationSampleTests extends AbstractStateMachineTests { public static class Config9 extends EnumStateMachineConfigurerAdapter { } // end::snippetN[] - + static class DummyShowSendEvent { - + // tag::snippetO[] @Autowired StateMachine stateMachine; - + void signalMachine() { stateMachine.sendEvent(Events.E1); - + Message message = MessageBuilder .withPayload(Events.E2) .setHeader("foo", "bar") @@ -332,7 +339,7 @@ public class DocsConfigurationSampleTests extends AbstractStateMachineTests { stateMachine.sendEvent(message); } // end::snippetO[] - + } } diff --git a/spring-statemachine-core/src/test/java/org/springframework/statemachine/listener/ListenerTests.java b/spring-statemachine-core/src/test/java/org/springframework/statemachine/listener/ListenerTests.java index 04fcfb1b..0770b551 100644 --- a/spring-statemachine-core/src/test/java/org/springframework/statemachine/listener/ListenerTests.java +++ b/spring-statemachine-core/src/test/java/org/springframework/statemachine/listener/ListenerTests.java @@ -22,6 +22,8 @@ import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; import java.util.ArrayList; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -35,6 +37,7 @@ import org.springframework.messaging.support.MessageBuilder; import org.springframework.statemachine.AbstractStateMachineTests; import org.springframework.statemachine.EnumStateMachine; import org.springframework.statemachine.StateContext; +import org.springframework.statemachine.StateMachine; import org.springframework.statemachine.StateMachineSystemConstants; import org.springframework.statemachine.action.Action; import org.springframework.statemachine.config.EnableStateMachine; @@ -54,7 +57,7 @@ public class ListenerTests extends AbstractStateMachineTests { @Test public void testStateEvents() { - AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(Config.class); + AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(Config1.class); assertTrue(ctx.containsBean(StateMachineSystemConstants.DEFAULT_ID_STATEMACHINE)); @SuppressWarnings("unchecked") EnumStateMachine machine = @@ -79,6 +82,26 @@ public class ListenerTests extends AbstractStateMachineTests { ctx.close(); } + @Test + public void testStartEndEvents() throws Exception { + AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(Config2.class); + assertTrue(ctx.containsBean(StateMachineSystemConstants.DEFAULT_ID_STATEMACHINE)); + @SuppressWarnings("unchecked") + EnumStateMachine machine = + ctx.getBean(StateMachineSystemConstants.DEFAULT_ID_STATEMACHINE, EnumStateMachine.class); + + TestStateMachineListener listener = new TestStateMachineListener(); + machine.addStateListener(listener); + + machine.start(); + machine.sendEvent(TestEvents.E1); + machine.sendEvent(TestEvents.E2); + assertThat(listener.stopLatch.await(2, TimeUnit.SECONDS), is(true)); + assertThat(listener.started, is(1)); + assertThat(listener.stopped, is(1)); + ctx.close(); + } + private static class LoggingAction implements Action { private static final Log log = LogFactory.getLog(LoggingAction.class); @@ -99,6 +122,9 @@ public class ListenerTests extends AbstractStateMachineTests { private static class TestStateMachineListener implements StateMachineListener { ArrayList states = new ArrayList(); + volatile int started = 0; + volatile int stopped = 0; + CountDownLatch stopLatch = new CountDownLatch(1); @Override public void stateChanged(State from, State to) { @@ -134,11 +160,22 @@ public class ListenerTests extends AbstractStateMachineTests { public void transitionEnded(Transition transition) { } + @Override + public void stateMachineStarted(StateMachine stateMachine) { + started++; + } + + @Override + public void stateMachineStopped(StateMachine stateMachine) { + stopped++; + stopLatch.countDown(); + } + } @Configuration @EnableStateMachine - static class Config extends EnumStateMachineConfigurerAdapter { + static class Config1 extends EnumStateMachineConfigurerAdapter { @Override public void configure(StateMachineStateConfigurer states) throws Exception { @@ -192,4 +229,40 @@ public class ListenerTests extends AbstractStateMachineTests { } + @Configuration + @EnableStateMachine + static class Config2 extends EnumStateMachineConfigurerAdapter { + + @Override + public void configure(StateMachineStateConfigurer states) throws Exception { + states + .withStates() + .initial(TestStates.S1) + .end(TestStates.S3) + .state(TestStates.S1) + .state(TestStates.S2) + .state(TestStates.S3); + } + + @Override + public void configure(StateMachineTransitionConfigurer transitions) throws Exception { + transitions + .withExternal() + .source(TestStates.S1) + .target(TestStates.S2) + .event(TestEvents.E1) + .and() + .withExternal() + .source(TestStates.S2) + .target(TestStates.S3) + .event(TestEvents.E2); + } + + @Bean + public TaskExecutor taskExecutor() { + return new SyncTaskExecutor(); + } + + } + } diff --git a/spring-statemachine-core/src/test/java/org/springframework/statemachine/state/RegionStateTests.java b/spring-statemachine-core/src/test/java/org/springframework/statemachine/state/RegionStateTests.java index 68997f9e..6d6f3e18 100644 --- a/spring-statemachine-core/src/test/java/org/springframework/statemachine/state/RegionStateTests.java +++ b/spring-statemachine-core/src/test/java/org/springframework/statemachine/state/RegionStateTests.java @@ -69,7 +69,7 @@ public class RegionStateTests extends AbstractStateMachineTests { transitions.add(transitionFromS2ToS3); SyncTaskExecutor taskExecutor = new SyncTaskExecutor(); - EnumStateMachine machine = new EnumStateMachine(states, transitions, stateSI, null); + EnumStateMachine machine = new EnumStateMachine(states, transitions, stateSI); machine.setTaskExecutor(taskExecutor); machine.start(); diff --git a/spring-statemachine-core/src/test/java/org/springframework/statemachine/state/SubmachineStateTests.java b/spring-statemachine-core/src/test/java/org/springframework/statemachine/state/SubmachineStateTests.java index fc63e3c6..5aade998 100644 --- a/spring-statemachine-core/src/test/java/org/springframework/statemachine/state/SubmachineStateTests.java +++ b/spring-statemachine-core/src/test/java/org/springframework/statemachine/state/SubmachineStateTests.java @@ -68,7 +68,7 @@ public class SubmachineStateTests extends AbstractStateMachineTests { transitions.add(transitionFromS2ToS3); SyncTaskExecutor taskExecutor = new SyncTaskExecutor(); - EnumStateMachine machine = new EnumStateMachine(states, transitions, stateSI, null); + EnumStateMachine machine = new EnumStateMachine(states, transitions, stateSI); machine.setTaskExecutor(taskExecutor); machine.start();