Fix StateMachineModelFactory usage
- When StateMachineModelFactory is passed into config it is now used everytime when machine is build which allows model factory to get a fresh model from its own storage if needed. - Shuffled stuff around in machine factory base classes to call StateMachineModelFactory only once during a machine build operation. - Other tweaks and a polish. - Fixes #254
This commit is contained in:
@@ -21,9 +21,9 @@ import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Stack;
|
||||
import java.util.UUID;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
@@ -39,12 +39,14 @@ import org.springframework.statemachine.access.StateMachineAccess;
|
||||
import org.springframework.statemachine.access.StateMachineFunction;
|
||||
import org.springframework.statemachine.action.Action;
|
||||
import org.springframework.statemachine.config.model.ChoiceData;
|
||||
import org.springframework.statemachine.config.model.DefaultStateMachineModel;
|
||||
import org.springframework.statemachine.config.model.EntryData;
|
||||
import org.springframework.statemachine.config.model.ExitData;
|
||||
import org.springframework.statemachine.config.model.HistoryData;
|
||||
import org.springframework.statemachine.config.model.JunctionData;
|
||||
import org.springframework.statemachine.config.model.StateData;
|
||||
import org.springframework.statemachine.config.model.StateMachineModel;
|
||||
import org.springframework.statemachine.config.model.StateMachineModelFactory;
|
||||
import org.springframework.statemachine.config.model.TransitionData;
|
||||
import org.springframework.statemachine.config.model.TransitionsData;
|
||||
import org.springframework.statemachine.config.model.verifier.CompositeStateMachineModelVerifier;
|
||||
@@ -55,27 +57,27 @@ import org.springframework.statemachine.region.Region;
|
||||
import org.springframework.statemachine.security.StateMachineSecurityInterceptor;
|
||||
import org.springframework.statemachine.state.AbstractState;
|
||||
import org.springframework.statemachine.state.ChoicePseudoState;
|
||||
import org.springframework.statemachine.state.ChoicePseudoState.ChoiceStateData;
|
||||
import org.springframework.statemachine.state.DefaultPseudoState;
|
||||
import org.springframework.statemachine.state.EntryPseudoState;
|
||||
import org.springframework.statemachine.state.ExitPseudoState;
|
||||
import org.springframework.statemachine.state.ForkPseudoState;
|
||||
import org.springframework.statemachine.state.HistoryPseudoState;
|
||||
import org.springframework.statemachine.state.JoinPseudoState;
|
||||
import org.springframework.statemachine.state.JoinPseudoState.JoinStateData;
|
||||
import org.springframework.statemachine.state.JunctionPseudoState;
|
||||
import org.springframework.statemachine.state.JunctionPseudoState.JunctionStateData;
|
||||
import org.springframework.statemachine.state.PseudoState;
|
||||
import org.springframework.statemachine.state.PseudoStateKind;
|
||||
import org.springframework.statemachine.state.RegionState;
|
||||
import org.springframework.statemachine.state.State;
|
||||
import org.springframework.statemachine.state.StateHolder;
|
||||
import org.springframework.statemachine.state.StateMachineState;
|
||||
import org.springframework.statemachine.state.ChoicePseudoState.ChoiceStateData;
|
||||
import org.springframework.statemachine.state.JoinPseudoState.JoinStateData;
|
||||
import org.springframework.statemachine.state.JunctionPseudoState.JunctionStateData;
|
||||
import org.springframework.statemachine.support.DefaultExtendedState;
|
||||
import org.springframework.statemachine.support.LifecycleObjectSupport;
|
||||
import org.springframework.statemachine.support.tree.Tree;
|
||||
import org.springframework.statemachine.support.tree.TreeTraverser;
|
||||
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.DefaultLocalTransition;
|
||||
@@ -85,7 +87,6 @@ import org.springframework.statemachine.transition.TransitionKind;
|
||||
import org.springframework.statemachine.trigger.EventTrigger;
|
||||
import org.springframework.statemachine.trigger.TimerTrigger;
|
||||
import org.springframework.statemachine.trigger.Trigger;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
@@ -101,7 +102,9 @@ public abstract class AbstractStateMachineFactory<S, E> extends LifecycleObjectS
|
||||
|
||||
private final Log log = LogFactory.getLog(AbstractStateMachineFactory.class);
|
||||
|
||||
private final StateMachineModel<S, E> stateMachineModel;
|
||||
private final StateMachineModel<S, E> defaultStateMachineModel;
|
||||
|
||||
private final StateMachineModelFactory<S, E> stateMachineModelFactory;
|
||||
|
||||
private Boolean contextEvents;
|
||||
|
||||
@@ -112,11 +115,12 @@ public abstract class AbstractStateMachineFactory<S, E> extends LifecycleObjectS
|
||||
/**
|
||||
* Instantiates a new abstract state machine factory.
|
||||
*
|
||||
* @param stateMachineModel the state machine model
|
||||
* @param defaultStateMachineModel the default state machine model
|
||||
* @param stateMachineModelFactory the state machine model factory
|
||||
*/
|
||||
public AbstractStateMachineFactory(StateMachineModel<S, E> stateMachineModel) {
|
||||
Assert.notNull(stateMachineModel, "StateMachineModel must be set");
|
||||
this.stateMachineModel = stateMachineModel;
|
||||
public AbstractStateMachineFactory(StateMachineModel<S, E> defaultStateMachineModel, StateMachineModelFactory<S, E> stateMachineModelFactory) {
|
||||
this.stateMachineModelFactory = stateMachineModelFactory;
|
||||
this.defaultStateMachineModel = defaultStateMachineModel;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -148,6 +152,7 @@ public abstract class AbstractStateMachineFactory<S, E> extends LifecycleObjectS
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public StateMachine<S, E> getStateMachine(UUID uuid, String machineId) {
|
||||
StateMachineModel<S, E> stateMachineModel = resolveStateMachineModel();
|
||||
if (stateMachineModel.getConfigurationData().isVerifierEnabled()) {
|
||||
StateMachineModelVerifier<S, E> verifier = stateMachineModel.getConfigurationData().getVerifier();
|
||||
if (verifier == null) {
|
||||
@@ -171,7 +176,7 @@ public abstract class AbstractStateMachineFactory<S, E> extends LifecycleObjectS
|
||||
Map<Object, StateMachine<S, E>> machineMap = new HashMap<Object, StateMachine<S,E>>();
|
||||
Map<S, StateHolder<S, E>> holderMap = new HashMap<S, StateHolder<S, E>>();
|
||||
|
||||
Iterator<Node<StateData<S, E>>> iterator = buildStateDataIterator();
|
||||
Iterator<Node<StateData<S, E>>> iterator = buildStateDataIterator(stateMachineModel);
|
||||
while (iterator.hasNext()) {
|
||||
Node<StateData<S, E>> node = iterator.next();
|
||||
StateData<S, E> stateData = node.getData();
|
||||
@@ -201,13 +206,13 @@ public abstract class AbstractStateMachineFactory<S, E> extends LifecycleObjectS
|
||||
Collection<StateData<S, E>> stateDatas = popSameParents(stateStack);
|
||||
int initialCount = getInitialCount(stateDatas);
|
||||
Collection<Collection<StateData<S, E>>> regionsStateDatas = splitIntoRegions(stateDatas);
|
||||
Collection<TransitionData<S, E>> transitionsData = getTransitionData(iterator.hasNext(), stateDatas);
|
||||
Collection<TransitionData<S, E>> transitionsData = getTransitionData(iterator.hasNext(), stateDatas, stateMachineModel);
|
||||
|
||||
if (initialCount > 1) {
|
||||
for (Collection<StateData<S, E>> regionStateDatas : regionsStateDatas) {
|
||||
machine = buildMachine(machineMap, stateMap, holderMap, regionStateDatas, transitionsData, resolveBeanFactory(),
|
||||
contextEvents, defaultExtendedState, stateMachineModel.getTransitionsData(), resolveTaskExecutor(),
|
||||
resolveTaskScheduler(), machineId, null);
|
||||
machine = buildMachine(machineMap, stateMap, holderMap, regionStateDatas, transitionsData, resolveBeanFactory(stateMachineModel),
|
||||
contextEvents, defaultExtendedState, stateMachineModel.getTransitionsData(), resolveTaskExecutor(stateMachineModel),
|
||||
resolveTaskScheduler(stateMachineModel), machineId, null, stateMachineModel);
|
||||
regionStack.push(new MachineStackItem<S, E>(machine));
|
||||
}
|
||||
|
||||
@@ -227,16 +232,16 @@ public abstract class AbstractStateMachineFactory<S, E> extends LifecycleObjectS
|
||||
states.add(rstate);
|
||||
Transition<S, E> initialTransition = new InitialTransition<S, E>(rstate);
|
||||
StateMachine<S, E> m = buildStateMachineInternal(states, new ArrayList<Transition<S, E>>(), rstate, initialTransition,
|
||||
null, defaultExtendedState, null, contextEvents, resolveBeanFactory(), resolveTaskExecutor(),
|
||||
resolveTaskScheduler(), beanName,
|
||||
null, defaultExtendedState, null, contextEvents, resolveBeanFactory(stateMachineModel), resolveTaskExecutor(stateMachineModel),
|
||||
resolveTaskScheduler(stateMachineModel), beanName,
|
||||
machineId != null ? machineId : stateMachineModel.getConfigurationData().getMachineId(),
|
||||
uuid);
|
||||
uuid, stateMachineModel);
|
||||
machine = m;
|
||||
}
|
||||
} else {
|
||||
machine = buildMachine(machineMap, stateMap, holderMap, stateDatas, transitionsData, resolveBeanFactory(), contextEvents,
|
||||
defaultExtendedState, stateMachineModel.getTransitionsData(), resolveTaskExecutor(), resolveTaskScheduler(),
|
||||
machineId, uuid);
|
||||
machine = buildMachine(machineMap, stateMap, holderMap, stateDatas, transitionsData, resolveBeanFactory(stateMachineModel), contextEvents,
|
||||
defaultExtendedState, stateMachineModel.getTransitionsData(), resolveTaskExecutor(stateMachineModel), resolveTaskScheduler(stateMachineModel),
|
||||
machineId, uuid, stateMachineModel);
|
||||
if (peek.isInitial() || (!peek.isInitial() && !machineMap.containsKey(peek.getParent()))) {
|
||||
machineMap.put(peek.getParent(), machine);
|
||||
}
|
||||
@@ -326,7 +331,7 @@ public abstract class AbstractStateMachineFactory<S, E> extends LifecycleObjectS
|
||||
return delegate;
|
||||
}
|
||||
|
||||
protected BeanFactory resolveBeanFactory() {
|
||||
protected BeanFactory resolveBeanFactory(StateMachineModel<S, E> stateMachineModel) {
|
||||
if (stateMachineModel.getConfigurationData().getBeanFactory() != null) {
|
||||
return stateMachineModel.getConfigurationData().getBeanFactory();
|
||||
} else {
|
||||
@@ -334,7 +339,7 @@ public abstract class AbstractStateMachineFactory<S, E> extends LifecycleObjectS
|
||||
}
|
||||
}
|
||||
|
||||
protected TaskExecutor resolveTaskExecutor() {
|
||||
protected TaskExecutor resolveTaskExecutor(StateMachineModel<S, E> stateMachineModel) {
|
||||
if (stateMachineModel.getConfigurationData().getTaskExecutor() != null) {
|
||||
return stateMachineModel.getConfigurationData().getTaskExecutor();
|
||||
} else {
|
||||
@@ -342,7 +347,7 @@ public abstract class AbstractStateMachineFactory<S, E> extends LifecycleObjectS
|
||||
}
|
||||
}
|
||||
|
||||
protected TaskScheduler resolveTaskScheduler() {
|
||||
protected TaskScheduler resolveTaskScheduler(StateMachineModel<S, E> stateMachineModel) {
|
||||
if (stateMachineModel.getConfigurationData().getTaskScheduler() != null) {
|
||||
return stateMachineModel.getConfigurationData().getTaskScheduler();
|
||||
} else {
|
||||
@@ -350,6 +355,22 @@ public abstract class AbstractStateMachineFactory<S, E> extends LifecycleObjectS
|
||||
}
|
||||
}
|
||||
|
||||
protected StateMachineModel<S, E> resolveStateMachineModel() {
|
||||
if (stateMachineModelFactory == null) {
|
||||
return defaultStateMachineModel;
|
||||
} else {
|
||||
StateMachineModel<S, E> m = stateMachineModelFactory.build();
|
||||
if (m.getConfigurationData() == null) {
|
||||
// if model doesn't have explicit configuration data,
|
||||
// get it from default model
|
||||
return new DefaultStateMachineModel<>(defaultStateMachineModel.getConfigurationData(), m.getStatesData(),
|
||||
m.getTransitionsData());
|
||||
} else {
|
||||
return m;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private int getInitialCount(Collection<StateData<S, E>> stateDatas) {
|
||||
int count = 0;
|
||||
for (StateData<S, E> stateData : stateDatas) {
|
||||
@@ -373,7 +394,7 @@ public abstract class AbstractStateMachineFactory<S, E> extends LifecycleObjectS
|
||||
return map.values();
|
||||
}
|
||||
|
||||
private Collection<TransitionData<S, E>> getTransitionData(boolean roots, Collection<StateData<S, E>> stateDatas) {
|
||||
private Collection<TransitionData<S, E>> getTransitionData(boolean roots, Collection<StateData<S, E>> stateDatas, StateMachineModel<S, E> stateMachineModel) {
|
||||
if (roots) {
|
||||
return resolveTransitionData(stateMachineModel.getTransitionsData().getTransitions(), stateDatas);
|
||||
} else {
|
||||
@@ -438,7 +459,7 @@ public abstract class AbstractStateMachineFactory<S, E> extends LifecycleObjectS
|
||||
Map<S, StateHolder<S, E>> holderMap, Collection<StateData<S, E>> stateDatas, Collection<TransitionData<S, E>> transitionsData,
|
||||
BeanFactory beanFactory, Boolean contextEvents, DefaultExtendedState defaultExtendedState,
|
||||
TransitionsData<S, E> stateMachineTransitions, TaskExecutor taskExecutor, TaskScheduler taskScheduler, String machineId,
|
||||
UUID uuid) {
|
||||
UUID uuid, StateMachineModel<S, E> stateMachineModel) {
|
||||
State<S, E> state = null;
|
||||
State<S, E> initialState = null;
|
||||
PseudoState<S, E> historyState = null;
|
||||
@@ -506,7 +527,7 @@ public abstract class AbstractStateMachineFactory<S, E> extends LifecycleObjectS
|
||||
continue;
|
||||
}
|
||||
state = buildStateInternal(stateData.getState(), stateData.getDeferred(), stateData.getEntryActions(),
|
||||
stateData.getExitActions(), stateData.getStateActions(), pseudoState);
|
||||
stateData.getExitActions(), stateData.getStateActions(), pseudoState, stateMachineModel);
|
||||
if (stateData.isInitial()) {
|
||||
initialState = state;
|
||||
initialAction = stateData.getInitialAction();
|
||||
@@ -534,7 +555,7 @@ public abstract class AbstractStateMachineFactory<S, E> extends LifecycleObjectS
|
||||
}
|
||||
PseudoState<S, E> pseudoState = new HistoryPseudoState<S, E>(PseudoStateKind.HISTORY_SHALLOW, defaultStateHolder, containingStateHolder);
|
||||
state = buildStateInternal(stateData.getState(), stateData.getDeferred(), stateData.getEntryActions(),
|
||||
stateData.getExitActions(), stateData.getStateActions(), pseudoState);
|
||||
stateData.getExitActions(), stateData.getStateActions(), pseudoState, stateMachineModel);
|
||||
states.add(state);
|
||||
stateMap.put(stateData.getState(), state);
|
||||
historyState = pseudoState;
|
||||
@@ -554,7 +575,7 @@ public abstract class AbstractStateMachineFactory<S, E> extends LifecycleObjectS
|
||||
}
|
||||
PseudoState<S, E> pseudoState = new HistoryPseudoState<S, E>(PseudoStateKind.HISTORY_DEEP, defaultStateHolder, containingStateHolder);
|
||||
state = buildStateInternal(stateData.getState(), stateData.getDeferred(), stateData.getEntryActions(),
|
||||
stateData.getExitActions(), stateData.getStateActions(), pseudoState);
|
||||
stateData.getExitActions(), stateData.getStateActions(), pseudoState, stateMachineModel);
|
||||
states.add(state);
|
||||
stateMap.put(stateData.getState(), state);
|
||||
historyState = pseudoState;
|
||||
@@ -573,7 +594,7 @@ public abstract class AbstractStateMachineFactory<S, E> extends LifecycleObjectS
|
||||
}
|
||||
PseudoState<S, E> pseudoState = new ChoicePseudoState<S, E>(choices);
|
||||
state = buildStateInternal(stateData.getState(), stateData.getDeferred(), stateData.getEntryActions(),
|
||||
stateData.getExitActions(), stateData.getStateActions(), pseudoState);
|
||||
stateData.getExitActions(), stateData.getStateActions(), pseudoState, stateMachineModel);
|
||||
states.add(state);
|
||||
stateMap.put(stateData.getState(), state);
|
||||
} else if (stateData.getPseudoStateKind() == PseudoStateKind.JUNCTION) {
|
||||
@@ -589,7 +610,7 @@ public abstract class AbstractStateMachineFactory<S, E> extends LifecycleObjectS
|
||||
}
|
||||
PseudoState<S, E> pseudoState = new JunctionPseudoState<S, E>(junctions);
|
||||
state = buildStateInternal(stateData.getState(), stateData.getDeferred(), stateData.getEntryActions(),
|
||||
stateData.getExitActions(), stateData.getStateActions(), pseudoState);
|
||||
stateData.getExitActions(), stateData.getStateActions(), pseudoState, stateMachineModel);
|
||||
states.add(state);
|
||||
stateMap.put(stateData.getState(), state);
|
||||
} else if (stateData.getPseudoStateKind() == PseudoStateKind.ENTRY) {
|
||||
@@ -599,7 +620,7 @@ public abstract class AbstractStateMachineFactory<S, E> extends LifecycleObjectS
|
||||
if (s.equals(entry.getSource())) {
|
||||
PseudoState<S, E> pseudoState = new EntryPseudoState<S, E>(stateMap.get(entry.getTarget()));
|
||||
state = buildStateInternal(stateData.getState(), stateData.getDeferred(), stateData.getEntryActions(),
|
||||
stateData.getExitActions(), stateData.getStateActions(), pseudoState);
|
||||
stateData.getExitActions(), stateData.getStateActions(), pseudoState, stateMachineModel);
|
||||
states.add(state);
|
||||
stateMap.put(stateData.getState(), state);
|
||||
break;
|
||||
@@ -616,7 +637,7 @@ public abstract class AbstractStateMachineFactory<S, E> extends LifecycleObjectS
|
||||
}
|
||||
PseudoState<S, E> pseudoState = new ExitPseudoState<S, E>(holder);
|
||||
state = buildStateInternal(stateData.getState(), stateData.getDeferred(), stateData.getEntryActions(),
|
||||
stateData.getExitActions(), stateData.getStateActions(), pseudoState);
|
||||
stateData.getExitActions(), stateData.getStateActions(), pseudoState, stateMachineModel);
|
||||
states.add(state);
|
||||
stateMap.put(stateData.getState(), state);
|
||||
break;
|
||||
@@ -631,7 +652,7 @@ public abstract class AbstractStateMachineFactory<S, E> extends LifecycleObjectS
|
||||
}
|
||||
PseudoState<S, E> pseudoState = new ForkPseudoState<S, E>(forks);
|
||||
state = buildStateInternal(stateData.getState(), stateData.getDeferred(), stateData.getEntryActions(),
|
||||
stateData.getExitActions(), stateData.getStateActions(), pseudoState);
|
||||
stateData.getExitActions(), stateData.getStateActions(), pseudoState, stateMachineModel);
|
||||
states.add(state);
|
||||
stateMap.put(stateData.getState(), state);
|
||||
} else if (stateData.getPseudoStateKind() == PseudoStateKind.JOIN) {
|
||||
@@ -675,7 +696,7 @@ public abstract class AbstractStateMachineFactory<S, E> extends LifecycleObjectS
|
||||
JoinPseudoState<S, E> pseudoState = new JoinPseudoState<S, E>(joins, joinTargets);
|
||||
|
||||
state = buildStateInternal(stateData.getState(), stateData.getDeferred(), stateData.getEntryActions(),
|
||||
stateData.getExitActions(), stateData.getStateActions(), pseudoState);
|
||||
stateData.getExitActions(), stateData.getStateActions(), pseudoState, stateMachineModel);
|
||||
states.add(state);
|
||||
stateMap.put(stateData.getState(), state);
|
||||
}
|
||||
@@ -754,28 +775,21 @@ public abstract class AbstractStateMachineFactory<S, E> extends LifecycleObjectS
|
||||
Transition<S, E> initialTransition = new InitialTransition<S, E>(initialState, initialAction);
|
||||
StateMachine<S, E> machine = buildStateMachineInternal(states, transitions, initialState, initialTransition,
|
||||
null, defaultExtendedState, historyState, contextEvents, beanFactory, taskExecutor, taskScheduler,
|
||||
beanName, machineId != null ? machineId : stateMachineModel.getConfigurationData().getMachineId(), uuid);
|
||||
beanName, machineId != null ? machineId : stateMachineModel.getConfigurationData().getMachineId(), uuid, stateMachineModel);
|
||||
return machine;
|
||||
}
|
||||
|
||||
protected abstract StateMachine<S, E> buildStateMachineInternal(Collection<State<S, E>> states,
|
||||
Collection<Transition<S, E>> transitions,
|
||||
State<S, E> initialState, Transition<S, E> initialTransition,
|
||||
Message<E> initialEvent, ExtendedState extendedState,
|
||||
PseudoState<S, E> historyState,
|
||||
Boolean contextEventsEnabled,
|
||||
BeanFactory beanFactory,
|
||||
TaskExecutor taskExecutor,
|
||||
TaskScheduler taskScheduler,
|
||||
String beanName,
|
||||
String machineId,
|
||||
UUID uuid);
|
||||
Collection<Transition<S, E>> transitions, State<S, E> initialState, Transition<S, E> initialTransition, Message<E> initialEvent,
|
||||
ExtendedState extendedState, PseudoState<S, E> historyState, Boolean contextEventsEnabled, BeanFactory beanFactory,
|
||||
TaskExecutor taskExecutor, TaskScheduler taskScheduler, String beanName, String machineId, UUID uuid,
|
||||
StateMachineModel<S, E> stateMachineModel);
|
||||
|
||||
protected abstract State<S, E> buildStateInternal(S id, Collection<E> deferred,
|
||||
Collection<? extends Action<S, E>> entryActions, Collection<? extends Action<S, E>> exitActions,
|
||||
Collection<? extends Action<S, E>> stateActions, PseudoState<S, E> pseudoState);
|
||||
Collection<? extends Action<S, E>> stateActions, PseudoState<S, E> pseudoState, StateMachineModel<S, E> stateMachineModel);
|
||||
|
||||
private Iterator<Node<StateData<S, E>>> buildStateDataIterator() {
|
||||
private Iterator<Node<StateData<S, E>>> buildStateDataIterator(StateMachineModel<S, E> stateMachineModel) {
|
||||
Tree<StateData<S, E>> tree = new Tree<StateData<S, E>>();
|
||||
treeAdd(tree, stateMachineModel.getStatesData().getStateData());
|
||||
return new TreeTraverser<Node<StateData<S, E>>>() {
|
||||
|
||||
@@ -28,6 +28,7 @@ import org.springframework.statemachine.ObjectStateMachine;
|
||||
import org.springframework.statemachine.StateMachine;
|
||||
import org.springframework.statemachine.action.Action;
|
||||
import org.springframework.statemachine.config.model.StateMachineModel;
|
||||
import org.springframework.statemachine.config.model.StateMachineModelFactory;
|
||||
import org.springframework.statemachine.region.Region;
|
||||
import org.springframework.statemachine.state.ObjectState;
|
||||
import org.springframework.statemachine.state.PseudoState;
|
||||
@@ -49,18 +50,28 @@ public class ObjectStateMachineFactory<S, E> extends AbstractStateMachineFactory
|
||||
/**
|
||||
* Instantiates a new object state machine factory.
|
||||
*
|
||||
* @param stateMachineModel the state machine model
|
||||
* @param defaultStateMachineModel the default state machine model
|
||||
*/
|
||||
public ObjectStateMachineFactory(StateMachineModel<S, E> stateMachineModel) {
|
||||
super(stateMachineModel);
|
||||
public ObjectStateMachineFactory(StateMachineModel<S, E> defaultStateMachineModel) {
|
||||
this(defaultStateMachineModel, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new object state machine factory.
|
||||
*
|
||||
* @param defaultStateMachineModel the default state machine model
|
||||
* @param stateMachineModelFactory the state machine model factory
|
||||
*/
|
||||
public ObjectStateMachineFactory(StateMachineModel<S, E> defaultStateMachineModel,
|
||||
StateMachineModelFactory<S, E> stateMachineModelFactory) {
|
||||
super(defaultStateMachineModel, stateMachineModelFactory);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected StateMachine<S, E> buildStateMachineInternal(Collection<State<S, E>> states,
|
||||
Collection<Transition<S, E>> transitions, State<S, E> initialState, Transition<S, E> initialTransition,
|
||||
Message<E> initialEvent, ExtendedState extendedState, PseudoState<S, E> historyState,
|
||||
Boolean contextEventsEnabled, BeanFactory beanFactory, TaskExecutor taskExecutor,
|
||||
TaskScheduler taskScheduler, String beanName, String machineId, UUID uuid) {
|
||||
protected StateMachine<S, E> buildStateMachineInternal(Collection<State<S, E>> states, Collection<Transition<S, E>> transitions,
|
||||
State<S, E> initialState, Transition<S, E> initialTransition, Message<E> initialEvent, ExtendedState extendedState,
|
||||
PseudoState<S, E> historyState, Boolean contextEventsEnabled, BeanFactory beanFactory, TaskExecutor taskExecutor,
|
||||
TaskScheduler taskScheduler, String beanName, String machineId, UUID uuid, StateMachineModel<S, E> stateMachineModel) {
|
||||
ObjectStateMachine<S, E> machine = new ObjectStateMachine<S, E>(states, transitions, initialState, initialTransition, initialEvent,
|
||||
extendedState, uuid);
|
||||
machine.setId(machineId);
|
||||
@@ -87,17 +98,17 @@ public class ObjectStateMachineFactory<S, E> extends AbstractStateMachineFactory
|
||||
@Override
|
||||
protected State<S, E> buildStateInternal(S id, Collection<E> deferred,
|
||||
Collection<? extends Action<S, E>> entryActions, Collection<? extends Action<S, E>> exitActions,
|
||||
Collection<? extends Action<S, E>> stateActions, PseudoState<S, E> pseudoState) {
|
||||
Collection<? extends Action<S, E>> stateActions, PseudoState<S, E> pseudoState, StateMachineModel<S, E> stateMachineModel) {
|
||||
ObjectState<S,E> objectState = new ObjectState<S, E>(id, deferred, entryActions, exitActions, stateActions, pseudoState, null, null);
|
||||
BeanFactory beanFactory = resolveBeanFactory();
|
||||
BeanFactory beanFactory = resolveBeanFactory(stateMachineModel);
|
||||
if (beanFactory != null) {
|
||||
objectState.setBeanFactory(beanFactory);
|
||||
}
|
||||
TaskExecutor taskExecutor = resolveTaskExecutor();
|
||||
TaskExecutor taskExecutor = resolveTaskExecutor(stateMachineModel);
|
||||
if (taskExecutor != null) {
|
||||
objectState.setTaskExecutor(taskExecutor);
|
||||
}
|
||||
TaskScheduler taskScheduler = resolveTaskScheduler();
|
||||
TaskScheduler taskScheduler = resolveTaskScheduler(stateMachineModel);
|
||||
if (taskScheduler != null) {
|
||||
objectState.setTaskScheduler(taskScheduler);
|
||||
}
|
||||
|
||||
@@ -126,8 +126,16 @@ public class StateMachineBuilder {
|
||||
TransitionsData<S, E> stateMachineTransitions = stateMachineConfig.getTransitions();
|
||||
StatesData<S, E> stateMachineStates = stateMachineConfig.getStates();
|
||||
ConfigurationData<S, E> stateMachineConfigurationConfig = stateMachineConfig.getStateMachineConfigurationConfig();
|
||||
ObjectStateMachineFactory<S, E> stateMachineFactory = new ObjectStateMachineFactory<S, E>(
|
||||
new DefaultStateMachineModel<S, E>(stateMachineConfigurationConfig, stateMachineStates, stateMachineTransitions));
|
||||
|
||||
ObjectStateMachineFactory<S, E> stateMachineFactory = null;
|
||||
if (stateMachineConfig.getModel() != null && stateMachineConfig.getModel().getFactory() != null) {
|
||||
stateMachineFactory = new ObjectStateMachineFactory<S, E>(
|
||||
new DefaultStateMachineModel<S, E>(stateMachineConfigurationConfig, null, null),
|
||||
stateMachineConfig.getModel().getFactory());
|
||||
} else {
|
||||
stateMachineFactory = new ObjectStateMachineFactory<S, E>(new DefaultStateMachineModel<S, E>(
|
||||
stateMachineConfigurationConfig, stateMachineStates, stateMachineTransitions), null);
|
||||
}
|
||||
|
||||
stateMachineFactory.setHandleAutostartup(stateMachineConfigurationConfig.isAutoStart());
|
||||
|
||||
|
||||
@@ -15,10 +15,19 @@
|
||||
*/
|
||||
package org.springframework.statemachine.config;
|
||||
|
||||
import org.springframework.statemachine.config.builders.ModelData;
|
||||
import org.springframework.statemachine.config.model.ConfigurationData;
|
||||
import org.springframework.statemachine.config.model.StatesData;
|
||||
import org.springframework.statemachine.config.model.TransitionsData;
|
||||
|
||||
/**
|
||||
* Generic pojo keeping relates configs together.
|
||||
*
|
||||
* @author Janne Valkealahti
|
||||
*
|
||||
* @param <S> the type of state
|
||||
* @param <E> the type of event
|
||||
*/
|
||||
public class StateMachineConfig<S, E> {
|
||||
|
||||
public final ConfigurationData<S, E> stateMachineConfigurationConfig;
|
||||
@@ -27,10 +36,34 @@ public class StateMachineConfig<S, E> {
|
||||
|
||||
public final StatesData<S, E> states;
|
||||
|
||||
public StateMachineConfig(ConfigurationData<S, E> stateMachineConfigurationConfig, TransitionsData<S, E> transitions, StatesData<S, E> states) {
|
||||
public final ModelData<S, E> model;
|
||||
|
||||
/**
|
||||
* Instantiates a new state machine config.
|
||||
*
|
||||
* @param stateMachineConfigurationConfig the state machine configuration config
|
||||
* @param transitions the transitions
|
||||
* @param states the states
|
||||
*/
|
||||
public StateMachineConfig(ConfigurationData<S, E> stateMachineConfigurationConfig, TransitionsData<S, E> transitions,
|
||||
StatesData<S, E> states) {
|
||||
this(stateMachineConfigurationConfig, transitions, states, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new state machine config.
|
||||
*
|
||||
* @param stateMachineConfigurationConfig the state machine configuration config
|
||||
* @param transitions the transitions
|
||||
* @param states the states
|
||||
* @param model the model
|
||||
*/
|
||||
public StateMachineConfig(ConfigurationData<S, E> stateMachineConfigurationConfig, TransitionsData<S, E> transitions,
|
||||
StatesData<S, E> states, ModelData<S, E> model) {
|
||||
this.stateMachineConfigurationConfig = stateMachineConfigurationConfig;
|
||||
this.transitions = transitions;
|
||||
this.states = states;
|
||||
this.model = model;
|
||||
}
|
||||
|
||||
public ConfigurationData<S, E> getStateMachineConfigurationConfig() {
|
||||
@@ -45,4 +78,7 @@ public class StateMachineConfig<S, E> {
|
||||
return states;
|
||||
}
|
||||
|
||||
public ModelData<S, E> getModel() {
|
||||
return model;
|
||||
}
|
||||
}
|
||||
@@ -19,7 +19,6 @@ import org.springframework.statemachine.config.StateMachineConfig;
|
||||
import org.springframework.statemachine.config.common.annotation.AbstractConfiguredAnnotationBuilder;
|
||||
import org.springframework.statemachine.config.common.annotation.AnnotationBuilder;
|
||||
import org.springframework.statemachine.config.model.ConfigurationData;
|
||||
import org.springframework.statemachine.config.model.StateMachineModel;
|
||||
import org.springframework.statemachine.config.model.StatesData;
|
||||
import org.springframework.statemachine.config.model.TransitionsData;
|
||||
|
||||
@@ -44,25 +43,12 @@ public class StateMachineConfigBuilder<S, E>
|
||||
StateMachineConfigurationBuilder<?, ?> configurationBuilder = getSharedObject(StateMachineConfigurationBuilder.class);
|
||||
StateMachineTransitionBuilder<?, ?> transitionBuilder = getSharedObject(StateMachineTransitionBuilder.class);
|
||||
StateMachineStateBuilder<?, ?> stateBuilder = getSharedObject(StateMachineStateBuilder.class);
|
||||
|
||||
ModelData<S, E> model = (ModelData<S, E>) modelBuilder.build();
|
||||
ConfigurationData<S, E> stateMachineConfigurationConfig = null;
|
||||
TransitionsData<S, E> transitions = null;
|
||||
StatesData<S, E> states = null;
|
||||
|
||||
if (model.getFactory() != null) {
|
||||
StateMachineModel<S,E> stateMachineModel = model.getFactory().build();
|
||||
transitions = stateMachineModel.getTransitionsData();
|
||||
states = stateMachineModel.getStatesData();
|
||||
}
|
||||
stateMachineConfigurationConfig = (ConfigurationData<S, E>) configurationBuilder.build();
|
||||
if (transitions == null) {
|
||||
transitionBuilder.setSharedObject(ConfigurationData.class, stateMachineConfigurationConfig);
|
||||
transitions = (TransitionsData<S, E>) transitionBuilder.build();
|
||||
}
|
||||
if (states == null) {
|
||||
states = (StatesData<S, E>) stateBuilder.build();
|
||||
}
|
||||
return new StateMachineConfig<S, E>(stateMachineConfigurationConfig, transitions, states);
|
||||
transitionBuilder.setSharedObject(ConfigurationData.class, stateMachineConfigurationConfig);
|
||||
TransitionsData<S, E> transitions = (TransitionsData<S, E>) transitionBuilder.build();
|
||||
StatesData<S, E> states = (StatesData<S, E>) stateBuilder.build();
|
||||
return new StateMachineConfig<S, E>(stateMachineConfigurationConfig, transitions, states, model);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -145,8 +145,17 @@ public class StateMachineConfiguration<S, E> extends
|
||||
TransitionsData<S, E> stateMachineTransitions = stateMachineConfig.getTransitions();
|
||||
StatesData<S, E> stateMachineStates = stateMachineConfig.getStates();
|
||||
ConfigurationData<S, E> stateMachineConfigurationConfig = stateMachineConfig.getStateMachineConfigurationConfig();
|
||||
ObjectStateMachineFactory<S, E> stateMachineFactory = new ObjectStateMachineFactory<S, E>(
|
||||
new DefaultStateMachineModel<S, E>(stateMachineConfigurationConfig, stateMachineStates, stateMachineTransitions));
|
||||
|
||||
ObjectStateMachineFactory<S, E> stateMachineFactory = null;
|
||||
if (stateMachineConfig.getModel() != null && stateMachineConfig.getModel().getFactory() != null) {
|
||||
stateMachineFactory = new ObjectStateMachineFactory<S, E>(
|
||||
new DefaultStateMachineModel<S, E>(stateMachineConfigurationConfig, null, null),
|
||||
stateMachineConfig.getModel().getFactory());
|
||||
} else {
|
||||
stateMachineFactory = new ObjectStateMachineFactory<S, E>(new DefaultStateMachineModel<S, E>(
|
||||
stateMachineConfigurationConfig, stateMachineStates, stateMachineTransitions), null);
|
||||
}
|
||||
|
||||
stateMachineFactory.setBeanFactory(getBeanFactory());
|
||||
stateMachineFactory.setContextEventsEnabled(contextEvents);
|
||||
stateMachineFactory.setBeanName(beanName);
|
||||
|
||||
@@ -134,8 +134,17 @@ public class StateMachineFactoryConfiguration<S, E> extends
|
||||
StatesData<S, E> stateMachineStates = stateMachineConfig.getStates();
|
||||
ConfigurationData<S, E> stateMachineConfigurationConfig = stateMachineConfig
|
||||
.getStateMachineConfigurationConfig();
|
||||
ObjectStateMachineFactory<S, E> objectStateMachineFactory = new ObjectStateMachineFactory<S, E>(
|
||||
new DefaultStateMachineModel<S, E>(stateMachineConfigurationConfig, stateMachineStates, stateMachineTransitions));
|
||||
|
||||
ObjectStateMachineFactory<S, E> objectStateMachineFactory = null;
|
||||
if (stateMachineConfig.getModel() != null && stateMachineConfig.getModel().getFactory() != null) {
|
||||
objectStateMachineFactory = new ObjectStateMachineFactory<S, E>(
|
||||
new DefaultStateMachineModel<S, E>(stateMachineConfigurationConfig, null, null),
|
||||
stateMachineConfig.getModel().getFactory());
|
||||
} else {
|
||||
objectStateMachineFactory = new ObjectStateMachineFactory<S, E>(new DefaultStateMachineModel<S, E>(
|
||||
stateMachineConfigurationConfig, stateMachineStates, stateMachineTransitions), null);
|
||||
}
|
||||
|
||||
objectStateMachineFactory.setBeanFactory(beanFactory);
|
||||
objectStateMachineFactory.setContextEventsEnabled(contextEvents);
|
||||
// explicitly tell factory to handle auto-start because
|
||||
|
||||
@@ -15,8 +15,6 @@
|
||||
*/
|
||||
package org.springframework.statemachine.config.model;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Default implementation of a {@link StateMachineModel}.
|
||||
*
|
||||
@@ -40,9 +38,6 @@ public class DefaultStateMachineModel<S, E> extends StateMachineModel<S, E> {
|
||||
*/
|
||||
public DefaultStateMachineModel(ConfigurationData<S, E> configurationData, StatesData<S, E> statesData,
|
||||
TransitionsData<S, E> transitionsData) {
|
||||
Assert.notNull(configurationData, "Configuration must be set");
|
||||
Assert.notNull(statesData, "States must be set");
|
||||
Assert.notNull(transitionsData, "Transitions must be set");
|
||||
this.configuration = configurationData;
|
||||
this.states = statesData;
|
||||
this.transitions = transitionsData;
|
||||
|
||||
@@ -33,8 +33,10 @@ import org.springframework.statemachine.StateContext;
|
||||
import org.springframework.statemachine.StateMachine;
|
||||
import org.springframework.statemachine.action.Action;
|
||||
import org.springframework.statemachine.config.EnableStateMachine;
|
||||
import org.springframework.statemachine.config.EnableStateMachineFactory;
|
||||
import org.springframework.statemachine.config.ObjectStateMachineFactory;
|
||||
import org.springframework.statemachine.config.StateMachineConfigurerAdapter;
|
||||
import org.springframework.statemachine.config.StateMachineFactory;
|
||||
import org.springframework.statemachine.config.builders.StateMachineModelConfigurer;
|
||||
|
||||
public class StateMachineModelFactoryTests extends AbstractStateMachineTests {
|
||||
@@ -68,6 +70,33 @@ public class StateMachineModelFactoryTests extends AbstractStateMachineTests {
|
||||
assertThat(stateMachine.getState().getIds(), contains("S2"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testModelRecreates() {
|
||||
context.register(Config3.class);
|
||||
context.refresh();
|
||||
@SuppressWarnings("unchecked")
|
||||
StateMachineFactory<String, String> stateMachineFactory = context.getBean(StateMachineFactory.class);
|
||||
StateMachine<String,String> stateMachine = stateMachineFactory.getStateMachine();
|
||||
TestStateMachineModelFactory modelFactory = context.getBean(TestStateMachineModelFactory.class);
|
||||
|
||||
stateMachine.start();
|
||||
assertThat(stateMachine.getState().getIds(), contains("S1"));
|
||||
stateMachine.sendEvent("E1");
|
||||
assertThat(stateMachine.getState().getIds(), contains("S2"));
|
||||
stateMachine.stop();
|
||||
|
||||
modelFactory.state1 = "SS1";
|
||||
modelFactory.state2 = "SS2";
|
||||
modelFactory.event1 = "EE1";
|
||||
|
||||
stateMachine = stateMachineFactory.getStateMachine();
|
||||
stateMachine.start();
|
||||
assertThat(stateMachine.getState().getIds(), contains("SS1"));
|
||||
stateMachine.sendEvent("EE1");
|
||||
assertThat(stateMachine.getState().getIds(), contains("SS2"));
|
||||
stateMachine.stop();
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class Config1 {
|
||||
@Bean
|
||||
@@ -106,9 +135,38 @@ public class StateMachineModelFactoryTests extends AbstractStateMachineTests {
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableStateMachineFactory
|
||||
public static class Config3 extends StateMachineConfigurerAdapter<String, String> {
|
||||
|
||||
@Override
|
||||
public void configure(StateMachineModelConfigurer<String, String> model) throws Exception {
|
||||
model
|
||||
.withModel()
|
||||
.factory(modelFactory());
|
||||
}
|
||||
|
||||
@Bean
|
||||
public StateMachineModelFactory<String, String> modelFactory() {
|
||||
return new TestStateMachineModelFactory();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Action<String, String> action1() {
|
||||
return new Action<String, String>() {
|
||||
@Override
|
||||
public void execute(StateContext<String, String> context) {
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static class TestStateMachineModelFactory implements StateMachineModelFactory<String, String>, BeanFactoryAware {
|
||||
private BeanFactory beanFactory;
|
||||
String state1 = "S1";
|
||||
String state2 = "S2";
|
||||
String event1 = "E1";
|
||||
|
||||
@Override
|
||||
public StateMachineModel<String, String> build() {
|
||||
@@ -120,12 +178,12 @@ public class StateMachineModelFactoryTests extends AbstractStateMachineTests {
|
||||
ConfigurationData<String, String> configurationData = new ConfigurationData<>();
|
||||
|
||||
Collection<StateData<String, String>> stateData = new ArrayList<>();
|
||||
stateData.add(new StateData<String, String>("S1", true));
|
||||
stateData.add(new StateData<String, String>(null, null, "S2", null, s2Actions, null));
|
||||
stateData.add(new StateData<String, String>(state1, true));
|
||||
stateData.add(new StateData<String, String>(null, null, state2, null, s2Actions, null));
|
||||
StatesData<String, String> statesData = new StatesData<>(stateData);
|
||||
|
||||
Collection<TransitionData<String, String>> transitionData = new ArrayList<>();
|
||||
transitionData.add(new TransitionData<String, String>("S1", "S2", "E1"));
|
||||
transitionData.add(new TransitionData<String, String>(state1, state2, event1));
|
||||
TransitionsData<String, String> transitionsData = new TransitionsData<>(transitionData);
|
||||
|
||||
StateMachineModel<String, String> stateMachineModel = new DefaultStateMachineModel<>(configurationData, statesData, transitionsData);
|
||||
|
||||
@@ -24,7 +24,6 @@ import java.nio.file.Path;
|
||||
import org.eclipse.uml2.uml.Model;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.statemachine.config.model.AbstractStateMachineModelFactory;
|
||||
import org.springframework.statemachine.config.model.ConfigurationData;
|
||||
import org.springframework.statemachine.config.model.DefaultStateMachineModel;
|
||||
import org.springframework.statemachine.config.model.StateMachineModel;
|
||||
import org.springframework.statemachine.config.model.StateMachineModelFactory;
|
||||
@@ -76,8 +75,8 @@ public class UmlStateMachineModelFactory extends AbstractStateMachineModelFactor
|
||||
}
|
||||
UmlModelParser parser = new UmlModelParser(model, this);
|
||||
DataHolder dataHolder = parser.parseModel();
|
||||
ConfigurationData<String, String> configurationData = new ConfigurationData<>();
|
||||
return new DefaultStateMachineModel<String, String>(configurationData, dataHolder.getStatesData(), dataHolder.getTransitionsData());
|
||||
// we don't set configurationData here, so assume null
|
||||
return new DefaultStateMachineModel<String, String>(null, dataHolder.getStatesData(), dataHolder.getTransitionsData());
|
||||
}
|
||||
|
||||
private Resource resolveResource() {
|
||||
|
||||
Reference in New Issue
Block a user