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.
This commit is contained in:
@@ -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 <S> the type of state
|
||||
@@ -44,4 +45,10 @@ public class EnumStateMachine<S extends Enum<S>, E extends Enum<E>> extends Abst
|
||||
super(states, transitions, initialState, endState);
|
||||
}
|
||||
|
||||
public EnumStateMachine(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) {
|
||||
super(states, transitions, initialState, initialTransition, endState, initialEvent, extendedState);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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<S extends Enum<S>, E extends Enum<E>> exten
|
||||
Collection<TransitionData<S, E>> transitionsData, BeanFactory beanFactory) {
|
||||
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) {
|
||||
@@ -269,8 +272,10 @@ public class EnumStateMachineFactory<S extends Enum<S>, E extends Enum<E>> 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<S extends Enum<S>, E extends Enum<E>> 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<S extends Enum<S>, E extends Enum<E>> exten
|
||||
}
|
||||
}
|
||||
|
||||
EnumStateMachine<S, E> machine = new EnumStateMachine<S, E>(/*stateMap.values()*/ states, transitions,
|
||||
initialState, endState);
|
||||
// TODO: should make a proper transition
|
||||
Transition<S, E> initialTransition = null;
|
||||
if (initialAction != null) {
|
||||
initialTransition = new InitialTransition<S, E>(initialState, initialAction);
|
||||
}
|
||||
|
||||
EnumStateMachine<S, E> machine = new EnumStateMachine<S, E>(states, transitions, initialState,
|
||||
initialTransition, endState, null, null);
|
||||
machine.afterPropertiesSet();
|
||||
if (beanFactory != null) {
|
||||
machine.setBeanFactory(beanFactory);
|
||||
|
||||
@@ -38,6 +38,7 @@ public class StateData<S, E> {
|
||||
private Collection<? extends Action<S, E>> entryActions;
|
||||
private Collection<? extends Action<S, E>> exitActions;
|
||||
private boolean initial = false;
|
||||
private Action<S, E> initialAction;
|
||||
private boolean end = false;
|
||||
|
||||
public StateData(Object parent, S state, Collection<E> deferred,
|
||||
@@ -81,6 +82,14 @@ public class StateData<S, E> {
|
||||
this.initial = initial;
|
||||
}
|
||||
|
||||
public void setInitialAction(Action<S, E> action) {
|
||||
this.initialAction = action;
|
||||
}
|
||||
|
||||
public Action<S, E> getInitialAction() {
|
||||
return initialAction;
|
||||
}
|
||||
|
||||
public boolean isEnd() {
|
||||
return end;
|
||||
}
|
||||
|
||||
@@ -35,7 +35,9 @@ public class DefaultStateConfigurer<S, E>
|
||||
|
||||
private final Collection<StateData<S, E>> incomplete = new ArrayList<StateData<S, E>>();
|
||||
|
||||
private S initial;
|
||||
private S initialState;
|
||||
|
||||
private Action<S, E> initialAction;
|
||||
|
||||
private S end;
|
||||
|
||||
@@ -47,8 +49,9 @@ public class DefaultStateConfigurer<S, E>
|
||||
for (StateData<S, E> 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<S, E>
|
||||
|
||||
@Override
|
||||
public StateConfigurer<S, E> initial(S initial) {
|
||||
this.initial = initial;
|
||||
this.initialState = initial;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StateConfigurer<S, E> initial(S initial, Action<S, E> action) {
|
||||
this.initialAction = action;
|
||||
return initial(initial);
|
||||
}
|
||||
|
||||
@Override
|
||||
public StateConfigurer<S, E> parent(S state) {
|
||||
this.parent = state;
|
||||
|
||||
@@ -27,6 +27,8 @@ public interface StateConfigurer<S, E> extends
|
||||
|
||||
StateConfigurer<S, E> initial(S initial);
|
||||
|
||||
StateConfigurer<S, E> initial(S initial, Action<S, E> action);
|
||||
|
||||
StateConfigurer<S, E> parent(S state);
|
||||
|
||||
StateConfigurer<S, E> state(S state);
|
||||
|
||||
@@ -79,6 +79,8 @@ public abstract class AbstractStateMachine<S, E> extends LifecycleObjectSupport
|
||||
|
||||
private final State<S,E> initialState;
|
||||
|
||||
private final Transition<S, E> initialTransition;
|
||||
|
||||
private final State<S,E> endState;
|
||||
|
||||
private final Message<E> initialEvent;
|
||||
@@ -125,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, State<S, E> 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<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, extendedState);
|
||||
this(states, transitions, initialState, null, null, null, extendedState);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -152,14 +154,15 @@ public abstract class AbstractStateMachine<S, E> extends LifecycleObjectSupport
|
||||
* @param extendedState the extended state of this machine
|
||||
*/
|
||||
public AbstractStateMachine(Collection<State<S, E>> states, Collection<Transition<S, E>> transitions,
|
||||
State<S, E> initialState, State<S, E> endState, Message<E> initialEvent, ExtendedState extendedState) {
|
||||
State<S, E> initialState, Transition<S, E> initialTransition, State<S, E> endState, 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;
|
||||
this.extendedState = extendedState != null ? extendedState : new DefaultExtendedState();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -213,6 +216,12 @@ public abstract class AbstractStateMachine<S, E> extends LifecycleObjectSupport
|
||||
super.doStart();
|
||||
registerTriggerListener();
|
||||
switchToState(initialState, initialEvent, null);
|
||||
// TODO: for now execute outside of switchToState
|
||||
if (initialTransition != null) {
|
||||
StateContext<S, E> stateContext = new DefaultStateContext<S, E>(
|
||||
initialEvent != null ? initialEvent.getHeaders() : null, extendedState, initialTransition, this);
|
||||
initialTransition.transit(stateContext);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -444,13 +453,13 @@ public abstract class AbstractStateMachine<S, E> 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);
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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<S, E> implements Transition<S, E> {
|
||||
|
||||
private final State<S, E> target;
|
||||
|
||||
private final Collection<Action<S, E>> actions;
|
||||
|
||||
public InitialTransition(State<S, E> target, Action<S, E> action) {
|
||||
this.target = target;
|
||||
ArrayList<Action<S,E>> list = new ArrayList<Action<S, E>>();
|
||||
list.add(action);
|
||||
this.actions = list;
|
||||
}
|
||||
|
||||
public InitialTransition(State<S, E> target, Collection<Action<S, E>> actions) {
|
||||
this.target = target;
|
||||
this.actions = actions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean transit(StateContext<S, E> context) {
|
||||
if (actions != null) {
|
||||
for (Action<S, E> action : actions) {
|
||||
action.execute(context);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public State<S, E> getSource() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public State<S, E> getTarget() {
|
||||
return target;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Action<S, E>> getActions() {
|
||||
return actions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Trigger<S, E> getTrigger() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TransitionKind getKind() {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user