From 1c4fccf76fe9d10ea31ee0e69d08b1d2836e503b Mon Sep 17 00:00:00 2001 From: Ben Hale Date: Fri, 22 Dec 2006 15:57:09 +0000 Subject: [PATCH] Updated the config schema and bean definition parser to accomodate changes from SWF-210. --- .../config/ExecutorBeanDefinitionParser.java | 103 +++++++++++- .../config/spring-webflow-config-1.0.xsd | 150 ++++++++++++------ .../WebFlowConfigNamespaceHandlerTests.java | 29 ++++ .../webflow/config/namespace-error-1.xml | 19 +++ .../webflow/config/namespace-error-2.xml | 23 +++ .../webflow/config/namespace-error-3.xml | 19 +++ 6 files changed, 293 insertions(+), 50 deletions(-) create mode 100644 spring-webflow/src/test/java/org/springframework/webflow/config/namespace-error-1.xml create mode 100644 spring-webflow/src/test/java/org/springframework/webflow/config/namespace-error-2.xml create mode 100644 spring-webflow/src/test/java/org/springframework/webflow/config/namespace-error-3.xml diff --git a/spring-webflow/src/main/java/org/springframework/webflow/config/ExecutorBeanDefinitionParser.java b/spring-webflow/src/main/java/org/springframework/webflow/config/ExecutorBeanDefinitionParser.java index 6ef3d740..445b492e 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/config/ExecutorBeanDefinitionParser.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/config/ExecutorBeanDefinitionParser.java @@ -20,6 +20,7 @@ import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.xml.AbstractBeanDefinitionParser; import org.springframework.beans.factory.xml.BeanDefinitionParser; import org.springframework.beans.factory.xml.ParserContext; +import org.springframework.core.enums.StaticLabeledEnumResolver; import org.springframework.util.StringUtils; import org.springframework.util.xml.DomUtils; import org.w3c.dom.Element; @@ -32,24 +33,41 @@ import org.w3c.dom.Element; class ExecutorBeanDefinitionParser extends AbstractBeanDefinitionParser { // elements and attributes - + + private static final String CONVERSATION_MANAGER_REF_ATTRIBUTE = "conversation-manager-ref"; + private static final String EXECUTION_ATTRIBUTES_ELEMENT = "execution-attributes"; private static final String EXECUTION_LISTENERS_ELEMENT = "execution-listeners"; + + private static final String MAX_CONTINUATIONS_ATTRIBUTE = "max-continuations"; + + private static final String MAX_CONVERSATIONS_ATTRIBUTE = "max-conversations"; private static final String REGISTRY_REF_ATTRIBUTE = "registry-ref"; + + private static final String REPOSITORY_ELEMENT = "repository"; private static final String REPOSITORY_TYPE_ATTRIBUTE = "repository-type"; + + private static final String TYPE_ATTRIBUTE = "type"; // properties + private static final String CONVERSATION_MANAGER_PROPERTY = "conversationManager"; + private static final String DEFINITION_LOCATOR_PROPERTY = "definitionLocator"; private static final String EXECUTION_ATTRIBUTES_PROPERTY = "executionAttributes"; private static final String EXECUTION_LISTENER_LOADER_PROPERTY = "executionListenerLoader"; + + private static final String MAX_CONTINUATIONS_PROPERTY = "maxContinuations"; + + private static final String MAX_CONVERSATIONS_PROPERTY = "maxConversations"; private static final String REPOSITORY_TYPE_PROPERTY = "repositoryType"; + protected AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) { BeanDefinitionBuilder definitionBuilder = BeanDefinitionBuilder @@ -57,10 +75,54 @@ class ExecutorBeanDefinitionParser extends AbstractBeanDefinitionParser { definitionBuilder.addPropertyReference(DEFINITION_LOCATOR_PROPERTY, getRegistryRef(element)); addExecutionAttributes(element, parserContext, definitionBuilder); addExecutionListenerLoader(element, parserContext, definitionBuilder); - definitionBuilder.addPropertyValue(REPOSITORY_TYPE_PROPERTY, getRepositoryType(element)); + configureRepository(element, definitionBuilder); return definitionBuilder.getBeanDefinition(); } + /** + * Configures a repository based on the repositoryType attribute + * or a repository tag. + * @param element the root element to extract repository configuration from + */ + private void configureRepository(Element element, BeanDefinitionBuilder definitionBuilder) { + Element repositoryElement = DomUtils.getChildElementByTagName(element, REPOSITORY_ELEMENT); + String repositoryTypeAttribute = getRepositoryType(element); + if(repositoryElement != null) { + if(StringUtils.hasText(repositoryTypeAttribute)) { + throw new IllegalArgumentException("The 'repositoryType' attribute of the 'executor' element must not have a value if there is a 'repository' element"); + } + definitionBuilder.addPropertyValue(REPOSITORY_TYPE_PROPERTY, getType(repositoryElement)); + configureContinuations(repositoryElement, definitionBuilder); + configureConversationManager(repositoryElement, definitionBuilder); + } else if (StringUtils.hasText(repositoryTypeAttribute)) { + definitionBuilder.addPropertyValue(REPOSITORY_TYPE_PROPERTY, repositoryTypeAttribute); + } + } + + private void configureConversationManager(Element repositoryElement, BeanDefinitionBuilder definitionBuilder) { + String conversationManagerRef = getConversationManagerRef(repositoryElement); + String maxConversations = getMaxConversations(repositoryElement); + if(StringUtils.hasText(conversationManagerRef)) { + if(StringUtils.hasText(maxConversations)) { + throw new IllegalArgumentException("The 'maxConversations' attribute of the 'repository' element must not have a value if there is a value for the 'conversation-manager-ref' attribute"); + } + definitionBuilder.addPropertyReference(CONVERSATION_MANAGER_PROPERTY, conversationManagerRef); + } else if (StringUtils.hasText(maxConversations)) { + definitionBuilder.addPropertyValue(MAX_CONVERSATIONS_PROPERTY, maxConversations); + } + } + + private void configureContinuations(Element repositoryElement, BeanDefinitionBuilder definitionBuilder) { + RepositoryType repositoryType = (RepositoryType) StaticLabeledEnumResolver.instance().getLabeledEnumByLabel(RepositoryType.class, getRepositoryType(repositoryElement)); + String maxContinuations = getMaxContinuations(repositoryElement); + if(StringUtils.hasText(maxContinuations)) { + if(repositoryType != RepositoryType.CONTINUATION) { + throw new IllegalArgumentException("The 'maxContinuations' attribute of the 'repository' element must not have a value if the 'type' attribute is not 'continuation'"); + } + definitionBuilder.addPropertyValue(MAX_CONTINUATIONS_PROPERTY, maxContinuations); + } + } + /** * Returns the name of the registry detailed in the bean definition. * @param element the element to extract the registry name from @@ -83,6 +145,43 @@ class ExecutorBeanDefinitionParser extends AbstractBeanDefinitionParser { private String getRepositoryType(Element element) { return element.getAttribute(REPOSITORY_TYPE_ATTRIBUTE).toUpperCase(); } + + /** + * Returns the name of the repository type enum field detailed in the bean + * definition. + * @param element the element to extract the repository type from + * @return the type of the repository + */ + private String getType(Element element) { + return element.getAttribute(TYPE_ATTRIBUTE).toUpperCase(); + } + + /** + * Returns the maximum number of continuations detailed in the bean definition. + * @param element the element to extract the max continuations from + * @return the max continuations + */ + private String getMaxContinuations(Element element) { + return element.getAttribute(MAX_CONTINUATIONS_ATTRIBUTE); + } + + /** + * Returns the maximum number of conversations detailed in the bean definition. + * @param element the element to extract the max conversations from + * @return the max conversations + */ + private String getMaxConversations(Element element) { + return element.getAttribute(MAX_CONVERSATIONS_ATTRIBUTE); + } + + /** + * Returns the name of the conversation manager detailed in the bean definition. + * @param element the element to extract the conversation manager name from + * @return the name of the conversation manager + */ + private String getConversationManagerRef(Element element) { + return element.getAttribute(CONVERSATION_MANAGER_REF_ATTRIBUTE); + } /** * Parse execution attribute definitions contained in given element. diff --git a/spring-webflow/src/main/java/org/springframework/webflow/config/spring-webflow-config-1.0.xsd b/spring-webflow/src/main/java/org/springframework/webflow/config/spring-webflow-config-1.0.xsd index 6280e27a..48c6c29d 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/config/spring-webflow-config-1.0.xsd +++ b/spring-webflow/src/main/java/org/springframework/webflow/config/spring-webflow-config-1.0.xsd @@ -93,7 +93,17 @@ an execution repository. - + + + + + + + + @@ -114,7 +124,7 @@ The listeners eligible for observing the lifecycle of executions launched by thi - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + @@ -180,7 +146,95 @@ The idref to the registry this executor will use to locate flow definitions for - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/spring-webflow/src/test/java/org/springframework/webflow/config/WebFlowConfigNamespaceHandlerTests.java b/spring-webflow/src/test/java/org/springframework/webflow/config/WebFlowConfigNamespaceHandlerTests.java index c1a103e7..5c962b25 100644 --- a/spring-webflow/src/test/java/org/springframework/webflow/config/WebFlowConfigNamespaceHandlerTests.java +++ b/spring-webflow/src/test/java/org/springframework/webflow/config/WebFlowConfigNamespaceHandlerTests.java @@ -17,6 +17,7 @@ package org.springframework.webflow.config; import junit.framework.TestCase; +import org.springframework.beans.factory.BeanDefinitionStoreException; import org.springframework.beans.factory.support.DefaultListableBeanFactory; import org.springframework.beans.factory.xml.XmlBeanDefinitionReader; import org.springframework.core.io.ClassPathResource; @@ -66,6 +67,7 @@ public class WebFlowConfigNamespaceHandlerTests extends TestCase { public void testDefaultExecutor() { FlowExecutorImpl flowExecutor = (FlowExecutorImpl)this.beanFactory.getBean("defaultExecutor"); + assertTrue(flowExecutor.getExecutionRepository() instanceof ContinuationFlowExecutionRepository); assertSame(this.beanFactory.getBean("withPathWithWildcards"), flowExecutor.getDefinitionLocator()); AttributeMap attribs = ((FlowExecutionImplFactory)flowExecutor.getExecutionFactory()).getExecutionAttributes(); assertEquals(1, attribs.size()); // defaults have been applied @@ -128,5 +130,32 @@ public class WebFlowConfigNamespaceHandlerTests extends TestCase { assertSame(StaticFlowExecutionListenerLoader.EMPTY_INSTANCE, ((FlowExecutionImplFactory)flowExecutor.getExecutionFactory()).getExecutionListenerLoader()); } + + public void testDuplicateRepositoryType() { + DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(); + XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory); + try { + reader.loadBeanDefinitions(new ClassPathResource("org/springframework/webflow/config/namespace-error-1.xml")); + fail("Should have thrown an BeanDefinitionStoreException exception"); + } catch (BeanDefinitionStoreException e) {} + } + + public void testConversationManagerRef() { + DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(); + XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory); + try { + reader.loadBeanDefinitions(new ClassPathResource("org/springframework/webflow/config/namespace-error-2.xml")); + fail("Should have thrown a BeanDefinitionStoreException exception"); + } catch (BeanDefinitionStoreException e) {} + } + + public void testMaxContinuation() { + DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(); + XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory); + try { + reader.loadBeanDefinitions(new ClassPathResource("org/springframework/webflow/config/namespace-error-3.xml")); + fail("Should have thrown a BeanDefinitionStoreException exception"); + } catch (BeanDefinitionStoreException e) {} + } } \ No newline at end of file diff --git a/spring-webflow/src/test/java/org/springframework/webflow/config/namespace-error-1.xml b/spring-webflow/src/test/java/org/springframework/webflow/config/namespace-error-1.xml new file mode 100644 index 00000000..13756d36 --- /dev/null +++ b/spring-webflow/src/test/java/org/springframework/webflow/config/namespace-error-1.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/spring-webflow/src/test/java/org/springframework/webflow/config/namespace-error-2.xml b/spring-webflow/src/test/java/org/springframework/webflow/config/namespace-error-2.xml new file mode 100644 index 00000000..2c822bb2 --- /dev/null +++ b/spring-webflow/src/test/java/org/springframework/webflow/config/namespace-error-2.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/spring-webflow/src/test/java/org/springframework/webflow/config/namespace-error-3.xml b/spring-webflow/src/test/java/org/springframework/webflow/config/namespace-error-3.xml new file mode 100644 index 00000000..4c00de3f --- /dev/null +++ b/spring-webflow/src/test/java/org/springframework/webflow/config/namespace-error-3.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + \ No newline at end of file