diff --git a/spring-statemachine-core/src/main/java/org/springframework/statemachine/config/model/AbstractStateMachineModelFactory.java b/spring-statemachine-core/src/main/java/org/springframework/statemachine/config/model/AbstractStateMachineModelFactory.java index 4c9a1503..453712f2 100644 --- a/spring-statemachine-core/src/main/java/org/springframework/statemachine/config/model/AbstractStateMachineModelFactory.java +++ b/spring-statemachine-core/src/main/java/org/springframework/statemachine/config/model/AbstractStateMachineModelFactory.java @@ -15,16 +15,15 @@ */ package org.springframework.statemachine.config.model; -import java.util.HashMap; -import java.util.Map; - import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactoryAware; import org.springframework.context.ResourceLoaderAware; +import org.springframework.core.io.DefaultResourceLoader; import org.springframework.core.io.ResourceLoader; import org.springframework.statemachine.action.Action; import org.springframework.statemachine.guard.Guard; +import org.springframework.util.Assert; /** * Base implementation of a {@link StateMachineModelFactory} providing @@ -43,20 +42,49 @@ import org.springframework.statemachine.guard.Guard; public abstract class AbstractStateMachineModelFactory implements StateMachineComponentResolver, BeanFactoryAware, ResourceLoaderAware { private BeanFactory beanFactory; - private ResourceLoader resourceLoader; - private final Map> registeredActions = new HashMap<>(); - private final Map> registeredGuards = new HashMap<>(); + private ResourceLoader resourceLoader = new DefaultResourceLoader(); + private StateMachineComponentResolver stateMachineComponentResolver; + private final DefaultStateMachineComponentResolver internalResolver = new DefaultStateMachineComponentResolver(); + + /** + * Instantiates a new abstract state machine model factory. + */ + public AbstractStateMachineModelFactory() { + } + + /** + * Instantiates a new abstract state machine model factory. + * + * @param resourceLoader the resource loader + * @param stateMachineComponentResolver the state machine component resolver + */ + public AbstractStateMachineModelFactory(ResourceLoader resourceLoader, + StateMachineComponentResolver stateMachineComponentResolver) { + this.resourceLoader = resourceLoader; + this.stateMachineComponentResolver = stateMachineComponentResolver; + } @Override public void setBeanFactory(BeanFactory beanFactory) throws BeansException { this.beanFactory = beanFactory; + internalResolver.setBeanFactory(beanFactory); } @Override public void setResourceLoader(ResourceLoader resourceLoader) { + Assert.notNull(resourceLoader, "resourceLoader cannot be null"); this.resourceLoader = resourceLoader; } + /** + * Sets the state machine component resolver. + * + * @param stateMachineComponentResolver the state machine component resolver + */ + public void setStateMachineComponentResolver(StateMachineComponentResolver stateMachineComponentResolver) { + this.stateMachineComponentResolver = stateMachineComponentResolver; + } + /** * Register {@link Action} into factory with a given id. * @@ -64,7 +92,7 @@ public abstract class AbstractStateMachineModelFactory implements StateMac * @param action the action */ public void registerAction(String id, Action action) { - registeredActions.put(id, action); + internalResolver.registerAction(id, action); } /** @@ -74,7 +102,50 @@ public abstract class AbstractStateMachineModelFactory implements StateMac * @param guard the guard */ public void registerGuard(String id, Guard guard) { - registeredGuards.put(id, guard); + internalResolver.registerGuard(id, guard); + } + + /** + * Gets the state machine component resolver. + * + * @return the state machine component resolver + */ + public StateMachineComponentResolver getStateMachineComponentResolver() { + return stateMachineComponentResolver; + } + + /** + * Resolve action. + * + * @param id the id + * @return the action + */ + public Action resolveAction(String id) { + Action a = internalResolver.resolveAction(id); + if (a == null && stateMachineComponentResolver != null) { + a = stateMachineComponentResolver.resolveAction(id); + } + if (a == null) { + throw new RuntimeException("Can't resolve action with id " + id + " either from registered actions nor beanfactory"); + } + return a; + } + + /** + * Resolve guard. + * + * @param id the id + * @return the guard + */ + public Guard resolveGuard(String id) { + Guard a = internalResolver.resolveGuard(id); + if (a == null && stateMachineComponentResolver != null) { + a = stateMachineComponentResolver.resolveGuard(id); + } + if (a == null) { + throw new RuntimeException("Can't resolve guard with id " + id + " either from registered guards nor beanfactory"); + } + return a; } /** @@ -94,42 +165,4 @@ public abstract class AbstractStateMachineModelFactory implements StateMac protected ResourceLoader getResourceLoader() { return resourceLoader; } - - /** - * Resolve action. - * - * @param id the id - * @return the action - */ - @SuppressWarnings("unchecked") - public Action resolveAction(String id) { - Action a = null; - a = registeredActions.get(id); - if (a == null && beanFactory != null) { - a = beanFactory.getBean(id, Action.class); - } - if (a == null) { - throw new RuntimeException("Can't resolve action with id " + id + " either from registered actions nor beanfactory"); - } - return a; - } - - /** - * Resolve guard. - * - * @param id the id - * @return the guard - */ - @SuppressWarnings("unchecked") - public Guard resolveGuard(String id) { - Guard g = null; - g = registeredGuards.get(id); - if (g == null && beanFactory != null) { - g = beanFactory.getBean(id, Guard.class); - } - if (g == null) { - throw new RuntimeException("Can't resolve guard with id " + id + " either from registered guards nor beanfactory"); - } - return g; - } } diff --git a/spring-statemachine-core/src/main/java/org/springframework/statemachine/config/model/DefaultStateMachineComponentResolver.java b/spring-statemachine-core/src/main/java/org/springframework/statemachine/config/model/DefaultStateMachineComponentResolver.java new file mode 100644 index 00000000..7c892c75 --- /dev/null +++ b/spring-statemachine-core/src/main/java/org/springframework/statemachine/config/model/DefaultStateMachineComponentResolver.java @@ -0,0 +1,121 @@ +/* + * Copyright 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.model; + +import java.util.HashMap; +import java.util.Map; + +import org.springframework.beans.factory.BeanFactory; +import org.springframework.statemachine.action.Action; +import org.springframework.statemachine.guard.Guard; + +/** + * Default implementation of a {@link StateMachineComponentResolver} which resolves + * from a {@link BeanFactory} if given or from a manually registered actions and guards. + * + * @author Janne Valkealahti + * + * @param the type of state + * @param the type of event + */ +public class DefaultStateMachineComponentResolver implements StateMachineComponentResolver { + + private BeanFactory beanFactory; + private final Map> registeredActions; + private final Map> registeredGuards; + + /** + * Instantiates a new default state machine component resolver. + */ + public DefaultStateMachineComponentResolver() { + this(null, null, null); + } + + /** + * Instantiates a new default state machine component resolver. + * + * @param registeredActions the registered actions + * @param registeredGuards the registered guards + */ + public DefaultStateMachineComponentResolver(Map> registeredActions, Map> registeredGuards) { + this(null, registeredActions, registeredGuards); + } + + /** + * Instantiates a new default state machine component resolver. + * + * @param beanFactory the bean factory + * @param registeredActions the registered actions + * @param registeredGuards the registered guards + */ + public DefaultStateMachineComponentResolver(BeanFactory beanFactory, Map> registeredActions, + Map> registeredGuards) { + this.beanFactory = beanFactory; + this.registeredActions = registeredActions != null ? registeredActions : new HashMap>(); + this.registeredGuards = registeredGuards != null ? registeredGuards : new HashMap>(); + } + + @SuppressWarnings("unchecked") + @Override + public Action resolveAction(String id) { + Action a = null; + a = registeredActions.get(id); + if (a == null && beanFactory != null) { + a = beanFactory.getBean(id, Action.class); + } + return a; + } + + @SuppressWarnings("unchecked") + @Override + public Guard resolveGuard(String id) { + Guard g = null; + g = registeredGuards.get(id); + if (g == null && beanFactory != null) { + g = beanFactory.getBean(id, Guard.class); + } + return g; + } + + /** + * Register {@link Action} with a given id. + * + * @param id the id + * @param action the action + */ + public void registerAction(String id, Action action) { + registeredActions.put(id, action); + } + + /** + * Register {@link Guard} with a given id. + * + * @param id the id + * @param guard the guard + */ + public void registerGuard(String id, Guard guard) { + registeredGuards.put(id, guard); + } + + /** + * Sets the bean factory. + * + * @param beanFactory the new bean factory + */ + public void setBeanFactory(BeanFactory beanFactory) { + this.beanFactory = beanFactory; + } +} diff --git a/spring-statemachine-core/src/main/java/org/springframework/statemachine/config/model/StateMachineComponentResolver.java b/spring-statemachine-core/src/main/java/org/springframework/statemachine/config/model/StateMachineComponentResolver.java index 147e1e83..6bbc71e2 100644 --- a/spring-statemachine-core/src/main/java/org/springframework/statemachine/config/model/StateMachineComponentResolver.java +++ b/spring-statemachine-core/src/main/java/org/springframework/statemachine/config/model/StateMachineComponentResolver.java @@ -19,8 +19,7 @@ import org.springframework.statemachine.action.Action; import org.springframework.statemachine.guard.Guard; /** - * Strategy interface for registering and resolving state machine - * components by their id's + * Strategy interface for resolving state machine components by their id's. * * @author Janne Valkealahti * @@ -29,22 +28,6 @@ import org.springframework.statemachine.guard.Guard; */ public interface StateMachineComponentResolver { - /** - * Register {@link Action} into factory with a given id. - * - * @param id the id - * @param action the action - */ - void registerAction(String id, Action action); - - /** - * Register {@link Guard} into factory with a given id. - * - * @param id the id - * @param guard the guard - */ - void registerGuard(String id, Guard guard); - /** * Resolve action. * diff --git a/spring-statemachine-uml/src/main/java/org/springframework/statemachine/uml/UmlStateMachineModelFactory.java b/spring-statemachine-uml/src/main/java/org/springframework/statemachine/uml/UmlStateMachineModelFactory.java index fd9538d1..26ec0852 100644 --- a/spring-statemachine-uml/src/main/java/org/springframework/statemachine/uml/UmlStateMachineModelFactory.java +++ b/spring-statemachine-uml/src/main/java/org/springframework/statemachine/uml/UmlStateMachineModelFactory.java @@ -22,17 +22,15 @@ import java.nio.file.Files; import java.nio.file.Path; import org.eclipse.uml2.uml.Model; -import org.springframework.core.io.DefaultResourceLoader; import org.springframework.core.io.Resource; -import org.springframework.core.io.ResourceLoader; import org.springframework.statemachine.config.model.AbstractStateMachineModelFactory; import org.springframework.statemachine.config.model.ConfigurationData; import org.springframework.statemachine.config.model.DefaultStateMachineModel; import org.springframework.statemachine.config.model.StateMachineModel; import org.springframework.statemachine.config.model.StateMachineModelFactory; import org.springframework.statemachine.uml.support.UmlModelParser; -import org.springframework.statemachine.uml.support.UmlUtils; import org.springframework.statemachine.uml.support.UmlModelParser.DataHolder; +import org.springframework.statemachine.uml.support.UmlUtils; import org.springframework.util.Assert; import org.springframework.util.FileCopyUtils; @@ -64,6 +62,7 @@ public class UmlStateMachineModelFactory extends AbstractStateMachineModelFactor * @param location the resource location */ public UmlStateMachineModelFactory(String location) { + Assert.notNull(location, "Location must be set"); this.location = location; } @@ -85,11 +84,7 @@ public class UmlStateMachineModelFactory extends AbstractStateMachineModelFactor if (resource != null) { return resource; } else { - ResourceLoader loader = getResourceLoader(); - if (loader == null) { - loader = new DefaultResourceLoader(); - } - return loader.getResource(location); + return getResourceLoader().getResource(location); } } diff --git a/spring-statemachine-uml/src/test/java/org/springframework/statemachine/uml/UmlStateMachineModelFactoryTests.java b/spring-statemachine-uml/src/test/java/org/springframework/statemachine/uml/UmlStateMachineModelFactoryTests.java index aecfbdb4..12d48132 100644 --- a/spring-statemachine-uml/src/test/java/org/springframework/statemachine/uml/UmlStateMachineModelFactoryTests.java +++ b/spring-statemachine-uml/src/test/java/org/springframework/statemachine/uml/UmlStateMachineModelFactoryTests.java @@ -39,6 +39,7 @@ import org.springframework.statemachine.action.Action; import org.springframework.statemachine.config.EnableStateMachine; import org.springframework.statemachine.config.StateMachineConfigurerAdapter; import org.springframework.statemachine.config.builders.StateMachineModelConfigurer; +import org.springframework.statemachine.config.model.DefaultStateMachineComponentResolver; import org.springframework.statemachine.config.model.StateData; import org.springframework.statemachine.config.model.StateMachineModel; import org.springframework.statemachine.config.model.StateMachineModelFactory; @@ -56,7 +57,7 @@ public class UmlStateMachineModelFactoryTests extends AbstractUmlTests { } @Test - public void testSimpleFlat() { + public void testSimpleFlat1() { context.refresh(); Resource model1 = new ClassPathResource("org/springframework/statemachine/uml/simple-flat.uml"); UmlStateMachineModelFactory builder = new UmlStateMachineModelFactory(model1); @@ -78,6 +79,30 @@ public class UmlStateMachineModelFactoryTests extends AbstractUmlTests { } } + @Test + public void testSimpleFlat2() { + context.refresh(); + Resource model1 = new ClassPathResource("org/springframework/statemachine/uml/simple-flat.uml"); + DefaultStateMachineComponentResolver resolver = new DefaultStateMachineComponentResolver<>(); + resolver.registerAction("action1", new LatchAction()); + UmlStateMachineModelFactory builder = new UmlStateMachineModelFactory(model1); + builder.setStateMachineComponentResolver(resolver); + assertThat(model1.exists(), is(true)); + StateMachineModel stateMachineModel = builder.build(); + assertThat(stateMachineModel, notNullValue()); + Collection> stateDatas = stateMachineModel.getStatesData().getStateData(); + assertThat(stateDatas.size(), is(2)); + for (StateData stateData : stateDatas) { + if (stateData.getState().equals("S1")) { + assertThat(stateData.isInitial(), is(true)); + } else if (stateData.getState().equals("S2")) { + assertThat(stateData.isInitial(), is(false)); + } else { + throw new IllegalArgumentException(); + } + } + } + @Test public void testSimpleSubmachine() { context.refresh();