Spring state machine with JPA persistence- Repository usage
Asked Answered
Z

1

5

I am trying to figure out how to easily use spring state machine including persistence with JPA. This is the problem I am dealing with:

Incompatible data types - factory and persistence

At a certain point in the program I would like to use the state machine which is connected to a user. There are repositories for that purpose (project spring-statemachine-data-jpa). At first there is a check if a state machine already exists for a player, using the repository. If not, creating a new state machine and persist it.

The problem is that I have different types of state machines. The factory creates a StateMachine<UserState, UserEvent>, the repository returns a JpaRepositoryStateMachine. These are not compatible to each other and for me it is not clear how to persist / create / restore the state machines.

Can you please clarify that for me?

@Autowired
private StateMachineRepository<JpaRepositoryStateMachine> repository;

public someMethod(User user) {

Optional<JpaRepositoryStateMachine> stateMachine = repository.findById(user.getId()); // JPA state machine

if(stateMachine.isEmpty()) {
            StateMachine<UserState, UserEvent> createdStateMachine = factory.getStateMachine(user.getId()); // spring state machine
            repository.save(createdStateMachine); // compile error
        }

// here: ready-to-use statemachine - how?

}

Thanks for your help!

Zealous answered 21/9, 2020 at 0:3 Comment(0)
B
7

Try to use SpringStateMachineService to get a state machine instance instead of explicitly retrieving it from repository or factory. You can use default implementation provided by Spring:

@Bean
public StateMachineService<State, Event> stateMachineService(
        final StateMachineFactory<State, Event> stateMachineFactory,
        final StateMachinePersist<WorkflowState, WorkflowEvent, String> stateMachinePersist) {
    return new DefaultStateMachineService<>(stateMachineFactory, stateMachinePersist);
}

So, your code will look like:

@Autowired
private StateMachineService<State, Event> stateMachineService;

public someMethod(User user) {
StateMachine<State, Event> stateMachine = stateMachineService.acquireStateMachine(user.getId(), false);

// here: ready-to-use statemachine - call stateMachine.start() for example

}

If you go inside the acquireStateMachine method you can see that it queries state machine from repository by id and creates a new one if nothing found.

You can use JpaPersistingStateMachineInterceptor to implicitly save and update state machine instance on every change.

@Bean
public JpaPersistingStateMachineInterceptor<State, Event, String>
        jpaPersistingStateMachineInterceptor() {
    return new JpaPersistingStateMachineInterceptor(stateMachineRepository);
}

See Persisting State Machine

Bulley answered 21/9, 2020 at 18:49 Comment(1)
Thank you, that did the trick! Now it is clear for me that using the Service-class instead of the repository is the way to go. With your help I also figured out how to successfull configure the state machine in order to make it persistable. Thanks :)Zealous

© 2022 - 2024 — McMap. All rights reserved.