Add config builder for distributed machine

- New configurer which can be used to define an ensemble which
  if is set automatically wraps a machine with a distributed
  state machine and sets it to use an given ensemble.
- Relates to #35
This commit is contained in:
Janne Valkealahti
2015-06-18 13:20:04 +01:00
parent 742010f1a5
commit e2fe4907d3
7 changed files with 225 additions and 45 deletions

View File

@@ -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<S, E> 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<S, E> distributedStateMachine = new DistributedStateMachine<>(
stateMachineConfigurationConfig.getStateMachineEnsemble(), machine);
machine = distributedStateMachine;
}
return machine;
}

View File

@@ -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<S, E>
private BeanFactory beanFactory;
private TaskExecutor taskExecutor;
private TaskScheduler taskScheculer;
private StateMachineEnsemble<S, E> 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<Object> objectPostProcessor,
boolean allowConfigurersOfSameType) {
super(objectPostProcessor, allowConfigurersOfSameType);
}
/**
* Instantiates a new state machine configuration builder.
*
* @param objectPostProcessor the object post processor
*/
public StateMachineConfigurationBuilder(ObjectPostProcessor<Object> objectPostProcessor) {
super(objectPostProcessor);
}
@@ -59,20 +77,49 @@ public class StateMachineConfigurationBuilder<S, E>
}
@Override
protected StateMachineConfigurationConfig<S, E> performBuild() throws Exception {
return new StateMachineConfigurationConfig<>(beanFactory, taskExecutor, taskScheculer);
public DistributedStateMachineConfigurer<S, E> withDistributed() throws Exception {
return apply(new DefaultDistributedStateMachineConfigurer<S, E>());
}
@Override
protected StateMachineConfigurationConfig<S, E> 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<S, E> ensemble) {
this.ensemble = ensemble;
}
}

View File

@@ -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 <S> the type of state
* @param <E> the type of event
*/
public class StateMachineConfigurationConfig<S, E> {
private final BeanFactory beanFactory;
private final TaskExecutor taskExecutor;
private final TaskScheduler taskScheculer;
private final StateMachineEnsemble<S, E> 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<S, E> 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<S, E> getStateMachineEnsemble() {
return ensemble;
}
}

View File

@@ -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<S, E> {
*/
ConfigurationConfigurer<S, E> withConfiguration() throws Exception;
/**
* Gets a configurer for distributed state machine config.
*
* @return {@link DistributedStateMachineConfigurer} for chaining
* @throws Exception if configuration error happens
*/
DistributedStateMachineConfigurer<S, E> withDistributed() throws Exception;
}

View File

@@ -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 <S> the type of state
* @param <E> the type of event
*/
public class DefaultDistributedStateMachineConfigurer<S, E>
extends AnnotationConfigurerAdapter<StateMachineConfigurationConfig<S, E>, StateMachineConfigurationConfigurer<S, E>, StateMachineConfigurationBuilder<S, E>>
implements DistributedStateMachineConfigurer<S, E> {
private StateMachineEnsemble<S, E> ensemble;
@Override
public void configure(StateMachineConfigurationBuilder<S, E> builder) throws Exception {
builder.setStateMachineEnsemble(ensemble);
}
@Override
public DistributedStateMachineConfigurer<S, E> ensemble(StateMachineEnsemble<S, E> ensemble) {
this.ensemble = ensemble;
return this;
}
}

View File

@@ -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 <S> the type of state
* @param <E> the type of event
*/
public interface DistributedStateMachineConfigurer<S, E> extends
AnnotationConfigurerBuilder<StateMachineConfigurationConfigurer<S, E>> {
/**
* Specify a {@link StateMachineEnsemble}.
*
* @param ensemble the state machine ensemble
* @return configurer for chaining
*/
DistributedStateMachineConfigurer<S, E> ensemble(StateMachineEnsemble<S, E> ensemble);
}

View File

@@ -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<String, String> internalMachine;
@Bean
public StateMachine<String, String> stateMachine() throws Exception {
DistributedStateMachine<String, String> machine =
new DistributedStateMachine<String, String>(ensemble(), internalMachine);
return machine;
}
@Bean
public ZookeeperStateMachineEnsemble<String, String> ensemble() throws Exception {
ZookeeperStateMachineEnsemble<String, String> ensemble =
new ZookeeperStateMachineEnsemble<String, String>(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<String, String> {
@Override
public void configure(StateMachineConfigurationConfigurer<String, String> config) throws Exception {
config
.withDistributed()
.ensemble(new ZookeeperStateMachineEnsemble<String, String>(curatorClient(), "/foo"));
}
@Override
public void configure(StateMachineStateConfigurer<String, String> 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[]