¿Cómo restaurar la máquina de estado desde el contexto creado en tiempo de ejecución?
tengo una maquina de estados
@EnableStateMachine
@Configuration
public class StateMachineConfiguration extends EnumStateMachineConfigurerAdapter<Status, Event> {
@Override
public void configure(StateMachineStateConfigurer<Status, Event> states) throws Exception {
states.withStates()
.initial(Status.DRAFT)
.states(EnumSet.allOf(Status.class));
}
@Override
public void configure(StateMachineTransitionConfigurer<Status, Event> transitions) throws Exception {
transitions
.withExternal()
.target(Status.INVITATION).source(Status.DRAFT)
.event(Event.INVITED)
.guard(new Guard())
.action(new ActionInvited())
.and()
.withExternal()
.target(Status.DECLINED).source(Status.INVITATION)
.event(Event.DECLINED)
.action(new ActionDeclined());
}
@Override
public void configure(StateMachineConfigurationConfigurer<Status, Event> config) throws Exception {
config.withConfiguration().autoStartup(true);
}
}
y tengo un modelo, por ejemplo Order . El modelo persiste en la base de datos. Extraigo el modelo de la base de datos, ahora mi modelo tiene un estado Order.status == INVITATION
. Quiero continuar procesando el modelo con statemachine, pero la instancia de statemachine comenzará a procesarse con el estado inicial BORRADOR pero necesito continuar procesando desde el estado INVITACIÓN . En otras palabras quiero ejecutar
stateMachine.sendEvent(MessageBuilder
.withPayload(Event.DECLINED)
.setHeader("orderId", order.id)
.build()
)
y ejecutar la acción ActionDeclined()
. No quiero conservar un contexto de máquina de estado en la base de datos. Quiero establecer un estado de stateMachine en el estado de mi modelo en tiempo de ejecución. ¿Cómo puedo hacer eso de la manera correcta? ¿Usar el constructor DefaultStateContext o tener otra forma más hermosa?
Un enfoque posible es crear el archivo StateMachine
sobre la marcha y rehidratar la máquina de estado desde la base de datos utilizando el estado del archivo Order
. En este caso es necesario realizar los siguientes pasos:
- Restableciendo el
StateMachine
en todas las regiones - Estado de carga
Order
desde la base de datos - Crear nuevo
DefaultStateMachineContext
y completar en consecuencia
Supongamos que tiene un método de compilación que devuelve nuevas máquinas de estado para procesar eventos de orden (usando StateMachineFactory ) , pero para una orden existente, rehidratará el estado de la base de datos.
StateMachine<Status, Event> build(long orderId) {
orderService.getOrder(orderId) //returns Optional
.map(order -> {
StateMachine<Status, Event> sm = stateMachineFactory.getStateMachine(Long.toString(orderId));
sm.stop();
rehydrateState(sm, sm.getExtendedState(), order.getStatus());
sm.start();
return sm;
})
.orElseGet(() -> createNewStateMachine(orderId);
}
void rehydrateState(StateMachine<Status, Event> newStateMachine, ExtendedState extendedState, Status orderStatus) {
newStateMachine.getStateMachineAccessor().doWithAllRegions(sma ->
sma.resetStateMachine(new DefaultStateMachineContext<>(orderStatus, null, null, extendedState));
});
}