Skip to content

Commit 609035a

Browse files
committed
Fix timer after restore
- Previously timer were only armed when state were entered, thus failing for timer to work if machine were restored. Now changing logic so that that state have a lifecycle which is called during machine reset. - Fixes #381
1 parent a9cf3e1 commit 609035a

File tree

3 files changed

+92
-7
lines changed

3 files changed

+92
-7
lines changed

spring-statemachine-core/src/main/java/org/springframework/statemachine/state/AbstractState.java

+31-7
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2015 the original author or authors.
2+
* Copyright 2017 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -198,17 +198,13 @@ public boolean shouldDefer(Message<E> event) {
198198
public void exit(StateContext<S, E> context) {
199199
cancelStateActions();
200200
stateListener.onExit(context);
201-
for (Trigger<S, E> trigger : triggers) {
202-
trigger.disarm();
203-
}
201+
disarmTriggers();
204202
}
205203

206204
@Override
207205
public void entry(StateContext<S, E> context) {
208206
stateListener.onEntry(context);
209-
for (Trigger<S, E> trigger : triggers) {
210-
trigger.arm();
211-
}
207+
armTriggers();
212208
scheduleStateActions(context);
213209
}
214210

@@ -292,6 +288,16 @@ public void removeActionListener(ActionListener<S, E> listener) {
292288
}
293289
}
294290

291+
@Override
292+
protected void doStart() {
293+
armTriggers();
294+
}
295+
296+
@Override
297+
protected void doStop() {
298+
disarmTriggers();
299+
}
300+
295301
/**
296302
* Gets the submachine.
297303
*
@@ -332,6 +338,24 @@ public List<Trigger<S, E>> getTriggers() {
332338
return triggers;
333339
}
334340

341+
/**
342+
* Arm triggers.
343+
*/
344+
protected void armTriggers() {
345+
for (Trigger<S, E> trigger : triggers) {
346+
trigger.arm();
347+
}
348+
}
349+
350+
/**
351+
* Disarm triggers.
352+
*/
353+
protected void disarmTriggers() {
354+
for (Trigger<S, E> trigger : triggers) {
355+
trigger.disarm();
356+
}
357+
}
358+
335359
/**
336360
* Cancel existing state actions and clear list.
337361
*/

spring-statemachine-core/src/main/java/org/springframework/statemachine/support/AbstractStateMachine.java

+4
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import org.springframework.beans.BeansException;
2121
import org.springframework.beans.factory.BeanFactory;
2222
import org.springframework.beans.factory.BeanFactoryAware;
23+
import org.springframework.context.Lifecycle;
2324
import org.springframework.messaging.Message;
2425
import org.springframework.messaging.MessageHeaders;
2526
import org.springframework.messaging.support.MessageBuilder;
@@ -719,6 +720,9 @@ public void apply(StateMachineAccess<S, E> function) {
719720
if (stateSet && stateMachineContext.getExtendedState() != null) {
720721
this.extendedState = stateMachineContext.getExtendedState();
721722
}
723+
if (currentState instanceof Lifecycle) {
724+
((Lifecycle)currentState).start();
725+
}
722726
}
723727

724728
@Override

spring-statemachine-core/src/test/java/org/springframework/statemachine/StateMachineResetTests.java

+57
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,9 @@
3333
import org.springframework.statemachine.access.StateMachineFunction;
3434
import org.springframework.statemachine.action.Action;
3535
import org.springframework.statemachine.config.EnableStateMachine;
36+
import org.springframework.statemachine.config.EnableStateMachineFactory;
3637
import org.springframework.statemachine.config.EnumStateMachineConfigurerAdapter;
38+
import org.springframework.statemachine.config.StateMachineFactory;
3739
import org.springframework.statemachine.config.builders.StateMachineConfigurationConfigurer;
3840
import org.springframework.statemachine.config.builders.StateMachineStateConfigurer;
3941
import org.springframework.statemachine.config.builders.StateMachineTransitionConfigurer;
@@ -251,6 +253,31 @@ public void apply(StateMachineAccess<States, Events> function) {
251253
assertThat(machine.getExtendedState().getVariables().size(), is(0));
252254
}
253255

256+
@Test
257+
public void testRestoreWithTimer() throws Exception {
258+
context.register(Config4.class);
259+
context.refresh();
260+
@SuppressWarnings("unchecked")
261+
StateMachineFactory<States, Events> factory = context.getBean(StateMachineSystemConstants.DEFAULT_ID_STATEMACHINEFACTORY,
262+
StateMachineFactory.class);
263+
StateMachine<States, Events> machine = factory.getStateMachine();
264+
265+
DefaultStateMachineContext<States, Events> stateMachineContext = new DefaultStateMachineContext<States, Events>(States.S1, null,
266+
null, null);
267+
machine.getStateMachineAccessor().doWithAllRegions(new StateMachineFunction<StateMachineAccess<States,Events>>() {
268+
269+
@Override
270+
public void apply(StateMachineAccess<States, Events> function) {
271+
function.resetStateMachine(stateMachineContext);
272+
}
273+
});
274+
275+
machine.start();
276+
Thread.sleep(1100);
277+
assertThat(machine.getState().getIds(), containsInAnyOrder(States.S2));
278+
279+
}
280+
254281
@Configuration
255282
@EnableStateMachine
256283
static class Config1 extends EnumStateMachineConfigurerAdapter<States, Events> {
@@ -420,6 +447,36 @@ public void execute(StateContext<States, Events> context) {
420447

421448
}
422449

450+
@Configuration
451+
@EnableStateMachineFactory
452+
static class Config4 extends EnumStateMachineConfigurerAdapter<States, Events> {
453+
454+
@Override
455+
public void configure(StateMachineStateConfigurer<States, Events> states)
456+
throws Exception {
457+
states
458+
.withStates()
459+
.initial(States.S0)
460+
.state(States.S1)
461+
.state(States.S2);
462+
}
463+
464+
@Override
465+
public void configure(StateMachineTransitionConfigurer<States, Events> transitions)
466+
throws Exception {
467+
transitions
468+
.withExternal()
469+
.source(States.S0)
470+
.target(States.S1)
471+
.event(Events.A)
472+
.and()
473+
.withExternal()
474+
.source(States.S1)
475+
.target(States.S2)
476+
.timerOnce(1000);
477+
}
478+
}
479+
423480
public static enum States {
424481
S0, S1, S11, S12, S2, S21, S211, S212
425482
}

0 commit comments

Comments
 (0)