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
This commit is contained in:
Gary Russell
2015-10-20 12:01:05 -04:00
committed by Artem Bilan
parent 56374212d1
commit b3571a1705
16 changed files with 386 additions and 141 deletions

View File

@@ -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;
}

View File

@@ -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<H extends MessageHandler>
implements FactoryBean<MessageHandler>, BeanFactoryAware {
implements FactoryBean<MessageHandler>, ApplicationContextAware, BeanFactoryAware, BeanNameAware,
ApplicationEventPublisherAware {
protected final Log logger = LogFactory.getLog(this.getClass());
@@ -64,8 +71,31 @@ public abstract class AbstractSimpleMessageHandlerFactoryBean<H extends MessageH
private volatile String componentName;
public AbstractSimpleMessageHandlerFactoryBean() {
super();
private ApplicationContext applicationContext;
private String beanName;
private ApplicationEventPublisher applicationEventPublisher;
private DestinationResolver<MessageChannel> 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<MessageChannel> channelResolver) {
this.channelResolver = channelResolver;
}
public void setOutputChannel(MessageChannel outputChannel) {
@@ -113,9 +143,19 @@ public abstract class AbstractSimpleMessageHandlerFactoryBean<H extends MessageH
// There was a problem when this method was called already
return null;
}
handler = createHandler();
if (handler instanceof BeanFactoryAware) {
((BeanFactoryAware) handler).setBeanFactory(getBeanFactory());
this.handler = createHandler();
if (this.handler instanceof ApplicationContextAware && this.applicationContext != null) {
((ApplicationContextAware) this.handler).setApplicationContext(this.applicationContext);
}
if (this.handler instanceof BeanFactoryAware && getBeanFactory() != null) {
((BeanFactoryAware) this.handler).setBeanFactory(getBeanFactory());
}
if (this.handler instanceof BeanNameAware && this.beanName != null) {
((BeanNameAware) this.handler).setBeanName(this.beanName);
}
if (this.handler instanceof ApplicationEventPublisherAware && this.applicationEventPublisher != null) {
((ApplicationEventPublisherAware) this.handler)
.setApplicationEventPublisher(this.applicationEventPublisher);
}
if (this.handler instanceof MessageProducer && this.outputChannel != null) {
((MessageProducer) this.handler).setOutputChannel(this.outputChannel);
@@ -124,8 +164,13 @@ public abstract class AbstractSimpleMessageHandlerFactoryBean<H extends MessageH
if (actualHandler == null) {
actualHandler = this.handler;
}
if (actualHandler instanceof IntegrationObjectSupport && this.componentName != null) {
((IntegrationObjectSupport) actualHandler).setComponentName(this.componentName);
if (actualHandler instanceof IntegrationObjectSupport) {
if (this.componentName != null) {
((IntegrationObjectSupport) actualHandler).setComponentName(this.componentName);
}
if (this.channelResolver != null) {
((IntegrationObjectSupport) actualHandler).setChannelResolver(this.channelResolver);
}
}
if (!CollectionUtils.isEmpty(this.adviceChain)) {
if (actualHandler instanceof AbstractReplyProducingMessageHandler) {
@@ -163,6 +208,15 @@ public abstract class AbstractSimpleMessageHandlerFactoryBean<H extends MessageH
if (this.handler != null) {
return this.handler.getClass();
}
return getPreCreationHandlerType();
}
/**
* Subclasses can override this to return a more specific type before handler creation.
* After handler creation, the actual type is used.
* @return the type.
*/
protected Class<? extends MessageHandler> getPreCreationHandlerType() {
return MessageHandler.class;
}

View File

@@ -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<AggregatingMessageHandler>
implements ApplicationContextAware, BeanNameAware, ApplicationEventPublisherAware {
public class AggregatorFactoryBean extends AbstractSimpleMessageHandlerFactoryBean<AggregatingMessageHandler> {
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<Advice> 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<MessageChannel> 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<Advice> 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<? extends MessageHandler> getPreCreationHandlerType() {
return AggregatingMessageHandler.class;
}
}

View File

@@ -141,4 +141,9 @@ public class FilterFactoryBean extends AbstractStandardMessageHandlerFactoryBean
&& this.discardWithinAdvice == null);
}
@Override
protected Class<? extends MessageHandler> getPreCreationHandlerType() {
return MessageFilter.class;
}
}

View File

@@ -147,4 +147,9 @@ public class RouterFactoryBean extends AbstractStandardMessageHandlerFactoryBean
&& this.ignoreSendFailures == null;
}
@Override
protected Class<? extends MessageHandler> getPreCreationHandlerType() {
return AbstractMessageRouter.class;
}
}

View File

@@ -146,4 +146,9 @@ public class SplitterFactoryBean extends AbstractStandardMessageHandlerFactoryBe
}
}
@Override
protected Class<? extends MessageHandler> getPreCreationHandlerType() {
return AbstractMessageSplitter.class;
}
}

View File

@@ -88,4 +88,9 @@ public class TransformerFactoryBean extends AbstractStandardMessageHandlerFactor
return true; // Any AMPH can be a transformer
}
@Override
protected Class<? extends MessageHandler> getPreCreationHandlerType() {
return MessageTransformingHandler.class;
}
}

View File

@@ -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);

View File

@@ -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 <T> Message<T> createMessage(T payload, Object correlationId, int sequenceSize, int sequenceNumber,

View File

@@ -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"));
}

View File

@@ -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 {

View File

@@ -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<String>("test"));
handler.getLatch().await(500, TimeUnit.MILLISECONDS);
assertEquals("test", handler.getMessageString());
context.close();
}
}

View File

@@ -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 {

View File

@@ -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();
}
}

View File

@@ -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();
}
}

View File

@@ -2,10 +2,10 @@
<beans:beans xmlns="http://www.springframework.org/schema/integration"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:beans="http://www.springframework.org/schema/beans"
xsi:schemaLocation="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">
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">
<channel id="outputChannel">
<queue capacity="5"/>
@@ -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">
<expire-advice-chain/>
</aggregator>
<beans:bean id="lockRegistry" class="org.springframework.integration.support.locks.DefaultLockRegistry"/>
<task:scheduler id="scheduler"/>
<beans:bean id="store" class="org.springframework.integration.store.SimpleMessageStore"/>
<channel id="aggregatorWithExpressionsInput"/>
<channel id="aggregatorWithExpressionsOutput"/>