Reputation: 225
I'm leaning ssm, blow is my demo config:
@Override
public void configure(StateMachineConfigurationConfigurer<States, Events> config) throws Exception {
config.withConfiguration()
.autoStartup(true)
.listener(listener());
}
@Override
public void configure(StateMachineStateConfigurer<States, Events> states) throws Exception {
states.withStates()
.initial(States.S_1)
.state(States.S_1, myAction(), null)
.end(States.S_END)
.states(EnumSet.allOf(States.class));
}
@Override
public void configure(StateMachineTransitionConfigurer<States, Events> transitions) throws Exception {
transitions
.withExternal()
.source(States.S_1).target(States.S_2).event(Events.E1).action(myAction());
}
I send two event to machine, but it run onece.
stateMachine.sendEvent(Events.E1);
stateMachine.sendEvent(Events.E1);
Does the ssm has state, how can I make it run stateless?
I just want to use it define my business procedure.
Upvotes: 2
Views: 1396
Reputation: 481
unfortunately the spring state machine cannot be run stateless. I also hope that this feature will be implemented and that the state machine can be run with a fully externalized state.
So long the solution is this:
@Configuration
@EnableStateMachineFactory
public class DomainStateMachineFactory extends
EnumStateMachineConfigurerAdapter<States, Events> {
@Overrides...
}
@Service
public class DomainStateService {
@Autowired
StateMachineFactory<States, Events> stateMachineFactory;
@Autowired
private DomainStateMachinePersister persister;
public StateTransitionEvaluationHolder processEvent( DomainEntity entity, Events event ) {
// create a brand new state machine
StateMachine<StatusDto, StatusEventDto> stateMachine = stateMachineFactory.getStateMachine();
// load the the state of your domain entity into the state machine
StateMachine<StatusDto, StatusEventDto> restoredStateMachine =
persister.restore( stateMachine, entity );
// register a state changed listener
restoredStateMachine.addStateListener(
new DomainStateMachineListener( entity ) );
// start the machine
restoredStateMachine.startReactively().block();
// process the event
restoredStateMachine.sendEvent( Mono.just( MessageBuilder.withPayload( event ).build() ) )
.blockFirst();
// stop the machine
restoredStateMachine.stopReactively().block();
}
}
a)
@Component
public class DomainEntityPersist implements
StateMachinePersist<States, Events, DomainEntity> {
@Override
public void write( StateMachineContext<States, Events> stateMachineContext,
DomainEntity entity ) {
throw new StateMachineException( "Persistence not supported. Persisted state remains in Domain Entity." );
}
@Override
public StateMachineContext<States, Events> read( DomainEntity entity ) {
ExtendedState extendedState = new DefaultExtendedState();
return new DefaultStateMachineContext<>( entity.getState(), null,
null, extendedState, null,
DomainStateMachineFactory.MACHINE_ID );
}
}
and b)
@Component
public class DomainEntityStateMachinePersister {
DomainEntityPersist persist;
StateMachinePersister<States, Events, DomainEntity> persister;
public DomainEntityStateMachinePersister ( DomainEntityPersist persist ) {
this.persist = persist;
this.persister = new DefaultStateMachinePersister<>( persist );
}
public void persist( StateMachine<States, Events> stateMachine,
DomainEntity entity ) {
try {
persister.persist( stateMachine, entity );
}
catch ( Exception e ) {
throw new StateMachineException( e );
}
}
public StateMachine<States, Events> restore(
StateMachine<States, Events> stateMachine, DomainEntity entity ) {
try {
return persister.restore( stateMachine, entity );
}
catch ( Exception e ) {
throw new StateMachineException( e );
}
}
}
public class DomainStateMachineListener extends
StateMachineListenerAdapter<States, Events> {
boolean changed = false;
DomainEntity entity;
public DomainStateMachineListener( DomainEntity entity ) {
this.entity = entity;
}
@Override
public void stateChanged( State<Statues, Events> from,
State<States, Events> to ) {
entity.setState( to.getId() );
setChanged( true );
}
}
An exhaustive and more detailed explanation can be found here:
Upvotes: 1
Reputation: 79
state machine are statefull as goal is to react on a saved state... And event does state change...
I think in your case you might not want a state machine but a "simple" service layer
Upvotes: 1
Reputation: 2646
Well it looks like event E1
takes machine from S_1
to S_2
. Sending that event again will not do anything as machine is already in state S_2
and transition from S_1
to S_2
cannot happen.
Not sure what you mean by making machine stateless?
Upvotes: 3