45. JPA Config

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.

sm datajpa 1

To access embedded console use JDBC URL jdbc:h2:mem:testdb if it’s not already set.

sm datajpa 2

From console you can see how database tables look like and modify those as you wish.

sm datajpa 3

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"
	}
]