diff --git a/src/main/java/de/w665/pr/statemachine/trafficlight/MinimumTimePassedGuard.java b/src/main/java/de/w665/pr/statemachine/trafficlight/MinimumTimePassedGuard.java new file mode 100644 index 0000000..b20003e --- /dev/null +++ b/src/main/java/de/w665/pr/statemachine/trafficlight/MinimumTimePassedGuard.java @@ -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 { + + private static final long MIN_TIME_BETWEEN_TRANSITIONS = 1000 * 2; // 2 Seconds + + private final TimingContext timingContext; + + @Override + public boolean evaluate(StateContext context) { + long currentTime = System.currentTimeMillis(); + long lastTransitionTime = timingContext.getLastTransitionTime(); + + if(lastTransitionTime == 0) { + return true; + } + + return (currentTime - lastTransitionTime) >= MIN_TIME_BETWEEN_TRANSITIONS; + } +} diff --git a/src/main/java/de/w665/pr/statemachine/trafficlight/TimingContext.java b/src/main/java/de/w665/pr/statemachine/trafficlight/TimingContext.java new file mode 100644 index 0000000..6531eae --- /dev/null +++ b/src/main/java/de/w665/pr/statemachine/trafficlight/TimingContext.java @@ -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; + } +} diff --git a/src/main/java/de/w665/pr/statemachine/trafficlight/TrafficLightStateMachineConfig.java b/src/main/java/de/w665/pr/statemachine/trafficlight/TrafficLightStateMachineConfig.java index d5fdc61..8db2cb4 100644 --- a/src/main/java/de/w665/pr/statemachine/trafficlight/TrafficLightStateMachineConfig.java +++ b/src/main/java/de/w665/pr/statemachine/trafficlight/TrafficLightStateMachineConfig.java @@ -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 { + private final MinimumTimePassedGuard minimumTimePassedGuard; + private final TimingContext timingContext; + @Override public void configure(StateMachineStateConfigurer 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 recordTransitionAction() { + return context -> timingContext.recordTransition(); } @Bean