diff --git a/spring-integration-core/src/main/java/org/springframework/integration/config/xml/PollerParser.java b/spring-integration-core/src/main/java/org/springframework/integration/config/xml/PollerParser.java index 0367423675..9ec0a67c7e 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/config/xml/PollerParser.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/config/xml/PollerParser.java @@ -16,6 +16,8 @@ package org.springframework.integration.config.xml; +import java.util.ArrayList; +import java.util.List; import java.util.concurrent.TimeUnit; import org.w3c.dom.Element; @@ -46,7 +48,12 @@ import org.springframework.util.xml.DomUtils; */ public class PollerParser extends AbstractBeanDefinitionParser { - @Override + public static final String MULTIPLE_TRIGGER_DEFINITIONS = "A cannot specify more than one trigger configuration."; + + public static final String NO_TRIGGER_DEFINITIONS = "A must have a one and only one trigger configuration."; + + + @Override protected String resolveId(Element element, AbstractBeanDefinition definition, ParserContext parserContext) throws BeanDefinitionStoreException { String id = super.resolveId(element, definition, parserContext); if (element.getAttribute("default").equals("true")) { @@ -91,34 +98,59 @@ public class PollerParser extends AbstractBeanDefinitionParser { } private void configureTrigger(Element pollerElement, BeanDefinitionBuilder targetBuilder, ParserContext parserContext) { - String triggerBeanName = null; - if (pollerElement.hasAttribute("trigger")) { - triggerBeanName = pollerElement.getAttribute("trigger"); + // Polling frequency can be configured either through attributes or by using sub-elements + // Since Spring Integration 2.0 trigger sub-elements are deprecated + String triggerAttribute = pollerElement.getAttribute("trigger"); + String fixedRateAttribute = pollerElement.getAttribute("fixed-rate"); + String fixedDelayAttribute = pollerElement.getAttribute("fixed-delay"); + String cronAttribute = pollerElement.getAttribute("cron"); + + List triggerBeanNames = new ArrayList(); + if (StringUtils.hasText(triggerAttribute)) { + triggerBeanNames.add(triggerAttribute); + } else if (StringUtils.hasText(fixedRateAttribute)) { + BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition( + "org.springframework.scheduling.support.PeriodicTrigger"); + builder.addConstructorArgValue(fixedRateAttribute); + builder.addPropertyValue("fixedRate", Boolean.TRUE); + String triggerBeanName = BeanDefinitionReaderUtils.registerWithGeneratedName(builder.getBeanDefinition(), parserContext.getRegistry()); + triggerBeanNames.add(triggerBeanName); + } else if (StringUtils.hasText(fixedDelayAttribute)) { + BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition( + "org.springframework.scheduling.support.PeriodicTrigger"); + builder.addConstructorArgValue(fixedDelayAttribute); + builder.addPropertyValue("fixedRate", Boolean.FALSE); + String triggerBeanName = BeanDefinitionReaderUtils.registerWithGeneratedName(builder.getBeanDefinition(), parserContext.getRegistry()); + triggerBeanNames.add(triggerBeanName); + } else if (StringUtils.hasText(cronAttribute)) { + BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition( + "org.springframework.scheduling.support.CronTrigger"); + builder.addConstructorArgValue(cronAttribute); + String triggerBeanName = BeanDefinitionReaderUtils.registerWithGeneratedName(builder.getBeanDefinition(), parserContext.getRegistry()); + triggerBeanNames.add(triggerBeanName); } Element intervalElement = DomUtils.getChildElementByTagName(pollerElement, "interval-trigger"); if (intervalElement != null) { - if (triggerBeanName != null) { - parserContext.getReaderContext().error( - "A element with the 'trigger' attribute cannot have or child elements. ", pollerElement); - } - triggerBeanName = parseIntervalTrigger(intervalElement, parserContext); + parserContext.getReaderContext().warning("Poller configuration via 'interval-trigger' subelements is deprecated, use attributes instead", pollerElement); + triggerBeanNames.add(parseIntervalTrigger(intervalElement, parserContext)); } else { Element cronElement = DomUtils.getChildElementByTagName(pollerElement, "cron-trigger"); + parserContext.getReaderContext().warning("Poller configuration via 'cron-trigger' subelements is deprecated, use attributes instead", pollerElement); if (cronElement != null) { - if (triggerBeanName != null) { - parserContext.getReaderContext().error( - "A element with the 'trigger' attribute cannot have or child elements. ", pollerElement); - } - triggerBeanName = parseCronTrigger(cronElement, parserContext); + triggerBeanNames.add(parseCronTrigger(cronElement, parserContext)); } } - if (triggerBeanName == null) { + if (triggerBeanNames.isEmpty()) { parserContext.getReaderContext().error( - "A element must include a trigger definition, either as a 'trigger' attribute, or as an or child element.", pollerElement); + NO_TRIGGER_DEFINITIONS, pollerElement); } - targetBuilder.addPropertyReference("trigger", triggerBeanName); - } + if (triggerBeanNames.size() > 1) { + parserContext.getReaderContext().error( + MULTIPLE_TRIGGER_DEFINITIONS, pollerElement); + } + targetBuilder.addPropertyReference("trigger", triggerBeanNames.get(0)); + } /** * Parse an "interval-trigger" element diff --git a/spring-integration-core/src/main/resources/org/springframework/integration/config/xml/spring-integration-2.0.xsd b/spring-integration-core/src/main/resources/org/springframework/integration/config/xml/spring-integration-2.0.xsd index cc038f0dc2..83b625f805 100644 --- a/spring-integration-core/src/main/resources/org/springframework/integration/config/xml/spring-integration-2.0.xsd +++ b/spring-integration-core/src/main/resources/org/springframework/integration/config/xml/spring-integration-2.0.xsd @@ -1018,10 +1018,12 @@ + + @@ -1046,7 +1048,21 @@ - + + + Fixed delay trigger (in milliseconds). + + + + + Fixed rate trigger (in milliseconds). + + + + + Cron trigger. + + diff --git a/spring-integration-core/src/test/java/org/springframework/integration/config/xml/CronTriggerParserTests-context.xml b/spring-integration-core/src/test/java/org/springframework/integration/config/xml/CronTriggerParserTests-context.xml index c90b6ff7f6..196369992b 100644 --- a/spring-integration-core/src/test/java/org/springframework/integration/config/xml/CronTriggerParserTests-context.xml +++ b/spring-integration-core/src/test/java/org/springframework/integration/config/xml/CronTriggerParserTests-context.xml @@ -1,14 +1,16 @@ - + http://www.springframework.org/schema/integration/spring-integration.xsd"> - + + + diff --git a/spring-integration-core/src/test/java/org/springframework/integration/config/xml/CronTriggerParserTests.java b/spring-integration-core/src/test/java/org/springframework/integration/config/xml/CronTriggerParserTests.java index 62bb79931f..687636cfd8 100644 --- a/spring-integration-core/src/test/java/org/springframework/integration/config/xml/CronTriggerParserTests.java +++ b/spring-integration-core/src/test/java/org/springframework/integration/config/xml/CronTriggerParserTests.java @@ -41,8 +41,8 @@ public class CronTriggerParserTests { private ApplicationContext context; @Test - public void checkConfig() { - Object poller = context.getBean("poller"); + public void checkConfigWithSubElement() { + Object poller = context.getBean("pollerWithSubElement"); assertEquals(PollerMetadata.class, poller.getClass()); PollerMetadata metadata = (PollerMetadata) poller; Trigger trigger = metadata.getTrigger(); @@ -54,4 +54,19 @@ public class CronTriggerParserTests { assertEquals("*/10 * 9-17 * * MON-FRI", expression); } + @Test + public void checkConfigWithAttribute() { + Object poller = context.getBean("pollerWithAttribute"); + assertEquals(PollerMetadata.class, poller.getClass()); + PollerMetadata metadata = (PollerMetadata) poller; + Trigger trigger = metadata.getTrigger(); + assertEquals(CronTrigger.class, trigger.getClass()); + DirectFieldAccessor accessor = new DirectFieldAccessor(trigger); + String expression = (String) new DirectFieldAccessor( + accessor.getPropertyValue("sequenceGenerator")) + .getPropertyValue("expression"); + assertEquals("*/10 * 9-17 * * MON-FRI", expression); + } + } + diff --git a/spring-integration-core/src/test/java/org/springframework/integration/config/xml/IntervalTriggerParserTests-context.xml b/spring-integration-core/src/test/java/org/springframework/integration/config/xml/IntervalTriggerParserTests-context.xml new file mode 100644 index 0000000000..b59c922e63 --- /dev/null +++ b/spring-integration-core/src/test/java/org/springframework/integration/config/xml/IntervalTriggerParserTests-context.xml @@ -0,0 +1,14 @@ + + + + + + + + \ No newline at end of file diff --git a/spring-integration-core/src/test/java/org/springframework/integration/config/xml/IntervalTriggerParserTests.java b/spring-integration-core/src/test/java/org/springframework/integration/config/xml/IntervalTriggerParserTests.java new file mode 100644 index 0000000000..757cc5731f --- /dev/null +++ b/spring-integration-core/src/test/java/org/springframework/integration/config/xml/IntervalTriggerParserTests.java @@ -0,0 +1,68 @@ +/* + * Copyright 2002-2010 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.integration.config.xml; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.DirectFieldAccessor; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.integration.scheduling.PollerMetadata; +import org.springframework.scheduling.Trigger; +import org.springframework.scheduling.support.PeriodicTrigger; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +/** + * @author Marius Bogoevici + */ +@ContextConfiguration +@RunWith(SpringJUnit4ClassRunner.class) +public class IntervalTriggerParserTests { + + @Autowired + ApplicationContext context; + + @Test + public void testFixedRateTrigger() { + Object poller = context.getBean("pollerWithFixedRateAttribute"); + assertEquals(PollerMetadata.class, poller.getClass()); + PollerMetadata metadata = (PollerMetadata) poller; + Trigger trigger = metadata.getTrigger(); + assertEquals(PeriodicTrigger.class, trigger.getClass()); + DirectFieldAccessor accessor = new DirectFieldAccessor(trigger); + Boolean fixedRate = (Boolean) accessor.getPropertyValue("fixedRate"); + Long period = (Long) accessor.getPropertyValue("period"); + assertEquals(fixedRate, true); + assertEquals(36l, period.longValue()); + } + + @Test + public void testFixedDelayTrigger() { + Object poller = context.getBean("pollerWithFixedDelayAttribute"); + assertEquals(PollerMetadata.class, poller.getClass()); + PollerMetadata metadata = (PollerMetadata) poller; + Trigger trigger = metadata.getTrigger(); + assertEquals(PeriodicTrigger.class, trigger.getClass()); + DirectFieldAccessor accessor = new DirectFieldAccessor(trigger); + Boolean fixedRate = (Boolean) accessor.getPropertyValue("fixedRate"); + Long period = (Long) accessor.getPropertyValue("period"); + assertEquals(fixedRate, false); + assertEquals(37l, period.longValue()); + } +} diff --git a/spring-integration-core/src/test/java/org/springframework/integration/config/xml/PollerParserTests.java b/spring-integration-core/src/test/java/org/springframework/integration/config/xml/PollerParserTests.java index 46f44a4f37..ea1e81cdb7 100644 --- a/spring-integration-core/src/test/java/org/springframework/integration/config/xml/PollerParserTests.java +++ b/spring-integration-core/src/test/java/org/springframework/integration/config/xml/PollerParserTests.java @@ -28,6 +28,7 @@ import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.integration.config.TestTrigger; import org.springframework.integration.context.IntegrationContextUtils; import org.springframework.integration.scheduling.PollerMetadata; +import org.springframework.scheduling.support.PeriodicTrigger; /** * @author Mark Fisher