Base support for local transitions
- resolves #5 - big conceptual changes to how sub-machines are handled order to get events working with a multi-level sub states. - added more typing throughout few interfaces to properly pass in state context via action axecution chain. this type change effectively caused change to most of the classes but not that much functional change of behaviour. - cleaning and tidy up
This commit is contained in:
@@ -100,6 +100,7 @@ project('spring-statemachine-core') {
|
||||
testCompile "org.hamcrest:hamcrest-core:$hamcrestVersion"
|
||||
testCompile "org.hamcrest:hamcrest-library:$hamcrestVersion"
|
||||
testCompile "junit:junit:$junitVersion"
|
||||
testRuntime("log4j:log4j:$log4jVersion")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,3 +2,5 @@ version=1.0.0.BUILD-SNAPSHOT
|
||||
springVersion = 4.1.4.RELEASE
|
||||
hamcrestVersion = 1.3
|
||||
junitVersion = 4.11
|
||||
log4jVersion = 1.2.17
|
||||
|
||||
|
||||
@@ -24,11 +24,11 @@ import org.springframework.statemachine.transition.Transition;
|
||||
* {@code StateContext} is representing a current context used in
|
||||
* {@link Transition}s, {@link Action}s and {@link Guard}s order to get access
|
||||
* to event headers and {@link ExtendedState}.
|
||||
*
|
||||
*
|
||||
* @author Janne Valkealahti
|
||||
*
|
||||
*/
|
||||
public interface StateContext {
|
||||
public interface StateContext<S, E> {
|
||||
|
||||
/**
|
||||
* Gets the event message headers.
|
||||
@@ -44,4 +44,11 @@ public interface StateContext {
|
||||
*/
|
||||
ExtendedState getExtendedState();
|
||||
|
||||
/**
|
||||
* Gets the transition.
|
||||
*
|
||||
* @return the transition
|
||||
*/
|
||||
Transition<S, E> getTransition();
|
||||
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ import org.springframework.statemachine.state.State;
|
||||
/**
|
||||
* {@code StateMachine} provides an APIs for generic finite state machine needed
|
||||
* for basic operations like working with states, events and a lifecycle.
|
||||
*
|
||||
*
|
||||
* @author Janne Valkealahti
|
||||
*
|
||||
* @param <S> the type of state
|
||||
@@ -43,17 +43,22 @@ public interface StateMachine<S, E> extends Region<S, E> {
|
||||
*/
|
||||
void start();
|
||||
|
||||
/**
|
||||
* Stop the state machine.
|
||||
*/
|
||||
void stop();
|
||||
|
||||
/**
|
||||
* Send an event {@code E} wrapped with a {@link Message} to the state
|
||||
* machine.
|
||||
*
|
||||
*
|
||||
* @param event the wrapped event to send
|
||||
*/
|
||||
void sendEvent(Message<E> event);
|
||||
|
||||
/**
|
||||
* Send an event {@code E} to the state machine.
|
||||
*
|
||||
*
|
||||
* @param event the event to send
|
||||
*/
|
||||
void sendEvent(E event);
|
||||
|
||||
@@ -22,15 +22,17 @@ import org.springframework.statemachine.StateContext;
|
||||
* events by executing an {@code Action} with a {@link StateContext}.
|
||||
*
|
||||
* @author Janne Valkealahti
|
||||
*
|
||||
*
|
||||
* @param <S> the type of state
|
||||
* @param <E> the type of event
|
||||
*/
|
||||
public interface Action {
|
||||
public interface Action<S, E> {
|
||||
|
||||
/**
|
||||
* Execute action with a {@link StateContext}.
|
||||
*
|
||||
* @param context the state context
|
||||
*/
|
||||
void execute(StateContext context);
|
||||
void execute(StateContext<S, E> context);
|
||||
|
||||
}
|
||||
|
||||
@@ -50,12 +50,12 @@ public class StateMachineStates<S, E> {
|
||||
public static class StateData<S, E> {
|
||||
private S state;
|
||||
private Collection<E> deferred;
|
||||
private Collection<Action> entryActions;
|
||||
private Collection<Action> exitActions;
|
||||
private Collection<Action<S, E>> entryActions;
|
||||
private Collection<Action<S, E>> exitActions;
|
||||
public StateData(S state, Collection<E> deferred) {
|
||||
this(state, deferred, null, null);
|
||||
}
|
||||
public StateData(S state, Collection<E> deferred, Collection<Action> entryActions, Collection<Action> exitActions) {
|
||||
public StateData(S state, Collection<E> deferred, Collection<Action<S, E>> entryActions, Collection<Action<S, E>> exitActions) {
|
||||
this.state = state;
|
||||
this.deferred = deferred;
|
||||
this.entryActions = entryActions;
|
||||
@@ -70,10 +70,10 @@ public class StateMachineStates<S, E> {
|
||||
public Collection<E> getDeferred() {
|
||||
return deferred;
|
||||
}
|
||||
public Collection<Action> getEntryActions() {
|
||||
public Collection<Action<S, E>> getEntryActions() {
|
||||
return entryActions;
|
||||
}
|
||||
public Collection<Action> getExitActions() {
|
||||
public Collection<Action<S, E>> getExitActions() {
|
||||
return exitActions;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,8 +24,10 @@ import org.springframework.statemachine.config.common.annotation.AbstractConfigu
|
||||
import org.springframework.statemachine.config.common.annotation.ObjectPostProcessor;
|
||||
import org.springframework.statemachine.config.configurers.DefaultExternalTransitionConfigurer;
|
||||
import org.springframework.statemachine.config.configurers.DefaultInternalTransitionConfigurer;
|
||||
import org.springframework.statemachine.config.configurers.DefaultLocalTransitionConfigurer;
|
||||
import org.springframework.statemachine.config.configurers.ExternalTransitionConfigurer;
|
||||
import org.springframework.statemachine.config.configurers.InternalTransitionConfigurer;
|
||||
import org.springframework.statemachine.config.configurers.LocalTransitionConfigurer;
|
||||
import org.springframework.statemachine.guard.Guard;
|
||||
import org.springframework.statemachine.transition.TransitionKind;
|
||||
|
||||
@@ -64,8 +66,13 @@ public class StateMachineTransitionBuilder<S, E>
|
||||
public InternalTransitionConfigurer<S, E> withInternal() throws Exception {
|
||||
return apply(new DefaultInternalTransitionConfigurer<S, E>());
|
||||
}
|
||||
|
||||
@Override
|
||||
public LocalTransitionConfigurer<S, E> withLocal() throws Exception {
|
||||
return apply(new DefaultLocalTransitionConfigurer<S, E>());
|
||||
}
|
||||
|
||||
public void add(S source, S target, E event, Collection<Action> actions, Guard guard, TransitionKind kind) {
|
||||
public void add(S source, S target, E event, Collection<Action<S, E>> actions, Guard<S, E> guard, TransitionKind kind) {
|
||||
transitionData.add(new TransitionData<S, E>(source, target, event, actions, guard, kind));
|
||||
}
|
||||
|
||||
|
||||
@@ -17,11 +17,14 @@ package org.springframework.statemachine.config.builders;
|
||||
|
||||
import org.springframework.statemachine.config.configurers.ExternalTransitionConfigurer;
|
||||
import org.springframework.statemachine.config.configurers.InternalTransitionConfigurer;
|
||||
import org.springframework.statemachine.config.configurers.LocalTransitionConfigurer;
|
||||
|
||||
public interface StateMachineTransitionConfigurer<S, E> {
|
||||
|
||||
ExternalTransitionConfigurer<S, E> withExternal() throws Exception;
|
||||
|
||||
InternalTransitionConfigurer<S, E> withInternal() throws Exception;
|
||||
|
||||
LocalTransitionConfigurer<S, E> withLocal() throws Exception;
|
||||
|
||||
}
|
||||
|
||||
@@ -37,10 +37,10 @@ public class StateMachineTransitions<S, E> {
|
||||
S source;
|
||||
S target;
|
||||
E event;
|
||||
Collection<Action> actions;
|
||||
Guard guard;
|
||||
Collection<Action<S, E>> actions;
|
||||
Guard<S, E> guard;
|
||||
TransitionKind kind;
|
||||
public TransitionData(S source, S target, E event, Collection<Action> actions, Guard guard, TransitionKind kind) {
|
||||
public TransitionData(S source, S target, E event, Collection<Action<S, E>> actions, Guard<S, E> guard, TransitionKind kind) {
|
||||
this.source = source;
|
||||
this.target = target;
|
||||
this.event = event;
|
||||
@@ -57,10 +57,10 @@ public class StateMachineTransitions<S, E> {
|
||||
public E getEvent() {
|
||||
return event;
|
||||
}
|
||||
public Collection<Action> getActions() {
|
||||
public Collection<Action<S, E>> getActions() {
|
||||
return actions;
|
||||
}
|
||||
public Guard getGuard() {
|
||||
public Guard<S, E> getGuard() {
|
||||
return guard;
|
||||
}
|
||||
public TransitionKind getKind() {
|
||||
|
||||
@@ -48,9 +48,9 @@ public class DefaultExternalTransitionConfigurer<S, E>
|
||||
|
||||
private E event;
|
||||
|
||||
private Collection<Action> actions = new ArrayList<Action>();
|
||||
private Collection<Action<S, E>> actions = new ArrayList<Action<S, E>>();
|
||||
|
||||
private Guard guard;
|
||||
private Guard<S, E> guard;
|
||||
|
||||
@Override
|
||||
public void configure(StateMachineTransitionBuilder<S, E> builder) throws Exception {
|
||||
@@ -76,13 +76,13 @@ public class DefaultExternalTransitionConfigurer<S, E>
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExternalTransitionConfigurer<S, E> action(Action action) {
|
||||
public ExternalTransitionConfigurer<S, E> action(Action<S, E> action) {
|
||||
actions.add(action);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExternalTransitionConfigurer<S, E> guard(Guard guard) {
|
||||
public ExternalTransitionConfigurer<S, E> guard(Guard<S, E> guard) {
|
||||
this.guard = guard;
|
||||
return this;
|
||||
}
|
||||
@@ -91,7 +91,7 @@ public class DefaultExternalTransitionConfigurer<S, E>
|
||||
public ExternalTransitionConfigurer<S, E> guardExpression(String expression) {
|
||||
SpelExpressionParser parser = new SpelExpressionParser(
|
||||
new SpelParserConfiguration(SpelCompilerMode.MIXED, null));
|
||||
this.guard = new SpelExpressionGuard(parser.parseExpression(expression));
|
||||
this.guard = new SpelExpressionGuard<S, E>(parser.parseExpression(expression));
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@@ -48,9 +48,9 @@ public class DefaultInternalTransitionConfigurer<S, E>
|
||||
|
||||
private E event;
|
||||
|
||||
private Collection<Action> actions = new ArrayList<Action>();
|
||||
private Collection<Action<S, E>> actions = new ArrayList<Action<S, E>>();
|
||||
|
||||
private Guard guard;
|
||||
private Guard<S, E> guard;
|
||||
|
||||
@Override
|
||||
public void configure(StateMachineTransitionBuilder<S, E> builder) throws Exception {
|
||||
@@ -70,13 +70,13 @@ public class DefaultInternalTransitionConfigurer<S, E>
|
||||
}
|
||||
|
||||
@Override
|
||||
public InternalTransitionConfigurer<S, E> action(Action action) {
|
||||
public InternalTransitionConfigurer<S, E> action(Action<S, E> action) {
|
||||
actions.add(action);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InternalTransitionConfigurer<S, E> guard(Guard guard) {
|
||||
public InternalTransitionConfigurer<S, E> guard(Guard<S, E> guard) {
|
||||
this.guard = guard;
|
||||
return this;
|
||||
}
|
||||
@@ -85,7 +85,7 @@ public class DefaultInternalTransitionConfigurer<S, E>
|
||||
public InternalTransitionConfigurer<S, E> guardExpression(String expression) {
|
||||
SpelExpressionParser parser = new SpelExpressionParser(
|
||||
new SpelParserConfiguration(SpelCompilerMode.MIXED, null));
|
||||
this.guard = new SpelExpressionGuard(parser.parseExpression(expression));
|
||||
this.guard = new SpelExpressionGuard<S, E>(parser.parseExpression(expression));
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@@ -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.configurers;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.springframework.expression.spel.SpelCompilerMode;
|
||||
import org.springframework.expression.spel.SpelParserConfiguration;
|
||||
import org.springframework.expression.spel.standard.SpelExpressionParser;
|
||||
import org.springframework.statemachine.action.Action;
|
||||
import org.springframework.statemachine.config.builders.StateMachineTransitionBuilder;
|
||||
import org.springframework.statemachine.config.builders.StateMachineTransitionConfigurer;
|
||||
import org.springframework.statemachine.config.builders.StateMachineTransitions;
|
||||
import org.springframework.statemachine.config.common.annotation.AnnotationConfigurerAdapter;
|
||||
import org.springframework.statemachine.guard.Guard;
|
||||
import org.springframework.statemachine.guard.SpelExpressionGuard;
|
||||
import org.springframework.statemachine.transition.TransitionKind;
|
||||
|
||||
/**
|
||||
* Default implementation of a {@link LocalTransitionConfigurer}.
|
||||
*
|
||||
* @author Janne Valkealahti
|
||||
*
|
||||
* @param <S> the type of state
|
||||
* @param <E> the type of event
|
||||
*/
|
||||
public class DefaultLocalTransitionConfigurer<S, E>
|
||||
extends AnnotationConfigurerAdapter<StateMachineTransitions<S, E>, StateMachineTransitionConfigurer<S, E>, StateMachineTransitionBuilder<S, E>>
|
||||
implements LocalTransitionConfigurer<S, E> {
|
||||
|
||||
private S source;
|
||||
|
||||
private S target;
|
||||
|
||||
private E event;
|
||||
|
||||
private Collection<Action<S, E>> actions = new ArrayList<Action<S, E>>();
|
||||
|
||||
private Guard<S, E> guard;
|
||||
|
||||
@Override
|
||||
public void configure(StateMachineTransitionBuilder<S, E> builder) throws Exception {
|
||||
builder.add(source, target, event, actions, guard, TransitionKind.LOCAL);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LocalTransitionConfigurer<S, E> source(S source) {
|
||||
this.source = source;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LocalTransitionConfigurer<S, E> target(S target) {
|
||||
this.target = target;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LocalTransitionConfigurer<S, E> event(E event) {
|
||||
this.event = event;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LocalTransitionConfigurer<S, E> action(Action<S, E> action) {
|
||||
actions.add(action);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LocalTransitionConfigurer<S, E> guard(Guard<S, E> guard) {
|
||||
this.guard = guard;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LocalTransitionConfigurer<S, E> guardExpression(String expression) {
|
||||
SpelExpressionParser parser = new SpelExpressionParser(
|
||||
new SpelParserConfiguration(SpelCompilerMode.MIXED, null));
|
||||
this.guard = new SpelExpressionGuard<S, E>(parser.parseExpression(expression));
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -61,7 +61,7 @@ public class DefaultStateConfigurer<S, E>
|
||||
}
|
||||
|
||||
@Override
|
||||
public StateConfigurer<S, E> state(S state, Collection<Action> entryActions, Collection<Action> exitActions) {
|
||||
public StateConfigurer<S, E> state(S state, Collection<Action<S, E>> entryActions, Collection<Action<S, E>> exitActions) {
|
||||
states.add(new StateData<S, E>(state, null, entryActions, exitActions));
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* 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 org.springframework.statemachine.transition.Transition;
|
||||
|
||||
/**
|
||||
* {@code TransitionConfigurer} interface for configuring local {@link Transition}s.
|
||||
*
|
||||
* @author Janne Valkealahti
|
||||
*
|
||||
* @param <S> the type of state
|
||||
* @param <E> the type of event
|
||||
*/
|
||||
public interface LocalTransitionConfigurer<S, E> extends
|
||||
TransitionConfigurer<LocalTransitionConfigurer<S, E>, S, E> {
|
||||
|
||||
/**
|
||||
* Specify a target state {@code S} for this {@link Transition}.
|
||||
*
|
||||
* @param target the target state {@code S}
|
||||
* @return configurer for chaining
|
||||
*/
|
||||
LocalTransitionConfigurer<S, E> target(S target);
|
||||
|
||||
}
|
||||
@@ -29,7 +29,7 @@ public interface StateConfigurer<S, E> extends
|
||||
|
||||
StateConfigurer<S, E> state(S state);
|
||||
|
||||
StateConfigurer<S, E> state(S state, Collection<Action> entryActions, Collection<Action> exitActions);
|
||||
StateConfigurer<S, E> state(S state, Collection<Action<S, E>> entryActions, Collection<Action<S, E>> exitActions);
|
||||
|
||||
StateConfigurer<S, E> state(S state, E... deferred);
|
||||
|
||||
|
||||
@@ -55,7 +55,7 @@ public interface TransitionConfigurer<T, S, E> extends
|
||||
* @param action the action
|
||||
* @return configurer for chaining
|
||||
*/
|
||||
T action(Action action);
|
||||
T action(Action<S, E> action);
|
||||
|
||||
/**
|
||||
* Specify a {@link Guard} for this {@link Transition}.
|
||||
@@ -63,7 +63,7 @@ public interface TransitionConfigurer<T, S, E> extends
|
||||
* @param guard the guard
|
||||
* @return configurer for chaining
|
||||
*/
|
||||
T guard(Guard guard);
|
||||
T guard(Guard<S, E> guard);
|
||||
|
||||
/**
|
||||
* Specify a {@link Guard} backed by a SpEL expression for this {@link Transition}.
|
||||
|
||||
@@ -24,9 +24,11 @@ import org.springframework.statemachine.StateContext;
|
||||
* {@code FALSE}.
|
||||
*
|
||||
* @author Janne Valkealahti
|
||||
*
|
||||
*
|
||||
* @param <S> the type of state
|
||||
* @param <E> the type of event
|
||||
*/
|
||||
public interface Guard {
|
||||
public interface Guard<S, E> {
|
||||
|
||||
/**
|
||||
* Evaluate a guard condition.
|
||||
@@ -34,6 +36,6 @@ public interface Guard {
|
||||
* @param context the state context
|
||||
* @return true, if guard evaluation is successful, false otherwise.
|
||||
*/
|
||||
boolean evaluate(StateContext context);
|
||||
boolean evaluate(StateContext<S, E> context);
|
||||
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ import org.springframework.util.Assert;
|
||||
* @author Janne Valkealahti
|
||||
*
|
||||
*/
|
||||
public class SpelExpressionGuard implements Guard {
|
||||
public class SpelExpressionGuard<S, E> implements Guard<S, E> {
|
||||
|
||||
private final Expression expression;
|
||||
|
||||
@@ -41,7 +41,7 @@ public class SpelExpressionGuard implements Guard {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean evaluate(StateContext context) {
|
||||
public boolean evaluate(StateContext<S, E> context) {
|
||||
StandardEvaluationContext evaluationContext = new StandardEvaluationContext(context);
|
||||
return expression.getValue(evaluationContext, Boolean.class);
|
||||
}
|
||||
|
||||
@@ -52,7 +52,7 @@ public abstract class AbstractSimpleState<S, E> extends AbstractState<S, E> {
|
||||
* @param entryActions the entry actions
|
||||
* @param exitActions the exit actions
|
||||
*/
|
||||
public AbstractSimpleState(S id, Collection<E> deferred, Collection<Action> entryActions, Collection<Action> exitActions) {
|
||||
public AbstractSimpleState(S id, Collection<E> deferred, Collection<Action<S, E>> entryActions, Collection<Action<S, E>> exitActions) {
|
||||
this(id, deferred, entryActions, exitActions, null);
|
||||
}
|
||||
|
||||
@@ -86,7 +86,7 @@ public abstract class AbstractSimpleState<S, E> extends AbstractState<S, E> {
|
||||
* @param pseudoState the pseudo state
|
||||
* @param regions the regions
|
||||
*/
|
||||
public AbstractSimpleState(S id, Collection<E> deferred, Collection<Action> entryActions, Collection<Action> exitActions,
|
||||
public AbstractSimpleState(S id, Collection<E> deferred, Collection<Action<S, E>> entryActions, Collection<Action<S, E>> exitActions,
|
||||
PseudoState pseudoState, Collection<Region<S, E>> regions) {
|
||||
super(deferred, entryActions, exitActions, pseudoState, regions);
|
||||
this.ids = new ArrayList<S>();
|
||||
@@ -103,7 +103,7 @@ public abstract class AbstractSimpleState<S, E> extends AbstractState<S, E> {
|
||||
* @param pseudoState the pseudo state
|
||||
* @param submachine the submachine
|
||||
*/
|
||||
public AbstractSimpleState(S id, Collection<E> deferred, Collection<Action> entryActions, Collection<Action> exitActions,
|
||||
public AbstractSimpleState(S id, Collection<E> deferred, Collection<Action<S, E>> entryActions, Collection<Action<S, E>> exitActions,
|
||||
PseudoState pseudoState, StateMachine<S, E> submachine) {
|
||||
super(deferred, entryActions, exitActions, pseudoState, submachine);
|
||||
this.ids = new ArrayList<S>();
|
||||
@@ -119,7 +119,7 @@ public abstract class AbstractSimpleState<S, E> extends AbstractState<S, E> {
|
||||
* @param exitActions the exit actions
|
||||
* @param pseudoState the pseudo state
|
||||
*/
|
||||
public AbstractSimpleState(S id, Collection<E> deferred, Collection<Action> entryActions, Collection<Action> exitActions,
|
||||
public AbstractSimpleState(S id, Collection<E> deferred, Collection<Action<S, E>> entryActions, Collection<Action<S, E>> exitActions,
|
||||
PseudoState pseudoState) {
|
||||
super(deferred, entryActions, exitActions, pseudoState);
|
||||
this.ids = new ArrayList<S>();
|
||||
|
||||
@@ -18,6 +18,7 @@ package org.springframework.statemachine.state;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.springframework.statemachine.StateContext;
|
||||
import org.springframework.statemachine.StateMachine;
|
||||
import org.springframework.statemachine.action.Action;
|
||||
import org.springframework.statemachine.region.Region;
|
||||
@@ -25,7 +26,7 @@ import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Base implementation of a {@link State}.
|
||||
*
|
||||
*
|
||||
* @author Janne Valkealahti
|
||||
*
|
||||
* @param <S> the type of state
|
||||
@@ -35,8 +36,8 @@ public abstract class AbstractState<S, E> implements State<S, E> {
|
||||
|
||||
private final PseudoState pseudoState;
|
||||
private final Collection<E> deferred;
|
||||
private final Collection<Action> entryActions;
|
||||
private final Collection<Action> exitActions;
|
||||
private final Collection<Action<S, E>> entryActions;
|
||||
private final Collection<Action<S, E>> exitActions;
|
||||
private final Collection<Region<S, E>> regions = new ArrayList<Region<S, E>>();
|
||||
private final StateMachine<S, E> submachine;
|
||||
|
||||
@@ -48,7 +49,7 @@ public abstract class AbstractState<S, E> implements State<S, E> {
|
||||
public AbstractState(PseudoState pseudoState) {
|
||||
this(null, null, null, pseudoState);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Instantiates a new abstract state.
|
||||
*
|
||||
@@ -65,10 +66,10 @@ public abstract class AbstractState<S, E> implements State<S, E> {
|
||||
* @param entryActions the entry actions
|
||||
* @param exitActions the exit actions
|
||||
*/
|
||||
public AbstractState(Collection<E> deferred, Collection<Action> entryActions, Collection<Action> exitActions) {
|
||||
public AbstractState(Collection<E> deferred, Collection<Action<S, E>> entryActions, Collection<Action<S, E>> exitActions) {
|
||||
this(deferred, entryActions, exitActions, null);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Instantiates a new abstract state.
|
||||
*
|
||||
@@ -77,7 +78,7 @@ public abstract class AbstractState<S, E> implements State<S, E> {
|
||||
* @param exitActions the exit actions
|
||||
* @param pseudoState the pseudo state
|
||||
*/
|
||||
public AbstractState(Collection<E> deferred, Collection<Action> entryActions, Collection<Action> exitActions,
|
||||
public AbstractState(Collection<E> deferred, Collection<Action<S, E>> entryActions, Collection<Action<S, E>> exitActions,
|
||||
PseudoState pseudoState) {
|
||||
this(deferred, entryActions, exitActions, pseudoState, null, null);
|
||||
}
|
||||
@@ -91,7 +92,7 @@ public abstract class AbstractState<S, E> implements State<S, E> {
|
||||
* @param pseudoState the pseudo state
|
||||
* @param submachine the submachine
|
||||
*/
|
||||
public AbstractState(Collection<E> deferred, Collection<Action> entryActions, Collection<Action> exitActions,
|
||||
public AbstractState(Collection<E> deferred, Collection<Action<S, E>> entryActions, Collection<Action<S, E>> exitActions,
|
||||
PseudoState pseudoState, StateMachine<S, E> submachine) {
|
||||
this(deferred, entryActions, exitActions, pseudoState, null, submachine);
|
||||
}
|
||||
@@ -105,11 +106,11 @@ public abstract class AbstractState<S, E> implements State<S, E> {
|
||||
* @param pseudoState the pseudo state
|
||||
* @param regions the regions
|
||||
*/
|
||||
public AbstractState(Collection<E> deferred, Collection<Action> entryActions, Collection<Action> exitActions,
|
||||
public AbstractState(Collection<E> deferred, Collection<Action<S, E>> entryActions, Collection<Action<S, E>> exitActions,
|
||||
PseudoState pseudoState, Collection<Region<S, E>> regions) {
|
||||
this(deferred, entryActions, exitActions, pseudoState, regions, null);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Instantiates a new abstract state.
|
||||
*
|
||||
@@ -120,13 +121,13 @@ public abstract class AbstractState<S, E> implements State<S, E> {
|
||||
* @param regions the regions
|
||||
* @param submachine the submachine
|
||||
*/
|
||||
private AbstractState(Collection<E> deferred, Collection<Action> entryActions, Collection<Action> exitActions,
|
||||
private AbstractState(Collection<E> deferred, Collection<Action<S, E>> entryActions, Collection<Action<S, E>> exitActions,
|
||||
PseudoState pseudoState, Collection<Region<S, E>> regions, StateMachine<S, E> submachine) {
|
||||
this.deferred = deferred;
|
||||
this.entryActions = entryActions;
|
||||
this.exitActions = exitActions;
|
||||
this.pseudoState = pseudoState;
|
||||
|
||||
|
||||
// use of private ctor should prevent user to
|
||||
// add regions and a submachine which is not allowed.
|
||||
if (regions != null) {
|
||||
@@ -134,10 +135,16 @@ public abstract class AbstractState<S, E> implements State<S, E> {
|
||||
}
|
||||
this.submachine = submachine;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public abstract void exit(E event, StateContext<S, E> context);
|
||||
|
||||
@Override
|
||||
public abstract void entry(E event, StateContext<S, E> context);
|
||||
|
||||
@Override
|
||||
public abstract Collection<S> getIds();
|
||||
|
||||
|
||||
@Override
|
||||
public PseudoState getPseudoState() {
|
||||
return pseudoState;
|
||||
@@ -149,12 +156,12 @@ public abstract class AbstractState<S, E> implements State<S, E> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Action> getEntryActions() {
|
||||
public Collection<Action<S, E>> getEntryActions() {
|
||||
return entryActions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Action> getExitActions() {
|
||||
public Collection<Action<S, E>> getExitActions() {
|
||||
return exitActions;
|
||||
}
|
||||
|
||||
@@ -177,11 +184,11 @@ public abstract class AbstractState<S, E> implements State<S, E> {
|
||||
public boolean isSubmachineState() {
|
||||
return submachine != null;
|
||||
}
|
||||
|
||||
|
||||
protected StateMachine<S, E> getSubmachine() {
|
||||
return submachine;
|
||||
}
|
||||
|
||||
|
||||
protected Collection<Region<S, E>> getRegions() {
|
||||
return regions;
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ package org.springframework.statemachine.state;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.springframework.statemachine.StateContext;
|
||||
import org.springframework.statemachine.StateMachine;
|
||||
import org.springframework.statemachine.action.Action;
|
||||
import org.springframework.statemachine.region.Region;
|
||||
@@ -68,7 +69,7 @@ public class EnumState<S extends Enum<S>, E extends Enum<E>> extends AbstractSim
|
||||
* @param entryActions the entry actions
|
||||
* @param exitActions the exit actions
|
||||
*/
|
||||
public EnumState(S id, Collection<E> deferred, Collection<Action> entryActions, Collection<Action> exitActions) {
|
||||
public EnumState(S id, Collection<E> deferred, Collection<Action<S, E>> entryActions, Collection<Action<S, E>> exitActions) {
|
||||
super(id, deferred, entryActions, exitActions);
|
||||
}
|
||||
|
||||
@@ -81,7 +82,7 @@ public class EnumState<S extends Enum<S>, E extends Enum<E>> extends AbstractSim
|
||||
* @param exitActions the exit actions
|
||||
* @param pseudoState the pseudo state
|
||||
*/
|
||||
public EnumState(S id, Collection<E> deferred, Collection<Action> entryActions, Collection<Action> exitActions,
|
||||
public EnumState(S id, Collection<E> deferred, Collection<Action<S, E>> entryActions, Collection<Action<S, E>> exitActions,
|
||||
PseudoState pseudoState) {
|
||||
super(id, deferred, entryActions, exitActions, pseudoState);
|
||||
}
|
||||
@@ -96,7 +97,7 @@ public class EnumState<S extends Enum<S>, E extends Enum<E>> extends AbstractSim
|
||||
* @param pseudoState the pseudo state
|
||||
* @param regions the regions
|
||||
*/
|
||||
public EnumState(S id, Collection<E> deferred, Collection<Action> entryActions, Collection<Action> exitActions,
|
||||
public EnumState(S id, Collection<E> deferred, Collection<Action<S, E>> entryActions, Collection<Action<S, E>> exitActions,
|
||||
PseudoState pseudoState, Collection<Region<S, E>> regions) {
|
||||
super(id, deferred, entryActions, exitActions, pseudoState, regions);
|
||||
}
|
||||
@@ -111,11 +112,31 @@ public class EnumState<S extends Enum<S>, E extends Enum<E>> extends AbstractSim
|
||||
* @param pseudoState the pseudo state
|
||||
* @param submachine the submachine
|
||||
*/
|
||||
public EnumState(S id, Collection<E> deferred, Collection<Action> entryActions, Collection<Action> exitActions,
|
||||
public EnumState(S id, Collection<E> deferred, Collection<Action<S, E>> entryActions, Collection<Action<S, E>> exitActions,
|
||||
PseudoState pseudoState, StateMachine<S, E> submachine) {
|
||||
super(id, deferred, entryActions, exitActions, pseudoState, submachine);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exit(E event, StateContext<S, E> context) {
|
||||
Collection<Action<S, E>> actions = getExitActions();
|
||||
if (actions != null) {
|
||||
for (Action<S, E> action : actions) {
|
||||
action.execute(context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void entry(E event, StateContext<S, E> context) {
|
||||
Collection<Action<S, E>> actions = getEntryActions();
|
||||
if (actions != null) {
|
||||
for (Action<S, E> action : actions) {
|
||||
action.execute(context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "EnumState [getIds()=" + getIds() + ", getClass()=" + getClass() + ", hashCode()=" + hashCode()
|
||||
|
||||
@@ -18,12 +18,13 @@ package org.springframework.statemachine.state;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.springframework.statemachine.StateContext;
|
||||
import org.springframework.statemachine.action.Action;
|
||||
import org.springframework.statemachine.region.Region;
|
||||
|
||||
/**
|
||||
* A {@link State} implementation where states are wrapped in a regions..
|
||||
*
|
||||
*
|
||||
* @author Janne Valkealahti
|
||||
*
|
||||
* @param <S> the type of state
|
||||
@@ -59,7 +60,7 @@ public class RegionState<S, E> extends AbstractState<S, E> {
|
||||
public RegionState(Collection<Region<S, E>> regions, PseudoState pseudoState) {
|
||||
super(null, null, null, pseudoState, regions);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Instantiates a new region state.
|
||||
*
|
||||
@@ -69,7 +70,7 @@ public class RegionState<S, E> extends AbstractState<S, E> {
|
||||
* @param exitActions the exit actions
|
||||
* @param pseudoState the pseudo state
|
||||
*/
|
||||
public RegionState(Collection<Region<S, E>> regions, Collection<E> deferred, Collection<Action> entryActions, Collection<Action> exitActions,
|
||||
public RegionState(Collection<Region<S, E>> regions, Collection<E> deferred, Collection<Action<S, E>> entryActions, Collection<Action<S, E>> exitActions,
|
||||
PseudoState pseudoState) {
|
||||
super(deferred, entryActions, exitActions, pseudoState, regions);
|
||||
}
|
||||
@@ -82,10 +83,22 @@ public class RegionState<S, E> extends AbstractState<S, E> {
|
||||
* @param entryActions the entry actions
|
||||
* @param exitActions the exit actions
|
||||
*/
|
||||
public RegionState(Collection<Region<S, E>> regions, Collection<E> deferred, Collection<Action> entryActions, Collection<Action> exitActions) {
|
||||
public RegionState(Collection<Region<S, E>> regions, Collection<E> deferred, Collection<Action<S, E>> entryActions, Collection<Action<S, E>> exitActions) {
|
||||
super(deferred, entryActions, exitActions, null, regions);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exit(E event, StateContext<S, E> context) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
@Override
|
||||
public void entry(E event, StateContext<S, E> context) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Collection<S> getIds() {
|
||||
ArrayList<S> ids = new ArrayList<S>();
|
||||
@@ -94,5 +107,5 @@ public class RegionState<S, E> extends AbstractState<S, E> {
|
||||
}
|
||||
return ids;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -17,11 +17,12 @@ package org.springframework.statemachine.state;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.springframework.statemachine.StateContext;
|
||||
import org.springframework.statemachine.action.Action;
|
||||
|
||||
/**
|
||||
* {@code State} is an interface representing possible state in a state machine.
|
||||
*
|
||||
*
|
||||
* @author Janne Valkealahti
|
||||
*
|
||||
* @param <S> the type of state
|
||||
@@ -29,6 +30,22 @@ import org.springframework.statemachine.action.Action;
|
||||
*/
|
||||
public interface State<S, E> {
|
||||
|
||||
/**
|
||||
* Initiate an exit sequence for the state.
|
||||
*
|
||||
* @param event the event
|
||||
* @param context the context
|
||||
*/
|
||||
void exit(E event, StateContext<S, E> context);
|
||||
|
||||
/**
|
||||
* Initiate an entry sequence for the state.
|
||||
*
|
||||
* @param event the event
|
||||
* @param context the context
|
||||
*/
|
||||
void entry(E event, StateContext<S, E> context);
|
||||
|
||||
/**
|
||||
* Gets the state identifiers. Usually returned collection contains only one
|
||||
* identifier except in a case where state is an orthogonal.
|
||||
@@ -41,7 +58,7 @@ public interface State<S, E> {
|
||||
* Gets a {@link PseudoState} attached to a {@code State}.
|
||||
* {@link PseudoState} is not required and thus this method return
|
||||
* {@code NULL} if it's not set.
|
||||
*
|
||||
*
|
||||
* @return pseudostate or null if state doesn't have one
|
||||
*/
|
||||
PseudoState getPseudoState();
|
||||
@@ -52,20 +69,20 @@ public interface State<S, E> {
|
||||
* @return the state deferred events
|
||||
*/
|
||||
Collection<E> getDeferredEvents();
|
||||
|
||||
|
||||
/**
|
||||
* Gets {@link Action}s executed entering in this state.
|
||||
*
|
||||
* @return the state entry actions
|
||||
*/
|
||||
Collection<Action> getEntryActions();
|
||||
Collection<Action<S, E>> getEntryActions();
|
||||
|
||||
/**
|
||||
* Gets {@link Action}s executed exiting from this state.
|
||||
*
|
||||
* @return the state exit actions
|
||||
*/
|
||||
Collection<Action> getExitActions();
|
||||
Collection<Action<S, E>> getExitActions();
|
||||
|
||||
/**
|
||||
* Checks if state is a simple state. A simple state does not have any
|
||||
|
||||
@@ -16,13 +16,17 @@
|
||||
package org.springframework.statemachine.state;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
|
||||
import org.springframework.statemachine.StateContext;
|
||||
import org.springframework.statemachine.StateMachine;
|
||||
import org.springframework.statemachine.action.Action;
|
||||
import org.springframework.statemachine.transition.Transition;
|
||||
import org.springframework.statemachine.transition.TransitionKind;
|
||||
|
||||
/**
|
||||
* A {@link State} implementation where state is wrapped in a substatemachine.
|
||||
*
|
||||
*
|
||||
* @author Janne Valkealahti
|
||||
*
|
||||
* @param <S> the type of state
|
||||
@@ -58,7 +62,7 @@ public class StateMachineState<S, E> extends AbstractState<S, E> {
|
||||
public StateMachineState(StateMachine<S, E> submachine, PseudoState pseudoState) {
|
||||
super(null, null, null, pseudoState, submachine);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Instantiates a new state machine state.
|
||||
*
|
||||
@@ -68,7 +72,7 @@ public class StateMachineState<S, E> extends AbstractState<S, E> {
|
||||
* @param exitActions the exit actions
|
||||
* @param pseudoState the pseudo state
|
||||
*/
|
||||
public StateMachineState(StateMachine<S, E> submachine, Collection<E> deferred, Collection<Action> entryActions, Collection<Action> exitActions,
|
||||
public StateMachineState(StateMachine<S, E> submachine, Collection<E> deferred, Collection<Action<S, E>> entryActions, Collection<Action<S, E>> exitActions,
|
||||
PseudoState pseudoState) {
|
||||
super(deferred, entryActions, exitActions, pseudoState, submachine);
|
||||
}
|
||||
@@ -81,13 +85,60 @@ public class StateMachineState<S, E> extends AbstractState<S, E> {
|
||||
* @param entryActions the entry actions
|
||||
* @param exitActions the exit actions
|
||||
*/
|
||||
public StateMachineState(StateMachine<S, E> submachine, Collection<E> deferred, Collection<Action> entryActions, Collection<Action> exitActions) {
|
||||
public StateMachineState(StateMachine<S, E> submachine, Collection<E> deferred, Collection<Action<S, E>> entryActions, Collection<Action<S, E>> exitActions) {
|
||||
super(deferred, entryActions, exitActions, null, submachine);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<S> getIds() {
|
||||
return getSubmachine().getState().getIds();
|
||||
State<S, E> state = getSubmachine().getState();
|
||||
if (state != null) {
|
||||
return state.getIds();
|
||||
} else {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void exit(E event, StateContext<S, E> context) {
|
||||
getSubmachine().getState().exit(event, context);
|
||||
getSubmachine().stop();
|
||||
Collection<Action<S, E>> actions = getExitActions();
|
||||
if (actions != null && !isLocal(context)) {
|
||||
for (Action<S, E> action : actions) {
|
||||
action.execute(context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void entry(E event, StateContext<S, E> context) {
|
||||
Collection<Action<S, E>> actions = getEntryActions();
|
||||
if (actions != null && !isLocal(context)) {
|
||||
for (Action<S, E> action : actions) {
|
||||
action.execute(context);
|
||||
}
|
||||
}
|
||||
if (getPseudoState() != null && getPseudoState().getKind() == PseudoStateKind.INITIAL) {
|
||||
getSubmachine().start();
|
||||
} else {
|
||||
getSubmachine().getState().entry(event, context);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isLocal(StateContext<S, E> context) {
|
||||
Transition<S, E> transition = context.getTransition();
|
||||
if (transition != null && TransitionKind.LOCAL == transition.getKind() && this == transition.getTarget()) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "StateMachineState [getIds()=" + getIds() + ", getClass()=" + getClass() + ", hashCode()=" + hashCode()
|
||||
+ ", toString()=" + super.toString() + "]";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -38,7 +38,6 @@ import org.springframework.messaging.support.MessageBuilder;
|
||||
import org.springframework.statemachine.ExtendedState;
|
||||
import org.springframework.statemachine.StateContext;
|
||||
import org.springframework.statemachine.StateMachine;
|
||||
import org.springframework.statemachine.action.Action;
|
||||
import org.springframework.statemachine.annotation.OnTransition;
|
||||
import org.springframework.statemachine.event.StateMachineEventPublisher;
|
||||
import org.springframework.statemachine.listener.CompositeStateMachineListener;
|
||||
@@ -56,7 +55,7 @@ import org.springframework.util.Assert;
|
||||
/**
|
||||
* Base implementation of a {@link StateMachine} loosely modelled from UML state
|
||||
* machine.
|
||||
*
|
||||
*
|
||||
* @author Janne Valkealahti
|
||||
*
|
||||
* @param <S> the type of state
|
||||
@@ -73,7 +72,7 @@ public abstract class AbstractStateMachine<S, E> extends LifecycleObjectSupport
|
||||
private final State<S,E> initialState;
|
||||
|
||||
private final State<S,E> endState;
|
||||
|
||||
|
||||
private final Message<E> initialEvent;
|
||||
|
||||
private final ExtendedState extendedState;
|
||||
@@ -112,7 +111,7 @@ public abstract class AbstractStateMachine<S, E> extends LifecycleObjectSupport
|
||||
State<S, E> initialState, State<S, E> endState) {
|
||||
this(states, transitions, initialState, endState, null, null);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Instantiates a new abstract state machine.
|
||||
*
|
||||
@@ -179,7 +178,7 @@ public abstract class AbstractStateMachine<S, E> extends LifecycleObjectSupport
|
||||
@Override
|
||||
protected void onInit() throws Exception {
|
||||
super.onInit();
|
||||
Assert.notNull(initialState, "Initial state must be set");
|
||||
Assert.notNull(initialState, "Initial state must be set");
|
||||
Assert.state(initialState.getPseudoState() != null
|
||||
&& initialState.getPseudoState().getKind() == PseudoStateKind.INITIAL,
|
||||
"Initial state's pseudostate kind must be INITIAL");
|
||||
@@ -188,14 +187,20 @@ public abstract class AbstractStateMachine<S, E> extends LifecycleObjectSupport
|
||||
@Override
|
||||
protected void doStart() {
|
||||
super.doStart();
|
||||
switchToState(initialState, initialEvent);
|
||||
switchToState(initialState, initialEvent, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doStop() {
|
||||
super.doStop();
|
||||
currentState = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addStateListener(StateMachineListener<State<S, E>, E> listener) {
|
||||
stateListener.register(listener);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean isComplete() {
|
||||
return (endState != null && endState.equals(currentState));
|
||||
@@ -206,62 +211,55 @@ public abstract class AbstractStateMachine<S, E> extends LifecycleObjectSupport
|
||||
* an unmodifiable copy because states in a state machine are immutable.
|
||||
*
|
||||
* @return immutable copy of existing states
|
||||
*/
|
||||
*/
|
||||
@Override
|
||||
public Collection<State<S, E>> getStates() {
|
||||
return Collections.unmodifiableCollection(states);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Collection<Transition<S, E>> getTransitions() {
|
||||
return transitions;
|
||||
}
|
||||
|
||||
private void switchToState(State<S,E> state, Message<E> event) {
|
||||
log.info("Moving into state=" + state + " from " + currentState);
|
||||
|
||||
exitFromState(currentState, event);
|
||||
|
||||
private void switchToState(State<S,E> state, Message<E> event, Transition<S,E> transition) {
|
||||
exitFromState(currentState, event, transition);
|
||||
notifyStateChanged(currentState, state);
|
||||
|
||||
|
||||
callHandlers(currentState, state, event);
|
||||
|
||||
|
||||
currentState = state;
|
||||
entryToState(state, event);
|
||||
entryToState(state, event, transition);
|
||||
|
||||
for (Transition<S,E> transition : transitions) {
|
||||
State<S,E> source = transition.getSource();
|
||||
State<S,E> target = transition.getTarget();
|
||||
if (transition.getTrigger() == null && source.equals(currentState)) {
|
||||
switchToState(target, event);
|
||||
// TODO: should handle triggerles transition some how differently
|
||||
for (Transition<S,E> t : transitions) {
|
||||
State<S,E> source = t.getSource();
|
||||
State<S,E> target = t.getTarget();
|
||||
if (t.getTrigger() == null && source.equals(currentState)) {
|
||||
switchToState(target, event, t);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void exitFromState(State<S, E> state, Message<E> event) {
|
||||
private void exitFromState(State<S, E> state, Message<E> event, Transition<S, E> transition) {
|
||||
if (state != null) {
|
||||
log.trace("Exit state=[" + state + "]");
|
||||
MessageHeaders messageHeaders = event != null ? event.getHeaders() : new MessageHeaders(
|
||||
new HashMap<String, Object>());
|
||||
Collection<Action> actions = state.getExitActions();
|
||||
if (actions != null) {
|
||||
for (Action action : actions) {
|
||||
action.execute(new DefaultStateContext(messageHeaders, extendedState));
|
||||
}
|
||||
}
|
||||
StateContext<S, E> stateContext = new DefaultStateContext<S, E>(messageHeaders, extendedState, transition);
|
||||
state.exit(event != null ? event.getPayload() : null, stateContext);
|
||||
}
|
||||
}
|
||||
|
||||
private void entryToState(State<S,E> state, Message<E> event) {
|
||||
private void entryToState(State<S, E> state, Message<E> event, Transition<S, E> transition) {
|
||||
if (state != null) {
|
||||
log.trace("Enter state=[" + state + "]");
|
||||
MessageHeaders messageHeaders = event != null ? event.getHeaders() : new MessageHeaders(
|
||||
new HashMap<String, Object>());
|
||||
Collection<Action> actions = state.getEntryActions();
|
||||
if (actions != null) {
|
||||
for (Action action : actions) {
|
||||
action.execute(new DefaultStateContext(messageHeaders, extendedState));
|
||||
}
|
||||
}
|
||||
StateContext<S, E> stateContext = new DefaultStateContext<S, E>(messageHeaders, extendedState, transition);
|
||||
state.entry(event != null ? event.getPayload() : null, stateContext);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -274,11 +272,13 @@ public abstract class AbstractStateMachine<S, E> extends LifecycleObjectSupport
|
||||
State<S,E> source = transition.getSource();
|
||||
State<S,E> target = transition.getTarget();
|
||||
Trigger<S, E> trigger = transition.getTrigger();
|
||||
if (source.equals(currentState)) {
|
||||
|
||||
if (StateMachineUtils.containsAtleastOne(source.getIds(), currentState.getIds())) {
|
||||
if (trigger != null && trigger.evaluate(queuedEvent.getPayload())) {
|
||||
boolean transit = transition.transit(new DefaultStateContext(queuedEvent.getHeaders(), extendedState));
|
||||
StateContext<S, E> stateContext = new DefaultStateContext<S, E>(queuedEvent.getHeaders(), extendedState, transition);
|
||||
boolean transit = transition.transit(stateContext);
|
||||
if (transit && transition.getKind() != TransitionKind.INTERNAL) {
|
||||
switchToState(target, queuedEvent);
|
||||
switchToState(target, queuedEvent, transition);
|
||||
}
|
||||
break;
|
||||
} else if (source.getDeferredEvents() != null && source.getDeferredEvents().contains(queuedEvent.getPayload())) {
|
||||
@@ -304,9 +304,10 @@ public abstract class AbstractStateMachine<S, E> extends LifecycleObjectSupport
|
||||
Trigger<S, E> trigger = transition.getTrigger();
|
||||
if (source.equals(currentState)) {
|
||||
if (trigger != null && trigger.evaluate(event.getPayload())) {
|
||||
boolean transit = transition.transit(new DefaultStateContext(event.getHeaders(), extendedState));
|
||||
StateContext<S, E> stateContext = new DefaultStateContext<S, E>(event.getHeaders(), extendedState, transition);
|
||||
boolean transit = transition.transit(stateContext);
|
||||
if (transit && transition.getKind() != TransitionKind.INTERNAL) {
|
||||
switchToState(target, event);
|
||||
switchToState(target, event, transition);
|
||||
}
|
||||
iterator.remove();
|
||||
}
|
||||
@@ -333,16 +334,16 @@ public abstract class AbstractStateMachine<S, E> extends LifecycleObjectSupport
|
||||
if (sourceState != null && targetState != null) {
|
||||
MessageHeaders messageHeaders = event != null ? event.getHeaders() : new MessageHeaders(
|
||||
new HashMap<String, Object>());
|
||||
StateContext stateContext = new DefaultStateContext(messageHeaders, extendedState);
|
||||
StateContext<S, E> stateContext = new DefaultStateContext<S, E>(messageHeaders, extendedState, null);
|
||||
getStateMachineHandlerResults(getStateMachineHandlers(sourceState, targetState), stateContext);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
private List<Object> getStateMachineHandlerResults(List<StateMachineHandler> stateMachineHandlers, final StateContext stateContext) {
|
||||
StateMachineRuntime runtime = new StateMachineRuntime() {
|
||||
private List<Object> getStateMachineHandlerResults(List<StateMachineHandler> stateMachineHandlers, final StateContext<S, E> stateContext) {
|
||||
StateMachineRuntime runtime = new StateMachineRuntime() {
|
||||
@Override
|
||||
public StateContext getStateContext() {
|
||||
public StateContext<S, E> getStateContext() {
|
||||
return stateContext;
|
||||
}
|
||||
};
|
||||
@@ -353,9 +354,9 @@ public abstract class AbstractStateMachine<S, E> extends LifecycleObjectSupport
|
||||
return results;
|
||||
}
|
||||
|
||||
private List<StateMachineHandler> getStateMachineHandlers(State<S,E> sourceState, State<S,E> targetState) {
|
||||
private List<StateMachineHandler> getStateMachineHandlers(State<S, E> sourceState, State<S, E> targetState) {
|
||||
BeanFactory beanFactory = getBeanFactory();
|
||||
|
||||
|
||||
// TODO think how to handle null bf
|
||||
if (beanFactory == null) {
|
||||
return Collections.emptyList();
|
||||
@@ -376,11 +377,11 @@ public abstract class AbstractStateMachine<S, E> extends LifecycleObjectSupport
|
||||
handlersList.add(entry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
OrderComparator comparator = new OrderComparator();
|
||||
Collections.sort(handlersList, comparator);
|
||||
return handlersList;
|
||||
}
|
||||
}
|
||||
|
||||
private void notifyStateChanged(State<S,E> source, State<S,E> target) {
|
||||
stateListener.stateChanged(source, target);
|
||||
@@ -389,5 +390,5 @@ public abstract class AbstractStateMachine<S, E> extends LifecycleObjectSupport
|
||||
eventPublisher.publishStateChanged(this, source, target);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -18,16 +18,20 @@ package org.springframework.statemachine.support;
|
||||
import org.springframework.messaging.MessageHeaders;
|
||||
import org.springframework.statemachine.ExtendedState;
|
||||
import org.springframework.statemachine.StateContext;
|
||||
import org.springframework.statemachine.transition.Transition;
|
||||
|
||||
public class DefaultStateContext implements StateContext {
|
||||
public class DefaultStateContext<S, E> implements StateContext<S, E> {
|
||||
|
||||
private final MessageHeaders messageHeaders;
|
||||
|
||||
private final ExtendedState extendedState;
|
||||
|
||||
private final Transition<S,E> transition;
|
||||
|
||||
public DefaultStateContext(MessageHeaders messageHeaders, ExtendedState extendedState) {
|
||||
public DefaultStateContext(MessageHeaders messageHeaders, ExtendedState extendedState, Transition<S,E> transition) {
|
||||
this.messageHeaders = messageHeaders;
|
||||
this.extendedState = extendedState;
|
||||
this.transition = transition;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -39,5 +43,10 @@ public class DefaultStateContext implements StateContext {
|
||||
public ExtendedState getExtendedState() {
|
||||
return extendedState;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Transition<S, E> getTransition() {
|
||||
return transition;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* 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.support;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* Various utility methods for state machine.
|
||||
*
|
||||
* @author Janne Valkealahti
|
||||
*
|
||||
*/
|
||||
public abstract class StateMachineUtils {
|
||||
|
||||
/**
|
||||
* Checks if right hand collection has atleast one same item as left hand
|
||||
* collection.
|
||||
*
|
||||
* @param <S> the generic type
|
||||
* @param left the left collection
|
||||
* @param right the right collection
|
||||
* @return true, right contains at least one item from left, false otherwise.
|
||||
*/
|
||||
public static <S> boolean containsAtleastOne(Collection<S> left, Collection<S> right) {
|
||||
if (left == null || right == null) {
|
||||
return false;
|
||||
}
|
||||
for (S id : left) {
|
||||
if (right.contains(id)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -23,7 +23,7 @@ import org.springframework.statemachine.state.State;
|
||||
|
||||
public abstract class AbstractExternalTransition<S, E> extends AbstractTransition<S, E> implements Transition<S, E> {
|
||||
|
||||
public AbstractExternalTransition(State<S,E> source, State<S,E> target, Collection<Action> actions, E event, Guard guard) {
|
||||
public AbstractExternalTransition(State<S,E> source, State<S,E> target, Collection<Action<S, E>> actions, E event, Guard<S, E> guard) {
|
||||
super(source, target, actions, event, TransitionKind.EXTERNAL, guard);
|
||||
}
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ import org.springframework.statemachine.state.State;
|
||||
|
||||
public class AbstractInternalTransition <S, E> extends AbstractTransition<S, E> implements Transition<S, E> {
|
||||
|
||||
public AbstractInternalTransition(State<S, E> source,Collection<Action> actions, E event, Guard guard) {
|
||||
public AbstractInternalTransition(State<S, E> source,Collection<Action<S, E>> actions, E event, Guard<S, E> guard) {
|
||||
super(source, source, actions, event, TransitionKind.INTERNAL, guard);
|
||||
}
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ import org.springframework.statemachine.state.State;
|
||||
|
||||
public class AbstractLocalTransition <S, E> extends AbstractTransition<S, E> implements Transition<S, E> {
|
||||
|
||||
public AbstractLocalTransition(State<S, E> source, State<S,E> target,Collection<Action> actions, E event, Guard guard) {
|
||||
public AbstractLocalTransition(State<S, E> source, State<S,E> target,Collection<Action<S, E>> actions, E event, Guard<S, E> guard) {
|
||||
super(source, target, actions, event, TransitionKind.LOCAL, guard);
|
||||
}
|
||||
|
||||
|
||||
@@ -39,16 +39,16 @@ public abstract class AbstractTransition<S, E> implements Transition<S, E> {
|
||||
|
||||
private final State<S,E> target;
|
||||
|
||||
private final Collection<Action> actions;
|
||||
private final Collection<Action<S, E>> actions;
|
||||
|
||||
private final TransitionKind kind;
|
||||
|
||||
private final Guard guard;
|
||||
private final Guard<S, E> guard;
|
||||
|
||||
private Trigger<S, E> trigger;
|
||||
|
||||
public AbstractTransition(State<S, E> source, State<S, E> target, Collection<Action> actions, E event,
|
||||
TransitionKind kind, Guard guard) {
|
||||
public AbstractTransition(State<S, E> source, State<S, E> target, Collection<Action<S, E>> actions, E event,
|
||||
TransitionKind kind, Guard<S, E> guard) {
|
||||
Assert.notNull(source, "Source must be set");
|
||||
// Assert.notNull(target, "Target must be set");
|
||||
Assert.notNull(kind, "Transition type must be set");
|
||||
@@ -73,7 +73,7 @@ public abstract class AbstractTransition<S, E> implements Transition<S, E> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Action> getActions() {
|
||||
public Collection<Action<S, E>> getActions() {
|
||||
return actions;
|
||||
}
|
||||
|
||||
@@ -83,14 +83,14 @@ public abstract class AbstractTransition<S, E> implements Transition<S, E> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean transit(StateContext context) {
|
||||
public boolean transit(StateContext<S, E> context) {
|
||||
if (guard != null) {
|
||||
if (!guard.evaluate(context)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (actions != null) {
|
||||
for (Action action : actions) {
|
||||
for (Action<S, E> action : actions) {
|
||||
action.execute(context);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ import org.springframework.statemachine.state.State;
|
||||
|
||||
public class DefaultExternalTransition<S, E> extends AbstractExternalTransition<S, E> {
|
||||
|
||||
public DefaultExternalTransition(State<S,E> source, State<S,E> target, Collection<Action> actions, E event, Guard guard) {
|
||||
public DefaultExternalTransition(State<S,E> source, State<S,E> target, Collection<Action<S, E>> actions, E event, Guard<S, E> guard) {
|
||||
super(source, target, actions, event, guard);
|
||||
}
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ import org.springframework.statemachine.state.State;
|
||||
|
||||
public class DefaultInternalTransition<S, E> extends AbstractInternalTransition<S, E> {
|
||||
|
||||
public DefaultInternalTransition(State<S, E> source, Collection<Action> actions, E event, Guard guard) {
|
||||
public DefaultInternalTransition(State<S, E> source, Collection<Action<S, E>> actions, E event, Guard<S, E> guard) {
|
||||
super(source, actions, event, guard);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* 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.transition;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.springframework.statemachine.action.Action;
|
||||
import org.springframework.statemachine.guard.Guard;
|
||||
import org.springframework.statemachine.state.State;
|
||||
|
||||
public class DefaultLocalTransition<S, E> extends AbstractLocalTransition<S, E> {
|
||||
|
||||
public DefaultLocalTransition(State<S,E> source, State<S,E> target, Collection<Action<S, E>> actions, E event, Guard<S, E> guard) {
|
||||
super(source, target, actions, event, guard);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "DefaultLocalTransition [getSource()=" + getSource() + ", getTarget()=" + getTarget() + "]";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -39,7 +39,7 @@ public interface Transition<S, E> {
|
||||
* @param context the state context
|
||||
* @return true, if transition happened, false otherwise
|
||||
*/
|
||||
boolean transit(StateContext context);
|
||||
boolean transit(StateContext<S, E> context);
|
||||
|
||||
/**
|
||||
* Gets the source state of this transition.
|
||||
@@ -60,7 +60,7 @@ public interface Transition<S, E> {
|
||||
*
|
||||
* @return the transition actions
|
||||
*/
|
||||
Collection<Action> getActions();
|
||||
Collection<Action<S, E>> getActions();
|
||||
|
||||
/**
|
||||
* Gets the transition trigger.
|
||||
|
||||
@@ -15,8 +15,12 @@
|
||||
*/
|
||||
package org.springframework.statemachine;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
@@ -30,46 +34,41 @@ import org.springframework.statemachine.guard.Guard;
|
||||
|
||||
/**
|
||||
* Base class for stace machine tests.
|
||||
*
|
||||
*
|
||||
* @author Janne Valkealahti
|
||||
*
|
||||
*/
|
||||
public abstract class AbstractStateMachineTests {
|
||||
|
||||
private final static Log log = LogFactory.getLog(AbstractStateMachineTests.class);
|
||||
|
||||
protected AnnotationConfigApplicationContext context;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
context = buildContext();
|
||||
}
|
||||
|
||||
|
||||
@After
|
||||
public void clean() {
|
||||
if (context != null) {
|
||||
context.close();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected AnnotationConfigApplicationContext buildContext() {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public enum TestStates {
|
||||
SI,S1,S2,S3,S4,SF
|
||||
SI,S1,S2,S3,S4,SF,
|
||||
S11,S111,S21,S211
|
||||
}
|
||||
|
||||
public enum TestSubStates {
|
||||
SUBSI,SUBS1,SUBS2,SUBS3,SUBS4
|
||||
}
|
||||
|
||||
public enum TestEvents {
|
||||
E1,E2,E3,E4,EF
|
||||
}
|
||||
|
||||
public enum TestSubEvents {
|
||||
SUBE1,SUBE2,SUBE3,SUBE4
|
||||
}
|
||||
|
||||
@Configuration
|
||||
public static class BaseConfig {
|
||||
|
||||
@@ -77,46 +76,86 @@ public abstract class AbstractStateMachineTests {
|
||||
public TaskExecutor taskExecutor() {
|
||||
return new SyncTaskExecutor();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
public static class TestEntryAction extends AbstractTestAction {
|
||||
|
||||
public TestEntryAction() {
|
||||
super();
|
||||
}
|
||||
|
||||
public TestEntryAction(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "TestEntryAction [message=" + message + "]";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class TestExitAction extends AbstractTestAction {
|
||||
|
||||
public TestExitAction() {
|
||||
super();
|
||||
}
|
||||
|
||||
public TestExitAction(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "TestExitAction [message=" + message + "]";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class TestAction extends AbstractTestAction {
|
||||
}
|
||||
|
||||
public static class TestGuard implements Guard {
|
||||
|
||||
|
||||
public static class TestGuard implements Guard<TestStates, TestEvents> {
|
||||
|
||||
public CountDownLatch onEvaluateLatch = new CountDownLatch(1);
|
||||
|
||||
boolean evaluationResult = true;
|
||||
|
||||
public TestGuard() {
|
||||
}
|
||||
|
||||
|
||||
public TestGuard(boolean evaluationResult) {
|
||||
this.evaluationResult = evaluationResult;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean evaluate(StateContext context) {
|
||||
public boolean evaluate(StateContext<TestStates, TestEvents> context) {
|
||||
onEvaluateLatch.countDown();
|
||||
return evaluationResult;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected static class AbstractTestAction implements Action {
|
||||
protected static class AbstractTestAction implements Action<TestStates, TestEvents> {
|
||||
|
||||
protected String message = null;
|
||||
public CountDownLatch onExecuteLatch = new CountDownLatch(1);
|
||||
|
||||
public List<StateContext<TestStates, TestEvents>> stateContexts = new ArrayList<StateContext<TestStates, TestEvents>>();
|
||||
|
||||
public AbstractTestAction() {
|
||||
}
|
||||
|
||||
public AbstractTestAction(String message) {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(StateContext context) {
|
||||
public void execute(StateContext<TestStates, TestEvents> context) {
|
||||
if (message != null) {
|
||||
log.info(this);
|
||||
}
|
||||
onExecuteLatch.countDown();
|
||||
stateContexts.add(context);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -26,8 +26,6 @@ import org.apache.commons.logging.LogFactory;
|
||||
import org.junit.Test;
|
||||
import org.springframework.core.task.SyncTaskExecutor;
|
||||
import org.springframework.messaging.support.MessageBuilder;
|
||||
import org.springframework.statemachine.EnumStateMachine;
|
||||
import org.springframework.statemachine.StateContext;
|
||||
import org.springframework.statemachine.action.Action;
|
||||
import org.springframework.statemachine.state.EnumState;
|
||||
import org.springframework.statemachine.state.State;
|
||||
@@ -53,17 +51,17 @@ public class EnumStateMachineTests extends AbstractStateMachineTests {
|
||||
|
||||
Collection<Transition<TestStates,TestEvents>> transitions = new ArrayList<Transition<TestStates,TestEvents>>();
|
||||
|
||||
Collection<Action> actionsFromSIToS1 = new ArrayList<Action>();
|
||||
Collection<Action<TestStates,TestEvents>> actionsFromSIToS1 = new ArrayList<Action<TestStates,TestEvents>>();
|
||||
actionsFromSIToS1.add(new LoggingAction("actionsFromSIToS1"));
|
||||
DefaultExternalTransition<TestStates,TestEvents> transitionFromSIToS1 =
|
||||
new DefaultExternalTransition<TestStates,TestEvents>(stateSI, stateS1, actionsFromSIToS1, TestEvents.E1, null);
|
||||
|
||||
Collection<Action> actionsFromS1ToS2 = new ArrayList<Action>();
|
||||
Collection<Action<TestStates,TestEvents>> actionsFromS1ToS2 = new ArrayList<Action<TestStates,TestEvents>>();
|
||||
actionsFromS1ToS2.add(new LoggingAction("actionsFromS1ToS2"));
|
||||
DefaultExternalTransition<TestStates,TestEvents> transitionFromS1ToS2 =
|
||||
new DefaultExternalTransition<TestStates,TestEvents>(stateS1, stateS2, actionsFromS1ToS2, TestEvents.E2, null);
|
||||
|
||||
Collection<Action> actionsFromS2ToS3 = new ArrayList<Action>();
|
||||
Collection<Action<TestStates,TestEvents>> actionsFromS2ToS3 = new ArrayList<Action<TestStates,TestEvents>>();
|
||||
actionsFromS1ToS2.add(new LoggingAction("actionsFromS2ToS3"));
|
||||
DefaultExternalTransition<TestStates,TestEvents> transitionFromS2ToS3 =
|
||||
new DefaultExternalTransition<TestStates,TestEvents>(stateS2, stateS3, actionsFromS2ToS3, TestEvents.E3, null);
|
||||
@@ -123,17 +121,17 @@ public class EnumStateMachineTests extends AbstractStateMachineTests {
|
||||
// transitions
|
||||
Collection<Transition<TestStates,TestEvents>> transitions = new ArrayList<Transition<TestStates,TestEvents>>();
|
||||
|
||||
Collection<Action> actionsFromSIToS1 = new ArrayList<Action>();
|
||||
Collection<Action<TestStates,TestEvents>> actionsFromSIToS1 = new ArrayList<Action<TestStates,TestEvents>>();
|
||||
actionsFromSIToS1.add(new LoggingAction("actionsFromSIToS1"));
|
||||
DefaultExternalTransition<TestStates,TestEvents> transitionFromSIToS1 =
|
||||
new DefaultExternalTransition<TestStates,TestEvents>(stateSI, stateS1, actionsFromSIToS1, TestEvents.E1, null);
|
||||
|
||||
Collection<Action> actionsFromS1ToS2 = new ArrayList<Action>();
|
||||
Collection<Action<TestStates,TestEvents>> actionsFromS1ToS2 = new ArrayList<Action<TestStates,TestEvents>>();
|
||||
actionsFromS1ToS2.add(new LoggingAction("actionsFromS1ToS2"));
|
||||
DefaultExternalTransition<TestStates,TestEvents> transitionFromS1ToS2 =
|
||||
new DefaultExternalTransition<TestStates,TestEvents>(stateS1, stateS2, actionsFromS1ToS2, TestEvents.E2, null);
|
||||
|
||||
Collection<Action> actionsFromS2ToS3 = new ArrayList<Action>();
|
||||
Collection<Action<TestStates,TestEvents>> actionsFromS2ToS3 = new ArrayList<Action<TestStates,TestEvents>>();
|
||||
actionsFromS1ToS2.add(new LoggingAction("actionsFromS2ToS3"));
|
||||
DefaultExternalTransition<TestStates,TestEvents> transitionFromS2ToS3 =
|
||||
new DefaultExternalTransition<TestStates,TestEvents>(stateS2, stateS3, actionsFromS2ToS3, TestEvents.E3, null);
|
||||
@@ -174,7 +172,7 @@ public class EnumStateMachineTests extends AbstractStateMachineTests {
|
||||
Collection<State<TestStates,TestEvents>> states = new ArrayList<State<TestStates,TestEvents>>();
|
||||
states.add(stateSI);
|
||||
|
||||
Collection<Action> actionsInSI = new ArrayList<Action>();
|
||||
Collection<Action<TestStates,TestEvents>> actionsInSI = new ArrayList<Action<TestStates,TestEvents>>();
|
||||
actionsInSI.add(new LoggingAction("actionsInSI"));
|
||||
DefaultInternalTransition<TestStates,TestEvents> transitionInternalSI =
|
||||
new DefaultInternalTransition<TestStates,TestEvents>(stateSI, actionsInSI, TestEvents.E1, null);
|
||||
@@ -191,7 +189,7 @@ public class EnumStateMachineTests extends AbstractStateMachineTests {
|
||||
machine.sendEvent(MessageBuilder.withPayload(TestEvents.E1).build());
|
||||
}
|
||||
|
||||
private static class LoggingAction implements Action {
|
||||
private static class LoggingAction implements Action<TestStates, TestEvents> {
|
||||
|
||||
private static final Log log = LogFactory.getLog(LoggingAction.class);
|
||||
|
||||
@@ -202,7 +200,7 @@ public class EnumStateMachineTests extends AbstractStateMachineTests {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(StateContext context) {
|
||||
public void execute(StateContext<TestStates, TestEvents> context) {
|
||||
log.info("Hello from LoggingAction " + message);
|
||||
}
|
||||
|
||||
|
||||
@@ -28,9 +28,6 @@ import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.task.SyncTaskExecutor;
|
||||
import org.springframework.core.task.TaskExecutor;
|
||||
import org.springframework.messaging.support.MessageBuilder;
|
||||
import org.springframework.statemachine.EnumStateMachine;
|
||||
import org.springframework.statemachine.StateContext;
|
||||
import org.springframework.statemachine.StateMachineSystemConstants;
|
||||
import org.springframework.statemachine.action.Action;
|
||||
import org.springframework.statemachine.config.EnableStateMachine;
|
||||
import org.springframework.statemachine.config.EnumStateMachineConfigurerAdapter;
|
||||
@@ -53,7 +50,7 @@ public class StateMachineTests extends AbstractStateMachineTests {
|
||||
ctx.close();
|
||||
}
|
||||
|
||||
private static class LoggingAction implements Action {
|
||||
private static class LoggingAction implements Action<TestStates, TestEvents> {
|
||||
|
||||
private static final Log log = LogFactory.getLog(StateMachineTests.LoggingAction.class);
|
||||
|
||||
@@ -64,7 +61,7 @@ public class StateMachineTests extends AbstractStateMachineTests {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(StateContext context) {
|
||||
public void execute(StateContext<TestStates, TestEvents> context) {
|
||||
log.info("Hello from LoggingAction " + message + " foo=" + context.getMessageHeaders().get("foo"));
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,234 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.core.task.SyncTaskExecutor;
|
||||
import org.springframework.statemachine.action.Action;
|
||||
import org.springframework.statemachine.state.DefaultPseudoState;
|
||||
import org.springframework.statemachine.state.EnumState;
|
||||
import org.springframework.statemachine.state.PseudoState;
|
||||
import org.springframework.statemachine.state.PseudoStateKind;
|
||||
import org.springframework.statemachine.state.State;
|
||||
import org.springframework.statemachine.state.StateMachineState;
|
||||
import org.springframework.statemachine.transition.DefaultExternalTransition;
|
||||
import org.springframework.statemachine.transition.DefaultLocalTransition;
|
||||
import org.springframework.statemachine.transition.Transition;
|
||||
|
||||
public class SubStateMachineTests extends AbstractStateMachineTests {
|
||||
|
||||
@Test
|
||||
public void testExternalTransition() throws Exception {
|
||||
/**
|
||||
* +-------------------------------------------+
|
||||
* *-init->| S1 |
|
||||
* +-------------------------------------------+
|
||||
* | entry/ |
|
||||
* | exit/ |
|
||||
* | +--------------------------+ |
|
||||
* | *-->| S11 | |
|
||||
* | +--------------------------+ |
|
||||
* | | entry/ | |
|
||||
* | | exit/ | |
|
||||
* | | +-----------+ | |
|
||||
* | | *-->| S111 | | |
|
||||
* | | +-----------+ | |
|
||||
* | | | entry/ | | |
|
||||
* |<----E1-----------| exit/ | | |
|
||||
* | | | | | |
|
||||
* | | +-----------+ | |
|
||||
* | | | |
|
||||
* | +--------------------------+ |
|
||||
* | |
|
||||
* +-------------------------------------------+
|
||||
*/
|
||||
PseudoState pseudoState = new DefaultPseudoState(PseudoStateKind.INITIAL);
|
||||
|
||||
TestEntryAction entryActionS111 = new TestEntryAction("S111");
|
||||
TestExitAction exitActionS111 = new TestExitAction("S111");
|
||||
Collection<Action<TestStates, TestEvents>> entryActionsS111 = new ArrayList<Action<TestStates, TestEvents>>();
|
||||
entryActionsS111.add(entryActionS111);
|
||||
Collection<Action<TestStates, TestEvents>> exitActionsS111 = new ArrayList<Action<TestStates, TestEvents>>();
|
||||
exitActionsS111.add(exitActionS111);
|
||||
State<TestStates,TestEvents> stateS111 = new EnumState<TestStates,TestEvents>(TestStates.S111, null, entryActionsS111, exitActionsS111, pseudoState);
|
||||
|
||||
// submachine 11
|
||||
Collection<State<TestStates,TestEvents>> substates111 = new ArrayList<State<TestStates,TestEvents>>();
|
||||
substates111.add(stateS111);
|
||||
Collection<Transition<TestStates,TestEvents>> subtransitions111 = new ArrayList<Transition<TestStates,TestEvents>>();
|
||||
EnumStateMachine<TestStates, TestEvents> submachine11 = new EnumStateMachine<TestStates, TestEvents>(substates111, subtransitions111, stateS111, null);
|
||||
|
||||
// submachine 1
|
||||
TestEntryAction entryActionS11 = new TestEntryAction("S11");
|
||||
TestExitAction exitActionS11 = new TestExitAction("S11");
|
||||
Collection<Action<TestStates, TestEvents>> entryActionsS11 = new ArrayList<Action<TestStates, TestEvents>>();
|
||||
entryActionsS11.add(entryActionS11);
|
||||
Collection<Action<TestStates, TestEvents>> exitActionsS11 = new ArrayList<Action<TestStates, TestEvents>>();
|
||||
exitActionsS11.add(exitActionS11);
|
||||
StateMachineState<TestStates,TestEvents> stateS11 = new StateMachineState<TestStates,TestEvents>(submachine11, null, entryActionsS11, exitActionsS11, pseudoState);
|
||||
|
||||
Collection<State<TestStates,TestEvents>> substates11 = new ArrayList<State<TestStates,TestEvents>>();
|
||||
substates11.add(stateS11);
|
||||
Collection<Transition<TestStates,TestEvents>> subtransitions11 = new ArrayList<Transition<TestStates,TestEvents>>();
|
||||
EnumStateMachine<TestStates, TestEvents> submachine1 = new EnumStateMachine<TestStates, TestEvents>(substates11, subtransitions11, stateS11, null);
|
||||
|
||||
// machine
|
||||
TestEntryAction entryActionS1 = new TestEntryAction("S1");
|
||||
TestExitAction exitActionS1 = new TestExitAction("S1");
|
||||
Collection<Action<TestStates, TestEvents>> entryActionsS1 = new ArrayList<Action<TestStates, TestEvents>>();
|
||||
entryActionsS1.add(entryActionS1);
|
||||
Collection<Action<TestStates, TestEvents>> exitActionsS1 = new ArrayList<Action<TestStates, TestEvents>>();
|
||||
exitActionsS1.add(exitActionS1);
|
||||
|
||||
StateMachineState<TestStates,TestEvents> stateS1 = new StateMachineState<TestStates,TestEvents>(submachine1, null, entryActionsS1, exitActionsS1, pseudoState);
|
||||
Collection<State<TestStates,TestEvents>> states = new ArrayList<State<TestStates,TestEvents>>();
|
||||
states.add(stateS1);
|
||||
Collection<Transition<TestStates,TestEvents>> transitions = new ArrayList<Transition<TestStates,TestEvents>>();
|
||||
DefaultExternalTransition<TestStates,TestEvents> transitionFromS11ToS1 =
|
||||
new DefaultExternalTransition<TestStates,TestEvents>(stateS111, stateS1, null, TestEvents.E1, null);
|
||||
transitions.add(transitionFromS11ToS1);
|
||||
EnumStateMachine<TestStates, TestEvents> machine = new EnumStateMachine<TestStates, TestEvents>(states, transitions, stateS1, null);
|
||||
|
||||
|
||||
SyncTaskExecutor taskExecutor = new SyncTaskExecutor();
|
||||
machine.setTaskExecutor(taskExecutor);
|
||||
machine.afterPropertiesSet();
|
||||
machine.start();
|
||||
submachine1.setTaskExecutor(taskExecutor);
|
||||
submachine11.setTaskExecutor(taskExecutor);
|
||||
|
||||
machine.sendEvent(TestEvents.E1);
|
||||
|
||||
assertThat(entryActionS111.onExecuteLatch.await(1, TimeUnit.SECONDS), is(true));
|
||||
assertThat(exitActionS111.onExecuteLatch.await(1, TimeUnit.SECONDS), is(true));
|
||||
assertThat(entryActionS11.onExecuteLatch.await(1, TimeUnit.SECONDS), is(true));
|
||||
assertThat(exitActionS11.onExecuteLatch.await(1, TimeUnit.SECONDS), is(true));
|
||||
assertThat(entryActionS1.onExecuteLatch.await(1, TimeUnit.SECONDS), is(true));
|
||||
assertThat(exitActionS1.onExecuteLatch.await(1, TimeUnit.SECONDS), is(true));
|
||||
|
||||
assertThat(entryActionS11.stateContexts.size(), is(2));
|
||||
assertThat(exitActionS11.stateContexts.size(), is(1));
|
||||
assertThat(entryActionS11.stateContexts.size(), is(2));
|
||||
assertThat(exitActionS11.stateContexts.size(), is(1));
|
||||
assertThat(entryActionS1.stateContexts.size(), is(2));
|
||||
assertThat(exitActionS1.stateContexts.size(), is(1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLocalTransition() throws Exception {
|
||||
/**
|
||||
* +-------------------------------------------+
|
||||
* *-init->| S1 |
|
||||
* +-------------------------------------------+
|
||||
* | entry/ |
|
||||
* | exit/ |
|
||||
* | +--------------------------+ |
|
||||
* | *-->| S11 | |
|
||||
* | +--------------------------+ |
|
||||
* | | entry/ | |
|
||||
* | | exit/ | |
|
||||
* | | +-----------+ | |
|
||||
* | | *-->| S111 | | |
|
||||
* | | +-----------+ | |
|
||||
* | | | entry/ | | |
|
||||
* |<----E1-----------| exit/ | | |
|
||||
* | | | | | |
|
||||
* | | +-----------+ | |
|
||||
* | | | |
|
||||
* | +--------------------------+ |
|
||||
* | |
|
||||
* +-------------------------------------------+
|
||||
*/
|
||||
PseudoState pseudoState = new DefaultPseudoState(PseudoStateKind.INITIAL);
|
||||
|
||||
TestEntryAction entryActionS111 = new TestEntryAction("S111");
|
||||
TestExitAction exitActionS111 = new TestExitAction("S111");
|
||||
Collection<Action<TestStates, TestEvents>> entryActionsS111 = new ArrayList<Action<TestStates, TestEvents>>();
|
||||
entryActionsS111.add(entryActionS111);
|
||||
Collection<Action<TestStates, TestEvents>> exitActionsS111 = new ArrayList<Action<TestStates, TestEvents>>();
|
||||
exitActionsS111.add(exitActionS111);
|
||||
State<TestStates,TestEvents> stateS111 = new EnumState<TestStates,TestEvents>(TestStates.S111, null, entryActionsS111, exitActionsS111, pseudoState);
|
||||
|
||||
// submachine 11
|
||||
Collection<State<TestStates,TestEvents>> substates111 = new ArrayList<State<TestStates,TestEvents>>();
|
||||
substates111.add(stateS111);
|
||||
Collection<Transition<TestStates,TestEvents>> subtransitions111 = new ArrayList<Transition<TestStates,TestEvents>>();
|
||||
EnumStateMachine<TestStates, TestEvents> submachine11 = new EnumStateMachine<TestStates, TestEvents>(substates111, subtransitions111, stateS111, null);
|
||||
|
||||
// submachine 1
|
||||
TestEntryAction entryActionS11 = new TestEntryAction("S11");
|
||||
TestExitAction exitActionS11 = new TestExitAction("S11");
|
||||
Collection<Action<TestStates, TestEvents>> entryActionsS11 = new ArrayList<Action<TestStates, TestEvents>>();
|
||||
entryActionsS11.add(entryActionS11);
|
||||
Collection<Action<TestStates, TestEvents>> exitActionsS11 = new ArrayList<Action<TestStates, TestEvents>>();
|
||||
exitActionsS11.add(exitActionS11);
|
||||
StateMachineState<TestStates,TestEvents> stateS11 = new StateMachineState<TestStates,TestEvents>(submachine11, null, entryActionsS11, exitActionsS11, pseudoState);
|
||||
|
||||
Collection<State<TestStates,TestEvents>> substates11 = new ArrayList<State<TestStates,TestEvents>>();
|
||||
substates11.add(stateS11);
|
||||
Collection<Transition<TestStates,TestEvents>> subtransitions11 = new ArrayList<Transition<TestStates,TestEvents>>();
|
||||
EnumStateMachine<TestStates, TestEvents> submachine1 = new EnumStateMachine<TestStates, TestEvents>(substates11, subtransitions11, stateS11, null);
|
||||
|
||||
// machine
|
||||
TestEntryAction entryActionS1 = new TestEntryAction("S1");
|
||||
TestExitAction exitActionS1 = new TestExitAction("S1");
|
||||
Collection<Action<TestStates, TestEvents>> entryActionsS1 = new ArrayList<Action<TestStates, TestEvents>>();
|
||||
entryActionsS1.add(entryActionS1);
|
||||
Collection<Action<TestStates, TestEvents>> exitActionsS1 = new ArrayList<Action<TestStates, TestEvents>>();
|
||||
exitActionsS1.add(exitActionS1);
|
||||
|
||||
StateMachineState<TestStates,TestEvents> stateS1 = new StateMachineState<TestStates,TestEvents>(submachine1, null, entryActionsS1, exitActionsS1, pseudoState);
|
||||
Collection<State<TestStates,TestEvents>> states = new ArrayList<State<TestStates,TestEvents>>();
|
||||
states.add(stateS1);
|
||||
Collection<Transition<TestStates,TestEvents>> transitions = new ArrayList<Transition<TestStates,TestEvents>>();
|
||||
DefaultLocalTransition<TestStates,TestEvents> transitionFromS11ToS1 =
|
||||
new DefaultLocalTransition<TestStates,TestEvents>(stateS111, stateS1, null, TestEvents.E1, null);
|
||||
transitions.add(transitionFromS11ToS1);
|
||||
EnumStateMachine<TestStates, TestEvents> machine = new EnumStateMachine<TestStates, TestEvents>(states, transitions, stateS1, null);
|
||||
|
||||
|
||||
SyncTaskExecutor taskExecutor = new SyncTaskExecutor();
|
||||
machine.setTaskExecutor(taskExecutor);
|
||||
machine.afterPropertiesSet();
|
||||
machine.start();
|
||||
submachine1.setTaskExecutor(taskExecutor);
|
||||
submachine11.setTaskExecutor(taskExecutor);
|
||||
|
||||
machine.sendEvent(TestEvents.E1);
|
||||
|
||||
assertThat(entryActionS111.onExecuteLatch.await(1, TimeUnit.SECONDS), is(true));
|
||||
assertThat(exitActionS111.onExecuteLatch.await(1, TimeUnit.SECONDS), is(true));
|
||||
assertThat(entryActionS11.onExecuteLatch.await(1, TimeUnit.SECONDS), is(true));
|
||||
assertThat(exitActionS11.onExecuteLatch.await(1, TimeUnit.SECONDS), is(true));
|
||||
assertThat(entryActionS1.onExecuteLatch.await(1, TimeUnit.SECONDS), is(true));
|
||||
assertThat(exitActionS1.onExecuteLatch.await(1, TimeUnit.SECONDS), is(false));
|
||||
|
||||
assertThat(entryActionS11.stateContexts.size(), is(2));
|
||||
assertThat(exitActionS11.stateContexts.size(), is(1));
|
||||
assertThat(entryActionS11.stateContexts.size(), is(2));
|
||||
assertThat(exitActionS11.stateContexts.size(), is(1));
|
||||
assertThat(entryActionS1.stateContexts.size(), is(1));
|
||||
assertThat(exitActionS1.stateContexts.size(), is(0));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -68,7 +68,7 @@ public class ActionTests extends AbstractStateMachineTests {
|
||||
|
||||
}
|
||||
|
||||
private static class TestCountAction implements Action {
|
||||
private static class TestCountAction implements Action<TestStates, TestEvents> {
|
||||
|
||||
int count = 0;
|
||||
|
||||
@@ -77,7 +77,7 @@ public class ActionTests extends AbstractStateMachineTests {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(StateContext context) {
|
||||
public void execute(StateContext<TestStates, TestEvents> context) {
|
||||
count++;
|
||||
}
|
||||
|
||||
|
||||
@@ -144,5 +144,34 @@ public class ConfigurationTests extends AbstractStateMachineTests {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableStateMachine
|
||||
public static class Config4 extends EnumStateMachineConfigurerAdapter<TestStates, TestEvents> {
|
||||
|
||||
@Override
|
||||
public void configure(StateMachineStateConfigurer<TestStates, TestEvents> states) throws Exception {
|
||||
states
|
||||
.withStates()
|
||||
.initial(TestStates.S1)
|
||||
.end(TestStates.SF)
|
||||
.states(EnumSet.allOf(TestStates.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(StateMachineTransitionConfigurer<TestStates, TestEvents> transitions) throws Exception {
|
||||
transitions
|
||||
.withExternal()
|
||||
.source(TestStates.SI)
|
||||
.target(TestStates.S1)
|
||||
.event(TestEvents.E1)
|
||||
.and()
|
||||
.withLocal()
|
||||
.source(TestStates.S1)
|
||||
.target(TestStates.S2)
|
||||
.event(TestEvents.E2);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -32,7 +32,6 @@ import org.springframework.core.io.Resource;
|
||||
import org.springframework.statemachine.config.common.annotation.simple.EnableSimpleTest2;
|
||||
import org.springframework.statemachine.config.common.annotation.simple.SimpleTestConfig;
|
||||
import org.springframework.statemachine.config.common.annotation.simple.SimpleTestConfigBeanABuilder;
|
||||
import org.springframework.statemachine.config.common.annotation.simple.SimpleTestConfigBeanB;
|
||||
import org.springframework.statemachine.config.common.annotation.simple.SimpleTestConfigBeanBConfigurer;
|
||||
import org.springframework.statemachine.config.common.annotation.simple.SimpleTestConfigBuilder;
|
||||
import org.springframework.statemachine.config.common.annotation.simple.SimpleTestConfigurerAdapter;
|
||||
|
||||
@@ -55,11 +55,11 @@ public class SpelExpressionGuardTests extends AbstractStateMachineTests {
|
||||
SpelExpressionParser parser = new SpelExpressionParser(
|
||||
new SpelParserConfiguration(SpelCompilerMode.MIXED, null));
|
||||
Expression expression = parser.parseExpression("messageHeaders.get('foo')=='bar'");
|
||||
SpelExpressionGuard guard = new SpelExpressionGuard(expression);
|
||||
SpelExpressionGuard<TestStates, TestEvents> guard = new SpelExpressionGuard<TestStates, TestEvents>(expression);
|
||||
Map<String, Object> map = new HashMap<String, Object>();
|
||||
map.put("foo", "bar");
|
||||
MessageHeaders headers = new MessageHeaders(map);
|
||||
DefaultStateContext stateContext = new DefaultStateContext(headers, null);
|
||||
DefaultStateContext<TestStates, TestEvents> stateContext = new DefaultStateContext<TestStates, TestEvents>(headers, null, null);
|
||||
|
||||
assertThat(guard.evaluate(stateContext), is(true));
|
||||
}
|
||||
|
||||
@@ -77,7 +77,7 @@ public class ListenerTests extends AbstractStateMachineTests {
|
||||
ctx.close();
|
||||
}
|
||||
|
||||
private static class LoggingAction implements Action {
|
||||
private static class LoggingAction implements Action<TestStates, TestEvents> {
|
||||
|
||||
private static final Log log = LogFactory.getLog(LoggingAction.class);
|
||||
|
||||
@@ -88,7 +88,7 @@ public class ListenerTests extends AbstractStateMachineTests {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(StateContext context) {
|
||||
public void execute(StateContext<TestStates, TestEvents> context) {
|
||||
log.info("Hello from LoggingAction " + message + " foo=" + context.getMessageHeaders().get("foo"));
|
||||
}
|
||||
|
||||
|
||||
@@ -71,8 +71,10 @@ public class StateActionTests extends AbstractStateMachineTests {
|
||||
|
||||
@Override
|
||||
public void configure(StateMachineStateConfigurer<TestStates, TestEvents> states) throws Exception {
|
||||
Collection<Action> entryActions = Arrays.asList(testEntryAction());
|
||||
Collection<Action> exitActions = Arrays.asList(testExitAction());
|
||||
@SuppressWarnings("unchecked")
|
||||
Collection<Action<TestStates, TestEvents>> entryActions = Arrays.asList(testEntryAction());
|
||||
@SuppressWarnings("unchecked")
|
||||
Collection<Action<TestStates, TestEvents>> exitActions = Arrays.asList(testExitAction());
|
||||
states
|
||||
.withStates()
|
||||
.initial(TestStates.S1)
|
||||
@@ -90,12 +92,12 @@ public class StateActionTests extends AbstractStateMachineTests {
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Action testEntryAction() {
|
||||
public Action<TestStates, TestEvents> testEntryAction() {
|
||||
return new TestEntryAction();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Action testExitAction() {
|
||||
public Action<TestStates, TestEvents> testExitAction() {
|
||||
return new TestExitAction();
|
||||
}
|
||||
|
||||
|
||||
@@ -126,8 +126,10 @@ public class TransitionTests extends AbstractStateMachineTests {
|
||||
|
||||
@Override
|
||||
public void configure(StateMachineStateConfigurer<TestStates, TestEvents> states) throws Exception {
|
||||
Collection<Action> entryActions = Arrays.asList(testEntryAction());
|
||||
Collection<Action> exitActions = Arrays.asList(testExitAction());
|
||||
@SuppressWarnings("unchecked")
|
||||
Collection<Action<TestStates, TestEvents>> entryActions = Arrays.asList(testEntryAction());
|
||||
@SuppressWarnings("unchecked")
|
||||
Collection<Action<TestStates, TestEvents>> exitActions = Arrays.asList(testExitAction());
|
||||
states
|
||||
.withStates()
|
||||
.initial(TestStates.S1)
|
||||
@@ -151,22 +153,22 @@ public class TransitionTests extends AbstractStateMachineTests {
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Action testEntryAction() {
|
||||
public Action<TestStates, TestEvents> testEntryAction() {
|
||||
return new TestEntryAction();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Action testExitAction() {
|
||||
public Action<TestStates, TestEvents> testExitAction() {
|
||||
return new TestExitAction();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Action externalTestAction() {
|
||||
public Action<TestStates, TestEvents> externalTestAction() {
|
||||
return new TestAction();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Action internalTestAction() {
|
||||
public Action<TestStates, TestEvents> internalTestAction() {
|
||||
return new TestAction();
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
log4j.rootCategory=INFO, stdout
|
||||
|
||||
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
|
||||
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
|
||||
log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %t %c{2} [%t] - %m%n
|
||||
|
||||
log4j.category.org.springframework.statemachine=TRACE
|
||||
|
||||
Reference in New Issue
Block a user