4

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!

Pille
  • 43
  • 1
  • 3

1 Answers1

6

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

Dauren D
  • 134
  • 1
  • 4
  • 2
    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 :) – Pille Sep 22 '20 at 09:54