From b3571a1705492cf69b871fc187a4c26fa9b767b4 Mon Sep 17 00:00:00 2001 From: Gary Russell Date: Tue, 20 Oct 2015 12:01:05 -0400 Subject: [PATCH] INT-3857: Avoid ctor Injection in Aggregator FB JIRA: https://jira.spring.io/browse/INT-3857 Setter injection avoids early instantiation of FB properties. Enhance aggregator parser tests to include several new properties to check coverage in FB. Clean up other tests. Polishing - PR Comments --- .../AbstractCorrelatingMessageHandler.java | 13 +- ...stractSimpleMessageHandlerFactoryBean.java | 70 ++++- .../config/AggregatorFactoryBean.java | 242 ++++++++++++------ .../integration/config/FilterFactoryBean.java | 5 + .../integration/config/RouterFactoryBean.java | 5 + .../config/SplitterFactoryBean.java | 5 + .../config/TransformerFactoryBean.java | 5 + .../config/xml/AggregatorParser.java | 19 +- .../config/AggregatorParserTests.java | 57 ++++- .../integration/config/ChainParserTests.java | 14 +- ...tionStrategyInvalidConfigurationTests.java | 16 +- .../config/EndpointParserTests.java | 4 +- .../config/IdGeneratorConfigurerTests.java | 24 +- ...lidChannelWithMessageStoreParserTests.java | 5 +- .../config/MessageBusParserTests.java | 18 +- .../config/aggregatorParserTests.xml | 25 +- 16 files changed, 386 insertions(+), 141 deletions(-) diff --git a/spring-integration-core/src/main/java/org/springframework/integration/aggregator/AbstractCorrelatingMessageHandler.java b/spring-integration-core/src/main/java/org/springframework/integration/aggregator/AbstractCorrelatingMessageHandler.java index c223868b64..73534dbb65 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/aggregator/AbstractCorrelatingMessageHandler.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/aggregator/AbstractCorrelatingMessageHandler.java @@ -24,6 +24,10 @@ import java.util.UUID; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.locks.Lock; +import org.aopalliance.aop.Advice; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + import org.springframework.aop.framework.ProxyFactory; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactoryAware; @@ -52,10 +56,6 @@ import org.springframework.scheduling.TaskScheduler; import org.springframework.util.Assert; import org.springframework.util.CollectionUtils; -import org.aopalliance.aop.Advice; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - /** * Abstract Message handler that holds a buffer of correlated messages in a * {@link MessageStore}. This class takes care of correlated groups of messages @@ -282,6 +282,11 @@ public abstract class AbstractCorrelatingMessageHandler extends AbstractMessageP this.minimumTimeoutForEmptyGroups = minimumTimeoutForEmptyGroups; } + /** + * Set {@code releasePartialSequences} on an underlying + * {@link SequenceSizeReleaseStrategy}. + * @param releasePartialSequences true to allow release. + */ public void setReleasePartialSequences(boolean releasePartialSequences) { this.releasePartialSequences = releasePartialSequences; } diff --git a/spring-integration-core/src/main/java/org/springframework/integration/config/AbstractSimpleMessageHandlerFactoryBean.java b/spring-integration-core/src/main/java/org/springframework/integration/config/AbstractSimpleMessageHandlerFactoryBean.java index 922b565869..3a4acf4b08 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/config/AbstractSimpleMessageHandlerFactoryBean.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/config/AbstractSimpleMessageHandlerFactoryBean.java @@ -24,8 +24,13 @@ import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactoryAware; import org.springframework.beans.factory.BeanInitializationException; +import org.springframework.beans.factory.BeanNameAware; import org.springframework.beans.factory.FactoryBean; import org.springframework.beans.factory.InitializingBean; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.context.ApplicationEventPublisherAware; import org.springframework.integration.context.IntegrationObjectSupport; import org.springframework.integration.context.Orderable; import org.springframework.integration.core.MessageProducer; @@ -33,6 +38,7 @@ import org.springframework.integration.handler.AbstractReplyProducingMessageHand import org.springframework.integration.support.context.NamedComponent; import org.springframework.messaging.MessageChannel; import org.springframework.messaging.MessageHandler; +import org.springframework.messaging.core.DestinationResolver; import org.springframework.util.Assert; import org.springframework.util.CollectionUtils; @@ -44,7 +50,8 @@ import org.springframework.util.CollectionUtils; * @author David Liu */ public abstract class AbstractSimpleMessageHandlerFactoryBean - implements FactoryBean, BeanFactoryAware { + implements FactoryBean, ApplicationContextAware, BeanFactoryAware, BeanNameAware, + ApplicationEventPublisherAware { protected final Log logger = LogFactory.getLog(this.getClass()); @@ -64,8 +71,31 @@ public abstract class AbstractSimpleMessageHandlerFactoryBean channelResolver; + + @Override + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { + this.applicationContext = applicationContext; + } + + @Override + public void setBeanName(String beanName) { + this.beanName = beanName; + } + + @Override + public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) { + this.applicationEventPublisher = applicationEventPublisher; + } + + public void setChannelResolver(DestinationResolver channelResolver) { + this.channelResolver = channelResolver; } public void setOutputChannel(MessageChannel outputChannel) { @@ -113,9 +143,19 @@ public abstract class AbstractSimpleMessageHandlerFactoryBean getPreCreationHandlerType() { return MessageHandler.class; } diff --git a/spring-integration-core/src/main/java/org/springframework/integration/config/AggregatorFactoryBean.java b/spring-integration-core/src/main/java/org/springframework/integration/config/AggregatorFactoryBean.java index 7bd1eacd4a..de355f066a 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/config/AggregatorFactoryBean.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/config/AggregatorFactoryBean.java @@ -19,13 +19,7 @@ import java.util.List; import org.aopalliance.aop.Advice; -import org.springframework.beans.BeansException; -import org.springframework.beans.factory.BeanNameAware; import org.springframework.beans.factory.FactoryBean; -import org.springframework.context.ApplicationContext; -import org.springframework.context.ApplicationContextAware; -import org.springframework.context.ApplicationEventPublisher; -import org.springframework.context.ApplicationEventPublisherAware; import org.springframework.expression.Expression; import org.springframework.integration.aggregator.AggregatingMessageHandler; import org.springframework.integration.aggregator.CorrelationStrategy; @@ -36,8 +30,9 @@ import org.springframework.integration.store.MessageGroupStore; import org.springframework.integration.support.locks.LockRegistry; import org.springframework.integration.support.management.AbstractMessageHandlerMetrics; import org.springframework.messaging.MessageChannel; -import org.springframework.messaging.core.DestinationResolver; +import org.springframework.messaging.MessageHandler; import org.springframework.scheduling.TaskScheduler; +import org.springframework.util.StringUtils; /** @@ -47,129 +42,222 @@ import org.springframework.scheduling.TaskScheduler; * @since 4.2 * */ -public class AggregatorFactoryBean extends AbstractSimpleMessageHandlerFactoryBean - implements ApplicationContextAware, BeanNameAware, ApplicationEventPublisherAware { +public class AggregatorFactoryBean extends AbstractSimpleMessageHandlerFactoryBean { - private final AggregatingMessageHandler aggregator; + private Object processorBean; - public AggregatorFactoryBean(Object processor) { - this(processor, null); + private String methodName; + + private Boolean expireGroupsUponCompletion; + + private Long sendTimeout; + + private String outputChannelName; + + private AbstractMessageHandlerMetrics metrics; + + private Boolean statsEnabled; + + private Boolean countsEnabled; + + private LockRegistry lockRegistry; + + private MessageGroupStore messageStore; + + private CorrelationStrategy correlationStrategy; + + private ReleaseStrategy releaseStrategy; + + private Expression groupTimeoutExpression; + + private List forceReleaseAdviceChain; + + private TaskScheduler taskScheduler; + + private MessageChannel discardChannel; + + private String discardChannelName; + + private Boolean sendPartialResultOnExpiry; + + private Long minimumTimeoutForEmptyGroups; + + private Boolean expireGroupsUponTimeout; + + public void setProcessorBean(Object processorBean) { + this.processorBean = processorBean; } - public AggregatorFactoryBean(Object processor, String methodName) { - MessageGroupProcessor outputProcessor; - if (processor instanceof MessageGroupProcessor) { - outputProcessor = (MessageGroupProcessor) processor; - } - else { - if (methodName == null) { - outputProcessor = new MethodInvokingMessageGroupProcessor(processor); - } - else { - outputProcessor = new MethodInvokingMessageGroupProcessor(processor, methodName); - } - } - this.aggregator = new AggregatingMessageHandler(outputProcessor); + public void setMethodName(String methodName) { + this.methodName = methodName; } - public void setExpireGroupsUponCompletion(boolean expireGroupsUponCompletion) { - this.aggregator.setExpireGroupsUponCompletion(expireGroupsUponCompletion); + public void setExpireGroupsUponCompletion(Boolean expireGroupsUponCompletion) { + this.expireGroupsUponCompletion = expireGroupsUponCompletion; } - public void setSendTimeout(long sendTimeout) { - this.aggregator.setSendTimeout(sendTimeout); + public void setSendTimeout(Long sendTimeout) { + this.sendTimeout = sendTimeout; } public void setOutputChannelName(String outputChannelName) { - this.aggregator.setOutputChannelName(outputChannelName); + this.outputChannelName = outputChannelName; } - public void configureMetrics(AbstractMessageHandlerMetrics metrics) { - this.aggregator.configureMetrics(metrics); + public void setMetrics(AbstractMessageHandlerMetrics metrics) { + this.metrics = metrics; } - @Override - public final void setBeanName(String beanName) { - this.aggregator.setBeanName(beanName); + public void setStatsEnabled(Boolean statsEnabled) { + this.statsEnabled = statsEnabled; } - @Override - public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { - this.aggregator.setApplicationContext(applicationContext); - } - - public void setChannelResolver(DestinationResolver channelResolver) { - this.aggregator.setChannelResolver(channelResolver); - } - - public void setStatsEnabled(boolean statsEnabled) { - this.aggregator.setStatsEnabled(statsEnabled); - } - - public void setCountsEnabled(boolean countsEnabled) { - this.aggregator.setCountsEnabled(countsEnabled); + public void setCountsEnabled(Boolean countsEnabled) { + this.countsEnabled = countsEnabled; } public void setLockRegistry(LockRegistry lockRegistry) { - this.aggregator.setLockRegistry(lockRegistry); + this.lockRegistry = lockRegistry; } - public void setMessageStore(MessageGroupStore store) { - this.aggregator.setMessageStore(store); + public void setMessageStore(MessageGroupStore messageStore) { + this.messageStore = messageStore; } public void setCorrelationStrategy(CorrelationStrategy correlationStrategy) { - this.aggregator.setCorrelationStrategy(correlationStrategy); + this.correlationStrategy = correlationStrategy; } public void setReleaseStrategy(ReleaseStrategy releaseStrategy) { - this.aggregator.setReleaseStrategy(releaseStrategy); + this.releaseStrategy = releaseStrategy; } public void setGroupTimeoutExpression(Expression groupTimeoutExpression) { - this.aggregator.setGroupTimeoutExpression(groupTimeoutExpression); + this.groupTimeoutExpression = groupTimeoutExpression; } public void setForceReleaseAdviceChain(List forceReleaseAdviceChain) { - this.aggregator.setForceReleaseAdviceChain(forceReleaseAdviceChain); + this.forceReleaseAdviceChain = forceReleaseAdviceChain; } public void setTaskScheduler(TaskScheduler taskScheduler) { - this.aggregator.setTaskScheduler(taskScheduler); - } - - @Override - public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) { - this.aggregator.setApplicationEventPublisher(applicationEventPublisher); + this.taskScheduler = taskScheduler; } public void setDiscardChannel(MessageChannel discardChannel) { - this.aggregator.setDiscardChannel(discardChannel); + this.discardChannel = discardChannel; } public void setDiscardChannelName(String discardChannelName) { - this.aggregator.setDiscardChannelName(discardChannelName); + this.discardChannelName = discardChannelName; } - public void setSendPartialResultOnExpiry(boolean sendPartialResultOnExpiry) { - this.aggregator.setSendPartialResultOnExpiry(sendPartialResultOnExpiry); + public void setSendPartialResultOnExpiry(Boolean sendPartialResultOnExpiry) { + this.sendPartialResultOnExpiry = sendPartialResultOnExpiry; } - public void setMinimumTimeoutForEmptyGroups(long minimumTimeoutForEmptyGroups) { - this.aggregator.setMinimumTimeoutForEmptyGroups(minimumTimeoutForEmptyGroups); + public void setMinimumTimeoutForEmptyGroups(Long minimumTimeoutForEmptyGroups) { + this.minimumTimeoutForEmptyGroups = minimumTimeoutForEmptyGroups; } - public void setReleasePartialSequences(boolean releasePartialSequences) { - this.aggregator.setReleasePartialSequences(releasePartialSequences); - } - - public void setExpireGroupsUponTimeout(boolean expireGroupsUponTimeout) { - this.aggregator.setExpireGroupsUponTimeout(expireGroupsUponTimeout); + public void setExpireGroupsUponTimeout(Boolean expireGroupsUponTimeout) { + this.expireGroupsUponTimeout = expireGroupsUponTimeout; } @Override protected AggregatingMessageHandler createHandler() { - return this.aggregator; + MessageGroupProcessor outputProcessor; + if (this.processorBean instanceof MessageGroupProcessor) { + outputProcessor = (MessageGroupProcessor) this.processorBean; + } + else { + if (!StringUtils.hasText(this.methodName)) { + outputProcessor = new MethodInvokingMessageGroupProcessor(this.processorBean); + } + else { + outputProcessor = new MethodInvokingMessageGroupProcessor(this.processorBean, this.methodName); + } + } + AggregatingMessageHandler aggregator = new AggregatingMessageHandler(outputProcessor); + + if (this.expireGroupsUponCompletion != null) { + aggregator.setExpireGroupsUponCompletion(this.expireGroupsUponCompletion); + } + + if (this.sendTimeout != null) { + aggregator.setSendTimeout(this.sendTimeout); + } + + if (this.outputChannelName != null) { + aggregator.setOutputChannelName(this.outputChannelName); + } + + if (this.metrics != null) { + aggregator.configureMetrics(this.metrics); + } + + if (this.statsEnabled != null) { + aggregator.setStatsEnabled(this.statsEnabled); + } + + if (this.countsEnabled != null) { + aggregator.setCountsEnabled(this.countsEnabled); + } + + if (this.lockRegistry != null) { + aggregator.setLockRegistry(this.lockRegistry); + } + + if (this.messageStore != null) { + aggregator.setMessageStore(this.messageStore); + } + + if (this.correlationStrategy != null) { + aggregator.setCorrelationStrategy(this.correlationStrategy); + } + + if (this.releaseStrategy != null) { + aggregator.setReleaseStrategy(this.releaseStrategy); + } + + if (this.groupTimeoutExpression != null) { + aggregator.setGroupTimeoutExpression(this.groupTimeoutExpression); + } + + if (this.forceReleaseAdviceChain != null) { + aggregator.setForceReleaseAdviceChain(this.forceReleaseAdviceChain); + } + + if (this.taskScheduler != null) { + aggregator.setTaskScheduler(this.taskScheduler); + } + + if (this.discardChannel != null) { + aggregator.setDiscardChannel(this.discardChannel); + } + + if (this.discardChannelName != null) { + aggregator.setDiscardChannelName(this.discardChannelName); + } + + if (this.sendPartialResultOnExpiry != null) { + aggregator.setSendPartialResultOnExpiry(this.sendPartialResultOnExpiry); + } + + if (this.minimumTimeoutForEmptyGroups != null) { + aggregator.setMinimumTimeoutForEmptyGroups(this.minimumTimeoutForEmptyGroups); + } + + if (this.expireGroupsUponTimeout != null) { + aggregator.setExpireGroupsUponTimeout(this.expireGroupsUponTimeout); + } + + return aggregator; + } + + @Override + protected Class getPreCreationHandlerType() { + return AggregatingMessageHandler.class; } } diff --git a/spring-integration-core/src/main/java/org/springframework/integration/config/FilterFactoryBean.java b/spring-integration-core/src/main/java/org/springframework/integration/config/FilterFactoryBean.java index 656558d80f..3eca41c320 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/config/FilterFactoryBean.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/config/FilterFactoryBean.java @@ -141,4 +141,9 @@ public class FilterFactoryBean extends AbstractStandardMessageHandlerFactoryBean && this.discardWithinAdvice == null); } + @Override + protected Class getPreCreationHandlerType() { + return MessageFilter.class; + } + } diff --git a/spring-integration-core/src/main/java/org/springframework/integration/config/RouterFactoryBean.java b/spring-integration-core/src/main/java/org/springframework/integration/config/RouterFactoryBean.java index e397edc05c..31829354c8 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/config/RouterFactoryBean.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/config/RouterFactoryBean.java @@ -147,4 +147,9 @@ public class RouterFactoryBean extends AbstractStandardMessageHandlerFactoryBean && this.ignoreSendFailures == null; } + @Override + protected Class getPreCreationHandlerType() { + return AbstractMessageRouter.class; + } + } diff --git a/spring-integration-core/src/main/java/org/springframework/integration/config/SplitterFactoryBean.java b/spring-integration-core/src/main/java/org/springframework/integration/config/SplitterFactoryBean.java index 04b23a88c9..8ec926e6dc 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/config/SplitterFactoryBean.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/config/SplitterFactoryBean.java @@ -146,4 +146,9 @@ public class SplitterFactoryBean extends AbstractStandardMessageHandlerFactoryBe } } + @Override + protected Class getPreCreationHandlerType() { + return AbstractMessageSplitter.class; + } + } diff --git a/spring-integration-core/src/main/java/org/springframework/integration/config/TransformerFactoryBean.java b/spring-integration-core/src/main/java/org/springframework/integration/config/TransformerFactoryBean.java index 414c99daff..f90cfa84db 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/config/TransformerFactoryBean.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/config/TransformerFactoryBean.java @@ -88,4 +88,9 @@ public class TransformerFactoryBean extends AbstractStandardMessageHandlerFactor return true; // Any AMPH can be a transformer } + @Override + protected Class getPreCreationHandlerType() { + return MessageTransformingHandler.class; + } + } diff --git a/spring-integration-core/src/main/java/org/springframework/integration/config/xml/AggregatorParser.java b/spring-integration-core/src/main/java/org/springframework/integration/config/xml/AggregatorParser.java index ed05dec0d7..2ee46f3df8 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/config/xml/AggregatorParser.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/config/xml/AggregatorParser.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2014 the original author or authors. + * Copyright 2002-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. @@ -48,9 +48,7 @@ public class AggregatorParser extends AbstractCorrelatingMessageHandlerParser { BeanComponentDefinition innerHandlerDefinition = IntegrationNamespaceUtils.parseInnerHandlerDefinition(element, parserContext); String ref = element.getAttribute(REF_ATTRIBUTE); - BeanDefinitionBuilder builder; - - builder = BeanDefinitionBuilder.genericBeanDefinition(AggregatorFactoryBean.class); + BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(AggregatorFactoryBean.class); BeanMetadataElement processor = null; if (innerHandlerDefinition != null || StringUtils.hasText(ref)) { @@ -60,24 +58,25 @@ public class AggregatorParser extends AbstractCorrelatingMessageHandlerParser { else { processor = new RuntimeBeanReference(ref); } - builder.addConstructorArgValue(processor); + builder.addPropertyValue("processorBean", processor); } else { if (StringUtils.hasText(element.getAttribute(EXPRESSION_ATTRIBUTE))) { String expression = element.getAttribute(EXPRESSION_ATTRIBUTE); - BeanDefinitionBuilder adapterBuilder = BeanDefinitionBuilder.genericBeanDefinition(ExpressionEvaluatingMessageGroupProcessor.class); + BeanDefinitionBuilder adapterBuilder = BeanDefinitionBuilder + .genericBeanDefinition(ExpressionEvaluatingMessageGroupProcessor.class); adapterBuilder.addConstructorArgValue(expression); - builder.addConstructorArgValue(adapterBuilder.getBeanDefinition()); + builder.addPropertyValue("processorBean", adapterBuilder.getBeanDefinition()); } else { - builder.addConstructorArgValue(BeanDefinitionBuilder.genericBeanDefinition(DefaultAggregatingMessageGroupProcessor.class) - .getBeanDefinition()); + builder.addPropertyValue("processorBean", BeanDefinitionBuilder + .genericBeanDefinition(DefaultAggregatingMessageGroupProcessor.class).getBeanDefinition()); } } if (StringUtils.hasText(element.getAttribute(METHOD_ATTRIBUTE))) { String method = element.getAttribute(METHOD_ATTRIBUTE); - builder.addConstructorArgValue(method); + builder.addPropertyValue("methodName", method); } this.doParse(builder, element, processor, parserContext); diff --git a/spring-integration-core/src/test/java/org/springframework/integration/config/AggregatorParserTests.java b/spring-integration-core/src/test/java/org/springframework/integration/config/AggregatorParserTests.java index 9362629f94..fdacb955ff 100644 --- a/spring-integration-core/src/test/java/org/springframework/integration/config/AggregatorParserTests.java +++ b/spring-integration-core/src/test/java/org/springframework/integration/config/AggregatorParserTests.java @@ -18,12 +18,15 @@ package org.springframework.integration.config; import static org.hamcrest.CoreMatchers.instanceOf; import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.Matchers.containsString; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; import java.util.ArrayList; import java.util.Collection; @@ -39,6 +42,7 @@ import org.springframework.beans.factory.BeanCreationException; import org.springframework.beans.factory.parsing.BeanDefinitionParsingException; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; +import org.springframework.expression.Expression; import org.springframework.integration.IntegrationMessageHeaderAccessor; import org.springframework.integration.MessageRejectedException; import org.springframework.integration.aggregator.AggregatingMessageHandler; @@ -52,6 +56,7 @@ import org.springframework.integration.aggregator.SimpleMessageGroupProcessor; import org.springframework.integration.channel.QueueChannel; import org.springframework.integration.endpoint.EventDrivenConsumer; import org.springframework.integration.support.MessageBuilder; +import org.springframework.integration.support.locks.LockRegistry; import org.springframework.integration.support.utils.IntegrationUtils; import org.springframework.integration.test.util.TestUtils; import org.springframework.messaging.Message; @@ -191,6 +196,16 @@ public class AggregatorParserTests { "The AggregatorEndpoint is not configured with the appropriate 'send partial results on timeout' flag", true, accessor.getPropertyValue("sendPartialResultOnExpiry")); assertFalse(TestUtils.getPropertyValue(consumer, "expireGroupsUponTimeout", Boolean.class)); + assertTrue(TestUtils.getPropertyValue(consumer, "expireGroupsUponCompletion", Boolean.class)); + assertEquals(123L, TestUtils.getPropertyValue(consumer, "minimumTimeoutForEmptyGroups")); + assertEquals("456", TestUtils.getPropertyValue(consumer, "groupTimeoutExpression", Expression.class) + .getExpressionString()); + assertSame(this.context.getBean(LockRegistry.class), TestUtils.getPropertyValue(consumer, "lockRegistry")); + assertSame(this.context.getBean("scheduler"), TestUtils.getPropertyValue(consumer, "taskScheduler")); + assertSame(this.context.getBean("store"), TestUtils.getPropertyValue(consumer, "messageStore")); + assertEquals(5, TestUtils.getPropertyValue(consumer, "order")); + assertNotNull(TestUtils.getPropertyValue(consumer, "forceReleaseAdviceChain")); + } @Test @@ -211,14 +226,26 @@ public class AggregatorParserTests { assertSame(mbf, TestUtils.getPropertyValue(handler, "outputProcessor.messageBuilderFactory")); } - @Test(expected = BeanCreationException.class) + @Test public void testMissingMethodOnAggregator() { - context = new ClassPathXmlApplicationContext("invalidMethodNameAggregator.xml", this.getClass()); + try { + new ClassPathXmlApplicationContext("invalidMethodNameAggregator.xml", this.getClass()).close(); + fail("Expected exception"); + } + catch (BeanCreationException e) { + assertThat(e.getMessage(), containsString("Adder] has no eligible methods")); + } } - @Test(expected = BeanCreationException.class) - public void testDuplicateReleaseStrategyDefinition() { - context = new ClassPathXmlApplicationContext("ReleaseStrategyMethodWithMissingReference.xml", this.getClass()); + @Test + public void testMissingReleaseStrategyDefinition() { + try { + new ClassPathXmlApplicationContext("ReleaseStrategyMethodWithMissingReference.xml", this.getClass()).close(); + fail("Expected exception"); + } + catch (BeanCreationException e) { + assertThat(e.getMessage(), containsString("No bean named 'testReleaseStrategy' is defined")); + } } @Test @@ -271,9 +298,15 @@ public class AggregatorParserTests { assertEquals(11l, reply.getPayload()); } - @Test(expected = BeanCreationException.class) + @Test public void testAggregatorWithInvalidReleaseStrategyMethod() { - context = new ClassPathXmlApplicationContext("invalidReleaseStrategyMethod.xml", this.getClass()); + try { + new ClassPathXmlApplicationContext("invalidReleaseStrategyMethod.xml", this.getClass()).close(); + fail("Expected exception"); + } + catch (BeanCreationException e) { + assertThat(e.getMessage(), containsString("TestReleaseStrategy] has no eligible methods")); + } } @Test @@ -292,9 +325,15 @@ public class AggregatorParserTests { assertEquals(60000L, minimumTimeoutForEmptyGroups.longValue()); } - @Test(expected=BeanDefinitionParsingException.class) + @Test public void testAggregatorFailureIfMutuallyExclusivityPresent() { - this.context = new ClassPathXmlApplicationContext("aggregatorParserFailTests.xml", this.getClass()); + try { + new ClassPathXmlApplicationContext("aggregatorParserFailTests.xml", this.getClass()).close(); + } + catch (BeanDefinitionParsingException e) { + assertThat(e.getMessage(), containsString( + "Exactly one of the 'release-strategy' or 'release-strategy-expression' attribute is allowed.")); + } } private static Message createMessage(T payload, Object correlationId, int sequenceSize, int sequenceNumber, diff --git a/spring-integration-core/src/test/java/org/springframework/integration/config/ChainParserTests.java b/spring-integration-core/src/test/java/org/springframework/integration/config/ChainParserTests.java index 5d1ad8804b..2120f9d35f 100644 --- a/spring-integration-core/src/test/java/org/springframework/integration/config/ChainParserTests.java +++ b/spring-integration-core/src/test/java/org/springframework/integration/config/ChainParserTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2014 the original author or authors. + * Copyright 2002-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. @@ -46,7 +46,7 @@ import org.springframework.beans.factory.BeanCreationException; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.context.ApplicationContext; +import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.integration.IntegrationMessageHeaderAccessor; import org.springframework.integration.MessageRejectedException; @@ -76,6 +76,7 @@ import org.springframework.util.StringUtils; * @author Dave Turanski * @author Artem Bilan * @author Gunnar Hillert + * @author Gary Russell */ @ContextConfiguration @RunWith(SpringJUnit4ClassRunner.class) @@ -325,7 +326,8 @@ public class ChainParserTests { @Test(expected = BeanCreationException.class) //INT-2275 public void invalidNestedChainWithLoggingChannelAdapter() { try { - new ClassPathXmlApplicationContext("invalidNestedChainWithOutboundChannelAdapter-context.xml", this.getClass()); + new ClassPathXmlApplicationContext("invalidNestedChainWithOutboundChannelAdapter-context.xml", + this.getClass()).close(); fail("BeanCreationException is expected!"); } catch (BeansException e) { @@ -338,7 +340,8 @@ public class ChainParserTests { @Test //INT-2605 public void checkSmartLifecycleConfig() { - ApplicationContext ctx = new ClassPathXmlApplicationContext("ChainParserSmartLifecycleAttributesTest.xml", this.getClass()); + ConfigurableApplicationContext ctx = new ClassPathXmlApplicationContext( + "ChainParserSmartLifecycleAttributesTest.xml", this.getClass()); AbstractEndpoint chainEndpoint = ctx.getBean("chain", AbstractEndpoint.class); assertEquals(false, chainEndpoint.isAutoStartup()); assertEquals(256, chainEndpoint.getPhase()); @@ -349,6 +352,7 @@ public class ChainParserTests { //INT-3108 MessageHandler serviceActivator = ctx.getBean("chain$child.sa-within-chain.handler", MessageHandler.class); assertTrue(TestUtils.getPropertyValue(serviceActivator, "requiresReply", Boolean.class)); + ctx.close(); } @Test @@ -406,7 +410,7 @@ public class ChainParserTests { assertTrue(handlers.get(1) instanceof ServiceActivatingHandler); assertEquals("headerEnricherChain$child#1", TestUtils.getPropertyValue(handlers.get(1), "componentName")); - assertNull(TestUtils.getPropertyValue(handlers.get(1), "beanName")); + assertEquals("headerEnricherChain$child#1.handler", TestUtils.getPropertyValue(handlers.get(1), "beanName")); assertFalse(this.beanFactory.containsBean("headerEnricherChain$child#1.handler")); } diff --git a/spring-integration-core/src/test/java/org/springframework/integration/config/CorrelationStrategyInvalidConfigurationTests.java b/spring-integration-core/src/test/java/org/springframework/integration/config/CorrelationStrategyInvalidConfigurationTests.java index e651734830..2db8017f89 100644 --- a/spring-integration-core/src/test/java/org/springframework/integration/config/CorrelationStrategyInvalidConfigurationTests.java +++ b/spring-integration-core/src/test/java/org/springframework/integration/config/CorrelationStrategyInvalidConfigurationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2010 the original author or authors. + * Copyright 2002-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. @@ -16,6 +16,9 @@ package org.springframework.integration.config; +import static org.hamcrest.Matchers.containsString; +import static org.junit.Assert.assertThat; + import org.junit.Test; import org.springframework.beans.factory.BeanCreationException; @@ -23,12 +26,19 @@ import org.springframework.context.support.ClassPathXmlApplicationContext; /** * @author Marius Bogoevici + * @author Gary Russell */ public class CorrelationStrategyInvalidConfigurationTests { - @Test(expected = BeanCreationException.class) + @Test public void testCorrelationStrategyWithVoidReturningMethods() throws Exception { - new ClassPathXmlApplicationContext("correlationStrategyWithVoidMethods.xml", CorrelationStrategyInvalidConfigurationTests.class); + try { + new ClassPathXmlApplicationContext("correlationStrategyWithVoidMethods.xml", + CorrelationStrategyInvalidConfigurationTests.class).close(); + } + catch (BeanCreationException e) { + assertThat(e.getMessage(), containsString("MessageCountReleaseStrategy] has no eligible methods")); + } } public static class VoidReturningCorrelationStrategy { diff --git a/spring-integration-core/src/test/java/org/springframework/integration/config/EndpointParserTests.java b/spring-integration-core/src/test/java/org/springframework/integration/config/EndpointParserTests.java index 0221835d42..2bb417d48f 100644 --- a/spring-integration-core/src/test/java/org/springframework/integration/config/EndpointParserTests.java +++ b/spring-integration-core/src/test/java/org/springframework/integration/config/EndpointParserTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2008 the original author or authors. + * Copyright 2002-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. @@ -29,6 +29,7 @@ import org.springframework.messaging.support.GenericMessage; /** * @author Mark Fisher + * @author Gary Russell */ public class EndpointParserTests { @@ -43,6 +44,7 @@ public class EndpointParserTests { channel.send(new GenericMessage("test")); handler.getLatch().await(500, TimeUnit.MILLISECONDS); assertEquals("test", handler.getMessageString()); + context.close(); } } diff --git a/spring-integration-core/src/test/java/org/springframework/integration/config/IdGeneratorConfigurerTests.java b/spring-integration-core/src/test/java/org/springframework/integration/config/IdGeneratorConfigurerTests.java index ca2abbed3b..d741f2fe28 100644 --- a/spring-integration-core/src/test/java/org/springframework/integration/config/IdGeneratorConfigurerTests.java +++ b/spring-integration-core/src/test/java/org/springframework/integration/config/IdGeneratorConfigurerTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2013 the original author or authors. + * Copyright 2002-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. @@ -51,7 +51,7 @@ public class IdGeneratorConfigurerTests { MessageHeaders headers = new MessageHeaders(null); assertEquals(1, headers.getId().getMostSignificantBits()); assertEquals(2, headers.getId().getLeastSignificantBits()); - context.destroy(); + context.close(); headers = new MessageHeaders(null); assertNotEquals(1, headers.getId().getMostSignificantBits()); assertNotEquals(2, headers.getId().getLeastSignificantBits()); @@ -70,7 +70,7 @@ public class IdGeneratorConfigurerTests { MessageHeaders headers = new MessageHeaders(null); assertNull(TestUtils.getPropertyValue(headers, "idGenerator")); - context.destroy(); + context.close(); } @Test @@ -82,7 +82,7 @@ public class IdGeneratorConfigurerTests { MessageHeaders headers = new MessageHeaders(null); assertNull(TestUtils.getPropertyValue(headers, "idGenerator")); - context.destroy(); + context.close(); } @Test @@ -100,8 +100,8 @@ public class IdGeneratorConfigurerTests { context2.registerBeanDefinition("foo", new RootBeanDefinition(MyIdGenerator.class)); context2.refresh(); - context.destroy(); - context2.destroy(); + context.close(); + context2.close(); headers = new MessageHeaders(null); assertNotEquals(1, headers.getId().getMostSignificantBits()); @@ -125,13 +125,13 @@ public class IdGeneratorConfigurerTests { context2.registerBeanDefinition("foo", new RootBeanDefinition(MyIdGenerator.class)); context2.refresh(); - context.destroy(); + context.close(); // we should still use the custom strategy headers = new MessageHeaders(null); assertEquals(1, headers.getId().getMostSignificantBits()); assertEquals(2, headers.getId().getLeastSignificantBits()); - context2.destroy(); + context2.close(); // back to default headers = new MessageHeaders(null); assertNotEquals(1, headers.getId().getMostSignificantBits()); @@ -162,8 +162,8 @@ public class IdGeneratorConfigurerTests { e.getMessage()); } - context.destroy(); - context2.destroy(); + context.close(); + context2.close(); } @Test @@ -175,7 +175,7 @@ public class IdGeneratorConfigurerTests { MessageHeaders headers = new MessageHeaders(null); assertSame(context.getBean(IdGenerator.class), TestUtils.getPropertyValue(headers, "idGenerator")); - context.destroy(); + context.close(); } @Test @@ -200,7 +200,7 @@ public class IdGeneratorConfigurerTests { assertEquals(1, headers.getId().getMostSignificantBits()); assertEquals(1, headers.getId().getLeastSignificantBits()); - context.destroy(); + context.close(); } public static class MyIdGenerator implements IdGenerator { diff --git a/spring-integration-core/src/test/java/org/springframework/integration/config/InvalidChannelWithMessageStoreParserTests.java b/spring-integration-core/src/test/java/org/springframework/integration/config/InvalidChannelWithMessageStoreParserTests.java index 23d5d2d02f..d38461cf00 100644 --- a/spring-integration-core/src/test/java/org/springframework/integration/config/InvalidChannelWithMessageStoreParserTests.java +++ b/spring-integration-core/src/test/java/org/springframework/integration/config/InvalidChannelWithMessageStoreParserTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2010 the original author or authors. + * Copyright 2002-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. @@ -20,6 +20,7 @@ import org.hamcrest.Matchers; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; + import org.springframework.beans.factory.parsing.BeanDefinitionParsingException; import org.springframework.context.support.ClassPathXmlApplicationContext; @@ -35,7 +36,7 @@ public class InvalidChannelWithMessageStoreParserTests { public void testRefAndStoreIllegal() throws Exception { exception.expect(BeanDefinitionParsingException.class); exception.expectMessage(Matchers.containsString("'message-store' attribute is not allowed")); - new ClassPathXmlApplicationContext(getClass().getSimpleName() + "-context.xml", getClass()); + new ClassPathXmlApplicationContext(getClass().getSimpleName() + "-context.xml", getClass()).close(); } } diff --git a/spring-integration-core/src/test/java/org/springframework/integration/config/MessageBusParserTests.java b/spring-integration-core/src/test/java/org/springframework/integration/config/MessageBusParserTests.java index 3a34890102..0c27db1f02 100644 --- a/spring-integration-core/src/test/java/org/springframework/integration/config/MessageBusParserTests.java +++ b/spring-integration-core/src/test/java/org/springframework/integration/config/MessageBusParserTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2010 the original author or authors. + * Copyright 2002-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. @@ -22,7 +22,7 @@ import static org.junit.Assert.assertNull; import org.junit.Test; import org.springframework.beans.DirectFieldAccessor; -import org.springframework.context.ApplicationContext; +import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.event.SimpleApplicationEventMulticaster; import org.springframework.context.support.AbstractApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; @@ -36,28 +36,31 @@ import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; /** * @author Mark Fisher * @author Marius Bogoevici + * @author Gary Russell */ public class MessageBusParserTests { @Test public void testErrorChannelReference() { - ApplicationContext context = new ClassPathXmlApplicationContext( + ConfigurableApplicationContext context = new ClassPathXmlApplicationContext( "messageBusWithErrorChannel.xml", this.getClass()); BeanFactoryChannelResolver resolver = new BeanFactoryChannelResolver(context); assertEquals(context.getBean("errorChannel"), resolver.resolveDestination("errorChannel")); + context.close(); } @Test public void testDefaultErrorChannel() { - ApplicationContext context = new ClassPathXmlApplicationContext( + ConfigurableApplicationContext context = new ClassPathXmlApplicationContext( "messageBusWithDefaults.xml", this.getClass()); BeanFactoryChannelResolver resolver = new BeanFactoryChannelResolver(context); assertEquals(context.getBean("errorChannel"), resolver.resolveDestination("errorChannel")); + context.close(); } @Test public void testMulticasterIsSyncByDefault() { - ApplicationContext context = new ClassPathXmlApplicationContext( + ConfigurableApplicationContext context = new ClassPathXmlApplicationContext( "messageBusWithDefaults.xml", this.getClass()); SimpleApplicationEventMulticaster multicaster = (SimpleApplicationEventMulticaster) context.getBean(AbstractApplicationContext.APPLICATION_EVENT_MULTICASTER_BEAN_NAME); @@ -69,6 +72,7 @@ public class MessageBusParserTests { else { assertNull(taskExecutor); } + context.close(); } @Test @@ -86,6 +90,7 @@ public class MessageBusParserTests { else { assertNull(taskExecutor); } + context.close(); } @Test @@ -98,6 +103,7 @@ public class MessageBusParserTests { DirectFieldAccessor accessor = new DirectFieldAccessor(multicaster); Object taskExecutor = accessor.getPropertyValue("taskExecutor"); assertEquals(ThreadPoolTaskExecutor.class, taskExecutor.getClass()); + context.close(); } @Test @@ -106,6 +112,7 @@ public class MessageBusParserTests { "messageBusWithTaskScheduler.xml", this.getClass()); TaskScheduler scheduler = (TaskScheduler) context.getBean("taskScheduler"); assertEquals(StubTaskScheduler.class, scheduler.getClass()); + context.close(); } @Test @@ -114,6 +121,7 @@ public class MessageBusParserTests { "messageBusWithTaskScheduler.xml", this.getClass()); TaskScheduler scheduler = (TaskScheduler) context.getBean("taskScheduler"); assertEquals(scheduler, IntegrationContextUtils.getTaskScheduler(context)); + context.close(); } } diff --git a/spring-integration-core/src/test/java/org/springframework/integration/config/aggregatorParserTests.xml b/spring-integration-core/src/test/java/org/springframework/integration/config/aggregatorParserTests.xml index fd193992cf..5029a63130 100644 --- a/spring-integration-core/src/test/java/org/springframework/integration/config/aggregatorParserTests.xml +++ b/spring-integration-core/src/test/java/org/springframework/integration/config/aggregatorParserTests.xml @@ -2,10 +2,10 @@ + xmlns:task="http://www.springframework.org/schema/task" + xsi:schemaLocation="http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task.xsd + http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd + http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd"> @@ -36,7 +36,22 @@ correlation-strategy="correlationStrategy" send-timeout="86420000" send-partial-result-on-expiry="true" - expire-groups-upon-timeout="false"/> + expire-groups-upon-completion="true" + expire-groups-upon-timeout="false" + empty-group-min-timeout="123" + group-timeout="456" + lock-registry="lockRegistry" + scheduler="scheduler" + message-store="store" + order="5"> + + + + + + + +