Make end state a proper pseudostate

- Remove end state from constructors and handle
  it as a pseudostate.
- When sm enters state marked with end, stop
  machine.
- Added new events which are used to notify sm
  start and stop which now makes sense with
  a proper end pseudostate.
This commit is contained in:
Janne Valkealahti
2015-04-11 09:57:17 +01:00
parent 2721437b23
commit 247c90ad90
20 changed files with 362 additions and 78 deletions

View File

@@ -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]
----

View File

@@ -41,14 +41,24 @@ public class EnumStateMachine<S extends Enum<S>, E extends Enum<E>> extends Abst
* @param initialState the initial state
*/
public EnumStateMachine(Collection<State<S, E>> states, Collection<Transition<S, E>> transitions,
State<S, E> initialState, State<S, E> endState) {
super(states, transitions, initialState, endState);
State<S, E> 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<State<S, E>> states, Collection<Transition<S, E>> transitions,
State<S, E> initialState, Transition<S, E> initialTransition, State<S, E> endState,
State<S, E> initialState, Transition<S, E> initialTransition,
Message<E> initialEvent, ExtendedState extendedState) {
super(states, transitions, initialState, initialTransition, endState, initialEvent, extendedState);
super(states, transitions, initialState, initialTransition, initialEvent, extendedState);
}
}

View File

@@ -191,7 +191,7 @@ public class EnumStateMachineFactory<S extends Enum<S>, E extends Enum<E>> exten
Collection<State<S, E>> states = new ArrayList<State<S, E>>();
states.add(rstate);
EnumStateMachine<S, E> m = new EnumStateMachine<S, E>(states, null, rstate,
null, null, null, defaultExtendedState);
null, null, defaultExtendedState);
if (contextEvents != null) {
m.setContextEventsEnabled(contextEvents);
}
@@ -278,7 +278,6 @@ public class EnumStateMachineFactory<S extends Enum<S>, E extends Enum<E>> exten
State<S, E> state = null;
State<S, E> initialState = null;
Action<S, E> initialAction = null;
State<S, E> endState = null;
Collection<State<S, E>> states = new ArrayList<State<S,E>>();
for (StateData<S, E> stateData : stateDatas) {
StateMachine<S, E> stateMachine = machineMap.get(stateData.getState());
@@ -299,6 +298,8 @@ public class EnumStateMachineFactory<S extends Enum<S>, E extends Enum<E>> exten
PseudoState pseudoState = null;
if (stateData.isInitial()) {
pseudoState = new DefaultPseudoState(PseudoStateKind.INITIAL);
} else if (stateData.isEnd()) {
pseudoState = new DefaultPseudoState(PseudoStateKind.END);
}
state = new EnumState<S, E>(stateData.getState(), stateData.getDeferred(),
stateData.getEntryActions(), stateData.getExitActions(), pseudoState);
@@ -306,9 +307,6 @@ public class EnumStateMachineFactory<S extends Enum<S>, E extends Enum<E>> exten
initialState = state;
initialAction = stateData.getInitialAction();
}
if (stateData.isEnd()) {
endState = state;
}
states.add(state);
}
@@ -355,7 +353,7 @@ public class EnumStateMachineFactory<S extends Enum<S>, E extends Enum<E>> exten
}
EnumStateMachine<S, E> machine = new EnumStateMachine<S, E>(states, transitions, initialState,
initialTransition, endState, null, defaultExtendedState);
initialTransition, null, defaultExtendedState);
if (contextEvents != null) {
machine.setContextEventsEnabled(contextEvents);
}

View File

@@ -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));
}
}
}

View File

@@ -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 + "]";
}
}

View File

@@ -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 + "]";
}
}

View File

@@ -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);
}

View File

@@ -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<S,E> extends AbstractCompositeListene
}
}
@Override
public void stateMachineStarted(StateMachine<S, E> stateMachine) {
for (Iterator<StateMachineListener<S, E>> iterator = getListeners().reverse(); iterator.hasNext();) {
StateMachineListener<S, E> listener = iterator.next();
listener.stateMachineStarted(stateMachine);
}
}
@Override
public void stateMachineStopped(StateMachine<S, E> stateMachine) {
for (Iterator<StateMachineListener<S, E>> iterator = getListeners().reverse(); iterator.hasNext();) {
StateMachineListener<S, E> listener = iterator.next();
listener.stateMachineStopped(stateMachine);
}
}
}

View File

@@ -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<S,E> {
*/
void transitionEnded(Transition<S, E> transition);
/**
* Notified when statemachine starts
*
* @param stateMachine the statemachine
*/
void stateMachineStarted(StateMachine<S, E> stateMachine);
/**
* Notified when statemachine stops
*
* @param stateMachine the statemachine
*/
void stateMachineStopped(StateMachine<S, E> stateMachine);
}

View File

@@ -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<S, E> implements StateMachineListener<S
public void transitionEnded(Transition<S, E> transition) {
}
@Override
public void stateMachineStarted(StateMachine<S, E> stateMachine) {
}
@Override
public void stateMachineStopped(StateMachine<S, E> stateMachine) {
}
}

View File

@@ -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
}

View File

@@ -81,8 +81,6 @@ public abstract class AbstractStateMachine<S, E> extends LifecycleObjectSupport
private final Transition<S, E> initialTransition;
private final State<S,E> endState;
private final Message<E> initialEvent;
private final ExtendedState extendedState;
@@ -119,19 +117,6 @@ public abstract class AbstractStateMachine<S, E> 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<State<S, E>> states, Collection<Transition<S, E>> transitions,
State<S, E> initialState, State<S, E> endState) {
this(states, transitions, initialState, null, endState, null, new DefaultExtendedState());
}
/**
* Instantiates a new abstract state machine.
*
@@ -142,7 +127,7 @@ public abstract class AbstractStateMachine<S, E> extends LifecycleObjectSupport
*/
public AbstractStateMachine(Collection<State<S, E>> states, Collection<Transition<S, E>> transitions,
State<S, E> 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<S, E> 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<State<S, E>> states, Collection<Transition<S, E>> transitions,
State<S, E> initialState, Transition<S, E> initialTransition, State<S, E> endState, Message<E> initialEvent, ExtendedState extendedState) {
State<S, E> initialState, Transition<S, E> initialTransition, Message<E> 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<S, E> 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<S, E> extends LifecycleObjectSupport
@Override
protected void doStop() {
super.doStop();
notifyStateMachineStopped(this);
currentState = null;
}
@@ -245,7 +230,12 @@ public abstract class AbstractStateMachine<S, E> 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<S, E> extends LifecycleObjectSupport
switchToState(target, event, t, stateMachine);
}
}
if (isComplete()) {
stop();
}
}
private State<S, E> findDeepParent(State<S, E> state) {
@@ -777,6 +769,26 @@ public abstract class AbstractStateMachine<S, E> extends LifecycleObjectSupport
}
}
private void notifyStateMachineStarted(StateMachine<S, E> stateMachine) {
stateListener.stateMachineStarted(stateMachine);
if (contextEventsEnabled) {
StateMachineEventPublisher eventPublisher = getStateMachineEventPublisher();
if (eventPublisher != null) {
eventPublisher.publishStateMachineStart(this, stateMachine);
}
}
}
private void notifyStateMachineStopped(StateMachine<S, E> stateMachine) {
stateListener.stateMachineStopped(stateMachine);
if (contextEventsEnabled) {
StateMachineEventPublisher eventPublisher = getStateMachineEventPublisher();
if (eventPublisher != null) {
eventPublisher.publishStateMachineStop(this, stateMachine);
}
}
}
private class TriggerQueueItem {
Trigger<S, E> trigger;
Message<E> message;
@@ -823,6 +835,16 @@ public abstract class AbstractStateMachine<S, E> extends LifecycleObjectSupport
stateListener.transitionEnded(transition);
}
@Override
public void stateMachineStarted(StateMachine<S, E> stateMachine) {
stateListener.stateMachineStarted(stateMachine);
}
@Override
public void stateMachineStopped(StateMachine<S, E> stateMachine) {
stateListener.stateMachineStopped(stateMachine);
}
}
}

View File

@@ -75,7 +75,7 @@ public class EnumStateMachineTests extends AbstractStateMachineTests {
transitions.add(transitionFromS2ToS3);
SyncTaskExecutor taskExecutor = new SyncTaskExecutor();
EnumStateMachine<TestStates, TestEvents> machine = new EnumStateMachine<TestStates, TestEvents>(states, transitions, stateSI, null);
EnumStateMachine<TestStates, TestEvents> machine = new EnumStateMachine<TestStates, TestEvents>(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<TestStates, TestEvents> machine = new EnumStateMachine<TestStates, TestEvents>(states, transitions, stateSI, null);
EnumStateMachine<TestStates, TestEvents> machine = new EnumStateMachine<TestStates, TestEvents>(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<TestStates, TestEvents> machine = new EnumStateMachine<TestStates, TestEvents>(states, transitions, stateSI, null);
EnumStateMachine<TestStates, TestEvents> machine = new EnumStateMachine<TestStates, TestEvents>(states, transitions, stateSI);
machine.setTaskExecutor(taskExecutor);
machine.start();

View File

@@ -87,7 +87,7 @@ public class RegionMachineTests {
transitions.add(transitionFromS2ToS3);
SyncTaskExecutor taskExecutor = new SyncTaskExecutor();
EnumStateMachine<TestStates, TestEvents> machine = new EnumStateMachine<TestStates, TestEvents>(states, transitions, stateSI, null);
EnumStateMachine<TestStates, TestEvents> machine = new EnumStateMachine<TestStates, TestEvents>(states, transitions, stateSI);
machine.setTaskExecutor(taskExecutor);
machine.afterPropertiesSet();
machine.start();
@@ -150,7 +150,7 @@ public class RegionMachineTests {
DefaultExternalTransition<TestStates,TestEvents> transitionFromS111ToS112 =
new DefaultExternalTransition<TestStates,TestEvents>(stateS111, stateS112, null, TestEvents.E2, null, new EventTrigger<TestStates,TestEvents>(TestEvents.E2));
transitions11.add(transitionFromS111ToS112);
EnumStateMachine<TestStates, TestEvents> machine11 = new EnumStateMachine<TestStates, TestEvents>(states11, transitions11, stateS111, null);
EnumStateMachine<TestStates, TestEvents> machine11 = new EnumStateMachine<TestStates, TestEvents>(states11, transitions11, stateS111);
machine11.setTaskExecutor(taskExecutor);
machine11.afterPropertiesSet();
@@ -161,7 +161,7 @@ public class RegionMachineTests {
DefaultExternalTransition<TestStates,TestEvents> transitionFromSIToS121 =
new DefaultExternalTransition<TestStates,TestEvents>(stateSI, stateS111, null, TestEvents.E3, null, new EventTrigger<TestStates,TestEvents>(TestEvents.E3));
transitions12.add(transitionFromSIToS121);
EnumStateMachine<TestStates, TestEvents> machine12 = new EnumStateMachine<TestStates, TestEvents>(states12, transitions12, stateS121, null);
EnumStateMachine<TestStates, TestEvents> machine12 = new EnumStateMachine<TestStates, TestEvents>(states12, transitions12, stateS121);
machine12.setTaskExecutor(taskExecutor);
machine12.afterPropertiesSet();
@@ -176,7 +176,7 @@ public class RegionMachineTests {
DefaultExternalTransition<TestStates,TestEvents> transitionFromSIToRegionstate =
new DefaultExternalTransition<TestStates,TestEvents>(stateSI, stateR, null, TestEvents.E1, null, new EventTrigger<TestStates,TestEvents>(TestEvents.E1));
transitions.add(transitionFromSIToRegionstate);
EnumStateMachine<TestStates, TestEvents> machine = new EnumStateMachine<TestStates, TestEvents>(states, transitions, stateR, null);
EnumStateMachine<TestStates, TestEvents> machine = new EnumStateMachine<TestStates, TestEvents>(states, transitions, stateR);
machine.setTaskExecutor(taskExecutor);
machine.afterPropertiesSet();

View File

@@ -94,7 +94,7 @@ public class SubStateMachineTests extends AbstractStateMachineTests {
Collection<State<TestStates,TestEvents>> substates111 = new ArrayList<State<TestStates,TestEvents>>();
substates111.add(stateS111);
Collection<Transition<TestStates,TestEvents>> subtransitions111 = new ArrayList<Transition<TestStates,TestEvents>>();
EnumStateMachine<TestStates, TestEvents> submachine11 = new EnumStateMachine<TestStates, TestEvents>(substates111, subtransitions111, stateS111, null);
EnumStateMachine<TestStates, TestEvents> submachine11 = new EnumStateMachine<TestStates, TestEvents>(substates111, subtransitions111, stateS111);
// submachine 1
TestEntryAction entryActionS11 = new TestEntryAction("S11");
@@ -108,7 +108,7 @@ public class SubStateMachineTests extends AbstractStateMachineTests {
Collection<State<TestStates,TestEvents>> substates11 = new ArrayList<State<TestStates,TestEvents>>();
substates11.add(stateS11);
Collection<Transition<TestStates,TestEvents>> subtransitions11 = new ArrayList<Transition<TestStates,TestEvents>>();
EnumStateMachine<TestStates, TestEvents> submachine1 = new EnumStateMachine<TestStates, TestEvents>(substates11, subtransitions11, stateS11, null);
EnumStateMachine<TestStates, TestEvents> submachine1 = new EnumStateMachine<TestStates, TestEvents>(substates11, subtransitions11, stateS11);
// machine
TestEntryAction entryActionS1 = new TestEntryAction("S1");
@@ -125,7 +125,7 @@ public class SubStateMachineTests extends AbstractStateMachineTests {
DefaultExternalTransition<TestStates,TestEvents> transitionFromS111ToS1 =
new DefaultExternalTransition<TestStates,TestEvents>(stateS111, stateS1, null, TestEvents.E1, null, new EventTrigger<TestStates,TestEvents>(TestEvents.E1));
transitions.add(transitionFromS111ToS1);
EnumStateMachine<TestStates, TestEvents> machine = new EnumStateMachine<TestStates, TestEvents>(states, transitions, stateS1, null);
EnumStateMachine<TestStates, TestEvents> machine = new EnumStateMachine<TestStates, TestEvents>(states, transitions, stateS1);
SyncTaskExecutor taskExecutor = new SyncTaskExecutor();
@@ -198,7 +198,7 @@ public class SubStateMachineTests extends AbstractStateMachineTests {
substates11.add(stateS111);
substates11.add(stateS112);
Collection<Transition<TestStates,TestEvents>> subtransitions11 = new ArrayList<Transition<TestStates,TestEvents>>();
EnumStateMachine<TestStates, TestEvents> submachine11 = new EnumStateMachine<TestStates, TestEvents>(substates11, subtransitions11, stateS111, null);
EnumStateMachine<TestStates, TestEvents> submachine11 = new EnumStateMachine<TestStates, TestEvents>(substates11, subtransitions11, stateS111);
// machine
TestEntryAction entryActionS1 = new TestEntryAction("S1");
@@ -215,7 +215,7 @@ public class SubStateMachineTests extends AbstractStateMachineTests {
DefaultExternalTransition<TestStates,TestEvents> transitionFromS111ToS112 =
new DefaultExternalTransition<TestStates,TestEvents>(stateS111, stateS112, null, TestEvents.E1, null, new EventTrigger<TestStates,TestEvents>(TestEvents.E1));
transitions.add(transitionFromS111ToS112);
EnumStateMachine<TestStates, TestEvents> machine = new EnumStateMachine<TestStates, TestEvents>(states, transitions, stateS1, null);
EnumStateMachine<TestStates, TestEvents> machine = new EnumStateMachine<TestStates, TestEvents>(states, transitions, stateS1);
SyncTaskExecutor taskExecutor = new SyncTaskExecutor();
@@ -281,7 +281,7 @@ public class SubStateMachineTests extends AbstractStateMachineTests {
Collection<State<TestStates,TestEvents>> substates111 = new ArrayList<State<TestStates,TestEvents>>();
substates111.add(stateS111);
Collection<Transition<TestStates,TestEvents>> subtransitions111 = new ArrayList<Transition<TestStates,TestEvents>>();
EnumStateMachine<TestStates, TestEvents> submachine11 = new EnumStateMachine<TestStates, TestEvents>(substates111, subtransitions111, stateS111, null);
EnumStateMachine<TestStates, TestEvents> submachine11 = new EnumStateMachine<TestStates, TestEvents>(substates111, subtransitions111, stateS111);
// submachine 1
TestEntryAction entryActionS11 = new TestEntryAction("S11");
@@ -295,7 +295,7 @@ public class SubStateMachineTests extends AbstractStateMachineTests {
Collection<State<TestStates,TestEvents>> substates11 = new ArrayList<State<TestStates,TestEvents>>();
substates11.add(stateS11);
Collection<Transition<TestStates,TestEvents>> subtransitions11 = new ArrayList<Transition<TestStates,TestEvents>>();
EnumStateMachine<TestStates, TestEvents> submachine1 = new EnumStateMachine<TestStates, TestEvents>(substates11, subtransitions11, stateS11, null);
EnumStateMachine<TestStates, TestEvents> submachine1 = new EnumStateMachine<TestStates, TestEvents>(substates11, subtransitions11, stateS11);
// machine
TestEntryAction entryActionS1 = new TestEntryAction("S1");
@@ -312,7 +312,7 @@ public class SubStateMachineTests extends AbstractStateMachineTests {
DefaultLocalTransition<TestStates,TestEvents> transitionFromS11ToS1 =
new DefaultLocalTransition<TestStates,TestEvents>(stateS111, stateS1, null, TestEvents.E1, null, new EventTrigger<TestStates,TestEvents>(TestEvents.E1));
transitions.add(transitionFromS11ToS1);
EnumStateMachine<TestStates, TestEvents> machine = new EnumStateMachine<TestStates, TestEvents>(states, transitions, stateS1, null);
EnumStateMachine<TestStates, TestEvents> machine = new EnumStateMachine<TestStates, TestEvents>(states, transitions, stateS1);
SyncTaskExecutor taskExecutor = new SyncTaskExecutor();

View File

@@ -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<TestStates,TestEvents> 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 {

View File

@@ -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<States, Events> transition) {
}
@Override
public void stateMachineStarted(StateMachine<States, Events> stateMachine) {
}
@Override
public void stateMachineStopped(StateMachine<States, Events> stateMachine) {
}
}
// end::snippetH[]
@@ -315,16 +322,16 @@ public class DocsConfigurationSampleTests extends AbstractStateMachineTests {
public static class Config9 extends EnumStateMachineConfigurerAdapter<States, Events> {
}
// end::snippetN[]
static class DummyShowSendEvent {
// tag::snippetO[]
@Autowired
StateMachine<States, Events> stateMachine;
void signalMachine() {
stateMachine.sendEvent(Events.E1);
Message<Events> message = MessageBuilder
.withPayload(Events.E2)
.setHeader("foo", "bar")
@@ -332,7 +339,7 @@ public class DocsConfigurationSampleTests extends AbstractStateMachineTests {
stateMachine.sendEvent(message);
}
// end::snippetO[]
}
}

View File

@@ -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<TestStates,TestEvents> 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<TestStates,TestEvents> 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<TestStates, TestEvents> {
private static final Log log = LogFactory.getLog(LoggingAction.class);
@@ -99,6 +122,9 @@ public class ListenerTests extends AbstractStateMachineTests {
private static class TestStateMachineListener implements StateMachineListener<TestStates, TestEvents> {
ArrayList<Holder> states = new ArrayList<Holder>();
volatile int started = 0;
volatile int stopped = 0;
CountDownLatch stopLatch = new CountDownLatch(1);
@Override
public void stateChanged(State<TestStates, TestEvents> from, State<TestStates, TestEvents> to) {
@@ -134,11 +160,22 @@ public class ListenerTests extends AbstractStateMachineTests {
public void transitionEnded(Transition<TestStates, TestEvents> transition) {
}
@Override
public void stateMachineStarted(StateMachine<TestStates, TestEvents> stateMachine) {
started++;
}
@Override
public void stateMachineStopped(StateMachine<TestStates, TestEvents> stateMachine) {
stopped++;
stopLatch.countDown();
}
}
@Configuration
@EnableStateMachine
static class Config extends EnumStateMachineConfigurerAdapter<TestStates, TestEvents> {
static class Config1 extends EnumStateMachineConfigurerAdapter<TestStates, TestEvents> {
@Override
public void configure(StateMachineStateConfigurer<TestStates, TestEvents> states) throws Exception {
@@ -192,4 +229,40 @@ public class ListenerTests extends AbstractStateMachineTests {
}
@Configuration
@EnableStateMachine
static class Config2 extends EnumStateMachineConfigurerAdapter<TestStates, TestEvents> {
@Override
public void configure(StateMachineStateConfigurer<TestStates, TestEvents> 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<TestStates, TestEvents> 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();
}
}
}

View File

@@ -69,7 +69,7 @@ public class RegionStateTests extends AbstractStateMachineTests {
transitions.add(transitionFromS2ToS3);
SyncTaskExecutor taskExecutor = new SyncTaskExecutor();
EnumStateMachine<TestStates, TestEvents> machine = new EnumStateMachine<TestStates, TestEvents>(states, transitions, stateSI, null);
EnumStateMachine<TestStates, TestEvents> machine = new EnumStateMachine<TestStates, TestEvents>(states, transitions, stateSI);
machine.setTaskExecutor(taskExecutor);
machine.start();

View File

@@ -68,7 +68,7 @@ public class SubmachineStateTests extends AbstractStateMachineTests {
transitions.add(transitionFromS2ToS3);
SyncTaskExecutor taskExecutor = new SyncTaskExecutor();
EnumStateMachine<TestStates, TestEvents> machine = new EnumStateMachine<TestStates, TestEvents>(states, transitions, stateSI, null);
EnumStateMachine<TestStates, TestEvents> machine = new EnumStateMachine<TestStates, TestEvents>(states, transitions, stateSI);
machine.setTaskExecutor(taskExecutor);
machine.start();