Add simple time passed guard

This commit is contained in:
Maximilian Walz
2025-04-16 16:18:09 +02:00
parent 93aba73e97
commit 5dd568f64a
3 changed files with 65 additions and 3 deletions

View File

@ -0,0 +1,27 @@
package de.w665.pr.statemachine.trafficlight;
import lombok.RequiredArgsConstructor;
import org.springframework.statemachine.StateContext;
import org.springframework.statemachine.guard.Guard;
import org.springframework.stereotype.Component;
@RequiredArgsConstructor
@Component
public class MinimumTimePassedGuard implements Guard<TrafficLightStates, TrafficLightEvents> {
private static final long MIN_TIME_BETWEEN_TRANSITIONS = 1000 * 2; // 2 Seconds
private final TimingContext timingContext;
@Override
public boolean evaluate(StateContext<TrafficLightStates, TrafficLightEvents> context) {
long currentTime = System.currentTimeMillis();
long lastTransitionTime = timingContext.getLastTransitionTime();
if(lastTransitionTime == 0) {
return true;
}
return (currentTime - lastTransitionTime) >= MIN_TIME_BETWEEN_TRANSITIONS;
}
}

View File

@ -0,0 +1,19 @@
package de.w665.pr.statemachine.trafficlight;
import org.springframework.stereotype.Component;
/**
* Tracks the time, when a light switch is triggered
*/
@Component
public class TimingContext {
private volatile long lastTransitionTime = 0;
public void recordTransition() {
this.lastTransitionTime = System.currentTimeMillis();
}
public long getLastTransitionTime() {
return lastTransitionTime;
}
}

View File

@ -1,5 +1,6 @@
package de.w665.pr.statemachine.trafficlight; package de.w665.pr.statemachine.trafficlight;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
@ -12,10 +13,14 @@ import org.springframework.statemachine.config.builders.StateMachineTransitionCo
import java.util.EnumSet; import java.util.EnumSet;
@Slf4j @Slf4j
@RequiredArgsConstructor
@Configuration @Configuration
@EnableStateMachine @EnableStateMachine
public class TrafficLightStateMachineConfig extends StateMachineConfigurerAdapter<TrafficLightStates, TrafficLightEvents> { public class TrafficLightStateMachineConfig extends StateMachineConfigurerAdapter<TrafficLightStates, TrafficLightEvents> {
private final MinimumTimePassedGuard minimumTimePassedGuard;
private final TimingContext timingContext;
@Override @Override
public void configure(StateMachineStateConfigurer<TrafficLightStates, TrafficLightEvents> states) throws Exception{ public void configure(StateMachineStateConfigurer<TrafficLightStates, TrafficLightEvents> states) throws Exception{
states states
@ -23,8 +28,8 @@ public class TrafficLightStateMachineConfig extends StateMachineConfigurerAdapte
.initial(TrafficLightStates.RED) .initial(TrafficLightStates.RED)
.state(TrafficLightStates.RED, redEntryAction(), redExitAction()) .state(TrafficLightStates.RED, redEntryAction(), redExitAction())
.state(TrafficLightStates.YELLOW, yellowEntryAction(), yellowExitAction()) .state(TrafficLightStates.YELLOW, yellowEntryAction(), yellowExitAction())
.state(TrafficLightStates.GREEN, greenEntryAction(), greenExitAction()) .state(TrafficLightStates.GREEN, greenEntryAction(), greenExitAction());
.states(EnumSet.allOf(TrafficLightStates.class)); // Do I need this line? Aren't all the states configured in the line above? /*.states(EnumSet.allOf(TrafficLightStates.class));*/ // Redundant -> Only used when all enum values should be added as states | We're defining them above already
} }
@Override @Override
@ -34,16 +39,27 @@ public class TrafficLightStateMachineConfig extends StateMachineConfigurerAdapte
.source(TrafficLightStates.RED) .source(TrafficLightStates.RED)
.target(TrafficLightStates.GREEN) .target(TrafficLightStates.GREEN)
.event(TrafficLightEvents.TIMER) .event(TrafficLightEvents.TIMER)
.guard(minimumTimePassedGuard)
.action(recordTransitionAction())
.and() .and()
.withExternal() .withExternal()
.source(TrafficLightStates.GREEN) .source(TrafficLightStates.GREEN)
.target(TrafficLightStates.YELLOW) .target(TrafficLightStates.YELLOW)
.event(TrafficLightEvents.TIMER) .event(TrafficLightEvents.TIMER)
.guard(minimumTimePassedGuard)
.action(recordTransitionAction())
.and() .and()
.withExternal() .withExternal()
.source(TrafficLightStates.YELLOW) .source(TrafficLightStates.YELLOW)
.target(TrafficLightStates.RED) .target(TrafficLightStates.RED)
.event(TrafficLightEvents.TIMER); .event(TrafficLightEvents.TIMER)
.guard(minimumTimePassedGuard)
.action(recordTransitionAction());
}
@Bean
public Action<TrafficLightStates, TrafficLightEvents> recordTransitionAction() {
return context -> timingContext.recordTransition();
} }
@Bean @Bean