From 3d9059a0750b5d6c5e88362fe122c9dadf6bd2c5 Mon Sep 17 00:00:00 2001 From: Janne Valkealahti Date: Sat, 10 Dec 2016 12:27:58 +0000 Subject: [PATCH] Update docs - Add section about machineId - Relates to #284 --- docs/src/reference/asciidoc/sm.adoc | 82 +++++++++++ .../docs/DocsConfigurationSampleTests10.java | 133 ++++++++++++++++++ 2 files changed, 215 insertions(+) create mode 100644 spring-statemachine-core/src/test/java/org/springframework/statemachine/docs/DocsConfigurationSampleTests10.java diff --git a/docs/src/reference/asciidoc/sm.adoc b/docs/src/reference/asciidoc/sm.adoc index e9153545..cb11f759 100644 --- a/docs/src/reference/asciidoc/sm.adoc +++ b/docs/src/reference/asciidoc/sm.adoc @@ -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 <> 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 +build(String machineId)` which a _StateMachineModelFactory_ +implementation may choose to use. + +_RepositoryStateMachineModelFactory_ <> 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 +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. diff --git a/spring-statemachine-core/src/test/java/org/springframework/statemachine/docs/DocsConfigurationSampleTests10.java b/spring-statemachine-core/src/test/java/org/springframework/statemachine/docs/DocsConfigurationSampleTests10.java new file mode 100644 index 00000000..960ea2e2 --- /dev/null +++ b/spring-statemachine-core/src/test/java/org/springframework/statemachine/docs/DocsConfigurationSampleTests10.java @@ -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 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 factory = context.getBean(StateMachineFactory.class); + StateMachine 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 { + +// tag::snippetA[] + @Override + public void configure(StateMachineConfigurationConfigurer config) + throws Exception { + config + .withConfiguration() + .machineId("mymachine"); + } +// end::snippetA[] + + @Override + public void configure(StateMachineStateConfigurer states) throws Exception { + states + .withStates() + .initial("S1") + .state("S2"); + } + + @Override + public void configure(StateMachineTransitionConfigurer transitions) throws Exception { + transitions + .withExternal() + .source("S1") + .target("S2") + .event("E1"); + } + } + + @Configuration + @EnableStateMachineFactory + public static class Config2 extends StateMachineConfigurerAdapter { + + @Override + public void configure(StateMachineConfigurationConfigurer config) + throws Exception { + config + .withConfiguration() + .machineId("mymachine"); + } + + @Override + public void configure(StateMachineStateConfigurer states) throws Exception { + states + .withStates() + .initial("S1") + .state("S2"); + } + + @Override + public void configure(StateMachineTransitionConfigurer transitions) throws Exception { + transitions + .withExternal() + .source("S1") + .target("S2") + .event("E1"); + } + } + + @Override + protected AnnotationConfigApplicationContext buildContext() { + return new AnnotationConfigApplicationContext(); + } +}