Better config model for substates
- streamline state model between config and state machine factory. - remove SubStateConfigurer and just use StateConfigurer.
This commit is contained in:
@@ -17,17 +17,15 @@ package org.springframework.statemachine.config;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Stack;
|
||||
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.statemachine.EnumStateMachine;
|
||||
import org.springframework.statemachine.StateMachine;
|
||||
import org.springframework.statemachine.config.builders.StateMachineStates;
|
||||
import org.springframework.statemachine.config.builders.StateMachineStates.StateData;
|
||||
import org.springframework.statemachine.config.builders.StateMachineStates.StateMachineStatesData;
|
||||
import org.springframework.statemachine.config.builders.StateMachineTransitions;
|
||||
import org.springframework.statemachine.config.builders.StateMachineTransitions.TransitionData;
|
||||
import org.springframework.statemachine.state.DefaultPseudoState;
|
||||
@@ -74,72 +72,84 @@ public class EnumStateMachineFactory<S extends Enum<S>, E extends Enum<E>> exten
|
||||
|
||||
@Override
|
||||
public StateMachine<S, E> getStateMachine() {
|
||||
StateMachine<S, E> machine = null;
|
||||
|
||||
// we store mappings from state id's to states which gets
|
||||
// created during the process. This is needed for transitions to
|
||||
// find a correct mappings because they use state id's, not actual
|
||||
// states.
|
||||
final Map<S, State<S, E>> stateMap = new HashMap<S, State<S, E>>();
|
||||
|
||||
// we eventually return this machine which is a last one build
|
||||
StateMachine<S, E> machine = null;
|
||||
Tree<StateData<S, E>> tree = new Tree<StateData<S, E>>();
|
||||
|
||||
Map<Object, StateMachineStatesData<S, E>> states = stateMachineStates.getStates();
|
||||
Tree<StateMachineStatesData<S, E>> tree = new Tree<StateMachineStatesData<S, E>>();
|
||||
|
||||
for (Entry<Object, StateMachineStatesData<S, E>> e : states.entrySet()) {
|
||||
Object id = e.getKey();
|
||||
StateMachineStatesData<S, E> value = e.getValue();
|
||||
Object parent = value.getParent();
|
||||
tree.add(value, id, parent);
|
||||
for (StateData<S, E> stateData : stateMachineStates.getStateDatas()) {
|
||||
Object id = stateData.getState();
|
||||
Object parent = stateData.getParent();
|
||||
tree.add(stateData, id, parent);
|
||||
}
|
||||
|
||||
TreeTraverser<Node<StateMachineStatesData<S, E>>> traverser = new TreeTraverser<Node<StateMachineStatesData<S, E>>>() {
|
||||
TreeTraverser<Node<StateData<S, E>>> traverser = new TreeTraverser<Node<StateData<S, E>>>() {
|
||||
@Override
|
||||
public Iterable<Node<StateMachineStatesData<S, E>>> children(Node<StateMachineStatesData<S, E>> root) {
|
||||
public Iterable<Node<StateData<S, E>>> children(Node<StateData<S, E>> root) {
|
||||
return root.getChildren();
|
||||
}
|
||||
};
|
||||
|
||||
Stack<StackItem<S, E>> stack = new Stack<StackItem<S, E>>();
|
||||
for (Node<StateMachineStatesData<S, E>> node : traverser.postOrderTraversal(tree.getRoot())) {
|
||||
System.out.println(node.getData());
|
||||
|
||||
Object parent = node.getData().getParent();
|
||||
|
||||
if (!stack.empty()) {
|
||||
StackItem<S, E> pop = stack.pop();
|
||||
machine = buildSubMachine(stateMap, pop.machine, node.getData(), stateMachineTransitions, getBeanFactory());
|
||||
stack.push(new StackItem<S, E>(machine, parent));
|
||||
// use two stack, first for states and second for machines
|
||||
Stack<StateMachine<S, E>> machineStack = new Stack<StateMachine<S, E>>();
|
||||
Stack<StateData<S, E>> stateStack = new Stack<StateData<S, E>>();
|
||||
for (Node<StateData<S, E>> node : traverser.postOrderTraversal(tree.getRoot())) {
|
||||
StateData<S, E> stateData = node.getData();
|
||||
if (stateStack.isEmpty()) {
|
||||
stateStack.push(stateData);
|
||||
} else {
|
||||
machine = buildSimpleMachine(stateMap, node.getData(), stateMachineTransitions, getBeanFactory());
|
||||
stack.push(new StackItem<S, E>(machine, parent));
|
||||
StateData<S, E> peek = stateStack.peek();
|
||||
if ((stateData != null) && ((peek.getParent() == null && stateData.getParent() == null) || peek.getParent().equals(stateData.getParent()))) {
|
||||
stateStack.push(stateData);
|
||||
} else {
|
||||
Collection<StateData<S, E>> stateDatas = new ArrayList<StateData<S,E>>();
|
||||
Enumeration<StateData<S, E>> elements = stateStack.elements();
|
||||
while (elements.hasMoreElements()) {
|
||||
StateData<S, E> next = elements.nextElement();
|
||||
stateDatas.add(next);
|
||||
}
|
||||
stateStack.clear();
|
||||
if (machineStack.isEmpty()) {
|
||||
machine = buildSimpleMachinexxx(stateMap, stateDatas, stateMachineTransitions, getBeanFactory());
|
||||
machineStack.push(machine);
|
||||
} else {
|
||||
StateMachine<S, E> pop = machineStack.pop();
|
||||
machine = buildSubMachinexxx(stateMap, pop, stateDatas, stateMachineTransitions, getBeanFactory());
|
||||
machineStack.push(machine);
|
||||
}
|
||||
stateStack.push(stateData);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
return machine;
|
||||
}
|
||||
|
||||
private static class StackItem<S, E> {
|
||||
StateMachine<S, E> machine;
|
||||
Object id;
|
||||
public StackItem(StateMachine<S, E> machine, Object id) {
|
||||
this.machine = machine;
|
||||
this.id = id;
|
||||
}
|
||||
}
|
||||
|
||||
private static <S extends Enum<S>, E extends Enum<E>> StateMachine<S, E> buildSimpleMachine(Map<S, State<S, E>> stateMap, StateMachineStatesData<S, E> statesData, StateMachineTransitions<S, E> transitionsData, BeanFactory beanFactory) {
|
||||
for (StateData<S, E> stateData : statesData.getStates()) {
|
||||
private static <S extends Enum<S>, E extends Enum<E>> StateMachine<S, E> buildSimpleMachinexxx(
|
||||
Map<S, State<S, E>> stateMap, Collection<StateData<S, E>> stateDatas,
|
||||
StateMachineTransitions<S, E> transitionsData, BeanFactory beanFactory) {
|
||||
State<S, E> initialState = null;
|
||||
State<S, E> endState = null;
|
||||
for (StateData<S, E> stateData : stateDatas) {
|
||||
|
||||
// TODO: doesn't feel right to tweak initial kind like this
|
||||
PseudoState pseudoState = null;
|
||||
if (stateData.getState() == statesData.getInitialState()) {
|
||||
if (stateData.isInitial()) {
|
||||
pseudoState = new DefaultPseudoState(PseudoStateKind.INITIAL);
|
||||
}
|
||||
stateMap.put(stateData.getState(), new EnumState<S, E>(stateData.getState(), stateData.getDeferred(),
|
||||
stateData.getEntryActions(), stateData.getExitActions(), pseudoState));
|
||||
EnumState<S,E> state = new EnumState<S, E>(stateData.getState(), stateData.getDeferred(),
|
||||
stateData.getEntryActions(), stateData.getExitActions(), pseudoState);
|
||||
if (stateData.isInitial()) {
|
||||
initialState = state;
|
||||
}
|
||||
if (stateData.isEnd()) {
|
||||
endState = state;
|
||||
}
|
||||
stateMap.put(stateData.getState(), state);
|
||||
}
|
||||
|
||||
Collection<Transition<S, E>> transitions = new ArrayList<Transition<S, E>>();
|
||||
@@ -160,7 +170,7 @@ public class EnumStateMachineFactory<S extends Enum<S>, E extends Enum<E>> exten
|
||||
}
|
||||
|
||||
EnumStateMachine<S, E> machine = new EnumStateMachine<S, E>(stateMap.values(), transitions,
|
||||
stateMap.get(statesData.getInitialState()), stateMap.get(statesData.getEndState()));
|
||||
initialState, endState);
|
||||
machine.afterPropertiesSet();
|
||||
if (beanFactory != null) {
|
||||
machine.setBeanFactory(beanFactory);
|
||||
@@ -168,10 +178,12 @@ public class EnumStateMachineFactory<S extends Enum<S>, E extends Enum<E>> exten
|
||||
return machine;
|
||||
}
|
||||
|
||||
private static <S extends Enum<S>, E extends Enum<E>> StateMachine<S, E> buildSubMachine(Map<S, State<S, E>> stateMap, StateMachine<S, E> submachine, StateMachineStatesData<S, E> statesData, StateMachineTransitions<S, E> transitionsData, BeanFactory beanFactory) {
|
||||
private static <S extends Enum<S>, E extends Enum<E>> StateMachine<S, E> buildSubMachinexxx(
|
||||
Map<S, State<S, E>> stateMap, StateMachine<S, E> submachine, Collection<StateData<S, E>> stateDatas,
|
||||
StateMachineTransitions<S, E> transitionsData, BeanFactory beanFactory) {
|
||||
Collection<State<S, E>> states = new ArrayList<State<S,E>>();
|
||||
State<S, E> state = null;
|
||||
for (StateData<S, E> stateData : statesData.getStates()) {
|
||||
for (StateData<S, E> stateData : stateDatas) {
|
||||
state = new StateMachineState<S, E>(stateData.getState(), submachine, stateData.getDeferred(),
|
||||
stateData.getEntryActions(), stateData.getExitActions(), new DefaultPseudoState(
|
||||
PseudoStateKind.INITIAL));
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* 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.config;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.springframework.statemachine.action.Action;
|
||||
import org.springframework.statemachine.state.State;
|
||||
|
||||
/**
|
||||
* {@code StateData} is a data representation of a {@link State} used as an
|
||||
* abstraction between a {@link StateMachineFactory} and a state machine
|
||||
* configuration.
|
||||
*
|
||||
* @author Janne Valkealahti
|
||||
*
|
||||
* @param <S> the type of state
|
||||
* @param <E> the type of event
|
||||
*/
|
||||
public class StateData<S, E> {
|
||||
|
||||
private Object parent;
|
||||
private S state;
|
||||
private Collection<E> deferred;
|
||||
private Collection<? extends Action<S, E>> entryActions;
|
||||
private Collection<? extends Action<S, E>> exitActions;
|
||||
private boolean initial = false;
|
||||
private boolean end = false;
|
||||
|
||||
public StateData(Object parent, S state, Collection<E> deferred,
|
||||
Collection<? extends Action<S, E>> entryActions, Collection<? extends Action<S, E>> exitActions) {
|
||||
this.state = state;
|
||||
this.deferred = deferred;
|
||||
this.entryActions = entryActions;
|
||||
this.exitActions = exitActions;
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
public S getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
public Collection<E> getDeferred() {
|
||||
return deferred;
|
||||
}
|
||||
|
||||
public Collection<? extends Action<S, E>> getEntryActions() {
|
||||
return entryActions;
|
||||
}
|
||||
|
||||
public Collection<? extends Action<S, E>> getExitActions() {
|
||||
return exitActions;
|
||||
}
|
||||
|
||||
public Object getParent() {
|
||||
return parent;
|
||||
}
|
||||
|
||||
public void setParent(Object parent) {
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
public boolean isInitial() {
|
||||
return initial;
|
||||
}
|
||||
|
||||
public void setInitial(boolean initial) {
|
||||
this.initial = initial;
|
||||
}
|
||||
|
||||
public boolean isEnd() {
|
||||
return end;
|
||||
}
|
||||
|
||||
public void setEnd(boolean end) {
|
||||
this.end = end;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "StateData [parent=" + parent + ", state=" + state + ", deferred=" + deferred + ", entryActions="
|
||||
+ entryActions + ", exitActions=" + exitActions + "]";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -15,19 +15,15 @@
|
||||
*/
|
||||
package org.springframework.statemachine.config.builders;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.statemachine.config.builders.StateMachineStates.StateData;
|
||||
import org.springframework.statemachine.config.builders.StateMachineStates.StateMachineStatesData;
|
||||
import org.springframework.statemachine.config.StateData;
|
||||
import org.springframework.statemachine.config.common.annotation.AbstractConfiguredAnnotationBuilder;
|
||||
import org.springframework.statemachine.config.common.annotation.AnnotationBuilder;
|
||||
import org.springframework.statemachine.config.common.annotation.ObjectPostProcessor;
|
||||
import org.springframework.statemachine.config.configurers.DefaultStateConfigurer;
|
||||
import org.springframework.statemachine.config.configurers.DefaultSubStateConfigurer;
|
||||
import org.springframework.statemachine.config.configurers.StateConfigurer;
|
||||
import org.springframework.statemachine.config.configurers.SubStateConfigurer;
|
||||
|
||||
/**
|
||||
* {@link AnnotationBuilder} for {@link StateMachineStates}.
|
||||
@@ -41,7 +37,7 @@ public class StateMachineStateBuilder<S, E>
|
||||
extends AbstractConfiguredAnnotationBuilder<StateMachineStates<S, E>, StateMachineStateConfigurer<S, E>, StateMachineStateBuilder<S, E>>
|
||||
implements StateMachineStateConfigurer<S, E> {
|
||||
|
||||
private final Map<Object, StateMachineStatesData<S, E>> data = new HashMap<Object, StateMachineStatesData<S,E>>();
|
||||
private final Collection<StateData<S, E>> stateDatas = new ArrayList<StateData<S,E>>();
|
||||
|
||||
public StateMachineStateBuilder() {
|
||||
super();
|
||||
@@ -58,26 +54,16 @@ public class StateMachineStateBuilder<S, E>
|
||||
|
||||
@Override
|
||||
protected StateMachineStates<S, E> performBuild() throws Exception {
|
||||
return new StateMachineStates<S, E>(data);
|
||||
return new StateMachineStates<S, E>(stateDatas);
|
||||
}
|
||||
|
||||
@Override
|
||||
public StateConfigurer<S, E> withStates() throws Exception {
|
||||
return apply(new DefaultStateConfigurer<S, E>(null, null));
|
||||
return apply(new DefaultStateConfigurer<S, E>());
|
||||
}
|
||||
|
||||
@Override
|
||||
public StateConfigurer<S, E> withStates(Object parent) throws Exception {
|
||||
return apply(new DefaultStateConfigurer<S, E>(null, parent));
|
||||
}
|
||||
|
||||
@Override
|
||||
public SubStateConfigurer<S, E> withSubStates(S state, Object parent) throws Exception {
|
||||
return apply(new DefaultSubStateConfigurer<S, E>(state, state, parent));
|
||||
}
|
||||
|
||||
public void add(Object id, Object parent, Collection<StateData<S, E>> states, S initialState, S endState) {
|
||||
data.put(id, new StateMachineStatesData<S, E>(states, initialState, endState, parent));
|
||||
public void addStateData(Collection<StateData<S, E>> stateDatas) {
|
||||
this.stateDatas.addAll(stateDatas);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -16,14 +16,9 @@
|
||||
package org.springframework.statemachine.config.builders;
|
||||
|
||||
import org.springframework.statemachine.config.configurers.StateConfigurer;
|
||||
import org.springframework.statemachine.config.configurers.SubStateConfigurer;
|
||||
|
||||
public interface StateMachineStateConfigurer<S, E> {
|
||||
|
||||
StateConfigurer<S, E> withStates() throws Exception;
|
||||
|
||||
StateConfigurer<S, E> withStates(Object parent) throws Exception;
|
||||
|
||||
SubStateConfigurer<S, E> withSubStates(S state, Object parent) throws Exception;
|
||||
|
||||
}
|
||||
|
||||
@@ -15,100 +15,29 @@
|
||||
*/
|
||||
package org.springframework.statemachine.config.builders;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.statemachine.action.Action;
|
||||
import org.springframework.statemachine.config.StateData;
|
||||
import org.springframework.statemachine.config.configurers.StateConfigurer;
|
||||
|
||||
/**
|
||||
* Data object used return and build data from a {@link StateConfigurer}.
|
||||
*
|
||||
* @author Janne Valkealahti
|
||||
*
|
||||
* @param <S> the type of state
|
||||
* @param <E> the type of event
|
||||
*/
|
||||
public class StateMachineStates<S, E> {
|
||||
|
||||
private final Map<Object, StateMachineStatesData<S, E>> states;
|
||||
private final Collection<StateData<S, E>> stateDatas;
|
||||
|
||||
public StateMachineStates(Map<Object, StateMachineStatesData<S, E>> states) {
|
||||
this.states = states;
|
||||
public StateMachineStates(Collection<StateData<S, E>> stateDatas) {
|
||||
this.stateDatas = stateDatas;
|
||||
}
|
||||
|
||||
public Map<Object, StateMachineStatesData<S, E>> getStates() {
|
||||
return states;
|
||||
}
|
||||
|
||||
public static class StateMachineStatesData<S, E> {
|
||||
private Collection<StateData<S, E>> states;
|
||||
|
||||
private final S initialState;
|
||||
|
||||
private final S endState;
|
||||
|
||||
private final Object parent;
|
||||
|
||||
public StateMachineStatesData(Collection<StateData<S, E>> states, S initialState, S endState, Object parent) {
|
||||
this.states = states;
|
||||
this.initialState = initialState;
|
||||
this.endState = endState;
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
public Collection<StateData<S, E>> getStates() {
|
||||
return states;
|
||||
}
|
||||
|
||||
public S getInitialState() {
|
||||
return initialState;
|
||||
}
|
||||
|
||||
public S getEndState() {
|
||||
return endState;
|
||||
}
|
||||
|
||||
public Object getParent() {
|
||||
return parent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "StateMachineStatesData [states=" + states + ", initialState=" + initialState + ", endState="
|
||||
+ endState + ", parent=" + parent + "]";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class StateData<S, E> {
|
||||
private S state;
|
||||
private Collection<E> deferred;
|
||||
private Collection<? extends Action<S, E>> entryActions;
|
||||
private Collection<? extends Action<S, E>> exitActions;
|
||||
public StateData(S state, Collection<E> deferred) {
|
||||
this(state, deferred, null, null);
|
||||
}
|
||||
public StateData(S state, Collection<E> deferred, Collection<? extends Action<S, E>> entryActions, Collection<? extends Action<S, E>> exitActions) {
|
||||
this.state = state;
|
||||
this.deferred = deferred;
|
||||
this.entryActions = entryActions;
|
||||
this.exitActions = exitActions;
|
||||
}
|
||||
public StateData(S state, E[] deferred) {
|
||||
this(state, deferred != null ? Arrays.asList(deferred) : new ArrayList<E>());
|
||||
}
|
||||
public S getState() {
|
||||
return state;
|
||||
}
|
||||
public Collection<E> getDeferred() {
|
||||
return deferred;
|
||||
}
|
||||
public Collection<? extends Action<S, E>> getEntryActions() {
|
||||
return entryActions;
|
||||
}
|
||||
public Collection<? extends Action<S, E>> getExitActions() {
|
||||
return exitActions;
|
||||
}
|
||||
@Override
|
||||
public String toString() {
|
||||
return "StateData [state=" + state + ", deferred=" + deferred + ", entryActions=" + entryActions
|
||||
+ ", exitActions=" + exitActions + "]";
|
||||
}
|
||||
|
||||
public Collection<StateData<S, E>> getStateDatas() {
|
||||
return stateDatas;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -16,38 +16,45 @@
|
||||
package org.springframework.statemachine.config.configurers;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.statemachine.action.Action;
|
||||
import org.springframework.statemachine.config.StateData;
|
||||
import org.springframework.statemachine.config.builders.StateMachineStateBuilder;
|
||||
import org.springframework.statemachine.config.builders.StateMachineStateConfigurer;
|
||||
import org.springframework.statemachine.config.builders.StateMachineStates;
|
||||
import org.springframework.statemachine.config.builders.StateMachineStates.StateData;
|
||||
import org.springframework.statemachine.config.common.annotation.AnnotationConfigurerAdapter;
|
||||
|
||||
public class DefaultStateConfigurer<S, E>
|
||||
extends AnnotationConfigurerAdapter<StateMachineStates<S, E>, StateMachineStateConfigurer<S, E>, StateMachineStateBuilder<S, E>>
|
||||
implements StateConfigurer<S, E> {
|
||||
|
||||
private final Object id;
|
||||
private Object parent;
|
||||
|
||||
private final Object parent;
|
||||
|
||||
private final Collection<StateData<S, E>> states = new ArrayList<StateData<S, E>>();
|
||||
private final Collection<StateData<S, E>> incomplete = new ArrayList<StateData<S, E>>();
|
||||
|
||||
private S initial;
|
||||
|
||||
private S end;
|
||||
|
||||
public DefaultStateConfigurer(Object id, Object parent) {
|
||||
this.id = id;
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(StateMachineStateBuilder<S, E> builder) throws Exception {
|
||||
builder.add(id, parent, states, initial, end);
|
||||
// before passing state datas to builder, update structure
|
||||
// for missing parent, initial and end state infos.
|
||||
Collection<StateData<S, E>> stateDatas = new ArrayList<StateData<S, E>>();
|
||||
for (StateData<S, E> s : incomplete) {
|
||||
s.setParent(parent);
|
||||
stateDatas.add(s);
|
||||
if (s.getState() == initial) {
|
||||
s.setInitial(true);
|
||||
}
|
||||
if (s.getState() == end) {
|
||||
s.setEnd(true);
|
||||
}
|
||||
}
|
||||
builder.addStateData(stateDatas);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -56,6 +63,12 @@ public class DefaultStateConfigurer<S, E>
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StateConfigurer<S, E> parent(S state) {
|
||||
this.parent = state;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StateConfigurer<S, E> end(S end) {
|
||||
this.end = end;
|
||||
@@ -70,13 +83,17 @@ public class DefaultStateConfigurer<S, E>
|
||||
@Override
|
||||
public StateConfigurer<S, E> state(S state, Collection<? extends Action<S, E>> entryActions,
|
||||
Collection<? extends Action<S, E>> exitActions) {
|
||||
states.add(new StateData<S, E>(state, null, entryActions, exitActions));
|
||||
addIncomplete(null, state, null, entryActions, exitActions);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StateConfigurer<S, E> state(S state, E... deferred) {
|
||||
states.add(new StateData<S, E>(state, deferred));
|
||||
Collection<E> d = null;
|
||||
if (deferred != null) {
|
||||
d = Arrays.asList(deferred);
|
||||
}
|
||||
addIncomplete(null, state, d, null, null);
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -88,4 +105,9 @@ public class DefaultStateConfigurer<S, E>
|
||||
return this;
|
||||
}
|
||||
|
||||
private void addIncomplete(Object parent, S state, Collection<E> deferred,
|
||||
Collection<? extends Action<S, E>> entryActions, Collection<? extends Action<S, E>> exitActions) {
|
||||
incomplete.add(new StateData<S, E>(parent, state, deferred, entryActions, exitActions));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,76 +0,0 @@
|
||||
/*
|
||||
* 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.config.configurers;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.springframework.statemachine.action.Action;
|
||||
import org.springframework.statemachine.config.builders.StateMachineStateBuilder;
|
||||
import org.springframework.statemachine.config.builders.StateMachineStateConfigurer;
|
||||
import org.springframework.statemachine.config.builders.StateMachineStates;
|
||||
import org.springframework.statemachine.config.builders.StateMachineStates.StateData;
|
||||
import org.springframework.statemachine.config.common.annotation.AnnotationConfigurerAdapter;
|
||||
|
||||
public class DefaultSubStateConfigurer<S, E>
|
||||
extends AnnotationConfigurerAdapter<StateMachineStates<S, E>, StateMachineStateConfigurer<S, E>, StateMachineStateBuilder<S, E>>
|
||||
implements SubStateConfigurer<S, E> {
|
||||
|
||||
private S state;
|
||||
private final Object id;
|
||||
private final Object parent;
|
||||
|
||||
private S initial;
|
||||
private Collection<? extends Action<S, E>> entryActions;
|
||||
private Collection<? extends Action<S, E>> exitActions;
|
||||
|
||||
private final Collection<StateData<S, E>> states = new ArrayList<StateData<S, E>>();
|
||||
|
||||
public DefaultSubStateConfigurer(S state, Object id) {
|
||||
this(state, id, null);
|
||||
}
|
||||
|
||||
public DefaultSubStateConfigurer(S state, Object id, Object parent) {
|
||||
this.state = state;
|
||||
this.id = id;
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(StateMachineStateBuilder<S, E> builder) throws Exception {
|
||||
states.add(new StateData<S, E>(state, null, entryActions, exitActions));
|
||||
builder.add(id, parent, states, initial, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SubStateConfigurer<S, E> initial(S initial) {
|
||||
this.initial = initial;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SubStateConfigurer<S, E> entry(Collection<? extends Action<S, E>> entryActions) {
|
||||
this.entryActions = entryActions;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SubStateConfigurer<S, E> exit(Collection<? extends Action<S, E>> exitActions) {
|
||||
this.exitActions = exitActions;
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -27,6 +27,8 @@ public interface StateConfigurer<S, E> extends
|
||||
|
||||
StateConfigurer<S, E> initial(S initial);
|
||||
|
||||
StateConfigurer<S, E> parent(S state);
|
||||
|
||||
StateConfigurer<S, E> state(S state);
|
||||
|
||||
StateConfigurer<S, E> state(S state, Collection<? extends Action<S, E>> entryActions,
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
/*
|
||||
* 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.config.configurers;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.springframework.statemachine.action.Action;
|
||||
import org.springframework.statemachine.config.builders.StateMachineStateConfigurer;
|
||||
import org.springframework.statemachine.config.common.annotation.AnnotationConfigurerBuilder;
|
||||
|
||||
public interface SubStateConfigurer<S, E> extends
|
||||
AnnotationConfigurerBuilder<StateMachineStateConfigurer<S, E>> {
|
||||
|
||||
SubStateConfigurer<S, E> initial(S initial);
|
||||
|
||||
SubStateConfigurer<S, E> entry(Collection<? extends Action<S, E>> entryActions);
|
||||
|
||||
SubStateConfigurer<S, E> exit(Collection<? extends Action<S, E>> exitActions);
|
||||
|
||||
}
|
||||
@@ -23,6 +23,8 @@ import java.util.Map;
|
||||
|
||||
/**
|
||||
* Utility class which can be used to represent a tree based data structure.
|
||||
* This tree utility is not very generic and needs to be used as it's meant to
|
||||
* be.
|
||||
*
|
||||
* @author Janne Valkealahti
|
||||
*
|
||||
@@ -30,13 +32,10 @@ import java.util.Map;
|
||||
*/
|
||||
public class Tree<T> {
|
||||
|
||||
private Node<T> root;
|
||||
private final Node<T> root = new Node<T>(null);
|
||||
private final Map<Object, Node<T>> map = new HashMap<Object, Node<T>>();
|
||||
private final List<DataWrap<T>> notMapped = new ArrayList<DataWrap<T>>();
|
||||
|
||||
public Tree() {
|
||||
}
|
||||
|
||||
public Node<T> getRoot() {
|
||||
return root;
|
||||
}
|
||||
@@ -54,7 +53,7 @@ public class Tree<T> {
|
||||
if (next.parent == null) {
|
||||
Node<T> n = new Node<T>(next.data);
|
||||
map.put(next.id, n);
|
||||
root = n;
|
||||
root.getChildren().add(n);
|
||||
iter.remove();
|
||||
} else {
|
||||
if (map.containsKey(next.parent)) {
|
||||
|
||||
@@ -62,8 +62,9 @@ public abstract class AbstractStateMachineTests {
|
||||
|
||||
public enum TestStates {
|
||||
SI,S1,S2,S3,S4,SF,
|
||||
S11,S111,S112,S12,S121,S122,
|
||||
S21,S211
|
||||
S10,S11,S101,S111,S112,S12,S121,S122,
|
||||
S20,S21,S201,S211,
|
||||
S1011,S1012,S2011,S2012
|
||||
}
|
||||
|
||||
public enum TestEvents {
|
||||
|
||||
@@ -380,19 +380,19 @@ public class SubStateMachineTests extends AbstractStateMachineTests {
|
||||
@Override
|
||||
public void configure(StateMachineStateConfigurer<TestStates, TestEvents> states) throws Exception {
|
||||
states
|
||||
.withSubStates(TestStates.S1, null)
|
||||
// .initial(TestStates.S11)
|
||||
.entry(Arrays.asList(entryActionS1()))
|
||||
.exit(Arrays.asList(exitActionS1()))
|
||||
.withStates()
|
||||
.initial(TestStates.S1)
|
||||
.state(TestStates.S1, Arrays.asList(entryActionS1()), Arrays.asList(exitActionS1()))
|
||||
.and()
|
||||
.withSubStates(TestStates.S11, TestStates.S1)
|
||||
// .initial(TestStates.S111)
|
||||
.entry(Arrays.asList(entryActionS11()))
|
||||
.exit(Arrays.asList(exitActionS11()))
|
||||
.and()
|
||||
.withStates(TestStates.S11)
|
||||
.initial(TestStates.S111)
|
||||
.state(TestStates.S111, Arrays.asList(entryActionS111()), Arrays.asList(exitActionS111()));
|
||||
.withStates()
|
||||
.parent(TestStates.S1)
|
||||
.initial(TestStates.S11)
|
||||
.state(TestStates.S11, Arrays.asList(entryActionS11()), Arrays.asList(exitActionS11()))
|
||||
.and()
|
||||
.withStates()
|
||||
.parent(TestStates.S11)
|
||||
.initial(TestStates.S111)
|
||||
.state(TestStates.S111, Arrays.asList(entryActionS111()), Arrays.asList(exitActionS111()));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -170,13 +170,17 @@ public class ConfigurationTests extends AbstractStateMachineTests {
|
||||
@Override
|
||||
public void configure(StateMachineStateConfigurer<TestStates, TestEvents> states) throws Exception {
|
||||
states
|
||||
.withSubStates(TestStates.S1, null)
|
||||
.withStates()
|
||||
.initial(TestStates.S1)
|
||||
.state(TestStates.S1)
|
||||
.and()
|
||||
.withStates(TestStates.S1)
|
||||
.initial(TestStates.S1)
|
||||
.end(TestStates.SF)
|
||||
.states(EnumSet.allOf(TestStates.class));
|
||||
.withStates()
|
||||
.parent(TestStates.S1)
|
||||
.initial(TestStates.S2)
|
||||
.end(TestStates.SF)
|
||||
.state(TestStates.SI)
|
||||
.state(TestStates.S2)
|
||||
.state(TestStates.S3);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -212,13 +216,14 @@ public class ConfigurationTests extends AbstractStateMachineTests {
|
||||
Collection<Action<TestStates, TestEvents>> actions3 = new ArrayList<Action<TestStates,TestEvents>>();
|
||||
actions3.add(action3());
|
||||
states
|
||||
.withSubStates(TestStates.S11, null)
|
||||
.entry(actions1)
|
||||
.exit(Arrays.asList(action2()))
|
||||
.withStates()
|
||||
.initial(TestStates.S11)
|
||||
.state(TestStates.S11, actions1, Arrays.asList(action2()))
|
||||
.and()
|
||||
.withStates(TestStates.S11)
|
||||
.initial(TestStates.S111)
|
||||
.state(TestStates.S111, actions3, Arrays.asList(action4()));
|
||||
.withStates()
|
||||
.parent(TestStates.S11)
|
||||
.initial(TestStates.S111)
|
||||
.state(TestStates.S111, actions3, Arrays.asList(action4()));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -247,5 +252,104 @@ public class ConfigurationTests extends AbstractStateMachineTests {
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
// +-----------------------------------------------------------------------------------------------------------------+
|
||||
// | SM |
|
||||
// +-----------------------------------------------------------------------------------------------------------------+
|
||||
// | | |
|
||||
// | +---------------------------------------+ | +---------------------------------------+ |
|
||||
// | *-->| S10 | | *-->| S20 | |
|
||||
// | +---------------------------------------+ | +---------------------------------------+ |
|
||||
// | | entry/ | | | entry/ | |
|
||||
// | | exit/ | | | exit/ | |
|
||||
// | | +--------------------------+ | | | +--------------------------+ | |
|
||||
// | | *-->| S101 | | | | *-->| S201 | | |
|
||||
// | | +--------------------------+ | | | +--------------------------+ | |
|
||||
// | | | entry/ | | | | | entry/ | | |
|
||||
// | | | exit/ | | | | | exit/ | | |
|
||||
// | | | +-----------+ | | | | | +-----------+ | | |
|
||||
// | | | *-->| S1011 | | | | | | *-->| S2011 | | | |
|
||||
// | | | +-----------+ | | | | | +-----------+ | | |
|
||||
// | | | | entry/ | | | | | | | entry/ | | | |
|
||||
// | | | | exit/ | | | | | | | exit/ | | | |
|
||||
// | | | | | | | | | | | | | | |
|
||||
// | | | +-----------+ | | | | | +-----------+ | | |
|
||||
// | | | | | | | | | | |
|
||||
// | | | | | | | | | | |
|
||||
// | | | | | | | | | | |
|
||||
// | | | +-----------+ | | | | | +-----------+ | | |
|
||||
// | | | | S1012 | | | | | | | S2012 | | | |
|
||||
// | | | +-----------+ | | | | | +-----------+ | | |
|
||||
// | | | | entry/ | | | | | | | entry/ | | | |
|
||||
// | | | | exit/ | | | | | | | exit/ | | | |
|
||||
// | | | | | | | | | | | | | | |
|
||||
// | | | +-----------+ | | | | | +-----------+ | | |
|
||||
// | | | | | | | | | | |
|
||||
// | | +--------------------------+ | | | +--------------------------+ | |
|
||||
// | | | | | | |
|
||||
// | | | | | | |
|
||||
// | +---------------------------------------+ | +---------------------------------------+ |
|
||||
// | | |
|
||||
// | +---------------------------------------+ | +---------------------------------------+ |
|
||||
// | | S11 | | | S21 | |
|
||||
// | +---------------------------------------+ | +---------------------------------------+ |
|
||||
// | | entry/ | | | entry/ | |
|
||||
// | | exit/ | | | exit/ | |
|
||||
// | | | | | | |
|
||||
// | +---------------------------------------+ | +---------------------------------------+ |
|
||||
// | | |
|
||||
// +--------------------------------------------------------+--------------------------------------------------------+
|
||||
*/
|
||||
|
||||
@Configuration
|
||||
@EnableStateMachine
|
||||
static class Config6 extends EnumStateMachineConfigurerAdapter<TestStates, TestEvents> {
|
||||
|
||||
@Override
|
||||
public void configure(StateMachineStateConfigurer<TestStates, TestEvents> states) throws Exception {
|
||||
states
|
||||
.withStates()
|
||||
.initial(TestStates.S10)
|
||||
.state(TestStates.S10)
|
||||
.state(TestStates.S11)
|
||||
.and()
|
||||
.withStates()
|
||||
.parent(TestStates.S10)
|
||||
.initial(TestStates.S101)
|
||||
.state(TestStates.S101)
|
||||
.and()
|
||||
.withStates()
|
||||
.parent(TestStates.S101)
|
||||
.initial(TestStates.S1011)
|
||||
.state(TestStates.S1011)
|
||||
.state(TestStates.S1012)
|
||||
.and()
|
||||
.withStates()
|
||||
.initial(TestStates.S20)
|
||||
.state(TestStates.S20)
|
||||
.state(TestStates.S21)
|
||||
.and()
|
||||
.withStates()
|
||||
.parent(TestStates.S20)
|
||||
.initial(TestStates.S201)
|
||||
.state(TestStates.S201)
|
||||
.and()
|
||||
.withStates()
|
||||
.parent(TestStates.S201)
|
||||
.initial(TestStates.S2011)
|
||||
.state(TestStates.S2011)
|
||||
.state(TestStates.S2012);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(StateMachineTransitionConfigurer<TestStates, TestEvents> transitions) throws Exception {
|
||||
transitions
|
||||
.withExternal()
|
||||
.source(TestStates.S111)
|
||||
.target(TestStates.S1)
|
||||
.event(TestEvents.E1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -66,4 +66,22 @@ public class TreeTests {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTree3() {
|
||||
Tree<String> tree = new Tree<String>();
|
||||
tree.add("S1", "S1", null);
|
||||
tree.add("S2", "S2", null);
|
||||
|
||||
TreeTraverser<Node<String>> traverser = new TreeTraverser<Node<String>>() {
|
||||
@Override
|
||||
public Iterable<Node<String>> children(Node<String> root) {
|
||||
return root.getChildren();
|
||||
}
|
||||
};
|
||||
|
||||
for (Node<String> node : traverser.postOrderTraversal(tree.getRoot())) {
|
||||
System.out.println(node.getData());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user