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:
Janne Valkealahti
2016-09-23 15:44:13 +01:00
parent 876bdc9671
commit 693d7b8951
10 changed files with 223 additions and 98 deletions

View File

@@ -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>>>() {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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() {