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!
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);
}