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