Documentation changes

- Document changes to JPA Entity model, persistence
  facilities and related new interfaces and services.
- Relates to #429
- Relates to #476
This commit is contained in:
Janne Valkealahti
2018-01-21 11:40:50 +00:00
parent 3481140126
commit 744d138944
14 changed files with 307 additions and 17 deletions

View File

@@ -451,6 +451,7 @@ 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/datajpapersist/src/main/java/'
from 'spring-statemachine-samples/monitoring/src/main/java/'
include '**/*.java'
include '**/*.uml'

Binary file not shown.

Before

Width:  |  Height:  |  Size: 173 KiB

After

Width:  |  Height:  |  Size: 108 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 73 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 73 KiB

View File

@@ -38,6 +38,8 @@ normal build cycle. Samples in this chapter are:
<<statemachine-examples-datajpa>> JPA Config.
<<statemachine-examples-datajpapersist>> JPA Persist.
<<statemachine-examples-monitoring>> Monitoring.
@@ -1495,6 +1497,87 @@ Actual source for populator data is shown below.
include::samples/data.json[]
----
[[statemachine-examples-datajpapersist]]
== JPA Persist
JPA Persist is an example how state machine concepts can be used
with persisting machine in a database. This sample is using
embedded _H2_ database with a _H2 Console_ to ease playing with a
database.
This sample uses `spring-statemachine-boot` which on default
auto-configures repositories and entity classes needed for JPA.
Thus only `@SpringBootApplication` is needed.
[source,java,indent=0]
----
include::samples/demo/datajpapersist/Application.java[tags=snippetA]
----
`StateMachineRuntimePersister` is a new interface working on a runtime
level of a 'StateMachine' and its implementation
`JpaPersistingStateMachineInterceptor` is meant to be used with a
'JPA'.
[source,java,indent=0]
----
include::samples/demo/datajpapersist/StateMachineConfig.java[tags=snippetA]
----
'StateMachine' can be configured to use runtime persistence by using
`withPersistence` config method.
[source,java,indent=0]
----
include::samples/demo/datajpapersist/StateMachineConfig.java[tags=snippetB]
----
In this sample we also use `DefaultStateMachineService` which makes it
easier to work with multiple machines
[source,java,indent=0]
----
include::samples/demo/datajpapersist/StateMachineConfig.java[tags=snippetC]
----
A logic using a `StateMachineService` in this sample is show below.
[source,java,indent=0]
----
include::samples/demo/datajpapersist/StateMachineController.java[tags=snippetA]
----
Let's get into actual demo. Run the boot based sample application:
[source,text,subs="attributes"]
----
# java -jar spring-statemachine-samples-datajpapersist-{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.
Machines in this sample have a simple configuration with states 'S1'
to 'S6' and events 'E1' to 'E6' transitioning machine between those
states. Two machine identifiers 'datajpapersist1' and
'datajpapersist2' can be used to request particular machine.
image::images/sm-datajpapersist-1.png[scaledwidth="100%"]
Sample defaults to using machine 'datajpapersist1' and goes to its
initial state 'S1'.
image::images/sm-datajpapersist-2.png[scaledwidth="100%"]
If events 'E1' and 'E2' are sent into machine 'datajpapersist1' its
state is persisted as 'S3'.
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-monitoring]]
== Monitoring
Monitoring is an example how state machine concepts can be used to

View File

@@ -36,6 +36,8 @@ that Spring Statemachine provides to any Spring based application.
<<sm-error-handling>> the state machine interceptor support.
<<sm-service>> the state machine service support.
<<sm-persist>> the state machine persisting support.
<<sm-boot>> the Spring Boot support.
@@ -490,6 +492,13 @@ include::samples/DocsConfigurationSampleTests.java[tags=snippetYC]
More about config model, refer to section <<devdocs-configmodel>>.
[NOTE]
====
Config methods `withSecurity`, `withMonitoring` and `withPersistence`
are documented in sections <<sm-security>>, <<sm-monitoring>> and
<<sm-persist-statemachineruntimepersister>> respectively.
====
=== Configuring Model
`StateMachineModelFactory` is a hook to configure statemachine model
without using a manual configuration. Essentially it is a third party
@@ -1758,6 +1767,19 @@ Actions defined for transitions also have their own error handling
logic <<statemachine-config-transition-actions-errorhandling>>.
====
[[sm-service]]
== State Machine Services
StateMachine services are higher level implementations meant to
provide more user level functionalities to ease normal runtime
operations. Currently only one service interface
<<sm-service-statemachineservice>> exists.
[[sm-service-statemachineservice]]
=== Using StateMachineService
`StateMachineService` is an interface meant to handle running machines
and have a simple methods to 'acquire' and 'release' machines. It has
one default implementation named `DefaultStateMachineService`.
[[sm-persist]]
== Persisting State Machine
Traditionally an instance of a state machine is used as is within a
@@ -1869,6 +1891,24 @@ Check sample <<statemachine-examples-eventservice>> for detailed usage.
`RedisConnectionFactory` for it to work and we recommend a
`JedisConnectionFactory` for it as seeing from above example.
[[sm-persist-statemachineruntimepersister]]
=== Using StateMachineRuntimePersister
`StateMachineRuntimePersister` is a simple extension to
`StateMachinePersist` adding interface level method to get
`StateMachineInterceptor` associated with it. This interceptor is then
required to persist machine during state changes without needing to
stop and start a machine.
Currently there are implementations for this interface for out-of-the-box
supported _Spring Data Repositories_. These are
`JpaStateMachineRuntimePersister`, `RedisStateMachineRuntimePersister`
and `MongoDbStateMachineRuntimePersister`.
[TIP]
====
Check sample <<statemachine-examples-datajpapersist>> for detailed usage.
====
[[sm-boot]]
== Spring Boot Support
Auto-configuration module `spring-statemachine-boot` contains all
@@ -2356,7 +2396,12 @@ sub-state.
image::images/papyrus-gs-15.png[scaledwidth="100%"]
[[sm-repository]]
== Repository Config Support
== Repository Support
This section contains documentation related to using 'Spring Data
Repositories' used in State Machine.
[[sm-repository-config]]
=== Repository Config
It is also possible to keep machine configuration in an external
storage where it will be loaded on demand instead of creating a static
configuration either using _JavaConfig_ or _UML_ based config. This
@@ -2402,14 +2447,26 @@ image::images/sm-repository-simplesubmachine.png[scaledwidth="100%", title="Simp
[[image-sm-repository-showcasemachine]]
image::images/sm-repository-showcasemachine.png[scaledwidth="100%", title="ShowcaseMachine"]
[[sm-repository-jpa]]
=== JPA
[[sm-repository-config-jpa]]
==== JPA
Actual _Repository_ implementations for a _JPA_ are
`JpaStateRepository`, `JpaTransitionRepository`, `JpaActionRepository`
and `JpaGuardRepository` which are backed by
_Entity_ classes `JpaRepositoryState`, `JpaRepositoryTransition`,
`JpaRepositoryAction` and `JpaRepositoryGuard` respectively.
[IMPORTANT]
====
Version '1.2.8' unfortunately had to made a change into JPA's _Entity_
model regarding used table names. Previously generated table names
always had a prefix 'JPA_REPOSITORY_' derived from _Entity_ class
names. As this caused breaking issues with databases imposing
restrictions on database object lengths, all _Entity_ classes have
spesific definitions to force table names. For example
'JPA_REPOSITORY_STATE' is now simple 'STATE' and so on with other
_Entity_ classes.
====
Generic way to update states and transition manually for jpa is shown
below. This is equivalent to machine shown in
<<image-sm-repository-simplemachine>>.
@@ -2463,8 +2520,8 @@ Complete example can be found from sample
repository can be pre-populated from existing _json_ file having a
definitions for entity classes.
[[sm-repository-redis]]
=== Redis
[[sm-repository-config-redis]]
==== Redis
Actual _Repository_ implementations for a _Redis_ are
`RedisStateRepository`, `RedisTransitionRepository`, `RedisActionRepository`
and `RedisGuardRepository` which are backed by
@@ -2488,8 +2545,8 @@ This is equivalent to machine shown in
include::samples/DocsRedisRepositorySampleTests1.java[tags=snippetB]
----
[[sm-repository-mongodb]]
=== MongoDB
[[sm-repository-config-mongodb]]
==== MongoDB
Actual _Repository_ implementations for a _MongoDB_ are
`MongoDbStateRepository`, `MongoDbTransitionRepository`, `MongoDbActionRepository`
and `MongoDbGuardRepository` which are backed by
@@ -2513,3 +2570,55 @@ This is equivalent to machine shown in
include::samples/DocsMongoDbRepositorySampleTests1.java[tags=snippetB]
----
[[sm-repository-persistence]]
=== Repository Persistence
Apart from storing machine configuration, shown in
<<sm-repository-config>>, in an external repository it is also
possible to persist machine into repositories.
Interface `StateMachineRepository` is a central access point
interacting with machine persistence and is backed by _Entity_ class
`RepositoryStateMachine`.
[[sm-repository-persistence-jpa]]
==== JPA
Actual _Repository_ implementation for a _JPA_ is
`JpaStateMachineRepository` which is backed by _Entity_ class
`JpaRepositoryStateMachine`.
Generic way to persist machine for jpa is shown below. This is
equivalent to machine shown in <<image-sm-repository-simplemachine>>.
[source,java,indent=0]
----
include::samples/DocsJpaRepositorySampleTests1.java[tags=snippetD]
----
[[sm-repository-persistence-redis]]
==== Redis
Actual _Repository_ implementation for a _Redis_ is
`RedisStateMachineRepository` which is backed by _Entity_ class
`RedisRepositoryStateMachine`.
Generic way to persist machine for jpa is shown below. This is
equivalent to machine shown in <<image-sm-repository-simplemachine>>.
[source,java,indent=0]
----
include::samples/DocsRedisRepositorySampleTests1.java[tags=snippetC]
----
[[sm-repository-persistence-mongodb]]
==== MongoDB
Actual _Repository_ implementation for a _MongoDB_ is
`MongoDbStateMachineRepository` which is backed by _Entity_ class
`MongoDbRepositoryStateMachine`.
Generic way to persist machine for jpa is shown below. This is
equivalent to machine shown in <<image-sm-repository-simplemachine>>.
[source,java,indent=0]
----
include::samples/DocsMongoDbRepositorySampleTests1.java[tags=snippetC]
----

View File

@@ -35,3 +35,10 @@ _UML_ support and integrations with external config repositories.
* Initial work for _Spring Boot_ support. <<sm-boot>>
* Support for tracing and monitoring. <<sm-monitoring>>
=== In 1.2.8
_Spring Statemachine 1.2.8_ contains a bit more functionality normally
not seen in a point release but these changes didn't merit a fork of
_Spring Statemachine 1.3_.
* JPA entity classes have changed table names <<sm-repository-config-jpa>>

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2016-2017 the original author or authors.
* Copyright 2016-2018 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.
@@ -246,6 +246,28 @@ public class JpaRepositoryTests extends AbstractRepositoryTests {
assertThat(transitionsRepository.count(), is(2l));
}
@Test
public void testRepository7() {
context.register(TestConfig.class);
context.refresh();
JpaStateMachineRepository stateMachineRepository = context.getBean(JpaStateMachineRepository.class);
JpaRepositoryStateMachine machine1 = new JpaRepositoryStateMachine();
machine1.setMachineId("machine1");
machine1.setState("S1");
machine1.setStateMachineContext(new byte[] { 0 });
assertThat(stateMachineRepository.count(), is(0l));
stateMachineRepository.save(machine1);
assertThat(stateMachineRepository.count(), is(1l));
JpaRepositoryStateMachine machine1x = stateMachineRepository.findOne("machine1");
assertThat(machine1x.getMachineId(), is(machine1.getMachineId()));
assertThat(machine1x.getState(), is(machine1.getState()));
assertThat(machine1x.getStateMachineContext().length, is(1));
}
@Override
protected AnnotationConfigApplicationContext buildContext() {
return new AnnotationConfigApplicationContext();

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2016 the original author or authors.
* Copyright 2016-2018 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.
@@ -21,11 +21,13 @@ import java.util.HashSet;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.statemachine.data.ActionRepository;
import org.springframework.statemachine.data.GuardRepository;
import org.springframework.statemachine.data.StateMachineRepository;
import org.springframework.statemachine.data.StateRepository;
import org.springframework.statemachine.data.TransitionRepository;
import org.springframework.statemachine.data.jpa.JpaRepositoryAction;
import org.springframework.statemachine.data.jpa.JpaRepositoryGuard;
import org.springframework.statemachine.data.jpa.JpaRepositoryState;
import org.springframework.statemachine.data.jpa.JpaRepositoryStateMachine;
import org.springframework.statemachine.data.jpa.JpaRepositoryTransition;
import org.springframework.statemachine.transition.TransitionKind;
@@ -206,4 +208,23 @@ public class DocsJpaRepositorySampleTests1 {
// end::snippetC4[]
}
}
public static class Config4 {
// tag::snippetD[]
@Autowired
StateMachineRepository<JpaRepositoryStateMachine> stateMachineRepository;
void persist() {
JpaRepositoryStateMachine machine = new JpaRepositoryStateMachine();
machine.setMachineId("machine");
machine.setState("S1");
// raw byte[] representation of a context
machine.setStateMachineContext(new byte[] { 0 });
stateMachineRepository.save(machine);
}
// end::snippetD[]
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2016 the original author or authors.
* Copyright 2016-2018 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.
@@ -16,9 +16,11 @@
package org.springframework.statemachine.data.mongodb.docs;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.statemachine.data.StateMachineRepository;
import org.springframework.statemachine.data.StateRepository;
import org.springframework.statemachine.data.TransitionRepository;
import org.springframework.statemachine.data.mongodb.MongoDbRepositoryState;
import org.springframework.statemachine.data.mongodb.MongoDbRepositoryStateMachine;
import org.springframework.statemachine.data.mongodb.MongoDbRepositoryTransition;
public class DocsMongoDbRepositorySampleTests1 {
@@ -83,4 +85,24 @@ public class DocsMongoDbRepositorySampleTests1 {
}
// end::snippetB[]
}
public static class Config3 {
// tag::snippetC[]
@Autowired
StateMachineRepository<MongoDbRepositoryStateMachine> stateMachineRepository;
void persist() {
MongoDbRepositoryStateMachine machine = new MongoDbRepositoryStateMachine();
machine.setMachineId("machine");
machine.setState("S1");
// raw byte[] representation of a context
machine.setStateMachineContext(new byte[] { 0 });
stateMachineRepository.save(machine);
}
// end::snippetC[]
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2016 the original author or authors.
* Copyright 2016-2018 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.
@@ -16,9 +16,11 @@
package org.springframework.statemachine.data.redis.docs;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.statemachine.data.StateMachineRepository;
import org.springframework.statemachine.data.StateRepository;
import org.springframework.statemachine.data.TransitionRepository;
import org.springframework.statemachine.data.redis.RedisRepositoryState;
import org.springframework.statemachine.data.redis.RedisRepositoryStateMachine;
import org.springframework.statemachine.data.redis.RedisRepositoryTransition;
public class DocsRedisRepositorySampleTests1 {
@@ -76,4 +78,23 @@ public class DocsRedisRepositorySampleTests1 {
}
// end::snippetB[]
}
public static class Config3 {
// tag::snippetC[]
@Autowired
StateMachineRepository<RedisRepositoryStateMachine> stateMachineRepository;
void persist() {
RedisRepositoryStateMachine machine = new RedisRepositoryStateMachine();
machine.setMachineId("machine");
machine.setState("S1");
// raw byte[] representation of a context
machine.setStateMachineContext(new byte[] { 0 });
stateMachineRepository.save(machine);
}
// end::snippetC[]
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2017 the original author or authors.
* Copyright 2017-2018 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.
@@ -35,11 +35,11 @@ import org.springframework.statemachine.service.StateMachineService;
@Configuration
public class StateMachineConfig {
//tag::snippetA[]
@Configuration
@EnableStateMachineFactory
public static class MachineConfig extends StateMachineConfigurerAdapter<States, Events> {
//tag::snippetB[]
@Autowired
private JpaStateMachineRepository jpaStateMachineRepository;
@@ -50,6 +50,7 @@ public class StateMachineConfig {
.withPersistence()
.runtimePersister(stateMachineRuntimePersister());
}
//end::snippetB[]
@Override
public void configure(StateMachineStateConfigurer<States, Events> states)
@@ -89,24 +90,26 @@ public class StateMachineConfig {
.event(Events.E6);
}
//tag::snippetA[]
@Bean
public StateMachineRuntimePersister<States, Events, String> stateMachineRuntimePersister() {
return new JpaPersistingStateMachineInterceptor<>(jpaStateMachineRepository);
}
}
//end::snippetA[]
}
@Configuration
public static class ServiceConfig {
//tag::snippetC[]
@Bean
public StateMachineService<States, Events> stateMachineService(StateMachineFactory<States, Events> stateMachineFactory,
StateMachineRuntimePersister<States, Events, String> stateMachineRuntimePersister) {
return new DefaultStateMachineService<States, Events>(stateMachineFactory, stateMachineRuntimePersister);
}
//end::snippetC[]
}
//tag::snippetB[]
public enum States {
S1, S2, S3, S4, S5, S6;
}
@@ -114,5 +117,4 @@ public class StateMachineConfig {
public enum Events {
E1, E2, E3, E4, E5, E6;
}
//end::snippetB[]
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2017 the original author or authors.
* Copyright 2017-2018 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.
@@ -73,6 +73,7 @@ public class StateMachineController {
return "states";
}
//tag::snippetA[]
private synchronized StateMachine<States, Events> getStateMachine(String machineId) throws Exception {
listener.resetMessages();
if (currentStateMachine == null) {
@@ -88,6 +89,7 @@ public class StateMachineController {
}
return currentStateMachine;
}
//end::snippetA[]
private Events[] getEvents() {
return EnumSet.allOf(Events.class).toArray(new Events[0]);