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:
Janne Valkealahti
2015-02-21 15:48:07 +00:00
parent a98e50247d
commit e6677f19c5
14 changed files with 368 additions and 311 deletions

View File

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

View File

@@ -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 + "]";
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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