/* * Copyright 2015-2016 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; import org.springframework.core.task.SyncTaskExecutor; import org.springframework.scheduling.concurrent.ConcurrentTaskScheduler; import org.springframework.statemachine.StateMachine; import org.springframework.statemachine.StateMachineException; import org.springframework.statemachine.config.builders.StateMachineConfigBuilder; import org.springframework.statemachine.config.builders.StateMachineConfigurationBuilder; import org.springframework.statemachine.config.builders.StateMachineConfigurationConfigurer; import org.springframework.statemachine.config.builders.StateMachineConfigurer; import org.springframework.statemachine.config.builders.StateMachineModelBuilder; import org.springframework.statemachine.config.builders.StateMachineModelConfigurer; import org.springframework.statemachine.config.builders.StateMachineStateBuilder; import org.springframework.statemachine.config.builders.StateMachineStateConfigurer; import org.springframework.statemachine.config.builders.StateMachineTransitionBuilder; import org.springframework.statemachine.config.builders.StateMachineTransitionConfigurer; import org.springframework.statemachine.config.common.annotation.AnnotationBuilder; import org.springframework.statemachine.config.common.annotation.ObjectPostProcessor; import org.springframework.statemachine.config.model.DefaultStateMachineModel; import org.springframework.statemachine.config.model.ConfigurationData; import org.springframework.statemachine.config.model.StatesData; import org.springframework.statemachine.config.model.TransitionsData; /** * {@code StateMachineBuilder} provides a builder pattern for * {@link StateMachine} using a similar concepts found from a * normal annotation based configuration. * * @author Janne Valkealahti * */ public class StateMachineBuilder { /** * Gets a builder for a {@link StateMachine}. * * @param <S> the type of state * @param <E> the type of event * @return the builder */ public static <S, E> Builder<S, E> builder() { return new Builder<S, E>(); } /** * {@code Builder} implementation handling logic of building * a {@link StateMachine} manually. * * @param <S> the type of state * @param <E> the type of event */ public static class Builder<S, E> { private StateMachineConfigBuilder<S, E> builder; private BuilderStateMachineConfigurerAdapter<S, E> adapter; /** * Instantiates a new builder. */ public Builder() { adapter = new BuilderStateMachineConfigurerAdapter<S, E>(); builder = new StateMachineConfigBuilder<S, E>(); } /** * Configure model. * * @return the state machine model configurer */ public StateMachineModelConfigurer<S, E> configureModel() { return adapter.modelBuilder; } /** * Configure configuration. * * @return the state machine configuration configurer */ public StateMachineConfigurationConfigurer<S, E> configureConfiguration() { return adapter.configurationBuilder; } /** * Configure states. * * @return the state machine state configurer */ public StateMachineStateConfigurer<S, E> configureStates() { return adapter.stateBuilder; } /** * Configure transitions. * * @return the state machine transition configurer */ public StateMachineTransitionConfigurer<S, E> configureTransitions() { return adapter.transitionBuilder; } /** * Builds a {@link StateMachine}. * * @return the state machine */ public StateMachine<S, E> build() { try { builder.apply(adapter); StateMachineConfig<S, E> stateMachineConfig = builder.getOrBuild(); TransitionsData<S, E> stateMachineTransitions = stateMachineConfig.getTransitions(); StatesData<S, E> stateMachineStates = stateMachineConfig.getStates(); ConfigurationData<S, E> stateMachineConfigurationConfig = stateMachineConfig.getStateMachineConfigurationConfig(); ObjectStateMachineFactory<S, E> stateMachineFactory = null; if (stateMachineConfig.getModel() != null && stateMachineConfig.getModel().getFactory() != null) { stateMachineFactory = new ObjectStateMachineFactory<S, E>( new DefaultStateMachineModel<S, E>(stateMachineConfigurationConfig, null, null), stateMachineConfig.getModel().getFactory()); } else { stateMachineFactory = new ObjectStateMachineFactory<S, E>(new DefaultStateMachineModel<S, E>( stateMachineConfigurationConfig, stateMachineStates, stateMachineTransitions), null); } stateMachineFactory.setHandleAutostartup(stateMachineConfigurationConfig.isAutoStart()); if (stateMachineConfigurationConfig.getBeanFactory() != null) { stateMachineFactory.setBeanFactory(stateMachineConfigurationConfig.getBeanFactory()); } if (stateMachineConfigurationConfig.getTaskExecutor() != null) { stateMachineFactory.setTaskExecutor(stateMachineConfigurationConfig.getTaskExecutor()); } else { stateMachineFactory.setTaskExecutor(new SyncTaskExecutor()); } if (stateMachineConfigurationConfig.getTaskScheduler() != null) { stateMachineFactory.setTaskScheduler(stateMachineConfigurationConfig.getTaskScheduler()); } else { stateMachineFactory.setTaskScheduler(new ConcurrentTaskScheduler()); } return stateMachineFactory.getStateMachine(); } catch (Exception e) { throw new StateMachineException("Error building state machine", e); } } } private static class BuilderStateMachineConfigurerAdapter<S extends Object, E extends Object> implements StateMachineConfigurer<S, E> { private StateMachineModelBuilder<S, E> modelBuilder; private StateMachineTransitionBuilder<S, E> transitionBuilder; private StateMachineStateBuilder<S, E> stateBuilder; private StateMachineConfigurationBuilder<S, E> configurationBuilder; BuilderStateMachineConfigurerAdapter() { try { getStateMachineModelBuilder(); getStateMachineTransitionBuilder(); getStateMachineStateBuilder(); getStateMachineConfigurationBuilder(); } catch (Exception e) { throw new StateMachineException("Error instantiating builder adapter", e); } } @Override public void init(StateMachineConfigBuilder<S, E> config) throws Exception { config.setSharedObject(StateMachineModelBuilder.class, getStateMachineModelBuilder()); config.setSharedObject(StateMachineTransitionBuilder.class, getStateMachineTransitionBuilder()); config.setSharedObject(StateMachineStateBuilder.class, getStateMachineStateBuilder()); config.setSharedObject(StateMachineConfigurationBuilder.class, getStateMachineConfigurationBuilder()); } @Override public void configure(StateMachineConfigBuilder<S, E> builder) throws Exception { } @Override public boolean isAssignable(AnnotationBuilder<StateMachineConfig<S, E>> builder) { return false; } @Override public void configure(StateMachineModelConfigurer<S, E> model) throws Exception { } @Override public void configure(StateMachineConfigurationConfigurer<S, E> config) throws Exception { } @Override public void configure(StateMachineStateConfigurer<S, E> states) throws Exception { } @Override public void configure(StateMachineTransitionConfigurer<S, E> transitions) throws Exception { } protected final StateMachineModelBuilder<S, E> getStateMachineModelBuilder() throws Exception { if (modelBuilder != null) { return modelBuilder; } modelBuilder = new StateMachineModelBuilder<S, E>(ObjectPostProcessor.QUIESCENT_POSTPROCESSOR, true); configure(modelBuilder); return modelBuilder; } protected final StateMachineTransitionBuilder<S, E> getStateMachineTransitionBuilder() throws Exception { if (transitionBuilder != null) { return transitionBuilder; } transitionBuilder = new StateMachineTransitionBuilder<S, E>(ObjectPostProcessor.QUIESCENT_POSTPROCESSOR, true); return transitionBuilder; } protected final StateMachineStateBuilder<S, E> getStateMachineStateBuilder() throws Exception { if (stateBuilder != null) { return stateBuilder; } stateBuilder = new StateMachineStateBuilder<S, E>(ObjectPostProcessor.QUIESCENT_POSTPROCESSOR, true); return stateBuilder; } protected final StateMachineConfigurationBuilder<S, E> getStateMachineConfigurationBuilder() throws Exception { if (configurationBuilder != null) { return configurationBuilder; } configurationBuilder = new StateMachineConfigurationBuilder<S, E>(ObjectPostProcessor.QUIESCENT_POSTPROCESSOR, true); return configurationBuilder; } } }