diff --git a/build.gradle b/build.gradle
index 39f26a6a..f998661e 100644
--- a/build.gradle
+++ b/build.gradle
@@ -568,6 +568,8 @@ configure(rootProject) {
from 'spring-statemachine-samples/eventservice/src/main/java/'
from 'spring-statemachine-samples/datajpa/src/main/java/'
from 'spring-statemachine-samples/datajpa/src/main/resources/'
+ from 'spring-statemachine-samples/datajpamultipersist/src/main/java/'
+ from 'spring-statemachine-samples/datajpamultipersist/src/main/resources/'
from 'spring-statemachine-samples/datapersist/src/main/java/'
from 'spring-statemachine-samples/monitoring/src/main/java/'
include '**/*.java'
diff --git a/docs/src/reference/asciidoc/images/sm-datajpamultipersist-1.png b/docs/src/reference/asciidoc/images/sm-datajpamultipersist-1.png
new file mode 100644
index 00000000..2cbc1498
Binary files /dev/null and b/docs/src/reference/asciidoc/images/sm-datajpamultipersist-1.png differ
diff --git a/docs/src/reference/asciidoc/images/sm-datajpamultipersist-2.png b/docs/src/reference/asciidoc/images/sm-datajpamultipersist-2.png
new file mode 100644
index 00000000..7f20c626
Binary files /dev/null and b/docs/src/reference/asciidoc/images/sm-datajpamultipersist-2.png differ
diff --git a/docs/src/reference/asciidoc/images/sm-datajpamultipersist-3.png b/docs/src/reference/asciidoc/images/sm-datajpamultipersist-3.png
new file mode 100644
index 00000000..6b12fb11
Binary files /dev/null and b/docs/src/reference/asciidoc/images/sm-datajpamultipersist-3.png differ
diff --git a/docs/src/reference/asciidoc/index-docinfo.xml b/docs/src/reference/asciidoc/index-docinfo.xml
index 7b5c8dfb..776e4bb3 100644
--- a/docs/src/reference/asciidoc/index-docinfo.xml
+++ b/docs/src/reference/asciidoc/index-docinfo.xml
@@ -13,6 +13,7 @@
2016
2017
2018
+ 2019
Pivotal Software, Inc.
diff --git a/docs/src/reference/asciidoc/sm-examples.adoc b/docs/src/reference/asciidoc/sm-examples.adoc
index b9299b73..dd216a39 100644
--- a/docs/src/reference/asciidoc/sm-examples.adoc
+++ b/docs/src/reference/asciidoc/sm-examples.adoc
@@ -40,6 +40,8 @@ normal build cycle. Samples in this chapter are:
<> Data Persist.
+<> Data Multi Persist.
+
<> Monitoring.
@@ -1605,6 +1607,90 @@ image::images/sm-datajpapersist-3.png[scaledwidth="100%"]
If requesting machine 'datajpapersist1' by not sending any events,
machine is restored back to its persisted state 'S3'.
+[[statemachine-examples-datajpamultipersist]]
+== Data Multi Persist
+Data Multi Persist is an example which is an extension of two other samples
+<> and <>.
+We still keep machine configuration in a database and persist into a
+database but this time we also have a machine containing two orthogonal
+regions showing how those are persisted independently. This sample
+is also using embedded _H2_ database with a _H2 Console_ to ease playing
+with a database.
+
+This sample uses `spring-statemachine-autoconfigure` which on default
+auto-configures repositories and entity classes needed for JPA.
+Thus only `@SpringBootApplication` is needed.
+
+[source,java,indent=0]
+----
+include::samples/demo/datajpamultipersist/Application.java[tags=snippetA]
+----
+
+We again create a `StateMachineRuntimePersister`.
+
+[source,java,indent=0]
+----
+include::samples/demo/datajpamultipersist/StateMachineConfig.java[tags=snippetA]
+----
+
+`StateMachineService` makes it easier to work with a machines.
+
+[source,java,indent=0]
+----
+include::samples/demo/datajpamultipersist/StateMachineConfig.java[tags=snippetB]
+----
+
+We use data from json to import configuration.
+
+[source,java,indent=0]
+----
+include::samples/demo/datajpamultipersist/StateMachineConfig.java[tags=snippetC]
+----
+
+What comes for a machine config `RepositoryStateMachineModelFactory`
+can be used as shown below.
+
+[source,java,indent=0]
+----
+include::samples/demo/datajpamultipersist/StateMachineConfig.java[tags=snippetD]
+----
+
+Let's get into actual demo. Run the boot based sample application:
+
+[source,text,subs="attributes"]
+----
+# java -jar spring-statemachine-samples-datajpamultipersist-{revnumber}.jar
+----
+
+Accessing application via _http://localhost:8080_ brings up a new
+constructed machine with every request and you can choose to send
+events to a machine. Possible events and machine configuration are
+updated from a database with every request. We also print out
+all state machine contexts and current root machine.
+
+image::images/sm-datajpamultipersist-1.png[scaledwidth="100%"]
+
+Machine _datajpamultipersist1_ is simple flat machine where states _S1_,
+_S2_ and _S3_ are transitioned with events _E1_, _E2_ and _E3_ meaning
+nothing new there. However machine _datajpamultipersist2_ contains two
+regions _R1_ and _R2_ directly under root level, thus a reason why
+root level machine really doesn't have a state at all but we still need
+that root level machine to host those regions.
+
+Regions _R1_ and _R2_ in machine _datajpamultipersist2_ contains states
+_S10_, _S11_, _S12_ and _S20_, _S21_, _S22_ respectively and events
+_E10_, _E11_ and _E12_ are used for region _R1_ and events _E20_, _E21_
+and _E22_ for region _R2_. Lets send events _E10_ and _E20_ to machine
+_datajpamultipersist2_ and see how things look like.
+
+image::images/sm-datajpamultipersist-2.png[scaledwidth="100%"]
+
+Regions have their own contexts with their own id's and where the actual
+id is postfixed with `#` plus `region id`. As shown below there are
+different contexts in a database for regions.
+
+image::images/sm-datajpamultipersist-3.png[scaledwidth="100%"]
+
[[statemachine-examples-monitoring]]
== Monitoring
Monitoring is an example how state machine concepts can be used to
diff --git a/docs/src/reference/asciidoc/sm.adoc b/docs/src/reference/asciidoc/sm.adoc
index 2008d69b..07ca3637 100644
--- a/docs/src/reference/asciidoc/sm.adoc
+++ b/docs/src/reference/asciidoc/sm.adoc
@@ -145,6 +145,17 @@ mean that a specific state must have multiple independent regions.
include::samples/DocsConfigurationSampleTests.java[tags=snippetP]
----
+When working with persisting machines with regions or generally
+relying any functionalities to reset a machine it may be required
+to have a dedicated id for a region itself. On default this id
+is just a generated _UUID_. As shown below `StateConfigurer` has
+a method `region(String id)` for it.
+
+[source,java,indent=0]
+----
+include::samples/DocsConfigurationSampleTests.java[tags=snippetPP]
+----
+
=== Configuring Transitions
We support three different types of transitions, `external`,
`internal` and `local`. Transitions are either triggered by a signal
@@ -1866,6 +1877,21 @@ is a runtime representation of a state machine which can be used to
restore an existing machine into a state represented by a particular
`StateMachineContext` object.
+`StateMachineContext` contains two different ways to include information
+for a child contexts. These are generally used when machine contains
+orthogonal regions. Firstly context can have a list of child context
+as is which takes a presence if exists, secondly it is possible
+to include a list of references which are used if raw context childs
+are not in place. These child references are really only way to
+persist a machine where multiple parallel regions are running
+independently.
+
+[TIP]
+====
+There is a sample <> showing
+how parallel regions can be persisted.
+====
+
[[sm-persist-statemachinepersister]]
=== Using StateMachinePersister
Building a `StateMachineContext` and then restoring a state machine
diff --git a/spring-statemachine-core/src/test/java/org/springframework/statemachine/docs/DocsConfigurationSampleTests.java b/spring-statemachine-core/src/test/java/org/springframework/statemachine/docs/DocsConfigurationSampleTests.java
index e610df8b..22032f89 100644
--- a/spring-statemachine-core/src/test/java/org/springframework/statemachine/docs/DocsConfigurationSampleTests.java
+++ b/spring-statemachine-core/src/test/java/org/springframework/statemachine/docs/DocsConfigurationSampleTests.java
@@ -631,6 +631,38 @@ public class DocsConfigurationSampleTests extends AbstractStateMachineTests {
}
// end::snippetP[]
+// tag::snippetPP[]
+ @Configuration
+ @EnableStateMachine
+ public class Config10RegionId
+ extends EnumStateMachineConfigurerAdapter {
+
+ @Override
+ public void configure(StateMachineStateConfigurer states)
+ throws Exception {
+ states
+ .withStates()
+ .initial(States2.S1)
+ .state(States2.S2)
+ .and()
+ .withStates()
+ .parent(States2.S2)
+ .region("R1")
+ .initial(States2.S2I)
+ .state(States2.S21)
+ .end(States2.S2F)
+ .and()
+ .withStates()
+ .parent(States2.S2)
+ .region("R2")
+ .initial(States2.S3I)
+ .state(States2.S31)
+ .end(States2.S3F);
+ }
+
+ }
+// end::snippetPP[]
+
// tag::snippetQ[]
@Configuration
@EnableStateMachine
diff --git a/spring-statemachine-samples/datajpamultipersist/src/main/java/demo/datajpamultipersist/StateMachineConfig.java b/spring-statemachine-samples/datajpamultipersist/src/main/java/demo/datajpamultipersist/StateMachineConfig.java
index 0d52443d..017787c9 100644
--- a/spring-statemachine-samples/datajpamultipersist/src/main/java/demo/datajpamultipersist/StateMachineConfig.java
+++ b/spring-statemachine-samples/datajpamultipersist/src/main/java/demo/datajpamultipersist/StateMachineConfig.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2018 the original author or authors.
+ * Copyright 2018-2019 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.
@@ -41,26 +41,33 @@ import org.springframework.statemachine.service.StateMachineService;
@Configuration
public class StateMachineConfig {
+//tag::snippetA[]
@Bean
public StateMachineRuntimePersister stateMachineRuntimePersister(
JpaStateMachineRepository jpaStateMachineRepository) {
return new JpaPersistingStateMachineInterceptor<>(jpaStateMachineRepository);
}
+//end::snippetA[]
+//tag::snippetB[]
@Bean
public StateMachineService stateMachineService(
StateMachineFactory stateMachineFactory,
StateMachineRuntimePersister stateMachineRuntimePersister) {
return new DefaultStateMachineService(stateMachineFactory, stateMachineRuntimePersister);
}
+//end::snippetB[]
+//tag::snippetC[]
@Bean
public StateMachineJackson2RepositoryPopulatorFactoryBean jackson2RepositoryPopulatorFactoryBean() {
StateMachineJackson2RepositoryPopulatorFactoryBean factoryBean = new StateMachineJackson2RepositoryPopulatorFactoryBean();
- factoryBean.setResources(new Resource[] { new ClassPathResource("data.json") });
+ factoryBean.setResources(new Resource[] { new ClassPathResource("datajpamultipersist.json") });
return factoryBean;
}
+//end::snippetC[]
+//tag::snippetD[]
@Configuration
@EnableStateMachineFactory
public static class Config extends StateMachineConfigurerAdapter {
@@ -95,4 +102,5 @@ public class StateMachineConfig {
return new RepositoryStateMachineModelFactory(stateRepository, transitionRepository);
}
}
+//end::snippetD[]
}
diff --git a/spring-statemachine-samples/datajpamultipersist/src/main/resources/data.json b/spring-statemachine-samples/datajpamultipersist/src/main/resources/datajpamultipersist.json
similarity index 100%
rename from spring-statemachine-samples/datajpamultipersist/src/main/resources/data.json
rename to spring-statemachine-samples/datajpamultipersist/src/main/resources/datajpamultipersist.json