Add base support for exit/entry points
- New concepts of using exit and entry points to transition between sub-states. - Add hooks to annotation config model. - Relates to #192
This commit is contained in:
@@ -38,6 +38,8 @@ 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.EntryData;
|
||||
import org.springframework.statemachine.config.model.ExitData;
|
||||
import org.springframework.statemachine.config.model.StateData;
|
||||
import org.springframework.statemachine.config.model.StateMachineModel;
|
||||
import org.springframework.statemachine.config.model.TransitionData;
|
||||
@@ -52,6 +54,8 @@ 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;
|
||||
@@ -59,6 +63,7 @@ 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.support.DefaultExtendedState;
|
||||
import org.springframework.statemachine.support.LifecycleObjectSupport;
|
||||
@@ -141,6 +146,7 @@ public abstract class AbstractStateMachineFactory<S, E> extends LifecycleObjectS
|
||||
Stack<MachineStackItem<S, E>> regionStack = new Stack<MachineStackItem<S, E>>();
|
||||
Stack<StateData<S, E>> stateStack = new Stack<StateData<S, E>>();
|
||||
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();
|
||||
while (iterator.hasNext()) {
|
||||
@@ -176,7 +182,7 @@ public abstract class AbstractStateMachineFactory<S, E> extends LifecycleObjectS
|
||||
|
||||
if (initialCount > 1) {
|
||||
for (Collection<StateData<S, E>> regionStateDatas : regionsStateDatas) {
|
||||
machine = buildMachine(machineMap, stateMap, regionStateDatas, transitionsData, resolveBeanFactory(),
|
||||
machine = buildMachine(machineMap, stateMap, holderMap, regionStateDatas, transitionsData, resolveBeanFactory(),
|
||||
contextEvents, defaultExtendedState, stateMachineModel.getTransitionsData(), resolveTaskExecutor(),
|
||||
resolveTaskScheduler(), machineId);
|
||||
regionStack.push(new MachineStackItem<S, E>(machine));
|
||||
@@ -204,7 +210,7 @@ public abstract class AbstractStateMachineFactory<S, E> extends LifecycleObjectS
|
||||
machine = m;
|
||||
}
|
||||
} else {
|
||||
machine = buildMachine(machineMap, stateMap, stateDatas, transitionsData, resolveBeanFactory(), contextEvents,
|
||||
machine = buildMachine(machineMap, stateMap, holderMap, stateDatas, transitionsData, resolveBeanFactory(), contextEvents,
|
||||
defaultExtendedState, stateMachineModel.getTransitionsData(), resolveTaskExecutor(), resolveTaskScheduler(),
|
||||
machineId);
|
||||
if (peek.isInitial() || (!peek.isInitial() && !machineMap.containsKey(peek.getParent()))) {
|
||||
@@ -261,6 +267,12 @@ public abstract class AbstractStateMachineFactory<S, E> extends LifecycleObjectS
|
||||
machine.addStateListener(listener);
|
||||
}
|
||||
|
||||
// go through holders and fix state references which
|
||||
// were not known at a time holder was created
|
||||
for (Entry<S, StateHolder<S, E>> holder : holderMap.entrySet()) {
|
||||
holder.getValue().setState(stateMap.get(holder.getKey()));
|
||||
}
|
||||
|
||||
return delegateAutoStartup(machine);
|
||||
}
|
||||
|
||||
@@ -397,12 +409,10 @@ public abstract class AbstractStateMachineFactory<S, E> extends LifecycleObjectS
|
||||
}
|
||||
|
||||
|
||||
private StateMachine<S, E> buildMachine(
|
||||
Map<Object, StateMachine<S, E>> machineMap, Map<S, State<S, E>> stateMap,
|
||||
Collection<StateData<S, E>> stateDatas, Collection<TransitionData<S, E>> transitionsData,
|
||||
private StateMachine<S, E> buildMachine(Map<Object, StateMachine<S, E>> machineMap, Map<S, State<S, E>> stateMap,
|
||||
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) {
|
||||
TransitionsData<S, E> stateMachineTransitions, TaskExecutor taskExecutor, TaskScheduler taskScheduler, String machineId) {
|
||||
State<S, E> state = null;
|
||||
State<S, E> initialState = null;
|
||||
PseudoState<S, E> historyState = null;
|
||||
@@ -456,6 +466,10 @@ public abstract class AbstractStateMachineFactory<S, E> extends LifecycleObjectS
|
||||
continue;
|
||||
} else if (stateData.getPseudoStateKind() == PseudoStateKind.CHOICE) {
|
||||
continue;
|
||||
} else if (stateData.getPseudoStateKind() == PseudoStateKind.ENTRY) {
|
||||
continue;
|
||||
} else if (stateData.getPseudoStateKind() == PseudoStateKind.EXIT) {
|
||||
continue;
|
||||
}
|
||||
state = buildStateInternal(stateData.getState(), stateData.getDeferred(), stateData.getEntryActions(),
|
||||
stateData.getExitActions(), pseudoState);
|
||||
@@ -482,6 +496,36 @@ public abstract class AbstractStateMachineFactory<S, E> extends LifecycleObjectS
|
||||
stateData.getExitActions(), pseudoState);
|
||||
states.add(state);
|
||||
stateMap.put(stateData.getState(), state);
|
||||
} else if (stateData.getPseudoStateKind() == PseudoStateKind.ENTRY) {
|
||||
S s = stateData.getState();
|
||||
Collection<EntryData<S, E>> entrys = stateMachineTransitions.getEntrys();
|
||||
for (EntryData<S, E> entry : entrys) {
|
||||
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(), pseudoState);
|
||||
states.add(state);
|
||||
stateMap.put(stateData.getState(), state);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (stateData.getPseudoStateKind() == PseudoStateKind.EXIT) {
|
||||
S s = stateData.getState();
|
||||
Collection<ExitData<S, E>> exits = stateMachineTransitions.getExits();
|
||||
for (ExitData<S, E> entry : exits) {
|
||||
if (s.equals(entry.getSource())) {
|
||||
StateHolder<S, E> holder = new StateHolder<S, E>(stateMap.get(entry.getTarget()));
|
||||
if (holder.getState() == null) {
|
||||
holderMap.put(entry.getTarget(), holder);
|
||||
}
|
||||
PseudoState<S, E> pseudoState = new ExitPseudoState<S, E>(holder);
|
||||
state = buildStateInternal(stateData.getState(), stateData.getDeferred(), stateData.getEntryActions(),
|
||||
stateData.getExitActions(), pseudoState);
|
||||
states.add(state);
|
||||
stateMap.put(stateData.getState(), state);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (stateData.getPseudoStateKind() == PseudoStateKind.FORK) {
|
||||
S s = stateData.getState();
|
||||
List<S> list = stateMachineTransitions.getForks().get(s);
|
||||
|
||||
@@ -27,11 +27,15 @@ import org.springframework.statemachine.config.common.annotation.AnnotationBuild
|
||||
import org.springframework.statemachine.config.common.annotation.ObjectPostProcessor;
|
||||
import org.springframework.statemachine.config.configurers.ChoiceTransitionConfigurer;
|
||||
import org.springframework.statemachine.config.configurers.DefaultChoiceTransitionConfigurer;
|
||||
import org.springframework.statemachine.config.configurers.DefaultEntryTransitionConfigurer;
|
||||
import org.springframework.statemachine.config.configurers.DefaultExitTransitionConfigurer;
|
||||
import org.springframework.statemachine.config.configurers.DefaultExternalTransitionConfigurer;
|
||||
import org.springframework.statemachine.config.configurers.DefaultForkTransitionConfigurer;
|
||||
import org.springframework.statemachine.config.configurers.DefaultInternalTransitionConfigurer;
|
||||
import org.springframework.statemachine.config.configurers.DefaultJoinTransitionConfigurer;
|
||||
import org.springframework.statemachine.config.configurers.DefaultLocalTransitionConfigurer;
|
||||
import org.springframework.statemachine.config.configurers.EntryTransitionConfigurer;
|
||||
import org.springframework.statemachine.config.configurers.ExitTransitionConfigurer;
|
||||
import org.springframework.statemachine.config.configurers.ExternalTransitionConfigurer;
|
||||
import org.springframework.statemachine.config.configurers.ForkTransitionConfigurer;
|
||||
import org.springframework.statemachine.config.configurers.InternalTransitionConfigurer;
|
||||
@@ -39,6 +43,8 @@ import org.springframework.statemachine.config.configurers.JoinTransitionConfigu
|
||||
import org.springframework.statemachine.config.configurers.LocalTransitionConfigurer;
|
||||
import org.springframework.statemachine.config.model.ChoiceData;
|
||||
import org.springframework.statemachine.config.model.ConfigurationData;
|
||||
import org.springframework.statemachine.config.model.EntryData;
|
||||
import org.springframework.statemachine.config.model.ExitData;
|
||||
import org.springframework.statemachine.config.model.TransitionsData;
|
||||
import org.springframework.statemachine.config.model.TransitionData;
|
||||
import org.springframework.statemachine.guard.Guard;
|
||||
@@ -62,23 +68,39 @@ public class StateMachineTransitionBuilder<S, E>
|
||||
private final Map<S, List<ChoiceData<S, E>>> choices = new HashMap<S, List<ChoiceData<S, E>>>();
|
||||
private final Map<S, List<S>> forks = new HashMap<S, List<S>>();
|
||||
private final Map<S, List<S>> joins = new HashMap<S, List<S>>();
|
||||
private final Collection<EntryData<S, E>> entryData = new ArrayList<EntryData<S, E>>();
|
||||
private final Collection<ExitData<S, E>> exitData = new ArrayList<ExitData<S, E>>();
|
||||
|
||||
/**
|
||||
* Instantiates a new state machine transition builder.
|
||||
*/
|
||||
public StateMachineTransitionBuilder() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new state machine transition builder.
|
||||
*
|
||||
* @param objectPostProcessor the object post processor
|
||||
* @param allowConfigurersOfSameType the allow configurers of same type
|
||||
*/
|
||||
public StateMachineTransitionBuilder(ObjectPostProcessor<Object> objectPostProcessor,
|
||||
boolean allowConfigurersOfSameType) {
|
||||
super(objectPostProcessor, allowConfigurersOfSameType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new state machine transition builder.
|
||||
*
|
||||
* @param objectPostProcessor the object post processor
|
||||
*/
|
||||
public StateMachineTransitionBuilder(ObjectPostProcessor<Object> objectPostProcessor) {
|
||||
super(objectPostProcessor);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TransitionsData<S, E> performBuild() throws Exception {
|
||||
return new TransitionsData<S, E>(transitionData, choices, forks, joins);
|
||||
return new TransitionsData<S, E>(transitionData, choices, forks, joins, entryData, exitData);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -111,7 +133,31 @@ public class StateMachineTransitionBuilder<S, E>
|
||||
return apply(new DefaultJoinTransitionConfigurer<S, E>());
|
||||
}
|
||||
|
||||
public void add(S source, S target, S state, E event, Long period, Integer count, Collection<Action<S, E>> actions,
|
||||
@Override
|
||||
public EntryTransitionConfigurer<S, E> withEntry() throws Exception {
|
||||
return apply(new DefaultEntryTransitionConfigurer<S, E>());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExitTransitionConfigurer<S, E> withExit() throws Exception {
|
||||
return apply(new DefaultExitTransitionConfigurer<S, E>());
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the transition.
|
||||
*
|
||||
* @param source the source
|
||||
* @param target the target
|
||||
* @param state the state
|
||||
* @param event the event
|
||||
* @param period the period
|
||||
* @param count the count
|
||||
* @param actions the actions
|
||||
* @param guard the guard
|
||||
* @param kind the kind
|
||||
* @param securityRule the security rule
|
||||
*/
|
||||
public void addTransition(S source, S target, S state, E event, Long period, Integer count, Collection<Action<S, E>> actions,
|
||||
Guard<S, E> guard, TransitionKind kind, SecurityRule securityRule) {
|
||||
// if rule not given, get it from global
|
||||
if (securityRule == null) {
|
||||
@@ -122,16 +168,53 @@ public class StateMachineTransitionBuilder<S, E>
|
||||
transitionData.add(new TransitionData<S, E>(source, target, state, event, period, count, actions, guard, kind, securityRule));
|
||||
}
|
||||
|
||||
public void add(S source, List<ChoiceData<S, E>> choices) {
|
||||
/**
|
||||
* Adds the choice.
|
||||
*
|
||||
* @param source the source
|
||||
* @param choices the choices
|
||||
*/
|
||||
public void addChoice(S source, List<ChoiceData<S, E>> choices) {
|
||||
this.choices.put(source, choices);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the entry.
|
||||
*
|
||||
* @param source the source
|
||||
* @param target the target
|
||||
*/
|
||||
public void addEntry(S source, S target) {
|
||||
this.entryData.add(new EntryData<S, E>(source, target));
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the exit.
|
||||
*
|
||||
* @param source the source
|
||||
* @param target the target
|
||||
*/
|
||||
public void addExit(S source, S target) {
|
||||
this.exitData.add(new ExitData<S, E>(source, target));
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the fork.
|
||||
*
|
||||
* @param source the source
|
||||
* @param targets the targets
|
||||
*/
|
||||
public void addFork(S source, List<S> targets) {
|
||||
this.forks.put(source, targets);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the join.
|
||||
*
|
||||
* @param target the target
|
||||
* @param sources the sources
|
||||
*/
|
||||
public void addJoin(S target, List<S> sources) {
|
||||
this.joins.put(target, sources);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
package org.springframework.statemachine.config.builders;
|
||||
|
||||
import org.springframework.statemachine.config.configurers.ChoiceTransitionConfigurer;
|
||||
import org.springframework.statemachine.config.configurers.EntryTransitionConfigurer;
|
||||
import org.springframework.statemachine.config.configurers.ExitTransitionConfigurer;
|
||||
import org.springframework.statemachine.config.configurers.ExternalTransitionConfigurer;
|
||||
import org.springframework.statemachine.config.configurers.ForkTransitionConfigurer;
|
||||
import org.springframework.statemachine.config.configurers.InternalTransitionConfigurer;
|
||||
@@ -88,4 +90,19 @@ public interface StateMachineTransitionConfigurer<S, E> {
|
||||
*/
|
||||
JoinTransitionConfigurer<S, E> withJoin() throws Exception;
|
||||
|
||||
/**
|
||||
* Gets a configurer for transition from an entrypoint pseudostate.
|
||||
*
|
||||
* @return {@link EntryTransitionConfigurer} for chaining
|
||||
* @throws Exception if configuration error happens
|
||||
*/
|
||||
EntryTransitionConfigurer<S, E> withEntry() throws Exception;
|
||||
|
||||
/**
|
||||
* Gets a configurer for transition from an exitpoint pseudostate.
|
||||
*
|
||||
* @return {@link ExitTransitionConfigurer} for chaining
|
||||
* @throws Exception if configuration error happens
|
||||
*/
|
||||
ExitTransitionConfigurer<S, E> withExit() throws Exception;
|
||||
}
|
||||
|
||||
@@ -52,7 +52,7 @@ public class DefaultChoiceTransitionConfigurer<S, E>
|
||||
if (last != null) {
|
||||
choices.add(last);
|
||||
}
|
||||
builder.add(source, choices);
|
||||
builder.addChoice(source, choices);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright 2016 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 org.springframework.statemachine.config.builders.StateMachineTransitionBuilder;
|
||||
import org.springframework.statemachine.config.builders.StateMachineTransitionConfigurer;
|
||||
import org.springframework.statemachine.config.common.annotation.AnnotationConfigurerAdapter;
|
||||
import org.springframework.statemachine.config.model.TransitionsData;
|
||||
|
||||
/**
|
||||
* Default implementation of a {@link EntryTransitionConfigurer}.
|
||||
*
|
||||
* @author Janne Valkealahti
|
||||
*
|
||||
* @param <S> the type of state
|
||||
* @param <E> the type of event
|
||||
*/
|
||||
public class DefaultEntryTransitionConfigurer<S, E>
|
||||
extends AnnotationConfigurerAdapter<TransitionsData<S, E>, StateMachineTransitionConfigurer<S, E>, StateMachineTransitionBuilder<S, E>>
|
||||
implements EntryTransitionConfigurer<S, E> {
|
||||
|
||||
private S source;
|
||||
private S target;
|
||||
|
||||
@Override
|
||||
public void configure(StateMachineTransitionBuilder<S, E> builder) throws Exception {
|
||||
builder.addEntry(source, target);
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntryTransitionConfigurer<S, E> source(S source) {
|
||||
this.source = source;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntryTransitionConfigurer<S, E> target(S target) {
|
||||
this.target = target;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright 2016 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 org.springframework.statemachine.config.builders.StateMachineTransitionBuilder;
|
||||
import org.springframework.statemachine.config.builders.StateMachineTransitionConfigurer;
|
||||
import org.springframework.statemachine.config.common.annotation.AnnotationConfigurerAdapter;
|
||||
import org.springframework.statemachine.config.model.TransitionsData;
|
||||
|
||||
/**
|
||||
* Default implementation of a {@link ExitTransitionConfigurer}.
|
||||
*
|
||||
* @author Janne Valkealahti
|
||||
*
|
||||
* @param <S> the type of state
|
||||
* @param <E> the type of event
|
||||
*/
|
||||
public class DefaultExitTransitionConfigurer<S, E>
|
||||
extends AnnotationConfigurerAdapter<TransitionsData<S, E>, StateMachineTransitionConfigurer<S, E>, StateMachineTransitionBuilder<S, E>>
|
||||
implements ExitTransitionConfigurer<S, E> {
|
||||
|
||||
private S source;
|
||||
private S target;
|
||||
|
||||
@Override
|
||||
public void configure(StateMachineTransitionBuilder<S, E> builder) throws Exception {
|
||||
builder.addExit(source, target);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExitTransitionConfigurer<S, E> source(S source) {
|
||||
this.source = source;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExitTransitionConfigurer<S, E> target(S target) {
|
||||
this.target = target;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -38,7 +38,7 @@ public class DefaultExternalTransitionConfigurer<S, E> extends AbstractTransitio
|
||||
|
||||
@Override
|
||||
public void configure(StateMachineTransitionBuilder<S, E> builder) throws Exception {
|
||||
builder.add(getSource(), getTarget(), getState(), getEvent(), getPeriod(), getCount(), getActions(), getGuard(), TransitionKind.EXTERNAL,
|
||||
builder.addTransition(getSource(), getTarget(), getState(), getEvent(), getPeriod(), getCount(), getActions(), getGuard(), TransitionKind.EXTERNAL,
|
||||
getSecurityRule());
|
||||
}
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ public class DefaultInternalTransitionConfigurer<S, E> extends AbstractTransitio
|
||||
|
||||
@Override
|
||||
public void configure(StateMachineTransitionBuilder<S, E> builder) throws Exception {
|
||||
builder.add(getSource(), getTarget(), getState(), getEvent(), getPeriod(), getCount(), getActions(), getGuard(), TransitionKind.INTERNAL,
|
||||
builder.addTransition(getSource(), getTarget(), getState(), getEvent(), getPeriod(), getCount(), getActions(), getGuard(), TransitionKind.INTERNAL,
|
||||
getSecurityRule());
|
||||
}
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ public class DefaultLocalTransitionConfigurer<S, E> extends AbstractTransitionCo
|
||||
|
||||
@Override
|
||||
public void configure(StateMachineTransitionBuilder<S, E> builder) throws Exception {
|
||||
builder.add(getSource(), getTarget(), getState(), getEvent(), getPeriod(), getCount(), getActions(), getGuard(), TransitionKind.LOCAL,
|
||||
builder.addTransition(getSource(), getTarget(), getState(), getEvent(), getPeriod(), getCount(), getActions(), getGuard(), TransitionKind.LOCAL,
|
||||
getSecurityRule());
|
||||
}
|
||||
|
||||
|
||||
@@ -44,26 +44,18 @@ public class DefaultStateConfigurer<S, E>
|
||||
implements StateConfigurer<S, E> {
|
||||
|
||||
private Object parent;
|
||||
|
||||
private final Object region = UUID.randomUUID().toString();
|
||||
|
||||
private final Map<S, StateData<S, E>> incomplete = new HashMap<S, StateData<S, E>>();
|
||||
|
||||
private S initialState;
|
||||
|
||||
private Action<S, E> initialAction;
|
||||
|
||||
private S end;
|
||||
|
||||
private S history;
|
||||
|
||||
private History historyType;
|
||||
|
||||
private final Collection<S> choices = new ArrayList<S>();
|
||||
|
||||
private final Collection<S> forks = new ArrayList<S>();
|
||||
|
||||
private final Collection<S> joins = new ArrayList<S>();
|
||||
private final Collection<S> exits = new ArrayList<S>();
|
||||
private final Collection<S> entrys = new ArrayList<S>();
|
||||
|
||||
@Override
|
||||
public void configure(StateMachineStateBuilder<S, E> builder) throws Exception {
|
||||
@@ -86,6 +78,10 @@ public class DefaultStateConfigurer<S, E>
|
||||
s.setPseudoStateKind(PseudoStateKind.FORK);
|
||||
} else if (joins.contains(s.getState())) {
|
||||
s.setPseudoStateKind(PseudoStateKind.JOIN);
|
||||
} else if (entrys.contains(s.getState())) {
|
||||
s.setPseudoStateKind(PseudoStateKind.ENTRY);
|
||||
} else if (exits.contains(s.getState())) {
|
||||
s.setPseudoStateKind(PseudoStateKind.EXIT);
|
||||
}
|
||||
if (s.getState() == history) {
|
||||
if (History.SHALLOW == historyType) {
|
||||
@@ -199,6 +195,20 @@ public class DefaultStateConfigurer<S, E>
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StateConfigurer<S, E> entry(S entry) {
|
||||
state(entry);
|
||||
entrys.add(entry);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StateConfigurer<S, E> exit(S exit) {
|
||||
state(exit);
|
||||
exits.add(exit);
|
||||
return this;
|
||||
}
|
||||
|
||||
private void addIncomplete(Object parent, S state, Collection<E> deferred,
|
||||
Collection<? extends Action<S, E>> entryActions, Collection<? extends Action<S, E>> exitActions) {
|
||||
StateData<S, E> stateData = incomplete.get(state);
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright 2016 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 org.springframework.statemachine.config.builders.StateMachineTransitionConfigurer;
|
||||
import org.springframework.statemachine.config.common.annotation.AnnotationConfigurerBuilder;
|
||||
import org.springframework.statemachine.transition.Transition;
|
||||
|
||||
/**
|
||||
* {@code TransitionConfigurer} interface for configuring {@link Transition}
|
||||
* with an entrypoint pseudo state.
|
||||
*
|
||||
* @author Janne Valkealahti
|
||||
*
|
||||
* @param <S> the type of state
|
||||
* @param <E> the type of event
|
||||
*/
|
||||
public interface EntryTransitionConfigurer<S, E>
|
||||
extends AnnotationConfigurerBuilder<StateMachineTransitionConfigurer<S, E>> {
|
||||
|
||||
/**
|
||||
* Specify a source state {@code S} for this {@link Transition}.
|
||||
*
|
||||
* @param source the source state {@code S}
|
||||
* @return configurer for chaining
|
||||
*/
|
||||
EntryTransitionConfigurer<S, E> source(S source);
|
||||
|
||||
/**
|
||||
* Specify a target state {@code S} for this {@link Transition}.
|
||||
*
|
||||
* @param target the target state {@code S}
|
||||
* @return configurer for chaining
|
||||
*/
|
||||
EntryTransitionConfigurer<S, E> target(S target);
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright 2016 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 org.springframework.statemachine.config.builders.StateMachineTransitionConfigurer;
|
||||
import org.springframework.statemachine.config.common.annotation.AnnotationConfigurerBuilder;
|
||||
import org.springframework.statemachine.transition.Transition;
|
||||
|
||||
/**
|
||||
* {@code TransitionConfigurer} interface for configuring {@link Transition}
|
||||
* with an exitpoint pseudo state.
|
||||
*
|
||||
* @author Janne Valkealahti
|
||||
*
|
||||
* @param <S> the type of state
|
||||
* @param <E> the type of event
|
||||
*/
|
||||
public interface ExitTransitionConfigurer<S, E>
|
||||
extends AnnotationConfigurerBuilder<StateMachineTransitionConfigurer<S, E>> {
|
||||
|
||||
/**
|
||||
* Specify a source state {@code S} for this {@link Transition}.
|
||||
*
|
||||
* @param source the source state {@code S}
|
||||
* @return configurer for chaining
|
||||
*/
|
||||
ExitTransitionConfigurer<S, E> source(S source);
|
||||
|
||||
/**
|
||||
* Specify a target state {@code S} for this {@link Transition}.
|
||||
*
|
||||
* @param target the target state {@code S}
|
||||
* @return configurer for chaining
|
||||
*/
|
||||
ExitTransitionConfigurer<S, E> target(S target);
|
||||
}
|
||||
@@ -149,6 +149,22 @@ public interface StateConfigurer<S, E> extends
|
||||
*/
|
||||
StateConfigurer<S, E> history(S history, History type);
|
||||
|
||||
/**
|
||||
* Specify a state {@code S} to be entrypoint pseudo state.
|
||||
*
|
||||
* @param entry the entrypoint pseudo state
|
||||
* @return configurer for chaining
|
||||
*/
|
||||
StateConfigurer<S, E> entry(S entry);
|
||||
|
||||
/**
|
||||
* Specify a state {@code S} to be exitpoint pseudo state.
|
||||
*
|
||||
* @param exit the exitpoint pseudo state
|
||||
* @return configurer for chaining
|
||||
*/
|
||||
StateConfigurer<S, E> exit(S exit);
|
||||
|
||||
/**
|
||||
* Enumeration of a possible history pseudostate type.
|
||||
*/
|
||||
@@ -166,5 +182,4 @@ public interface StateConfigurer<S, E> extends
|
||||
*/
|
||||
DEEP
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright 2016 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.model;
|
||||
|
||||
/**
|
||||
* A simple data object keeping entrypoint related configs in a same place.
|
||||
*
|
||||
* @param <S> the type of state
|
||||
* @param <E> the type of event
|
||||
*/
|
||||
public class EntryData<S, E> {
|
||||
private final S source;
|
||||
private final S target;
|
||||
|
||||
/**
|
||||
* Instantiates a new entry data.
|
||||
*
|
||||
* @param source the source
|
||||
* @param target the target
|
||||
*/
|
||||
public EntryData(S source, S target) {
|
||||
this.source = source;
|
||||
this.target = target;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the source.
|
||||
*
|
||||
* @return the source
|
||||
*/
|
||||
public S getSource() {
|
||||
return source;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the target.
|
||||
*
|
||||
* @return the target
|
||||
*/
|
||||
public S getTarget() {
|
||||
return target;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright 2016 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.model;
|
||||
|
||||
/**
|
||||
* A simple data object keeping exitpoint related configs in a same place.
|
||||
*
|
||||
* @param <S> the type of state
|
||||
* @param <E> the type of event
|
||||
*/
|
||||
public class ExitData<S, E> {
|
||||
private final S source;
|
||||
private final S target;
|
||||
|
||||
/**
|
||||
* Instantiates a new exit data.
|
||||
*
|
||||
* @param source the source
|
||||
* @param target the target
|
||||
*/
|
||||
public ExitData(S source, S target) {
|
||||
this.source = source;
|
||||
this.target = target;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the source.
|
||||
*
|
||||
* @return the source
|
||||
*/
|
||||
public S getSource() {
|
||||
return source;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the target.
|
||||
*
|
||||
* @return the target
|
||||
*/
|
||||
public S getTarget() {
|
||||
return target;
|
||||
}
|
||||
}
|
||||
@@ -33,6 +33,8 @@ public class TransitionsData<S, E> {
|
||||
private final Map<S, List<ChoiceData<S, E>>> choices;
|
||||
private final Map<S, List<S>> forks;
|
||||
private final Map<S, List<S>> joins;
|
||||
private final Collection<EntryData<S, E>> entrys;
|
||||
private final Collection<ExitData<S, E>> exits;
|
||||
|
||||
/**
|
||||
* Instantiates a new transitions data.
|
||||
@@ -40,7 +42,7 @@ public class TransitionsData<S, E> {
|
||||
* @param transitionsData the transitions data
|
||||
*/
|
||||
public TransitionsData(Collection<TransitionData<S, E>> transitionsData) {
|
||||
this(transitionsData, null, null, null);
|
||||
this(transitionsData, null, null, null, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -50,13 +52,17 @@ public class TransitionsData<S, E> {
|
||||
* @param choices the choices
|
||||
* @param forks the forks
|
||||
* @param joins the joins
|
||||
* @param entrys the entrys
|
||||
* @param exits the exits
|
||||
*/
|
||||
public TransitionsData(Collection<TransitionData<S, E>> transitionsData,
|
||||
Map<S, List<ChoiceData<S, E>>> choices, Map<S, List<S>> forks, Map<S, List<S>> joins) {
|
||||
public TransitionsData(Collection<TransitionData<S, E>> transitionsData, Map<S, List<ChoiceData<S, E>>> choices, Map<S, List<S>> forks,
|
||||
Map<S, List<S>> joins, Collection<EntryData<S, E>> entrys, Collection<ExitData<S, E>> exits) {
|
||||
this.transitions = transitionsData;
|
||||
this.choices = choices;
|
||||
this.forks = forks;
|
||||
this.joins = joins;
|
||||
this.entrys = entrys;
|
||||
this.exits = exits;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -95,4 +101,21 @@ public class TransitionsData<S, E> {
|
||||
return joins;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the entrys.
|
||||
*
|
||||
* @return the entrys
|
||||
*/
|
||||
public Collection<EntryData<S, E>> getEntrys() {
|
||||
return entrys;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the exits.
|
||||
*
|
||||
* @return the exits
|
||||
*/
|
||||
public Collection<ExitData<S, E>> getExits() {
|
||||
return exits;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright 2016 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.state;
|
||||
|
||||
import org.springframework.statemachine.StateContext;
|
||||
|
||||
/**
|
||||
* Entrypoint implementation of a {@link PseudoState}.
|
||||
*
|
||||
* @author Janne Valkealahti
|
||||
*
|
||||
* @param <S> the type of state
|
||||
* @param <E> the type of event
|
||||
*/
|
||||
public class EntryPseudoState<S, E> implements PseudoState<S, E> {
|
||||
|
||||
private final State<S, E> state;
|
||||
|
||||
/**
|
||||
* Instantiates a new entry pseudo state.
|
||||
*
|
||||
* @param state the state
|
||||
*/
|
||||
public EntryPseudoState(State<S, E> state) {
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
@Override
|
||||
final public PseudoStateKind getKind() {
|
||||
return PseudoStateKind.ENTRY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public State<S, E> entry(StateContext<S, E> context) {
|
||||
return state;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exit(StateContext<S, E> context) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addPseudoStateListener(PseudoStateListener<S, E> listener) {
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright 2016 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.state;
|
||||
|
||||
import org.springframework.statemachine.StateContext;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Exitpoint implementation of a {@link PseudoState}.
|
||||
*
|
||||
* @author Janne Valkealahti
|
||||
*
|
||||
* @param <S> the type of state
|
||||
* @param <E> the type of event
|
||||
*/
|
||||
public class ExitPseudoState<S, E> implements PseudoState<S, E> {
|
||||
|
||||
private StateHolder<S, E> state;
|
||||
|
||||
/**
|
||||
* Instantiates a new exit pseudo state.
|
||||
*
|
||||
* @param state the state
|
||||
*/
|
||||
public ExitPseudoState(StateHolder<S, E> state) {
|
||||
Assert.notNull(state, "Holder must be set");
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
@Override
|
||||
final public PseudoStateKind getKind() {
|
||||
return PseudoStateKind.EXIT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public State<S, E> entry(StateContext<S, E> context) {
|
||||
return state.getState();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exit(StateContext<S, E> context) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addPseudoStateListener(PseudoStateListener<S, E> listener) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the state holder.
|
||||
*
|
||||
* @return the state holder
|
||||
*/
|
||||
public StateHolder<S, E> getStateHolder() {
|
||||
return state;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
* Copyright 2015-2016 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.
|
||||
@@ -43,6 +43,11 @@ public enum PseudoStateKind {
|
||||
FORK,
|
||||
|
||||
/** Join kind */
|
||||
JOIN
|
||||
JOIN,
|
||||
|
||||
/** Entrypoint kind */
|
||||
ENTRY,
|
||||
|
||||
/** Exitpoint kind */
|
||||
EXIT
|
||||
}
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright 2016 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.state;
|
||||
|
||||
/**
|
||||
* Utility class using holder pattern to keep a {@link State} reference.
|
||||
*
|
||||
* @author Janne Valkealahti
|
||||
*
|
||||
* @param <S> the type of state
|
||||
* @param <E> the type of event
|
||||
*/
|
||||
public class StateHolder<S, E> {
|
||||
|
||||
private State<S, E> state;
|
||||
|
||||
/**
|
||||
* Instantiates a new state holder.
|
||||
*
|
||||
* @param state the state
|
||||
*/
|
||||
public StateHolder(State<S, E> state) {
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the state.
|
||||
*
|
||||
* @return the state
|
||||
*/
|
||||
public State<S, E> getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the state.
|
||||
*
|
||||
* @param state the state
|
||||
*/
|
||||
public void setState(State<S, E> state) {
|
||||
this.state = state;
|
||||
}
|
||||
}
|
||||
@@ -733,6 +733,14 @@ public abstract class AbstractStateMachine<S, E> extends StateMachineObjectSuppo
|
||||
callPreStateChangeInterceptors(toState, message, transition, stateMachine);
|
||||
}
|
||||
|
||||
setCurrentState(toState, message, transition, true, stateMachine);
|
||||
} else if (kind == PseudoStateKind.ENTRY) {
|
||||
StateContext<S, E> stateContext = buildStateContext(Stage.STATE_CHANGED, message, transition, stateMachine);
|
||||
State<S, E> toState = state.getPseudoState().entry(stateContext);
|
||||
setCurrentState(toState, message, transition, true, stateMachine);
|
||||
} else if (kind == PseudoStateKind.EXIT) {
|
||||
StateContext<S, E> stateContext = buildStateContext(Stage.STATE_CHANGED, message, transition, stateMachine);
|
||||
State<S, E> toState = state.getPseudoState().entry(stateContext);
|
||||
setCurrentState(toState, message, transition, true, stateMachine);
|
||||
} else if (kind == PseudoStateKind.FORK) {
|
||||
ForkPseudoState<S, E> fps = (ForkPseudoState<S, E>) state.getPseudoState();
|
||||
|
||||
@@ -76,7 +76,7 @@ public class StateMachineModelTests {
|
||||
Map<String, List<ChoiceData<String, String>>> choices = new HashMap<>();
|
||||
Map<String, List<String>> forks = new HashMap<>();
|
||||
Map<String, List<String>> joins = new HashMap<>();
|
||||
TransitionsData<String, String> transitionsData = new TransitionsData<>(transitions, choices, forks, joins);
|
||||
TransitionsData<String, String> transitionsData = new TransitionsData<>(transitions, choices, forks, joins, null, null);
|
||||
|
||||
StateMachineModel<String, String> stateMachineModel = new DefaultStateMachineModel<>(configurationData, statesData, transitionsData);
|
||||
ObjectStateMachineFactory<String, String> factory = new ObjectStateMachineFactory<>(stateMachineModel);
|
||||
|
||||
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
* Copyright 2016 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.state;
|
||||
|
||||
import static org.hamcrest.Matchers.contains;
|
||||
import static org.hamcrest.Matchers.notNullValue;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.statemachine.AbstractStateMachineTests;
|
||||
import org.springframework.statemachine.StateMachine;
|
||||
import org.springframework.statemachine.StateMachineSystemConstants;
|
||||
import org.springframework.statemachine.config.EnableStateMachine;
|
||||
import org.springframework.statemachine.config.StateMachineConfigurerAdapter;
|
||||
import org.springframework.statemachine.config.builders.StateMachineStateConfigurer;
|
||||
import org.springframework.statemachine.config.builders.StateMachineTransitionConfigurer;
|
||||
|
||||
public class ExitEntryStateTests extends AbstractStateMachineTests {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test
|
||||
public void testSimpleEntryExit() {
|
||||
context.register(Config1.class);
|
||||
context.refresh();
|
||||
StateMachine<String, String> machine =
|
||||
context.getBean(StateMachineSystemConstants.DEFAULT_ID_STATEMACHINE, StateMachine.class);
|
||||
assertThat(machine, notNullValue());
|
||||
machine.start();
|
||||
assertThat(machine.getState().getIds(), contains("S1"));
|
||||
machine.sendEvent("ENTRY1");
|
||||
assertThat(machine.getState().getIds(), contains("S2", "S22"));
|
||||
machine.sendEvent("EXIT1");
|
||||
assertThat(machine.getState().getIds(), contains("S4"));
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableStateMachine
|
||||
static class Config1 extends StateMachineConfigurerAdapter<String, String> {
|
||||
|
||||
@Override
|
||||
public void configure(StateMachineStateConfigurer<String, String> states) throws Exception {
|
||||
// entry point takes to S22 instead of initial S21
|
||||
// exit point takes to S4 instead from S2 to S3
|
||||
states
|
||||
.withStates()
|
||||
.initial("S1")
|
||||
.state("S2")
|
||||
.state("S3")
|
||||
.state("S4")
|
||||
.state("S5")
|
||||
.and()
|
||||
.withStates()
|
||||
.parent("S2")
|
||||
.initial("S21")
|
||||
.entry("S2ENTRY1")
|
||||
.entry("S2ENTRY2")
|
||||
.exit("S2EXIT1")
|
||||
.exit("S2EXIT2")
|
||||
.state("S22")
|
||||
.state("S23");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(StateMachineTransitionConfigurer<String, String> transitions) throws Exception {
|
||||
transitions
|
||||
.withExternal()
|
||||
.source("S1").target("S2")
|
||||
.event("E1")
|
||||
.and()
|
||||
.withExternal()
|
||||
.source("S2").target("S3")
|
||||
.event("E2")
|
||||
.and()
|
||||
.withExternal()
|
||||
.source("S1").target("S2ENTRY1")
|
||||
.event("ENTRY1")
|
||||
.and()
|
||||
.withExternal()
|
||||
.source("S1").target("S2ENTRY2")
|
||||
.event("ENTRY2")
|
||||
.and()
|
||||
.withExternal()
|
||||
.source("S22").target("S2EXIT1")
|
||||
.event("EXIT1")
|
||||
.and()
|
||||
.withExternal()
|
||||
.source("S22").target("S2EXIT2")
|
||||
.event("EXIT2")
|
||||
.and()
|
||||
.withEntry()
|
||||
.source("S2ENTRY1").target("S22")
|
||||
.and()
|
||||
.withEntry()
|
||||
.source("S2ENTRY2").target("S23")
|
||||
.and()
|
||||
.withExit()
|
||||
.source("S2EXIT1").target("S4")
|
||||
.and()
|
||||
.withExit()
|
||||
.source("S2EXIT2").target("S5");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected AnnotationConfigApplicationContext buildContext() {
|
||||
return new AnnotationConfigApplicationContext();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user