diff --git a/spring-statemachine-core/src/main/java/org/springframework/statemachine/config/AbstractStateMachineFactory.java b/spring-statemachine-core/src/main/java/org/springframework/statemachine/config/AbstractStateMachineFactory.java index 27e180e0..7eb48f9a 100644 --- a/spring-statemachine-core/src/main/java/org/springframework/statemachine/config/AbstractStateMachineFactory.java +++ b/spring-statemachine-core/src/main/java/org/springframework/statemachine/config/AbstractStateMachineFactory.java @@ -40,6 +40,7 @@ import org.springframework.statemachine.config.builders.StateMachineTransitions; import org.springframework.statemachine.config.builders.StateMachineTransitions.ChoiceData; import org.springframework.statemachine.config.builders.StateMachineTransitions.TransitionData; import org.springframework.statemachine.ensemble.DistributedStateMachine; +import org.springframework.statemachine.listener.StateMachineListener; import org.springframework.statemachine.region.Region; import org.springframework.statemachine.state.ChoicePseudoState; import org.springframework.statemachine.state.ChoicePseudoState.ChoiceStateData; @@ -218,6 +219,10 @@ public abstract class AbstractStateMachineFactory extends LifecycleObjectS machine = distributedStateMachine; } + for (StateMachineListener listener : stateMachineConfigurationConfig.getStateMachineListeners()) { + machine.addStateListener(listener); + } + return delegateAutoStartup(machine); } diff --git a/spring-statemachine-core/src/main/java/org/springframework/statemachine/config/builders/StateMachineConfigurationBuilder.java b/spring-statemachine-core/src/main/java/org/springframework/statemachine/config/builders/StateMachineConfigurationBuilder.java index 5ea05462..9facc25f 100644 --- a/spring-statemachine-core/src/main/java/org/springframework/statemachine/config/builders/StateMachineConfigurationBuilder.java +++ b/spring-statemachine-core/src/main/java/org/springframework/statemachine/config/builders/StateMachineConfigurationBuilder.java @@ -15,6 +15,9 @@ */ package org.springframework.statemachine.config.builders; +import java.util.ArrayList; +import java.util.List; + import org.springframework.beans.factory.BeanFactory; import org.springframework.core.task.TaskExecutor; import org.springframework.scheduling.TaskScheduler; @@ -26,6 +29,7 @@ import org.springframework.statemachine.config.configurers.DefaultConfigurationC import org.springframework.statemachine.config.configurers.DefaultDistributedStateMachineConfigurer; import org.springframework.statemachine.config.configurers.DistributedStateMachineConfigurer; import org.springframework.statemachine.ensemble.StateMachineEnsemble; +import org.springframework.statemachine.listener.StateMachineListener; /** * {@link AnnotationBuilder} for {@link StateMachineStates}. @@ -44,6 +48,7 @@ public class StateMachineConfigurationBuilder private TaskScheduler taskScheculer; private boolean autoStart = false; private StateMachineEnsemble ensemble; + private final List> listeners = new ArrayList>(); /** * Instantiates a new state machine configuration builder. @@ -84,7 +89,7 @@ public class StateMachineConfigurationBuilder @Override protected StateMachineConfigurationConfig performBuild() throws Exception { - return new StateMachineConfigurationConfig<>(beanFactory, taskExecutor, taskScheculer, autoStart, ensemble); + return new StateMachineConfigurationConfig<>(beanFactory, taskExecutor, taskScheculer, autoStart, ensemble, listeners); } /** @@ -132,4 +137,14 @@ public class StateMachineConfigurationBuilder this.autoStart = autoStart; } + /** + * Sets the state machine listeners. + * + * @param listeners the listeners + */ + public void setStateMachineListeners(List> listeners) { + this.listeners.clear(); + this.listeners.addAll(listeners); + } + } diff --git a/spring-statemachine-core/src/main/java/org/springframework/statemachine/config/builders/StateMachineConfigurationConfig.java b/spring-statemachine-core/src/main/java/org/springframework/statemachine/config/builders/StateMachineConfigurationConfig.java index 443c21ea..e7d909ee 100644 --- a/spring-statemachine-core/src/main/java/org/springframework/statemachine/config/builders/StateMachineConfigurationConfig.java +++ b/spring-statemachine-core/src/main/java/org/springframework/statemachine/config/builders/StateMachineConfigurationConfig.java @@ -15,10 +15,13 @@ */ package org.springframework.statemachine.config.builders; +import java.util.List; + import org.springframework.beans.factory.BeanFactory; import org.springframework.core.task.TaskExecutor; import org.springframework.scheduling.TaskScheduler; import org.springframework.statemachine.ensemble.StateMachineEnsemble; +import org.springframework.statemachine.listener.StateMachineListener; /** * Configuration object used to keep things together in {@link StateMachineConfigurationBuilder}. @@ -35,6 +38,7 @@ public class StateMachineConfigurationConfig { private final TaskScheduler taskScheduler; private final boolean autoStart; private final StateMachineEnsemble ensemble; + private final List> listeners; /** * Instantiates a new state machine configuration config. @@ -44,14 +48,17 @@ public class StateMachineConfigurationConfig { * @param taskScheduler the task scheduler * @param autoStart the autostart flag * @param ensemble the state machine ensemble + * @param listeners the state machine listeners */ public StateMachineConfigurationConfig(BeanFactory beanFactory, TaskExecutor taskExecutor, - TaskScheduler taskScheduler, boolean autoStart, StateMachineEnsemble ensemble) { + TaskScheduler taskScheduler, boolean autoStart, StateMachineEnsemble ensemble, + List> listeners) { this.beanFactory = beanFactory; this.taskExecutor = taskExecutor; this.taskScheduler = taskScheduler; this.autoStart = autoStart; this.ensemble = ensemble; + this.listeners = listeners; } /** @@ -98,4 +105,14 @@ public class StateMachineConfigurationConfig { public boolean isAutoStart() { return autoStart; } + + /** + * Gets the state machine listeners. + * + * @return the state machine listeners + */ + public List> getStateMachineListeners() { + return listeners; + } + } diff --git a/spring-statemachine-core/src/main/java/org/springframework/statemachine/config/configurers/ConfigurationConfigurer.java b/spring-statemachine-core/src/main/java/org/springframework/statemachine/config/configurers/ConfigurationConfigurer.java index 1ede9cbb..010d2504 100644 --- a/spring-statemachine-core/src/main/java/org/springframework/statemachine/config/configurers/ConfigurationConfigurer.java +++ b/spring-statemachine-core/src/main/java/org/springframework/statemachine/config/configurers/ConfigurationConfigurer.java @@ -19,7 +19,9 @@ import org.springframework.beans.factory.BeanFactory; import org.springframework.core.task.TaskExecutor; import org.springframework.scheduling.TaskScheduler; import org.springframework.statemachine.config.builders.StateMachineConfigurationConfigurer; +import org.springframework.statemachine.config.builders.StateMachineConfigurer; import org.springframework.statemachine.config.common.annotation.AnnotationConfigurerBuilder; +import org.springframework.statemachine.listener.StateMachineListener; /** * Base {@code ConfigConfigurer} interface for configuring generic config. @@ -65,4 +67,14 @@ public interface ConfigurationConfigurer extends */ ConfigurationConfigurer autoStartup(boolean autoStartup); + /** + * Specify a {@link StateMachineListener} to be registered + * with a state machine. This method can be called multiple times + * to register multiple listeners. + * + * @param listener the listener to register + * @return the configuration configurer + */ + ConfigurationConfigurer listener(StateMachineListener listener); + } diff --git a/spring-statemachine-core/src/main/java/org/springframework/statemachine/config/configurers/DefaultConfigurationConfigurer.java b/spring-statemachine-core/src/main/java/org/springframework/statemachine/config/configurers/DefaultConfigurationConfigurer.java index 2be7639a..e9e87689 100644 --- a/spring-statemachine-core/src/main/java/org/springframework/statemachine/config/configurers/DefaultConfigurationConfigurer.java +++ b/spring-statemachine-core/src/main/java/org/springframework/statemachine/config/configurers/DefaultConfigurationConfigurer.java @@ -15,6 +15,9 @@ */ package org.springframework.statemachine.config.configurers; +import java.util.ArrayList; +import java.util.List; + import org.springframework.beans.factory.BeanFactory; import org.springframework.core.task.TaskExecutor; import org.springframework.scheduling.TaskScheduler; @@ -22,6 +25,7 @@ import org.springframework.statemachine.config.builders.StateMachineConfiguratio import org.springframework.statemachine.config.builders.StateMachineConfigurationConfig; import org.springframework.statemachine.config.builders.StateMachineConfigurationConfigurer; import org.springframework.statemachine.config.common.annotation.AnnotationConfigurerAdapter; +import org.springframework.statemachine.listener.StateMachineListener; /** * Default implementation of a {@link ConfigurationConfigurer}. @@ -39,6 +43,7 @@ public class DefaultConfigurationConfigurer private TaskExecutor taskExecutor; private TaskScheduler taskScheculer; private boolean autoStart = false; + private final List> listeners = new ArrayList>(); @Override public void configure(StateMachineConfigurationBuilder builder) throws Exception { @@ -46,6 +51,7 @@ public class DefaultConfigurationConfigurer builder.setTaskExecutor(taskExecutor); builder.setTaskScheculer(taskScheculer); builder.setAutoStart(autoStart); + builder.setStateMachineListeners(listeners); } @Override @@ -72,4 +78,10 @@ public class DefaultConfigurationConfigurer return this; } + @Override + public ConfigurationConfigurer listener(StateMachineListener listener) { + this.listeners.add(listener); + return this; + } + } diff --git a/spring-statemachine-core/src/test/java/org/springframework/statemachine/config/ConfigurationTests.java b/spring-statemachine-core/src/test/java/org/springframework/statemachine/config/ConfigurationTests.java index 7a4bf302..17402652 100644 --- a/spring-statemachine-core/src/test/java/org/springframework/statemachine/config/ConfigurationTests.java +++ b/spring-statemachine-core/src/test/java/org/springframework/statemachine/config/ConfigurationTests.java @@ -24,6 +24,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.EnumSet; +import java.util.List; import org.junit.Test; import org.springframework.context.annotation.AnnotationConfigApplicationContext; @@ -34,10 +35,12 @@ import org.springframework.core.task.TaskExecutor; import org.springframework.statemachine.AbstractStateMachineTests; import org.springframework.statemachine.ObjectStateMachine; import org.springframework.statemachine.StateMachineSystemConstants; +import org.springframework.statemachine.TestUtils; import org.springframework.statemachine.action.Action; import org.springframework.statemachine.config.builders.StateMachineConfigurationConfigurer; import org.springframework.statemachine.config.builders.StateMachineStateConfigurer; import org.springframework.statemachine.config.builders.StateMachineTransitionConfigurer; +import org.springframework.statemachine.listener.StateMachineListenerAdapter; /** * Tests for state machine configuration. @@ -122,6 +125,19 @@ public class ConfigurationTests extends AbstractStateMachineTests { assertThat(machine.isRunning(), is(true)); } + @SuppressWarnings({ "unchecked" }) + @Test + public void testRegisterListeners() throws Exception { + context.register(Config10.class); + context.refresh(); + ObjectStateMachine machine = + context.getBean(StateMachineSystemConstants.DEFAULT_ID_STATEMACHINE, ObjectStateMachine.class); + Object o1 = TestUtils.readField("stateListener", machine); + Object o2 = TestUtils.readField("listeners", o1); + Object o3 = TestUtils.readField("list", o2); + assertThat(((List)o3).size(), is(2)); + } + @Configuration @EnableStateMachine public static class Config1 extends EnumStateMachineConfigurerAdapter { @@ -464,4 +480,26 @@ public class ConfigurationTests extends AbstractStateMachineTests { } + @Configuration + @EnableStateMachine + public static class Config10 extends EnumStateMachineConfigurerAdapter { + + @Override + public void configure(StateMachineConfigurationConfigurer config) throws Exception { + config + .withConfiguration() + .listener(new StateMachineListenerAdapter()) + .listener(new StateMachineListenerAdapter()); + } + + @Override + public void configure(StateMachineStateConfigurer states) throws Exception { + states + .withStates() + .initial(TestStates.S1) + .states(EnumSet.allOf(TestStates.class)); + } + + } + }