Reputation: 451
I aim to create a new state machine instance if it does not exist in the database, and store config and context in the database. However, I cannot set the default config in the database. If I don't put the machine ID explicitly in the database when I insert transitions, I get the "Must have at least one transition" exception when I try to create a new state machine.
Here is my configuration:
@Configuration
@RequiredArgsConstructor
@EnableStateMachine
public class StateMachineConfig {
@Bean
public StateMachineRuntimePersister<String, String, String> stateMachineRuntimePersister(
JpaStateMachineRepository jpaStateMachineRepository) {
return new JpaPersistingStateMachineInterceptor<>(jpaStateMachineRepository);
}
@Bean
public StateMachineService<String, String> stateMachineService(
StateMachineFactory<String, String> stateMachineFactory,
StateMachineRuntimePersister<String, String, String> stateMachineRuntimePersister) {
return new DefaultStateMachineService<>(stateMachineFactory, stateMachineRuntimePersister);
}
@Bean
public StateMachineJackson2RepositoryPopulatorFactoryBean jackson2RepositoryPopulatorFactoryBean() {
StateMachineJackson2RepositoryPopulatorFactoryBean factoryBean = new StateMachineJackson2RepositoryPopulatorFactoryBean();
factoryBean.setResources(new Resource[]{new ClassPathResource("data.json")});
return factoryBean;
}
@Configuration
@EnableStateMachineFactory
public static class Config extends StateMachineConfigurerAdapter<String, String> {
@Autowired
private StateRepository<? extends RepositoryState> stateRepository;
@Autowired
private TransitionRepository<? extends RepositoryTransition> transitionRepository;
@Autowired
private StateMachineRuntimePersister<String, String, String> stateMachineRuntimePersister;
@Override
public void configure(StateMachineConfigurationConfigurer<String, String> config)
throws Exception {
config
.withPersistence()
.runtimePersister(stateMachineRuntimePersister);
}
@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);
}
}
Here is my controller:
@RequestMapping("/state")
public String feedAndGetStates(
@RequestParam(value = "events", required = false) List<String> events,
@RequestParam(value = "machine", required = false, defaultValue = MACHINE_ID_1) String machine,
Model model) throws Exception {
StateMachine<String, String> stateMachine = getStateMachine(machine);
if (events != null) {
for (String event : events) {
stateMachine
.sendEvent(Mono.just(MessageBuilder
.withPayload(event).build()))
.blockLast();
}
}
StringBuilder contextBuf = new StringBuilder();
StateMachineContext<String, String> stateMachineContext = stateMachinePersist.read(machine);
if (stateMachineContext != null) {
contextBuf.append(stateMachineContext.toString());
}
if (ObjectUtils.nullSafeEquals(machine, MACHINE_ID_2)) {
stateMachineContext = stateMachinePersist.read(MACHINE_ID_2R1);
if (stateMachineContext != null) {
contextBuf.append("\n---\n");
contextBuf.append(stateMachineContext.toString());
}
stateMachineContext = stateMachinePersist.read(MACHINE_ID_2R2);
if (stateMachineContext != null) {
contextBuf.append("\n---\n");
contextBuf.append(stateMachineContext.toString());
}
}
model.addAttribute("allMachines", MACHINES);
model.addAttribute("machine", machine);
model.addAttribute("currentMachine", currentStateMachine);
model.addAttribute("allEvents", getEvents());
model.addAttribute("messages", createMessages(listener.getMessages()));
model.addAttribute("context", contextBuf.toString());
return "states";
}
private synchronized StateMachine<String, String> getStateMachine(String machineId) throws Exception {
listener.resetMessages();
if (currentStateMachine == null) {
currentStateMachine = stateMachineService.acquireStateMachine(machineId, false);
currentStateMachine.addStateListener(listener);
currentStateMachine.startReactively().block();
} else if (!ObjectUtils.nullSafeEquals(currentStateMachine.getId(), machineId)) {
stateMachineService.releaseStateMachine(currentStateMachine.getId());
currentStateMachine.stopReactively().block();
currentStateMachine = stateMachineService.acquireStateMachine(machineId, false);
currentStateMachine.addStateListener(listener);
currentStateMachine.startReactively().block();
}
return currentStateMachine;
}
I have these transitions in the database, without machineId because I am going to create machine run time and it will be assigned automatically.
Is there any way to define transitions in the database without machineId and to create a state machine with random machineId runtime? If I define transitions in class, I don't have to specify machineID, but when I define them in the DB, it doesn't work without machineId.
Upvotes: 1
Views: 39