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 df23585b..edc64fb7 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 @@ -38,6 +38,7 @@ import org.springframework.statemachine.config.builders.StateMachineStates; 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.region.Region; import org.springframework.statemachine.state.ChoicePseudoState; import org.springframework.statemachine.state.ChoicePseudoState.ChoiceStateData; @@ -196,6 +197,16 @@ public abstract class AbstractStateMachineFactory extends LifecycleObjectS } }); + + // setup distributed state machine if needed. + // we wrap previously build machine with a distributed + // state machine and set it to use given ensemble. + if (stateMachineConfigurationConfig.getStateMachineEnsemble() != null) { + DistributedStateMachine distributedStateMachine = new DistributedStateMachine<>( + stateMachineConfigurationConfig.getStateMachineEnsemble(), machine); + machine = distributedStateMachine; + } + return 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 31eddfbc..e25038c7 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 @@ -23,6 +23,9 @@ import org.springframework.statemachine.config.common.annotation.AnnotationBuild import org.springframework.statemachine.config.common.annotation.ObjectPostProcessor; import org.springframework.statemachine.config.configurers.ConfigurationConfigurer; import org.springframework.statemachine.config.configurers.DefaultConfigurationConfigurer; +import org.springframework.statemachine.config.configurers.DefaultDistributedStateMachineConfigurer; +import org.springframework.statemachine.config.configurers.DistributedStateMachineConfigurer; +import org.springframework.statemachine.ensemble.StateMachineEnsemble; /** * {@link AnnotationBuilder} for {@link StateMachineStates}. @@ -39,16 +42,31 @@ public class StateMachineConfigurationBuilder private BeanFactory beanFactory; private TaskExecutor taskExecutor; private TaskScheduler taskScheculer; + private StateMachineEnsemble ensemble; + /** + * Instantiates a new state machine configuration builder. + */ public StateMachineConfigurationBuilder() { super(); } + /** + * Instantiates a new state machine configuration builder. + * + * @param objectPostProcessor the object post processor + * @param allowConfigurersOfSameType the allow configurers of same type + */ public StateMachineConfigurationBuilder(ObjectPostProcessor objectPostProcessor, boolean allowConfigurersOfSameType) { super(objectPostProcessor, allowConfigurersOfSameType); } + /** + * Instantiates a new state machine configuration builder. + * + * @param objectPostProcessor the object post processor + */ public StateMachineConfigurationBuilder(ObjectPostProcessor objectPostProcessor) { super(objectPostProcessor); } @@ -59,20 +77,49 @@ public class StateMachineConfigurationBuilder } @Override - protected StateMachineConfigurationConfig performBuild() throws Exception { - return new StateMachineConfigurationConfig<>(beanFactory, taskExecutor, taskScheculer); + public DistributedStateMachineConfigurer withDistributed() throws Exception { + return apply(new DefaultDistributedStateMachineConfigurer()); } + @Override + protected StateMachineConfigurationConfig performBuild() throws Exception { + return new StateMachineConfigurationConfig<>(beanFactory, taskExecutor, taskScheculer, ensemble); + } + + /** + * Sets the bean factory. + * + * @param beanFactory the new bean factory + */ public void setBeanFactory(BeanFactory beanFactory) { this.beanFactory = beanFactory; } + /** + * Sets the task executor. + * + * @param taskExecutor the new task executor + */ public void setTaskExecutor(TaskExecutor taskExecutor) { this.taskExecutor = taskExecutor; } + /** + * Sets the task scheculer. + * + * @param taskScheculer the new task scheculer + */ public void setTaskScheculer(TaskScheduler taskScheculer) { this.taskScheculer = taskScheculer; } + /** + * Sets the state machine ensemble. + * + * @param ensemble the ensemble + */ + public void setStateMachineEnsemble(StateMachineEnsemble ensemble) { + this.ensemble = ensemble; + } + } 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 fa875399..8eadd128 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 @@ -18,30 +18,73 @@ package org.springframework.statemachine.config.builders; import org.springframework.beans.factory.BeanFactory; import org.springframework.core.task.TaskExecutor; import org.springframework.scheduling.TaskScheduler; +import org.springframework.statemachine.ensemble.StateMachineEnsemble; +/** + * Configuration object used to keep things together in {@link StateMachineConfigurationBuilder}. + * + * @author Janne Valkealahti + * + * @param the type of state + * @param the type of event + */ public class StateMachineConfigurationConfig { private final BeanFactory beanFactory; private final TaskExecutor taskExecutor; private final TaskScheduler taskScheculer; + private final StateMachineEnsemble ensemble; + /** + * Instantiates a new state machine configuration config. + * + * @param beanFactory the bean factory + * @param taskExecutor the task executor + * @param taskScheculer the task scheculer + * @param ensemble the state machine ensemble + */ public StateMachineConfigurationConfig(BeanFactory beanFactory, TaskExecutor taskExecutor, - TaskScheduler taskScheculer) { + TaskScheduler taskScheculer, StateMachineEnsemble ensemble) { this.beanFactory = beanFactory; this.taskExecutor = taskExecutor; this.taskScheculer = taskScheculer; + this.ensemble = ensemble; } + /** + * Gets the bean factory. + * + * @return the bean factory + */ public BeanFactory getBeanFactory() { return beanFactory; } + /** + * Gets the task executor. + * + * @return the task executor + */ public TaskExecutor getTaskExecutor() { return taskExecutor; } + /** + * Gets the task scheculer. + * + * @return the task scheculer + */ public TaskScheduler getTaskScheculer() { return taskScheculer; } + /** + * Gets the state machine ensemble. + * + * @return the state machine ensemble + */ + public StateMachineEnsemble getStateMachineEnsemble() { + return ensemble; + } + } diff --git a/spring-statemachine-core/src/main/java/org/springframework/statemachine/config/builders/StateMachineConfigurationConfigurer.java b/spring-statemachine-core/src/main/java/org/springframework/statemachine/config/builders/StateMachineConfigurationConfigurer.java index 75e95987..7295e860 100644 --- a/spring-statemachine-core/src/main/java/org/springframework/statemachine/config/builders/StateMachineConfigurationConfigurer.java +++ b/spring-statemachine-core/src/main/java/org/springframework/statemachine/config/builders/StateMachineConfigurationConfigurer.java @@ -16,6 +16,7 @@ package org.springframework.statemachine.config.builders; import org.springframework.statemachine.config.configurers.ConfigurationConfigurer; +import org.springframework.statemachine.config.configurers.DistributedStateMachineConfigurer; /** * Configurer interface exposing generic config. @@ -35,4 +36,12 @@ public interface StateMachineConfigurationConfigurer { */ ConfigurationConfigurer withConfiguration() throws Exception; + /** + * Gets a configurer for distributed state machine config. + * + * @return {@link DistributedStateMachineConfigurer} for chaining + * @throws Exception if configuration error happens + */ + DistributedStateMachineConfigurer withDistributed() throws Exception; + } diff --git a/spring-statemachine-core/src/main/java/org/springframework/statemachine/config/configurers/DefaultDistributedStateMachineConfigurer.java b/spring-statemachine-core/src/main/java/org/springframework/statemachine/config/configurers/DefaultDistributedStateMachineConfigurer.java new file mode 100644 index 00000000..97b7a868 --- /dev/null +++ b/spring-statemachine-core/src/main/java/org/springframework/statemachine/config/configurers/DefaultDistributedStateMachineConfigurer.java @@ -0,0 +1,49 @@ +/* + * Copyright 2015 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.statemachine.config.configurers; + +import org.springframework.statemachine.config.builders.StateMachineConfigurationBuilder; +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.ensemble.StateMachineEnsemble; + +/** + * Default implementation of a {@link DistributedStateMachineConfigurer}. + * + * @author Janne Valkealahti + * + * @param the type of state + * @param the type of event + */ +public class DefaultDistributedStateMachineConfigurer + extends AnnotationConfigurerAdapter, StateMachineConfigurationConfigurer, StateMachineConfigurationBuilder> + implements DistributedStateMachineConfigurer { + + private StateMachineEnsemble ensemble; + + @Override + public void configure(StateMachineConfigurationBuilder builder) throws Exception { + builder.setStateMachineEnsemble(ensemble); + } + + @Override + public DistributedStateMachineConfigurer ensemble(StateMachineEnsemble ensemble) { + this.ensemble = ensemble; + return this; + } + +} diff --git a/spring-statemachine-core/src/main/java/org/springframework/statemachine/config/configurers/DistributedStateMachineConfigurer.java b/spring-statemachine-core/src/main/java/org/springframework/statemachine/config/configurers/DistributedStateMachineConfigurer.java new file mode 100644 index 00000000..fc37354b --- /dev/null +++ b/spring-statemachine-core/src/main/java/org/springframework/statemachine/config/configurers/DistributedStateMachineConfigurer.java @@ -0,0 +1,42 @@ +/* + * Copyright 2015 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.statemachine.config.configurers; + +import org.springframework.statemachine.config.builders.StateMachineConfigurationConfigurer; +import org.springframework.statemachine.config.common.annotation.AnnotationConfigurerBuilder; +import org.springframework.statemachine.ensemble.StateMachineEnsemble; + +/** + * Base {@code DistributedStateMachineConfigurer} interface for configuring + * distributed state machine. + * + * @author Janne Valkealahti + * + * @param the type of state + * @param the type of event + */ +public interface DistributedStateMachineConfigurer extends + AnnotationConfigurerBuilder> { + + /** + * Specify a {@link StateMachineEnsemble}. + * + * @param ensemble the state machine ensemble + * @return configurer for chaining + */ + DistributedStateMachineConfigurer ensemble(StateMachineEnsemble ensemble); + +} diff --git a/spring-statemachine-samples/zookeeper/src/main/java/demo/zookeeper/Application.java b/spring-statemachine-samples/zookeeper/src/main/java/demo/zookeeper/Application.java index 13511865..0c424e67 100644 --- a/spring-statemachine-samples/zookeeper/src/main/java/demo/zookeeper/Application.java +++ b/spring-statemachine-samples/zookeeper/src/main/java/demo/zookeeper/Application.java @@ -18,65 +18,32 @@ package demo.zookeeper; import org.apache.curator.framework.CuratorFramework; import org.apache.curator.framework.CuratorFrameworkFactory; import org.apache.curator.retry.ExponentialBackoffRetry; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.shell.Bootstrap; -import org.springframework.statemachine.StateMachine; import org.springframework.statemachine.config.EnableStateMachine; import org.springframework.statemachine.config.StateMachineConfigurerAdapter; +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.ensemble.DistributedStateMachine; import org.springframework.statemachine.zookeeper.ZookeeperStateMachineEnsemble; @Configuration public class Application { - @Configuration - static class ZkConfig { - - @Qualifier("internalStateMachine") - @Autowired - StateMachine internalMachine; - - @Bean - public StateMachine stateMachine() throws Exception { - DistributedStateMachine machine = - new DistributedStateMachine(ensemble(), internalMachine); - return machine; - } - - @Bean - public ZookeeperStateMachineEnsemble ensemble() throws Exception { - ZookeeperStateMachineEnsemble ensemble = - new ZookeeperStateMachineEnsemble(curatorClient(), "/foo"); - return ensemble; - } - - // for now lets not close it here, we need to let - // some other framework, ie cloud, to create curator - @Bean//(destroyMethod = "close") - public CuratorFramework curatorClient() throws Exception { - CuratorFramework client = CuratorFrameworkFactory.builder().defaultData(new byte[0]) - .retryPolicy(new ExponentialBackoffRetry(1000, 3)) - .connectString("localhost:2181").build(); - // for testing we start it here, thought initiator - // is trying to start it if not already done - client.start(); - return client; - } - - } - - //tag::snippetA[] @Configuration - @EnableStateMachine(name="internalStateMachine") + @EnableStateMachine static class StateMachineConfig extends StateMachineConfigurerAdapter { + @Override + public void configure(StateMachineConfigurationConfigurer config) throws Exception { + config + .withDistributed() + .ensemble(new ZookeeperStateMachineEnsemble(curatorClient(), "/foo")); + } + @Override public void configure(StateMachineStateConfigurer states) throws Exception { @@ -101,6 +68,18 @@ public class Application { .event("PUSH"); } + @Bean + public CuratorFramework curatorClient() throws Exception { + CuratorFramework client = CuratorFrameworkFactory.builder().defaultData(new byte[0]) + .retryPolicy(new ExponentialBackoffRetry(1000, 3)) + .connectString("localhost:2181").build(); + // for testing we start it here, thought initiator + // is trying to start it if not already done + client.start(); + return client; + } + + } //end::snippetA[]