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