JPA Config is an example how state machine concepts can be used with a machine configuration kept in a database. This sample is using embedded H2 database with a H2 Console to ease playing with a database.
To enable automatic scan of needed Entity classes and JPA Repositories, a boot application can be annotated with a custom locations as shown below.
@SpringBootApplication @EntityScan(basePackages = {"org.springframework.statemachine.data.jpa"}) @EnableJpaRepositories(basePackages = {"org.springframework.statemachine.data.jpa"}) public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } }
What comes for a machine config RepositoryStateMachineModelFactory
can be used as shown below.
@Configuration @EnableStateMachineFactory public static class Config extends StateMachineConfigurerAdapter<String, String> { @Autowired private StateRepository<? extends RepositoryState> stateRepository; @Autowired private TransitionRepository<? extends RepositoryTransition> transitionRepository; @Override public void configure(StateMachineModelConfigurer<String, String> model) throws Exception { model .withModel() .factory(modelFactory()); } @Bean public StateMachineModelFactory<String, String> modelFactory() { return new RepositoryStateMachineModelFactory(stateRepository, transitionRepository); } }
Lets get into actual demo. Run the boot based sample application:
# java -jar spring-statemachine-samples-datajpa-1.2.0.M1.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.
To access embedded console use JDBC URL jdbc:h2:mem:testdb
if it’s
not already set.
From console you can see how database tables look like and modify those as you wish.
Now that you got this far you probably wondered how those default
states and transitions got populated into a database. Spring Data
already have a nice trick to auto populate repositories and we simply
use this feature via Jackson2RepositoryPopulatorFactoryBean
.
@Bean public Jackson2RepositoryPopulatorFactoryBean jackson2RepositoryPopulatorFactoryBean() { Jackson2RepositoryPopulatorFactoryBean factoryBean = new Jackson2RepositoryPopulatorFactoryBean(); factoryBean.setResources(new Resource[]{new ClassPathResource("data.json")}); return factoryBean; }
Actual source for populator data is shown below.
[ { "_class": "org.springframework.statemachine.data.jpa.JpaRepositoryState", "initial": true, "state": "S1" }, { "_class": "org.springframework.statemachine.data.jpa.JpaRepositoryState", "initial": false, "state": "S2" }, { "_class": "org.springframework.statemachine.data.jpa.JpaRepositoryState", "initial": false, "state": "S3" }, { "_class": "org.springframework.statemachine.data.jpa.JpaRepositoryTransition", "source": "S1", "target": "S2", "event": "E1" }, { "_class": "org.springframework.statemachine.data.jpa.JpaRepositoryTransition", "source": "S2", "target": "S3", "event": "E2" } ]