Update docs

- Add section about machineId
- Relates to #284
This commit is contained in:
Janne Valkealahti
2016-12-10 12:27:58 +00:00
parent 457c924e67
commit 3d9059a075
2 changed files with 215 additions and 0 deletions

View File

@@ -521,6 +521,80 @@ just how Spring Framework works with _Beans_.
include::samples/DocsConfigurationSampleTests7.java[tags=snippetA]
----
[[sm-machineid]]
== State Machine ID
Various classes and interfaces use `machineId` either as a variable or
parameter in a methods. This chapter takes a closer look how
`machineId` relates to normal machine operation and instantiation.
During a runtime `machineId` really don't have any big operational
role except to distinguish machines from each other for example when
following logs or doing deeper debugging. Having a lot of different
machine instances quickly gets user lost in translation if there is
no easy way to identify these instances and option to set this
`machineId` was given to a user.
=== With @EnableStateMachine
Setting `machineId` via JavaConfig as `mymachine` then exposes that
for logs as shown above. This same `machineId` is also available via
method `StateMachine.getId()`.
[source,java,indent=0]
----
include::samples/DocsConfigurationSampleTests10.java[tags=snippetA]
----
[source,text]
----
11:23:54,509 INFO main support.LifecycleObjectSupport [main] -
started S2 S1 / S1 / uuid=8fe53d34-8c85-49fd-a6ba-773da15fcaf1 / id=mymachine
----
[NOTE]
====
Manual builder <<state-machine-via-builder>> uses same config
interface meaning behaviour would be equivalent.
====
=== With @EnableStateMachineFactory
You'll see same `machineId` getting configured if you use a
_StateMachineFactory_ and request a new machine using id.
[source,java,indent=0]
----
include::samples/DocsConfigurationSampleTests10.java[tags=snippetB]
----
=== With StateMachineModelFactory
Behind a scenes all machine configurations are first translated into a
_StateMachineModel_ so that _StateMachineFactory_ don't need to know
from where configuration originated as machine can be built from
JavaConfig, UML or Repository. If user wants to go crazy a custom
_StateMachineModel_ can also be used which would be a lowest possible
level to define configuration.
What all these has to do with a `machineId`?
_StateMachineModelFactory_ also have a method `StateMachineModel<S, E>
build(String machineId)` which a _StateMachineModelFactory_
implementation may choose to use.
_RepositoryStateMachineModelFactory_ <<sm-repository>> uses
`machineId` to support different configurations in a persistent
storage used via _Spring Data Repository_ interfaces. For example both
_StateRepository_ and _TransitionRepository_ have a method `List<T>
findByMachineId(String machineId)` order to build different states and
transitions by a `machineId`. With
_RepositoryStateMachineModelFactory_ if `machineId` is used as empty
or NULL defaults to repository config(in a backing persistent model)
without known machine id.
[NOTE]
====
_UmlStateMachineModelFactory_ currently doesn't distinguish between
different machine id's as uml source is always coming from a same
file. Thought this may get changed in future releases.
====
[[sm-factories]]
== State Machine Factories
There are use cases when state machine needs to be created dynamically
@@ -2233,6 +2307,14 @@ what _Spring Data_ supports. Using a real _Repository_ related
_Entity_ class comes into play when you manually try to write new
states or transitions into a backed repository.
[TIP]
====
Entity classes for _RepositoryState_ and _RepositoryTransition_ have
`machineId` field which is in users disposal and can be used to
differentiate between configurations for example if machines are built
via _StateMachineFactory_.
====
Actual out of a box implementations are documented in below sections
where images below are uml equivalent statecharts of a repository
configs.

View File

@@ -0,0 +1,133 @@
/*
* 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.containsInAnyOrder;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertThat;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Configuration;
import org.springframework.statemachine.AbstractStateMachineTests;
import org.springframework.statemachine.StateMachine;
import org.springframework.statemachine.StateMachineSystemConstants;
import org.springframework.statemachine.config.EnableStateMachine;
import org.springframework.statemachine.config.EnableStateMachineFactory;
import org.springframework.statemachine.config.StateMachineConfigurerAdapter;
import org.springframework.statemachine.config.StateMachineFactory;
import org.springframework.statemachine.config.builders.StateMachineConfigurationConfigurer;
import org.springframework.statemachine.config.builders.StateMachineStateConfigurer;
import org.springframework.statemachine.config.builders.StateMachineTransitionConfigurer;
public class DocsConfigurationSampleTests10 extends AbstractStateMachineTests {
@Test
public void testConfig1() throws Exception {
context.register(Config1.class);
context.refresh();
@SuppressWarnings("unchecked")
StateMachine<String, String> machine = context.getBean(StateMachineSystemConstants.DEFAULT_ID_STATEMACHINE, StateMachine.class);
machine.start();
assertThat(machine.getState().getIds(), containsInAnyOrder("S1"));
assertThat(machine.getId(), is("mymachine"));
machine.sendEvent("E1");
assertThat(machine.getState().getIds(), containsInAnyOrder("S2"));
}
@Test
public void testConfig2() throws Exception {
context.register(Config2.class);
context.refresh();
@SuppressWarnings("unchecked")
// tag::snippetB[]
StateMachineFactory<String, String> factory = context.getBean(StateMachineFactory.class);
StateMachine<String, String> machine = factory.getStateMachine("mymachine");
// end::snippetB[]
machine.start();
assertThat(machine.getState().getIds(), containsInAnyOrder("S1"));
assertThat(machine.getId(), is("mymachine"));
machine.sendEvent("E1");
assertThat(machine.getState().getIds(), containsInAnyOrder("S2"));
}
@Configuration
@EnableStateMachine
public static class Config1 extends StateMachineConfigurerAdapter<String, String> {
// tag::snippetA[]
@Override
public void configure(StateMachineConfigurationConfigurer<String, String> config)
throws Exception {
config
.withConfiguration()
.machineId("mymachine");
}
// end::snippetA[]
@Override
public void configure(StateMachineStateConfigurer<String, String> states) throws Exception {
states
.withStates()
.initial("S1")
.state("S2");
}
@Override
public void configure(StateMachineTransitionConfigurer<String, String> transitions) throws Exception {
transitions
.withExternal()
.source("S1")
.target("S2")
.event("E1");
}
}
@Configuration
@EnableStateMachineFactory
public static class Config2 extends StateMachineConfigurerAdapter<String, String> {
@Override
public void configure(StateMachineConfigurationConfigurer<String, String> config)
throws Exception {
config
.withConfiguration()
.machineId("mymachine");
}
@Override
public void configure(StateMachineStateConfigurer<String, String> states) throws Exception {
states
.withStates()
.initial("S1")
.state("S2");
}
@Override
public void configure(StateMachineTransitionConfigurer<String, String> transitions) throws Exception {
transitions
.withExternal()
.source("S1")
.target("S2")
.event("E1");
}
}
@Override
protected AnnotationConfigApplicationContext buildContext() {
return new AnnotationConfigApplicationContext();
}
}