Base support for submachines and regions
- resolves issues #2 and #4 - refactor states so that we can use submachines and regions to compose a state. - refactor some concepts around StateMachine now that it extends Region.
This commit is contained in:
@@ -17,6 +17,8 @@ package org.springframework.statemachine;
|
||||
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.statemachine.listener.StateMachineListener;
|
||||
import org.springframework.statemachine.region.Region;
|
||||
import org.springframework.statemachine.state.State;
|
||||
|
||||
/**
|
||||
* {@code StateMachine} provides an APIs for generic finite state machine needed
|
||||
@@ -27,21 +29,14 @@ import org.springframework.statemachine.listener.StateMachineListener;
|
||||
* @param <S> the type of state
|
||||
* @param <E> the type of event
|
||||
*/
|
||||
public interface StateMachine<S, E> {
|
||||
public interface StateMachine<S, E> extends Region<S, E> {
|
||||
|
||||
/**
|
||||
* Gets the initial state {@code S}.
|
||||
*
|
||||
* @return initial state
|
||||
*/
|
||||
S getInitialState();
|
||||
|
||||
/**
|
||||
* Gets the current state {@code S}.
|
||||
*
|
||||
* @return current state
|
||||
*/
|
||||
S getState();
|
||||
State<S,E> getInitialState();
|
||||
|
||||
/**
|
||||
* Start the state machine.
|
||||
@@ -68,6 +63,6 @@ public interface StateMachine<S, E> {
|
||||
*
|
||||
* @param listener the listener
|
||||
*/
|
||||
void addStateListener(StateMachineListener<S, E> listener);
|
||||
void addStateListener(StateMachineListener<State<S,E>, E> listener);
|
||||
|
||||
}
|
||||
|
||||
@@ -45,8 +45,8 @@ import org.springframework.statemachine.transition.TransitionKind;
|
||||
* @param <E> the type of event
|
||||
*/
|
||||
public class EnumStateMachineFactory<S extends Enum<S>, E extends Enum<E>> extends LifecycleObjectSupport implements
|
||||
StateMachineFactory<State<S, E>, E> {
|
||||
|
||||
StateMachineFactory<S, E> {
|
||||
|
||||
private final StateMachineTransitions<S, E> stateMachineTransitions;
|
||||
|
||||
private final StateMachineStates<S, E> stateMachineStates;
|
||||
@@ -64,11 +64,11 @@ public class EnumStateMachineFactory<S extends Enum<S>, E extends Enum<E>> exten
|
||||
}
|
||||
|
||||
@Override
|
||||
public StateMachine<State<S, E>, E> getStateMachine() {
|
||||
public StateMachine<S, E> getStateMachine() {
|
||||
return stateMachine();
|
||||
}
|
||||
|
||||
public StateMachine<State<S, E>, E> stateMachine() {
|
||||
public StateMachine<S, E> stateMachine() {
|
||||
Map<S, State<S, E>> stateMap = new HashMap<S, State<S, E>>();
|
||||
for (StateData<S, E> stateData : stateMachineStates.getStates()) {
|
||||
|
||||
|
||||
@@ -21,7 +21,6 @@ import org.springframework.statemachine.config.builders.StateMachineStates;
|
||||
import org.springframework.statemachine.config.builders.StateMachineTransitions;
|
||||
import org.springframework.statemachine.config.common.annotation.AbstractImportingAnnotationConfiguration;
|
||||
import org.springframework.statemachine.config.common.annotation.AnnotationConfigurer;
|
||||
import org.springframework.statemachine.state.State;
|
||||
|
||||
@Configuration
|
||||
public class StateMachineConfiguration<S extends Enum<S>, E extends Enum<E>> extends
|
||||
@@ -43,7 +42,7 @@ public class StateMachineConfiguration<S extends Enum<S>, E extends Enum<E>> ext
|
||||
}
|
||||
|
||||
private static class StateMachineDelegatingFactoryBean<S extends Enum<S>, E extends Enum<E>> implements
|
||||
FactoryBean<StateMachine<State<S, E>, E>>, BeanFactoryAware, InitializingBean {
|
||||
FactoryBean<StateMachine<S, E>>, BeanFactoryAware, InitializingBean {
|
||||
|
||||
private final StateMachineConfigBuilder<S, E> builder;
|
||||
|
||||
@@ -51,7 +50,7 @@ public class StateMachineConfiguration<S extends Enum<S>, E extends Enum<E>> ext
|
||||
|
||||
private BeanFactory beanFactory;
|
||||
|
||||
private StateMachine<State<S, E>, E> stateMachine;
|
||||
private StateMachine<S, E> stateMachine;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public StateMachineDelegatingFactoryBean(StateMachineConfigBuilder<S, E> builder) {
|
||||
@@ -59,7 +58,7 @@ public class StateMachineConfiguration<S extends Enum<S>, E extends Enum<E>> ext
|
||||
}
|
||||
|
||||
@Override
|
||||
public StateMachine<State<S, E>, E> getObject() throws Exception {
|
||||
public StateMachine<S, E> getObject() throws Exception {
|
||||
return stateMachine;
|
||||
}
|
||||
|
||||
|
||||
@@ -21,7 +21,6 @@ import org.springframework.statemachine.config.builders.StateMachineStates;
|
||||
import org.springframework.statemachine.config.builders.StateMachineTransitions;
|
||||
import org.springframework.statemachine.config.common.annotation.AbstractImportingAnnotationConfiguration;
|
||||
import org.springframework.statemachine.config.common.annotation.AnnotationConfigurer;
|
||||
import org.springframework.statemachine.state.State;
|
||||
|
||||
@Configuration
|
||||
public class StateMachineFactoryConfiguration<S extends Enum<S>, E extends Enum<E>> extends
|
||||
@@ -43,7 +42,7 @@ public class StateMachineFactoryConfiguration<S extends Enum<S>, E extends Enum<
|
||||
}
|
||||
|
||||
private static class StateMachineFactoryDelegatingFactoryBean<S extends Enum<S>, E extends Enum<E>> implements
|
||||
FactoryBean<StateMachineFactory<State<S, E>, E>>, BeanFactoryAware, InitializingBean {
|
||||
FactoryBean<StateMachineFactory<S, E>>, BeanFactoryAware, InitializingBean {
|
||||
|
||||
private final StateMachineConfigBuilder<S, E> builder;
|
||||
|
||||
@@ -51,7 +50,7 @@ public class StateMachineFactoryConfiguration<S extends Enum<S>, E extends Enum<
|
||||
|
||||
private BeanFactory beanFactory;
|
||||
|
||||
private StateMachineFactory<State<S, E>, E> stateMachineFactory;
|
||||
private StateMachineFactory<S, E> stateMachineFactory;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public StateMachineFactoryDelegatingFactoryBean(StateMachineConfigBuilder<S, E> builder) {
|
||||
@@ -59,7 +58,7 @@ public class StateMachineFactoryConfiguration<S extends Enum<S>, E extends Enum<
|
||||
}
|
||||
|
||||
@Override
|
||||
public StateMachineFactory<State<S, E>, E> getObject() throws Exception {
|
||||
public StateMachineFactory<S, E> getObject() throws Exception {
|
||||
return stateMachineFactory;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* 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.region;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.springframework.statemachine.state.State;
|
||||
import org.springframework.statemachine.transition.Transition;
|
||||
|
||||
/**
|
||||
* A region is an orthogonal part of either a composite state or a state
|
||||
* machine. It contains states and transitions.
|
||||
*
|
||||
* @author Janne Valkealahti
|
||||
*
|
||||
* @param <S> the type of state
|
||||
* @param <E> the type of event
|
||||
*/
|
||||
public interface Region<S, E> {
|
||||
|
||||
/**
|
||||
* Gets the current {@link State}.
|
||||
*
|
||||
* @return current state
|
||||
*/
|
||||
State<S,E> getState();
|
||||
|
||||
/**
|
||||
* Gets the {@link State}s defined in this region. Returned collection is
|
||||
* an unmodifiable copy because states in a state machine are immutable.
|
||||
*
|
||||
* @return immutable copy of states
|
||||
*/
|
||||
Collection<State<S, E>> getStates();
|
||||
|
||||
/**
|
||||
* Gets a {@link Transition}s for this region.
|
||||
*
|
||||
* @return immutable copy of transitions
|
||||
*/
|
||||
Collection<Transition<S,E>> getTransitions();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
/*
|
||||
* 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.state;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
|
||||
import org.springframework.statemachine.StateMachine;
|
||||
import org.springframework.statemachine.action.Action;
|
||||
import org.springframework.statemachine.region.Region;
|
||||
|
||||
/**
|
||||
* Base implementation of a {@link State} having a single state identifier.
|
||||
*
|
||||
* @author Janne Valkealahti
|
||||
*
|
||||
* @param <S> the type of state
|
||||
* @param <E> the type of event
|
||||
*/
|
||||
public abstract class AbstractSimpleState<S, E> extends AbstractState<S, E> {
|
||||
|
||||
private final Collection<S> ids;
|
||||
|
||||
/**
|
||||
* Instantiates a new abstract simple state.
|
||||
*
|
||||
* @param id the id
|
||||
*/
|
||||
public AbstractSimpleState(S id) {
|
||||
this(id, null, null, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new abstract simple state.
|
||||
*
|
||||
* @param id the id
|
||||
* @param deferred the deferred
|
||||
* @param entryActions the entry actions
|
||||
* @param exitActions the exit actions
|
||||
*/
|
||||
public AbstractSimpleState(S id, Collection<E> deferred, Collection<Action> entryActions, Collection<Action> exitActions) {
|
||||
this(id, deferred, entryActions, exitActions, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new abstract simple state.
|
||||
*
|
||||
* @param id the id
|
||||
* @param deferred the deferred
|
||||
*/
|
||||
public AbstractSimpleState(S id, Collection<E> deferred) {
|
||||
this(id, deferred, null, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new abstract simple state.
|
||||
*
|
||||
* @param id the id
|
||||
* @param pseudoState the pseudo state
|
||||
*/
|
||||
public AbstractSimpleState(S id, PseudoState pseudoState) {
|
||||
this(id, null, null, null, pseudoState);
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new abstract simple state.
|
||||
*
|
||||
* @param id the id
|
||||
* @param deferred the deferred
|
||||
* @param entryActions the entry actions
|
||||
* @param exitActions the exit actions
|
||||
* @param pseudoState the pseudo state
|
||||
* @param regions the regions
|
||||
*/
|
||||
public AbstractSimpleState(S id, Collection<E> deferred, Collection<Action> entryActions, Collection<Action> exitActions,
|
||||
PseudoState pseudoState, Collection<Region<S, E>> regions) {
|
||||
super(deferred, entryActions, exitActions, pseudoState, regions);
|
||||
this.ids = new ArrayList<S>();
|
||||
this.ids.add(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new abstract simple state.
|
||||
*
|
||||
* @param id the id
|
||||
* @param deferred the deferred
|
||||
* @param entryActions the entry actions
|
||||
* @param exitActions the exit actions
|
||||
* @param pseudoState the pseudo state
|
||||
* @param submachine the submachine
|
||||
*/
|
||||
public AbstractSimpleState(S id, Collection<E> deferred, Collection<Action> entryActions, Collection<Action> exitActions,
|
||||
PseudoState pseudoState, StateMachine<S, E> submachine) {
|
||||
super(deferred, entryActions, exitActions, pseudoState, submachine);
|
||||
this.ids = new ArrayList<S>();
|
||||
this.ids.add(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new abstract simple state.
|
||||
*
|
||||
* @param id the id
|
||||
* @param deferred the deferred
|
||||
* @param entryActions the entry actions
|
||||
* @param exitActions the exit actions
|
||||
* @param pseudoState the pseudo state
|
||||
*/
|
||||
public AbstractSimpleState(S id, Collection<E> deferred, Collection<Action> entryActions, Collection<Action> exitActions,
|
||||
PseudoState pseudoState) {
|
||||
super(deferred, entryActions, exitActions, pseudoState);
|
||||
this.ids = new ArrayList<S>();
|
||||
this.ids.add(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<S> getIds() {
|
||||
return Collections.unmodifiableCollection(ids);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -15,9 +15,13 @@
|
||||
*/
|
||||
package org.springframework.statemachine.state;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.springframework.statemachine.StateMachine;
|
||||
import org.springframework.statemachine.action.Action;
|
||||
import org.springframework.statemachine.region.Region;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Base implementation of a {@link State}.
|
||||
@@ -29,74 +33,110 @@ import org.springframework.statemachine.action.Action;
|
||||
*/
|
||||
public abstract class AbstractState<S, E> implements State<S, E> {
|
||||
|
||||
private final S id;
|
||||
private final PseudoState pseudoState;
|
||||
private final Collection<E> deferred;
|
||||
private final Collection<Action> entryActions;
|
||||
private final Collection<Action> exitActions;
|
||||
private final Collection<Region<S, E>> regions = new ArrayList<Region<S, E>>();
|
||||
private final StateMachine<S, E> submachine;
|
||||
|
||||
/**
|
||||
* Instantiates a new abstract state.
|
||||
*
|
||||
* @param id the id
|
||||
*/
|
||||
public AbstractState(S id) {
|
||||
this(id, null, null, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new abstract state.
|
||||
*
|
||||
* @param id the id
|
||||
* @param pseudoState the pseudo state
|
||||
*/
|
||||
public AbstractState(S id, PseudoState pseudoState) {
|
||||
this(id, null, null, null, pseudoState);
|
||||
public AbstractState(PseudoState pseudoState) {
|
||||
this(null, null, null, pseudoState);
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new abstract state.
|
||||
*
|
||||
* @param id the id
|
||||
* @param deferred the deferred
|
||||
*/
|
||||
public AbstractState(S id, Collection<E> deferred) {
|
||||
this(id, deferred, null, null);
|
||||
public AbstractState(Collection<E> deferred) {
|
||||
this(deferred, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new abstract state.
|
||||
*
|
||||
* @param id the id
|
||||
* @param deferred the deferred
|
||||
* @param entryActions the entry actions
|
||||
* @param exitActions the exit actions
|
||||
*/
|
||||
public AbstractState(S id, Collection<E> deferred, Collection<Action> entryActions, Collection<Action> exitActions) {
|
||||
this(id, deferred, entryActions, exitActions, null);
|
||||
public AbstractState(Collection<E> deferred, Collection<Action> entryActions, Collection<Action> exitActions) {
|
||||
this(deferred, entryActions, exitActions, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new abstract state.
|
||||
*
|
||||
* @param id the id
|
||||
* @param deferred the deferred
|
||||
* @param entryActions the entry actions
|
||||
* @param exitActions the exit actions
|
||||
* @param pseudoState the pseudo state
|
||||
*/
|
||||
public AbstractState(S id, Collection<E> deferred, Collection<Action> entryActions, Collection<Action> exitActions, PseudoState pseudoState) {
|
||||
this.id = id;
|
||||
public AbstractState(Collection<E> deferred, Collection<Action> entryActions, Collection<Action> exitActions,
|
||||
PseudoState pseudoState) {
|
||||
this(deferred, entryActions, exitActions, pseudoState, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new abstract state.
|
||||
*
|
||||
* @param deferred the deferred
|
||||
* @param entryActions the entry actions
|
||||
* @param exitActions the exit actions
|
||||
* @param pseudoState the pseudo state
|
||||
* @param submachine the submachine
|
||||
*/
|
||||
public AbstractState(Collection<E> deferred, Collection<Action> entryActions, Collection<Action> exitActions,
|
||||
PseudoState pseudoState, StateMachine<S, E> submachine) {
|
||||
this(deferred, entryActions, exitActions, pseudoState, null, submachine);
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new abstract state.
|
||||
*
|
||||
* @param deferred the deferred
|
||||
* @param entryActions the entry actions
|
||||
* @param exitActions the exit actions
|
||||
* @param pseudoState the pseudo state
|
||||
* @param regions the regions
|
||||
*/
|
||||
public AbstractState(Collection<E> deferred, Collection<Action> entryActions, Collection<Action> exitActions,
|
||||
PseudoState pseudoState, Collection<Region<S, E>> regions) {
|
||||
this(deferred, entryActions, exitActions, pseudoState, regions, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new abstract state.
|
||||
*
|
||||
* @param deferred the deferred
|
||||
* @param entryActions the entry actions
|
||||
* @param exitActions the exit actions
|
||||
* @param pseudoState the pseudo state
|
||||
* @param regions the regions
|
||||
* @param submachine the submachine
|
||||
*/
|
||||
private AbstractState(Collection<E> deferred, Collection<Action> entryActions, Collection<Action> 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) {
|
||||
this.regions.addAll(regions);
|
||||
}
|
||||
this.submachine = submachine;
|
||||
}
|
||||
|
||||
@Override
|
||||
public S getId() {
|
||||
return id;
|
||||
}
|
||||
public abstract Collection<S> getIds();
|
||||
|
||||
@Override
|
||||
public PseudoState getPseudoState() {
|
||||
@@ -107,21 +147,49 @@ public abstract class AbstractState<S, E> implements State<S, E> {
|
||||
public Collection<E> getDeferredEvents() {
|
||||
return deferred;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Collection<Action> getEntryActions() {
|
||||
return entryActions;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Collection<Action> getExitActions() {
|
||||
return exitActions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "AbstractState [id=" + id + ", pseudoState=" + pseudoState + ", deferred=" + deferred
|
||||
+ ", entryActions=" + entryActions + ", exitActions=" + exitActions + "]";
|
||||
public boolean isComposite() {
|
||||
return !regions.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOrthogonal() {
|
||||
return regions.size() > 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSimple() {
|
||||
return isSubmachineState() && isComposite();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSubmachineState() {
|
||||
return submachine != null;
|
||||
}
|
||||
|
||||
protected StateMachine<S, E> getSubmachine() {
|
||||
return submachine;
|
||||
}
|
||||
|
||||
protected Collection<Region<S, E>> getRegions() {
|
||||
return regions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "AbstractState [ids=" + StringUtils.collectionToCommaDelimitedString(getIds()) + ", pseudoState=" + pseudoState + ", deferred=" + deferred
|
||||
+ ", entryActions=" + entryActions + ", exitActions=" + exitActions + "]";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -17,34 +17,108 @@ package org.springframework.statemachine.state;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.springframework.statemachine.StateMachine;
|
||||
import org.springframework.statemachine.action.Action;
|
||||
import org.springframework.statemachine.region.Region;
|
||||
|
||||
public class EnumState<S extends Enum<S>, E extends Enum<E>> extends AbstractState<S, E> {
|
||||
/**
|
||||
* A {@link State} implementation where state and event is enum based.
|
||||
*
|
||||
* @author Janne Valkealahti
|
||||
*
|
||||
* @param <S> the type of state
|
||||
* @param <E> the type of event
|
||||
*/
|
||||
public class EnumState<S extends Enum<S>, E extends Enum<E>> extends AbstractSimpleState<S, E> {
|
||||
|
||||
/**
|
||||
* Instantiates a new enum state.
|
||||
*
|
||||
* @param id the id
|
||||
*/
|
||||
public EnumState(S id) {
|
||||
super(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new enum state.
|
||||
*
|
||||
* @param id the id
|
||||
* @param pseudoState the pseudo state
|
||||
*/
|
||||
public EnumState(S id, PseudoState pseudoState) {
|
||||
super(id, pseudoState);
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new enum state.
|
||||
*
|
||||
* @param id the id
|
||||
* @param deferred the deferred
|
||||
*/
|
||||
public EnumState(S id, Collection<E> deferred) {
|
||||
super(id, deferred);
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new enum state.
|
||||
*
|
||||
* @param id the id
|
||||
* @param deferred the deferred
|
||||
* @param entryActions the entry actions
|
||||
* @param exitActions the exit actions
|
||||
*/
|
||||
public EnumState(S id, Collection<E> deferred, Collection<Action> entryActions, Collection<Action> exitActions) {
|
||||
super(id, deferred, entryActions, exitActions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new enum state.
|
||||
*
|
||||
* @param id the id
|
||||
* @param deferred the deferred
|
||||
* @param entryActions the entry actions
|
||||
* @param exitActions the exit actions
|
||||
* @param pseudoState the pseudo state
|
||||
*/
|
||||
public EnumState(S id, Collection<E> deferred, Collection<Action> entryActions, Collection<Action> exitActions,
|
||||
PseudoState pseudoState) {
|
||||
super(id, deferred, entryActions, exitActions, pseudoState);
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new enum state.
|
||||
*
|
||||
* @param id the id
|
||||
* @param deferred the deferred
|
||||
* @param entryActions the entry actions
|
||||
* @param exitActions the exit actions
|
||||
* @param pseudoState the pseudo state
|
||||
* @param regions the regions
|
||||
*/
|
||||
public EnumState(S id, Collection<E> deferred, Collection<Action> entryActions, Collection<Action> exitActions,
|
||||
PseudoState pseudoState, Collection<Region<S, E>> regions) {
|
||||
super(id, deferred, entryActions, exitActions, pseudoState, regions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new enum state.
|
||||
*
|
||||
* @param id the id
|
||||
* @param deferred the deferred
|
||||
* @param entryActions the entry actions
|
||||
* @param exitActions the exit actions
|
||||
* @param pseudoState the pseudo state
|
||||
* @param submachine the submachine
|
||||
*/
|
||||
public EnumState(S id, Collection<E> deferred, Collection<Action> entryActions, Collection<Action> exitActions,
|
||||
PseudoState pseudoState, StateMachine<S, E> submachine) {
|
||||
super(id, deferred, entryActions, exitActions, pseudoState, submachine);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "EnumState [getId()=" + getId() + ", getClass()=" + getClass() + ", hashCode()=" + hashCode()
|
||||
return "EnumState [getIds()=" + getIds() + ", getClass()=" + getClass() + ", hashCode()=" + hashCode()
|
||||
+ ", toString()=" + super.toString() + "]";
|
||||
}
|
||||
|
||||
|
||||
@@ -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.state;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
|
||||
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
|
||||
* @param <E> the type of event
|
||||
*/
|
||||
public class RegionState<S, E> extends AbstractState<S, E> {
|
||||
|
||||
/**
|
||||
* Instantiates a new region state.
|
||||
*
|
||||
* @param regions the regions
|
||||
*/
|
||||
public RegionState(Collection<Region<S, E>> regions) {
|
||||
super(null, null, null, null, regions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new region state.
|
||||
*
|
||||
* @param regions the regions
|
||||
* @param deferred the deferred
|
||||
*/
|
||||
public RegionState(Collection<Region<S, E>> regions, Collection<E> deferred) {
|
||||
super(deferred, null, null, null, regions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new region state.
|
||||
*
|
||||
* @param regions the regions
|
||||
* @param pseudoState the pseudo state
|
||||
*/
|
||||
public RegionState(Collection<Region<S, E>> regions, PseudoState pseudoState) {
|
||||
super(null, null, null, pseudoState, regions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new region state.
|
||||
*
|
||||
* @param regions the regions
|
||||
* @param deferred the deferred
|
||||
* @param entryActions the entry actions
|
||||
* @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,
|
||||
PseudoState pseudoState) {
|
||||
super(deferred, entryActions, exitActions, pseudoState, regions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new region state.
|
||||
*
|
||||
* @param regions the regions
|
||||
* @param deferred the deferred
|
||||
* @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) {
|
||||
super(deferred, entryActions, exitActions, null, regions);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<S> getIds() {
|
||||
ArrayList<S> ids = new ArrayList<S>();
|
||||
for (Region<S, E> r : getRegions()) {
|
||||
ids.addAll(r.getState().getIds());
|
||||
}
|
||||
return ids;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -30,11 +30,12 @@ import org.springframework.statemachine.action.Action;
|
||||
public interface State<S, E> {
|
||||
|
||||
/**
|
||||
* Gets the state identifier.
|
||||
* Gets the state identifiers. Usually returned collection contains only one
|
||||
* identifier except in a case where state is an orthogonal.
|
||||
*
|
||||
* @return the identifier
|
||||
* @return the state identifiers
|
||||
*/
|
||||
S getId();
|
||||
Collection<S> getIds();
|
||||
|
||||
/**
|
||||
* Gets a {@link PseudoState} attached to a {@code State}.
|
||||
@@ -65,5 +66,38 @@ public interface State<S, E> {
|
||||
* @return the state exit actions
|
||||
*/
|
||||
Collection<Action> getExitActions();
|
||||
|
||||
|
||||
/**
|
||||
* Checks if state is a simple state. A simple state does not have any
|
||||
* regions and it does not refer to any submachine state machine.
|
||||
*
|
||||
* @return true, if state is a simple state
|
||||
*/
|
||||
boolean isSimple();
|
||||
|
||||
/**
|
||||
* Checks if state is a composite state. A composite state is a state that
|
||||
* contains at least one region.
|
||||
*
|
||||
* @return true, if state is a composite state
|
||||
*/
|
||||
boolean isComposite();
|
||||
|
||||
/**
|
||||
* Checks if state is an orthogonal state. An orthogonal composite state
|
||||
* contains two or more regions. If this method returns {@code TRUE},
|
||||
* {@link #isComposite()} will also always return {@code TRUE}.
|
||||
*
|
||||
* @return true, if state is an orthogonal state
|
||||
*/
|
||||
boolean isOrthogonal();
|
||||
|
||||
/**
|
||||
* Checks if state is a submachine state. This kind of state refers to a
|
||||
* state machine(submachine).
|
||||
*
|
||||
* @return true, if state is a submachine state
|
||||
*/
|
||||
boolean isSubmachineState();
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* 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.state;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.springframework.statemachine.StateMachine;
|
||||
import org.springframework.statemachine.action.Action;
|
||||
|
||||
/**
|
||||
* A {@link State} implementation where state is wrapped in a substatemachine.
|
||||
*
|
||||
* @author Janne Valkealahti
|
||||
*
|
||||
* @param <S> the type of state
|
||||
* @param <E> the type of event
|
||||
*/
|
||||
public class StateMachineState<S, E> extends AbstractState<S, E> {
|
||||
|
||||
/**
|
||||
* Instantiates a new state machine state.
|
||||
*
|
||||
* @param submachine the submachine
|
||||
*/
|
||||
public StateMachineState(StateMachine<S, E> submachine) {
|
||||
super(null, null, null, null, submachine);
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new state machine state.
|
||||
*
|
||||
* @param submachine the submachine
|
||||
* @param deferred the deferred
|
||||
*/
|
||||
public StateMachineState(StateMachine<S, E> submachine, Collection<E> deferred) {
|
||||
super(deferred, null, null, null, submachine);
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new state machine state.
|
||||
*
|
||||
* @param submachine the submachine
|
||||
* @param pseudoState the pseudo state
|
||||
*/
|
||||
public StateMachineState(StateMachine<S, E> submachine, PseudoState pseudoState) {
|
||||
super(null, null, null, pseudoState, submachine);
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new state machine state.
|
||||
*
|
||||
* @param submachine the submachine
|
||||
* @param deferred the deferred
|
||||
* @param entryActions the entry actions
|
||||
* @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,
|
||||
PseudoState pseudoState) {
|
||||
super(deferred, entryActions, exitActions, pseudoState, submachine);
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new state machine state.
|
||||
*
|
||||
* @param submachine the submachine
|
||||
* @param deferred the deferred
|
||||
* @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) {
|
||||
super(deferred, entryActions, exitActions, null, submachine);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<S> getIds() {
|
||||
return getSubmachine().getState().getIds();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -61,7 +61,7 @@ import org.springframework.util.Assert;
|
||||
* @param <S> the type of state
|
||||
* @param <E> the type of event
|
||||
*/
|
||||
public abstract class AbstractStateMachine<S, E> extends LifecycleObjectSupport implements StateMachine<State<S,E>, E> {
|
||||
public abstract class AbstractStateMachine<S, E> extends LifecycleObjectSupport implements StateMachine<S, E> {
|
||||
|
||||
private static final Log log = LogFactory.getLog(AbstractStateMachine.class);
|
||||
|
||||
@@ -180,10 +180,16 @@ 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
|
||||
*/
|
||||
public Collection<State<S,E>> getStates() {
|
||||
*/
|
||||
@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);
|
||||
@@ -337,8 +343,9 @@ public abstract class AbstractStateMachine<S, E> extends LifecycleObjectSupport
|
||||
OnTransition annotation = entry.getValue().getAnnotation();
|
||||
String source = annotation.source();
|
||||
String target = annotation.target();
|
||||
String s = sourceState.getId().toString();
|
||||
String t = targetState.getId().toString();
|
||||
// TODO: need major fixes
|
||||
String s = sourceState.getIds().iterator().next().toString();
|
||||
String t = targetState.getIds().iterator().next().toString();
|
||||
if (s.equals(source) && t.equals(target)) {
|
||||
handlersList.add(entry.getValue());
|
||||
}
|
||||
|
||||
@@ -33,16 +33,47 @@ import org.springframework.statemachine.trigger.Trigger;
|
||||
*/
|
||||
public interface Transition<S, E> {
|
||||
|
||||
/**
|
||||
* Transit this transition with a give state context.
|
||||
*
|
||||
* @param context the state context
|
||||
* @return true, if transition happened, false otherwise
|
||||
*/
|
||||
boolean transit(StateContext context);
|
||||
|
||||
/**
|
||||
* Gets the source state of this transition.
|
||||
*
|
||||
* @return the source state
|
||||
*/
|
||||
State<S,E> getSource();
|
||||
|
||||
/**
|
||||
* Gets the target state of this transition.
|
||||
*
|
||||
* @return the target state
|
||||
*/
|
||||
State<S,E> getTarget();
|
||||
|
||||
/**
|
||||
* Gets the transition actions.
|
||||
*
|
||||
* @return the transition actions
|
||||
*/
|
||||
Collection<Action> getActions();
|
||||
|
||||
/**
|
||||
* Gets the transition trigger.
|
||||
*
|
||||
* @return the transition trigger
|
||||
*/
|
||||
Trigger<S, E> getTrigger();
|
||||
|
||||
/**
|
||||
* Gets the transition kind.
|
||||
*
|
||||
* @return the transition kind
|
||||
*/
|
||||
TransitionKind getKind();
|
||||
|
||||
}
|
||||
|
||||
@@ -58,10 +58,18 @@ public abstract class AbstractStateMachineTests {
|
||||
SI,S1,S2,S3,S4
|
||||
}
|
||||
|
||||
public enum TestSubStates {
|
||||
SUBSI,SUBS1,SUBS2,SUBS3,SUBS4
|
||||
}
|
||||
|
||||
public enum TestEvents {
|
||||
E1,E2,E3,E4
|
||||
}
|
||||
|
||||
public enum TestSubEvents {
|
||||
SUBE1,SUBE2,SUBE3,SUBE4
|
||||
}
|
||||
|
||||
@Configuration
|
||||
public static class BaseConfig {
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
*/
|
||||
package org.springframework.statemachine;
|
||||
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.Matchers.contains;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
import org.junit.Test;
|
||||
@@ -30,7 +30,6 @@ import org.springframework.statemachine.config.EnumStateMachineConfigurerAdapter
|
||||
import org.springframework.statemachine.config.EnumStateMachineFactory;
|
||||
import org.springframework.statemachine.config.builders.StateMachineStateConfigurer;
|
||||
import org.springframework.statemachine.config.builders.StateMachineTransitionConfigurer;
|
||||
import org.springframework.statemachine.state.State;
|
||||
|
||||
public class StateMachineFactoryTests extends AbstractStateMachineTests {
|
||||
|
||||
@@ -41,11 +40,11 @@ public class StateMachineFactoryTests extends AbstractStateMachineTests {
|
||||
|
||||
EnumStateMachineFactory<TestStates, TestEvents> stateMachineFactory =
|
||||
ctx.getBean(StateMachineSystemConstants.DEFAULT_ID_STATEMACHINEFACTORY, EnumStateMachineFactory.class);
|
||||
StateMachine<State<TestStates, TestEvents>, TestEvents> machine = stateMachineFactory.getStateMachine();
|
||||
StateMachine<TestStates,TestEvents> machine = stateMachineFactory.getStateMachine();
|
||||
|
||||
assertThat(machine.getState().getId(), is(TestStates.S1));
|
||||
assertThat(machine.getState().getIds(), contains(TestStates.S1));
|
||||
machine.sendEvent(MessageBuilder.withPayload(TestEvents.E1).build());
|
||||
assertThat(machine.getState().getId(), is(TestStates.S2));
|
||||
assertThat(machine.getState().getIds(), contains(TestStates.S2));
|
||||
ctx.close();
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
package org.springframework.statemachine.guard;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.Matchers.contains;
|
||||
import static org.hamcrest.Matchers.notNullValue;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
@@ -27,12 +28,12 @@ import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.task.SyncTaskExecutor;
|
||||
import org.springframework.core.task.TaskExecutor;
|
||||
import org.springframework.statemachine.EnumStateMachine;
|
||||
import org.springframework.statemachine.StateMachineSystemConstants;
|
||||
import org.springframework.statemachine.AbstractStateMachineTests.TestAction;
|
||||
import org.springframework.statemachine.AbstractStateMachineTests.TestEvents;
|
||||
import org.springframework.statemachine.AbstractStateMachineTests.TestGuard;
|
||||
import org.springframework.statemachine.AbstractStateMachineTests.TestStates;
|
||||
import org.springframework.statemachine.EnumStateMachine;
|
||||
import org.springframework.statemachine.StateMachineSystemConstants;
|
||||
import org.springframework.statemachine.config.EnableStateMachine;
|
||||
import org.springframework.statemachine.config.EnumStateMachineConfigurerAdapter;
|
||||
import org.springframework.statemachine.config.builders.StateMachineStateConfigurer;
|
||||
@@ -77,12 +78,12 @@ public class GuardTests {
|
||||
assertThat(testAction, notNullValue());
|
||||
|
||||
machine.start();
|
||||
assertThat(machine.getState().getId(), is(TestStates.S1));
|
||||
assertThat(machine.getState().getIds(), contains(TestStates.S1));
|
||||
|
||||
machine.sendEvent(TestEvents.E1);
|
||||
assertThat(testGuard.onEvaluateLatch.await(2, TimeUnit.SECONDS), is(true));
|
||||
assertThat(testAction.onExecuteLatch.await(2, TimeUnit.SECONDS), is(false));
|
||||
assertThat(machine.getState().getId(), is(TestStates.S1));
|
||||
assertThat(machine.getState().getIds(), contains(TestStates.S1));
|
||||
|
||||
ctx.close();
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
package org.springframework.statemachine.guard;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.Matchers.contains;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
@@ -39,7 +40,6 @@ import org.springframework.statemachine.config.EnableStateMachine;
|
||||
import org.springframework.statemachine.config.EnumStateMachineConfigurerAdapter;
|
||||
import org.springframework.statemachine.config.builders.StateMachineStateConfigurer;
|
||||
import org.springframework.statemachine.config.builders.StateMachineTransitionConfigurer;
|
||||
import org.springframework.statemachine.guard.SpelExpressionGuard;
|
||||
import org.springframework.statemachine.support.DefaultStateContext;
|
||||
|
||||
/**
|
||||
@@ -72,9 +72,9 @@ public class SpelExpressionGuardTests extends AbstractStateMachineTests {
|
||||
EnumStateMachine<TestStates,TestEvents> machine =
|
||||
ctx.getBean(StateMachineSystemConstants.DEFAULT_ID_STATEMACHINE, EnumStateMachine.class);
|
||||
|
||||
assertThat(machine.getState().getId(), is(TestStates.S1));
|
||||
assertThat(machine.getState().getIds(), contains(TestStates.S1));
|
||||
machine.sendEvent(MessageBuilder.withPayload(TestEvents.E1).build());
|
||||
assertThat(machine.getState().getId(), is(TestStates.S1));
|
||||
assertThat(machine.getState().getIds(), contains(TestStates.S1));
|
||||
ctx.close();
|
||||
}
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package org.springframework.statemachine.listener;
|
||||
|
||||
import static org.hamcrest.Matchers.contains;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.Matchers.notNullValue;
|
||||
import static org.junit.Assert.assertThat;
|
||||
@@ -40,7 +41,6 @@ import org.springframework.statemachine.config.EnableStateMachine;
|
||||
import org.springframework.statemachine.config.EnumStateMachineConfigurerAdapter;
|
||||
import org.springframework.statemachine.config.builders.StateMachineStateConfigurer;
|
||||
import org.springframework.statemachine.config.builders.StateMachineTransitionConfigurer;
|
||||
import org.springframework.statemachine.listener.StateMachineListener;
|
||||
import org.springframework.statemachine.state.State;
|
||||
|
||||
/**
|
||||
@@ -65,12 +65,12 @@ public class ListenerTests extends AbstractStateMachineTests {
|
||||
assertThat(machine, notNullValue());
|
||||
machine.sendEvent(MessageBuilder.withPayload(TestEvents.E1).setHeader("foo", "jee1").build());
|
||||
assertThat(listener.states.size(), is(1));
|
||||
assertThat(listener.states.get(0).from.getId(), is(TestStates.S1));
|
||||
assertThat(listener.states.get(0).to.getId(), is(TestStates.S2));
|
||||
assertThat(listener.states.get(0).from.getIds(), contains(TestStates.S1));
|
||||
assertThat(listener.states.get(0).to.getIds(), contains(TestStates.S2));
|
||||
machine.sendEvent(MessageBuilder.withPayload(TestEvents.E2).setHeader("foo", "jee2").build());
|
||||
assertThat(listener.states.size(), is(2));
|
||||
assertThat(listener.states.get(1).from.getId(), is(TestStates.S2));
|
||||
assertThat(listener.states.get(1).to.getId(), is(TestStates.S3));
|
||||
assertThat(listener.states.get(1).from.getIds(), contains(TestStates.S2));
|
||||
assertThat(listener.states.get(1).to.getIds(), contains(TestStates.S3));
|
||||
machine.sendEvent(MessageBuilder.withPayload(TestEvents.E4).setHeader("foo", "jee2").build());
|
||||
assertThat(listener.states.size(), is(2));
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
*/
|
||||
package org.springframework.statemachine.state;
|
||||
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.Matchers.contains;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
@@ -49,7 +49,7 @@ public class InitialStateTests extends AbstractStateMachineTests {
|
||||
EnumStateMachine<TestStates,TestEvents> machine =
|
||||
context.getBean(StateMachineSystemConstants.DEFAULT_ID_STATEMACHINE, EnumStateMachine.class);
|
||||
|
||||
assertThat(machine.getState().getId(), is(TestStates.S1));
|
||||
assertThat(machine.getState().getIds(), contains(TestStates.S1));
|
||||
}
|
||||
|
||||
@Test(expected = Exception.class)
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* 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.state;
|
||||
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.Matchers.contains;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.core.task.SyncTaskExecutor;
|
||||
import org.springframework.statemachine.AbstractStateMachineTests;
|
||||
import org.springframework.statemachine.EnumStateMachine;
|
||||
import org.springframework.statemachine.region.Region;
|
||||
import org.springframework.statemachine.transition.DefaultExternalTransition;
|
||||
import org.springframework.statemachine.transition.Transition;
|
||||
|
||||
/**
|
||||
* Tests for states using a submachine.
|
||||
*
|
||||
* @author Janne Valkealahti
|
||||
*
|
||||
*/
|
||||
public class RegionStateTests extends AbstractStateMachineTests {
|
||||
|
||||
@Test
|
||||
public void testSimpleRegionState() {
|
||||
|
||||
State<TestStates,TestEvents> stateSI = new EnumState<TestStates,TestEvents>(TestStates.SI);
|
||||
State<TestStates,TestEvents> stateS1 = new EnumState<TestStates,TestEvents>(TestStates.S1);
|
||||
State<TestStates,TestEvents> stateS2 = new EnumState<TestStates,TestEvents>(TestStates.S2);
|
||||
State<TestStates,TestEvents> stateS3 = new EnumState<TestStates,TestEvents>(TestStates.S3);
|
||||
|
||||
Collection<State<TestStates,TestEvents>> states = new ArrayList<State<TestStates,TestEvents>>();
|
||||
states.add(stateSI);
|
||||
states.add(stateS1);
|
||||
states.add(stateS2);
|
||||
states.add(stateS3);
|
||||
|
||||
Collection<Transition<TestStates,TestEvents>> transitions = new ArrayList<Transition<TestStates,TestEvents>>();
|
||||
|
||||
DefaultExternalTransition<TestStates,TestEvents> transitionFromSIToS1 =
|
||||
new DefaultExternalTransition<TestStates,TestEvents>(stateSI, stateS1, null, TestEvents.E1, null);
|
||||
|
||||
DefaultExternalTransition<TestStates,TestEvents> transitionFromS1ToS2 =
|
||||
new DefaultExternalTransition<TestStates,TestEvents>(stateS1, stateS2, null, TestEvents.E2, null);
|
||||
|
||||
DefaultExternalTransition<TestStates,TestEvents> transitionFromS2ToS3 =
|
||||
new DefaultExternalTransition<TestStates,TestEvents>(stateS2, stateS3, null, TestEvents.E3, null);
|
||||
|
||||
transitions.add(transitionFromSIToS1);
|
||||
transitions.add(transitionFromS1ToS2);
|
||||
transitions.add(transitionFromS2ToS3);
|
||||
|
||||
SyncTaskExecutor taskExecutor = new SyncTaskExecutor();
|
||||
EnumStateMachine<TestStates, TestEvents> machine = new EnumStateMachine<TestStates, TestEvents>(states, transitions, stateSI);
|
||||
machine.setTaskExecutor(taskExecutor);
|
||||
machine.start();
|
||||
|
||||
Collection<Region<TestStates,TestEvents>> regions = new ArrayList<Region<TestStates,TestEvents>>();
|
||||
regions.add(machine);
|
||||
RegionState<TestStates,TestEvents> state = new RegionState<TestStates,TestEvents>(regions);
|
||||
|
||||
assertThat(state.isSimple(), is(false));
|
||||
assertThat(state.isComposite(), is(true));
|
||||
assertThat(state.isOrthogonal(), is(false));
|
||||
assertThat(state.isSubmachineState(), is(false));
|
||||
|
||||
assertThat(state.getIds(), contains(TestStates.SI));
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* 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.state;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.Matchers.contains;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.core.task.SyncTaskExecutor;
|
||||
import org.springframework.statemachine.AbstractStateMachineTests;
|
||||
import org.springframework.statemachine.EnumStateMachine;
|
||||
import org.springframework.statemachine.transition.DefaultExternalTransition;
|
||||
import org.springframework.statemachine.transition.Transition;
|
||||
|
||||
/**
|
||||
* Tests for states using a submachine.
|
||||
*
|
||||
* @author Janne Valkealahti
|
||||
*
|
||||
*/
|
||||
public class SubmachineStateTests extends AbstractStateMachineTests {
|
||||
|
||||
@Test
|
||||
public void testSimpleSubmachineState() {
|
||||
|
||||
State<TestStates,TestEvents> stateSI = new EnumState<TestStates,TestEvents>(TestStates.SI);
|
||||
State<TestStates,TestEvents> stateS1 = new EnumState<TestStates,TestEvents>(TestStates.S1);
|
||||
State<TestStates,TestEvents> stateS2 = new EnumState<TestStates,TestEvents>(TestStates.S2);
|
||||
State<TestStates,TestEvents> stateS3 = new EnumState<TestStates,TestEvents>(TestStates.S3);
|
||||
|
||||
Collection<State<TestStates,TestEvents>> states = new ArrayList<State<TestStates,TestEvents>>();
|
||||
states.add(stateSI);
|
||||
states.add(stateS1);
|
||||
states.add(stateS2);
|
||||
states.add(stateS3);
|
||||
|
||||
Collection<Transition<TestStates,TestEvents>> transitions = new ArrayList<Transition<TestStates,TestEvents>>();
|
||||
|
||||
DefaultExternalTransition<TestStates,TestEvents> transitionFromSIToS1 =
|
||||
new DefaultExternalTransition<TestStates,TestEvents>(stateSI, stateS1, null, TestEvents.E1, null);
|
||||
|
||||
DefaultExternalTransition<TestStates,TestEvents> transitionFromS1ToS2 =
|
||||
new DefaultExternalTransition<TestStates,TestEvents>(stateS1, stateS2, null, TestEvents.E2, null);
|
||||
|
||||
DefaultExternalTransition<TestStates,TestEvents> transitionFromS2ToS3 =
|
||||
new DefaultExternalTransition<TestStates,TestEvents>(stateS2, stateS3, null, TestEvents.E3, null);
|
||||
|
||||
transitions.add(transitionFromSIToS1);
|
||||
transitions.add(transitionFromS1ToS2);
|
||||
transitions.add(transitionFromS2ToS3);
|
||||
|
||||
SyncTaskExecutor taskExecutor = new SyncTaskExecutor();
|
||||
EnumStateMachine<TestStates, TestEvents> machine = new EnumStateMachine<TestStates, TestEvents>(states, transitions, stateSI);
|
||||
machine.setTaskExecutor(taskExecutor);
|
||||
machine.start();
|
||||
|
||||
StateMachineState<TestStates,TestEvents> state = new StateMachineState<TestStates,TestEvents>(machine);
|
||||
|
||||
assertThat(state.isSimple(), is(false));
|
||||
assertThat(state.isComposite(), is(false));
|
||||
assertThat(state.isOrthogonal(), is(false));
|
||||
assertThat(state.isSubmachineState(), is(true));
|
||||
|
||||
assertThat(state.getIds(), contains(TestStates.SI));
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -16,6 +16,7 @@
|
||||
package org.springframework.statemachine.transition;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.Matchers.contains;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
@@ -54,9 +55,9 @@ public class TransitionTests extends AbstractStateMachineTests {
|
||||
EnumStateMachine<TestStates,TestEvents> machine =
|
||||
ctx.getBean(StateMachineSystemConstants.DEFAULT_ID_STATEMACHINE, EnumStateMachine.class);
|
||||
|
||||
assertThat(machine.getState().getId(), is(TestStates.S1));
|
||||
assertThat(machine.getState().getIds(), contains(TestStates.S1));
|
||||
machine.sendEvent(MessageBuilder.withPayload(TestEvents.E1).build());
|
||||
assertThat(machine.getState().getId(), is(TestStates.S3));
|
||||
assertThat(machine.getState().getIds(), contains(TestStates.S3));
|
||||
ctx.close();
|
||||
|
||||
}
|
||||
@@ -74,7 +75,7 @@ public class TransitionTests extends AbstractStateMachineTests {
|
||||
TestAction externalTestAction = ctx.getBean("externalTestAction", TestAction.class);
|
||||
TestAction internalTestAction = ctx.getBean("internalTestAction", TestAction.class);
|
||||
|
||||
assertThat(machine.getState().getId(), is(TestStates.S1));
|
||||
assertThat(machine.getState().getIds(), contains(TestStates.S1));
|
||||
assertThat(testExitAction.onExecuteLatch.await(1, TimeUnit.SECONDS), is(false));
|
||||
assertThat(testEntryAction.onExecuteLatch.await(1, TimeUnit.SECONDS), is(false));
|
||||
|
||||
@@ -88,7 +89,7 @@ public class TransitionTests extends AbstractStateMachineTests {
|
||||
assertThat(testEntryAction.onExecuteLatch.await(1, TimeUnit.SECONDS), is(true));
|
||||
assertThat(externalTestAction.onExecuteLatch.await(1, TimeUnit.SECONDS), is(true));
|
||||
|
||||
assertThat(machine.getState().getId(), is(TestStates.S2));
|
||||
assertThat(machine.getState().getIds(), contains(TestStates.S2));
|
||||
ctx.close();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user