From 4bf49654b9cf911c387721d47fd688f1bfcc7bfa Mon Sep 17 00:00:00 2001 From: Janne Valkealahti Date: Fri, 27 Mar 2015 12:59:50 +0000 Subject: [PATCH] Add initial action and fix internal transition event - New InitialTransition with initial action to get a change to modify variables when sm is started. - Fixes a case where internal transition did't send transition event. --- .../statemachine/EnumStateMachine.java | 9 ++- .../config/EnumStateMachineFactory.java | 16 +++- .../statemachine/config/StateData.java | 9 +++ .../configurers/DefaultStateConfigurer.java | 15 +++- .../config/configurers/StateConfigurer.java | 2 + .../support/AbstractStateMachine.java | 25 ++++-- .../transition/InitialTransition.java | 79 +++++++++++++++++++ 7 files changed, 141 insertions(+), 14 deletions(-) create mode 100644 spring-statemachine-core/src/main/java/org/springframework/statemachine/transition/InitialTransition.java 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 11aa8b19..c6509d92 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 @@ -17,6 +17,7 @@ package org.springframework.statemachine; import java.util.Collection; +import org.springframework.messaging.Message; import org.springframework.statemachine.state.State; import org.springframework.statemachine.support.AbstractStateMachine; import org.springframework.statemachine.transition.Transition; @@ -24,7 +25,7 @@ import org.springframework.statemachine.transition.Transition; /** * Specialisation of a {@link StateMachine} using enums * as its {@link State} and event types. - * + * * @author Janne Valkealahti * * @param the type of state @@ -44,4 +45,10 @@ public class EnumStateMachine, E extends Enum> extends Abst super(states, transitions, initialState, endState); } + public EnumStateMachine(Collection> states, Collection> transitions, + State initialState, Transition initialTransition, State endState, + Message initialEvent, ExtendedState extendedState) { + super(states, transitions, initialState, initialTransition, endState, 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 dd252a93..79497664 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 @@ -25,6 +25,7 @@ import java.util.Stack; import org.springframework.beans.factory.BeanFactory; import org.springframework.statemachine.EnumStateMachine; import org.springframework.statemachine.StateMachine; +import org.springframework.statemachine.action.Action; import org.springframework.statemachine.config.builders.StateMachineStates; import org.springframework.statemachine.config.builders.StateMachineTransitions; import org.springframework.statemachine.config.builders.StateMachineTransitions.TransitionData; @@ -42,6 +43,7 @@ import org.springframework.statemachine.support.tree.Tree.Node; import org.springframework.statemachine.support.tree.TreeTraverser; import org.springframework.statemachine.transition.DefaultExternalTransition; import org.springframework.statemachine.transition.DefaultInternalTransition; +import org.springframework.statemachine.transition.InitialTransition; import org.springframework.statemachine.transition.Transition; import org.springframework.statemachine.transition.TransitionKind; import org.springframework.statemachine.trigger.EventTrigger; @@ -258,6 +260,7 @@ public class EnumStateMachineFactory, E extends Enum> exten Collection> transitionsData, BeanFactory beanFactory) { State state = null; State initialState = null; + Action initialAction = null; State endState = null; Collection> states = new ArrayList>(); for (StateData stateData : stateDatas) { @@ -269,8 +272,10 @@ public class EnumStateMachineFactory, E extends Enum> exten // TODO: below if/else doesn't feel right if (stateDatas.size() > 1 && stateData.isInitial()) { initialState = state; + initialAction = stateData.getInitialAction(); } else if (stateDatas.size() == 1) { initialState = state; + initialAction = stateData.getInitialAction(); } states.add(state); } else { @@ -282,6 +287,7 @@ public class EnumStateMachineFactory, E extends Enum> exten stateData.getEntryActions(), stateData.getExitActions(), pseudoState); if (stateData.isInitial()) { initialState = state; + initialAction = stateData.getInitialAction(); } if (stateData.isEnd()) { endState = state; @@ -325,8 +331,14 @@ public class EnumStateMachineFactory, E extends Enum> exten } } - EnumStateMachine machine = new EnumStateMachine(/*stateMap.values()*/ states, transitions, - initialState, endState); + // TODO: should make a proper transition + Transition initialTransition = null; + if (initialAction != null) { + initialTransition = new InitialTransition(initialState, initialAction); + } + + EnumStateMachine machine = new EnumStateMachine(states, transitions, initialState, + initialTransition, endState, null, null); machine.afterPropertiesSet(); if (beanFactory != null) { machine.setBeanFactory(beanFactory); diff --git a/spring-statemachine-core/src/main/java/org/springframework/statemachine/config/StateData.java b/spring-statemachine-core/src/main/java/org/springframework/statemachine/config/StateData.java index 1da75b1e..7abd3c69 100644 --- a/spring-statemachine-core/src/main/java/org/springframework/statemachine/config/StateData.java +++ b/spring-statemachine-core/src/main/java/org/springframework/statemachine/config/StateData.java @@ -38,6 +38,7 @@ public class StateData { private Collection> entryActions; private Collection> exitActions; private boolean initial = false; + private Action initialAction; private boolean end = false; public StateData(Object parent, S state, Collection deferred, @@ -81,6 +82,14 @@ public class StateData { this.initial = initial; } + public void setInitialAction(Action action) { + this.initialAction = action; + } + + public Action getInitialAction() { + return initialAction; + } + public boolean isEnd() { return end; } diff --git a/spring-statemachine-core/src/main/java/org/springframework/statemachine/config/configurers/DefaultStateConfigurer.java b/spring-statemachine-core/src/main/java/org/springframework/statemachine/config/configurers/DefaultStateConfigurer.java index 4b2ae153..6cb5ad19 100644 --- a/spring-statemachine-core/src/main/java/org/springframework/statemachine/config/configurers/DefaultStateConfigurer.java +++ b/spring-statemachine-core/src/main/java/org/springframework/statemachine/config/configurers/DefaultStateConfigurer.java @@ -35,7 +35,9 @@ public class DefaultStateConfigurer private final Collection> incomplete = new ArrayList>(); - private S initial; + private S initialState; + + private Action initialAction; private S end; @@ -47,8 +49,9 @@ public class DefaultStateConfigurer for (StateData s : incomplete) { s.setParent(parent); stateDatas.add(s); - if (s.getState() == initial) { + if (s.getState() == initialState) { s.setInitial(true); + s.setInitialAction(initialAction); } if (s.getState() == end) { s.setEnd(true); @@ -59,10 +62,16 @@ public class DefaultStateConfigurer @Override public StateConfigurer initial(S initial) { - this.initial = initial; + this.initialState = initial; return this; } + @Override + public StateConfigurer initial(S initial, Action action) { + this.initialAction = action; + return initial(initial); + } + @Override public StateConfigurer parent(S state) { this.parent = state; diff --git a/spring-statemachine-core/src/main/java/org/springframework/statemachine/config/configurers/StateConfigurer.java b/spring-statemachine-core/src/main/java/org/springframework/statemachine/config/configurers/StateConfigurer.java index dbf78dcb..b98a9e69 100644 --- a/spring-statemachine-core/src/main/java/org/springframework/statemachine/config/configurers/StateConfigurer.java +++ b/spring-statemachine-core/src/main/java/org/springframework/statemachine/config/configurers/StateConfigurer.java @@ -27,6 +27,8 @@ public interface StateConfigurer extends StateConfigurer initial(S initial); + StateConfigurer initial(S initial, Action action); + StateConfigurer parent(S state); StateConfigurer state(S state); 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 49eea724..518c0756 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 @@ -79,6 +79,8 @@ public abstract class AbstractStateMachine extends LifecycleObjectSupport private final State initialState; + private final Transition initialTransition; + private final State endState; private final Message initialEvent; @@ -125,7 +127,7 @@ public abstract class AbstractStateMachine extends LifecycleObjectSupport */ public AbstractStateMachine(Collection> states, Collection> transitions, State initialState, State endState) { - this(states, transitions, initialState, endState, null, new DefaultExtendedState()); + this(states, transitions, initialState, null, endState, null, new DefaultExtendedState()); } /** @@ -138,7 +140,7 @@ public abstract class AbstractStateMachine extends LifecycleObjectSupport */ public AbstractStateMachine(Collection> states, Collection> transitions, State initialState, ExtendedState extendedState) { - this(states, transitions, initialState, null, null, extendedState); + this(states, transitions, initialState, null, null, null, extendedState); } /** @@ -152,14 +154,15 @@ public abstract class AbstractStateMachine extends LifecycleObjectSupport * @param extendedState the extended state of this machine */ public AbstractStateMachine(Collection> states, Collection> transitions, - State initialState, State endState, Message initialEvent, ExtendedState extendedState) { + State initialState, Transition initialTransition, State endState, 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; + this.extendedState = extendedState != null ? extendedState : new DefaultExtendedState(); } @Override @@ -213,6 +216,12 @@ public abstract class AbstractStateMachine extends LifecycleObjectSupport super.doStart(); registerTriggerListener(); switchToState(initialState, initialEvent, null); + // TODO: for now execute outside of switchToState + if (initialTransition != null) { + StateContext stateContext = new DefaultStateContext( + initialEvent != null ? initialEvent.getHeaders() : null, extendedState, initialTransition, this); + initialTransition.transit(stateContext); + } } @Override @@ -444,13 +453,13 @@ public abstract class AbstractStateMachine extends LifecycleObjectSupport notifyTransitionStart(transition); callHandlers(transition.getSource(), transition.getTarget(), queuedEvent); boolean transit = transition.transit(stateContext); - if (transit && transition.getKind() != TransitionKind.INTERNAL) { - switchToState(transition.getTarget(), queuedEvent, transition); + if (transit) { + if (transition.getKind() != TransitionKind.INTERNAL) { + switchToState(transition.getTarget(), queuedEvent, transition); + } notifyTransition(transition); } notifyTransitionEnd(transition); - - } } diff --git a/spring-statemachine-core/src/main/java/org/springframework/statemachine/transition/InitialTransition.java b/spring-statemachine-core/src/main/java/org/springframework/statemachine/transition/InitialTransition.java new file mode 100644 index 00000000..f19bb038 --- /dev/null +++ b/spring-statemachine-core/src/main/java/org/springframework/statemachine/transition/InitialTransition.java @@ -0,0 +1,79 @@ +/* + * 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.transition; + +import java.util.ArrayList; +import java.util.Collection; + +import org.springframework.statemachine.StateContext; +import org.springframework.statemachine.action.Action; +import org.springframework.statemachine.state.State; +import org.springframework.statemachine.trigger.Trigger; + +public class InitialTransition implements Transition { + + private final State target; + + private final Collection> actions; + + public InitialTransition(State target, Action action) { + this.target = target; + ArrayList> list = new ArrayList>(); + list.add(action); + this.actions = list; + } + + public InitialTransition(State target, Collection> actions) { + this.target = target; + this.actions = actions; + } + + @Override + public boolean transit(StateContext context) { + if (actions != null) { + for (Action action : actions) { + action.execute(context); + } + } + return false; + } + + @Override + public State getSource() { + return null; + } + + @Override + public State getTarget() { + return target; + } + + @Override + public Collection> getActions() { + return actions; + } + + @Override + public Trigger getTrigger() { + return null; + } + + @Override + public TransitionKind getKind() { + return null; + } + +}