Polish model usage
- Make model data classes easier to use for simple use cases. - Start adding dev docs. - Generic docs changes. - Relates to #172 - Relates to #158 - Relates to #185
This commit is contained in:
@@ -626,3 +626,24 @@ What's happening in above chart:
|
||||
* At a same time we request states from all machines and plot it.
|
||||
* Finally we do a simple transition back to `S21` from `S211` to make
|
||||
sure that all state machines are still functioning properly.
|
||||
|
||||
[[devdocs]]
|
||||
== Developer Documentation
|
||||
This appendix provides generic information for a developers who may
|
||||
want to contribute or other people who want to understand how state
|
||||
machine works or what are its internal concepts.
|
||||
|
||||
[[devdocs-configmodel]]
|
||||
=== StateMachine Config Model
|
||||
`StateMachineModel` and other related SPI classes are an abstraction
|
||||
between various configuration and factory classes. This also allows
|
||||
easier integation for others to build state machines.
|
||||
|
||||
As shown above a state machine can be instantiated by building a model
|
||||
using configuration data classes and then asking a factory to build a
|
||||
state machine.
|
||||
|
||||
[source,java,indent=0]
|
||||
----
|
||||
include::samples/DocsConfigurationSampleTests6.java[tags=snippetA]
|
||||
----
|
||||
|
||||
@@ -330,6 +330,22 @@ include::samples/DocsConfigurationSampleTests.java[tags=snippetYB]
|
||||
|
||||
More about distributed states, refer to section <<sm-distributed>>.
|
||||
|
||||
`StateMachineModelVerifier` is an interface what is used internally to
|
||||
do some sanity checks for a state machine structure. Its purpose is to
|
||||
fail fast early instead of letting common configuration errors into a
|
||||
state machine itself. On default verifier is automatically enabled and
|
||||
`DefaultStateMachineModelVerifier` implementation is used.
|
||||
|
||||
With `withVerifier()` user can disable verifier or set a custom one if
|
||||
needed.
|
||||
|
||||
[source,java,indent=0]
|
||||
----
|
||||
include::samples/DocsConfigurationSampleTests.java[tags=snippetYC]
|
||||
----
|
||||
|
||||
More about config model, refer to section <<devdocs-configmodel>>.
|
||||
|
||||
[[sm-factories]]
|
||||
== State Machine Factories
|
||||
There are use cases when state machine needs to be created dynamically
|
||||
|
||||
@@ -15,13 +15,17 @@
|
||||
*/
|
||||
package org.springframework.statemachine.config.model;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.core.task.SyncTaskExecutor;
|
||||
import org.springframework.core.task.TaskExecutor;
|
||||
import org.springframework.scheduling.TaskScheduler;
|
||||
import org.springframework.scheduling.concurrent.ConcurrentTaskScheduler;
|
||||
import org.springframework.security.access.AccessDecisionManager;
|
||||
import org.springframework.statemachine.config.builders.StateMachineConfigurationBuilder;
|
||||
import org.springframework.statemachine.config.model.verifier.DefaultStateMachineModelVerifier;
|
||||
import org.springframework.statemachine.config.model.verifier.StateMachineModelVerifier;
|
||||
import org.springframework.statemachine.ensemble.StateMachineEnsemble;
|
||||
import org.springframework.statemachine.listener.StateMachineListener;
|
||||
@@ -52,7 +56,15 @@ public class ConfigurationData<S, E> {
|
||||
private final SecurityRule transitionSecurityRule;
|
||||
|
||||
/**
|
||||
* Instantiates a new state machine configuration config.
|
||||
* Instantiates a new state machine configuration config data.
|
||||
*/
|
||||
public ConfigurationData() {
|
||||
this(null, new SyncTaskExecutor(), new ConcurrentTaskScheduler(), false, null, new ArrayList<StateMachineListener<S, E>>(), false,
|
||||
null, null, null, null, true, new DefaultStateMachineModelVerifier<S, E>());
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new state machine configuration config data.
|
||||
*
|
||||
* @param beanFactory the bean factory
|
||||
* @param taskExecutor the task executor
|
||||
|
||||
@@ -45,6 +45,25 @@ public class StateData<S, E> {
|
||||
private boolean end = false;
|
||||
private PseudoStateKind pseudoStateKind;
|
||||
|
||||
/**
|
||||
* Instantiates a new state data.
|
||||
*
|
||||
* @param state the state
|
||||
*/
|
||||
public StateData(S state) {
|
||||
this(state, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new state data.
|
||||
*
|
||||
* @param state the state
|
||||
* @param initial the initial
|
||||
*/
|
||||
public StateData(S state, boolean initial) {
|
||||
this(null, null, state, null, null, null, initial);
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new state data.
|
||||
*
|
||||
@@ -57,12 +76,29 @@ public class StateData<S, E> {
|
||||
*/
|
||||
public StateData(Object parent, Object region, S state, Collection<E> deferred,
|
||||
Collection<? extends Action<S, E>> entryActions, Collection<? extends Action<S, E>> exitActions) {
|
||||
this(parent, region, state, deferred, entryActions, exitActions, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new state data.
|
||||
*
|
||||
* @param parent the parent
|
||||
* @param region the region
|
||||
* @param state the state
|
||||
* @param deferred the deferred
|
||||
* @param entryActions the entry actions
|
||||
* @param exitActions the exit actions
|
||||
* @param initial the initial
|
||||
*/
|
||||
public StateData(Object parent, Object region, S state, Collection<E> deferred,
|
||||
Collection<? extends Action<S, E>> entryActions, Collection<? extends Action<S, E>> exitActions, boolean initial) {
|
||||
this.state = state;
|
||||
this.deferred = deferred;
|
||||
this.entryActions = entryActions;
|
||||
this.exitActions = exitActions;
|
||||
this.parent = parent;
|
||||
this.region = region;
|
||||
this.initial = initial;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -40,6 +40,17 @@ public class TransitionData<S, E> {
|
||||
private final TransitionKind kind;
|
||||
private final SecurityRule securityRule;
|
||||
|
||||
/**
|
||||
* Instantiates a new transition data.
|
||||
*
|
||||
* @param source the source
|
||||
* @param target the target
|
||||
* @param event the event
|
||||
*/
|
||||
public TransitionData(S source, S target, E event) {
|
||||
this(source, target, null, event, null, null, null, null, TransitionKind.EXTERNAL, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new transition data.
|
||||
*
|
||||
|
||||
@@ -34,17 +34,26 @@ public class TransitionsData<S, E> {
|
||||
private final Map<S, List<S>> forks;
|
||||
private final Map<S, List<S>> joins;
|
||||
|
||||
/**
|
||||
* Instantiates a new transitions data.
|
||||
*
|
||||
* @param transitionsData the transitions data
|
||||
*/
|
||||
public TransitionsData(Collection<TransitionData<S, E>> transitionsData) {
|
||||
this(transitionsData, null, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new state machine transitions.
|
||||
*
|
||||
* @param transitions the transitions
|
||||
* @param transitionsData the transitions data
|
||||
* @param choices the choices
|
||||
* @param forks the forks
|
||||
* @param joins the joins
|
||||
*/
|
||||
public TransitionsData(Collection<TransitionData<S, E>> transitions,
|
||||
public TransitionsData(Collection<TransitionData<S, E>> transitionsData,
|
||||
Map<S, List<ChoiceData<S, E>>> choices, Map<S, List<S>> forks, Map<S, List<S>> joins) {
|
||||
this.transitions = transitions;
|
||||
this.transitions = transitionsData;
|
||||
this.choices = choices;
|
||||
this.forks = forks;
|
||||
this.joins = joins;
|
||||
|
||||
@@ -87,4 +87,27 @@ public class StateMachineModelTests {
|
||||
stateMachine.sendEvent("E1");
|
||||
assertThat(stateMachine.getState().getIds(), contains("S2"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMinimalConfig() {
|
||||
ConfigurationData<String, String> configurationData = new ConfigurationData<>();
|
||||
|
||||
Collection<StateData<String, String>> stateData = new ArrayList<>();
|
||||
stateData.add(new StateData<String, String>("S1", true));
|
||||
stateData.add(new StateData<String, String>("S2"));
|
||||
StatesData<String, String> statesData = new StatesData<>(stateData);
|
||||
|
||||
Collection<TransitionData<String, String>> transitionData = new ArrayList<>();
|
||||
transitionData.add(new TransitionData<String, String>("S1", "S2", "E1"));
|
||||
TransitionsData<String, String> transitionsData = new TransitionsData<>(transitionData);
|
||||
|
||||
StateMachineModel<String, String> stateMachineModel = new DefaultStateMachineModel<>(configurationData, statesData, transitionsData);
|
||||
ObjectStateMachineFactory<String, String> factory = new ObjectStateMachineFactory<>(stateMachineModel);
|
||||
|
||||
StateMachine<String,String> stateMachine = factory.getStateMachine();
|
||||
stateMachine.start();
|
||||
assertThat(stateMachine.getState().getIds(), contains("S1"));
|
||||
stateMachine.sendEvent("E1");
|
||||
assertThat(stateMachine.getState().getIds(), contains("S2"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,6 +49,8 @@ import org.springframework.statemachine.config.builders.StateMachineConfiguratio
|
||||
import org.springframework.statemachine.config.builders.StateMachineStateConfigurer;
|
||||
import org.springframework.statemachine.config.builders.StateMachineTransitionConfigurer;
|
||||
import org.springframework.statemachine.config.configurers.StateConfigurer.History;
|
||||
import org.springframework.statemachine.config.model.StateMachineModel;
|
||||
import org.springframework.statemachine.config.model.verifier.StateMachineModelVerifier;
|
||||
import org.springframework.statemachine.ensemble.StateMachineEnsemble;
|
||||
import org.springframework.statemachine.event.OnExtendedStateChanged;
|
||||
import org.springframework.statemachine.event.OnStateMachineError;
|
||||
@@ -814,7 +816,6 @@ public class DocsConfigurationSampleTests extends AbstractStateMachineTests {
|
||||
.taskScheduler(new ConcurrentTaskScheduler())
|
||||
.listener(new StateMachineListenerAdapter<States, Events>());
|
||||
}
|
||||
|
||||
}
|
||||
// end::snippetYA[]
|
||||
|
||||
@@ -838,10 +839,37 @@ public class DocsConfigurationSampleTests extends AbstractStateMachineTests {
|
||||
// naturally not null but should return ensemble instance
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
// end::snippetYB[]
|
||||
|
||||
// tag::snippetYC[]
|
||||
@Configuration
|
||||
@EnableStateMachine
|
||||
public class Config19
|
||||
extends EnumStateMachineConfigurerAdapter<States, Events> {
|
||||
|
||||
@Override
|
||||
public void configure(StateMachineConfigurationConfigurer<States, Events> config)
|
||||
throws Exception {
|
||||
config
|
||||
.withVerifier()
|
||||
.enabled(true)
|
||||
.verifier(verifier());
|
||||
}
|
||||
|
||||
@Bean
|
||||
public StateMachineModelVerifier<States, Events> verifier() {
|
||||
return new StateMachineModelVerifier<States, Events>() {
|
||||
|
||||
@Override
|
||||
public void verify(StateMachineModel<States, Events> model) {
|
||||
// throw exception indicating malformed model
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
// end::snippetYC[]
|
||||
|
||||
public class AccessorSamples {
|
||||
|
||||
StateMachine<String, String> stateMachine = null;
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright 2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.statemachine.docs;
|
||||
|
||||
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.statemachine.StateMachine;
|
||||
import org.springframework.statemachine.config.ObjectStateMachineFactory;
|
||||
import org.springframework.statemachine.config.model.ConfigurationData;
|
||||
import org.springframework.statemachine.config.model.DefaultStateMachineModel;
|
||||
import org.springframework.statemachine.config.model.StateData;
|
||||
import org.springframework.statemachine.config.model.StateMachineModel;
|
||||
import org.springframework.statemachine.config.model.StatesData;
|
||||
import org.springframework.statemachine.config.model.TransitionData;
|
||||
import org.springframework.statemachine.config.model.TransitionsData;
|
||||
|
||||
public class DocsConfigurationSampleTests6 {
|
||||
|
||||
@Test
|
||||
public void testMinimalConfig() {
|
||||
// tag::snippetA[]
|
||||
// setup configuration data
|
||||
ConfigurationData<String, String> configurationData = new ConfigurationData<>();
|
||||
|
||||
// setup states data
|
||||
Collection<StateData<String, String>> stateData = new ArrayList<>();
|
||||
stateData.add(new StateData<String, String>("S1", true));
|
||||
stateData.add(new StateData<String, String>("S2"));
|
||||
StatesData<String, String> statesData = new StatesData<>(stateData);
|
||||
|
||||
// setup transitions data
|
||||
Collection<TransitionData<String, String>> transitionData = new ArrayList<>();
|
||||
transitionData.add(new TransitionData<String, String>("S1", "S2", "E1"));
|
||||
TransitionsData<String, String> transitionsData = new TransitionsData<>(transitionData);
|
||||
|
||||
// setup model
|
||||
StateMachineModel<String, String> stateMachineModel = new DefaultStateMachineModel<>(configurationData, statesData,
|
||||
transitionsData);
|
||||
|
||||
// instantiate machine via factory
|
||||
ObjectStateMachineFactory<String, String> factory = new ObjectStateMachineFactory<>(stateMachineModel);
|
||||
StateMachine<String, String> stateMachine = factory.getStateMachine();
|
||||
// end::snippetA[]
|
||||
stateMachine.start();
|
||||
assertThat(stateMachine.getState().getIds(), contains("S1"));
|
||||
stateMachine.sendEvent("E1");
|
||||
assertThat(stateMachine.getState().getIds(), contains("S2"));
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user