diff --git a/spring-integration-amqp/src/test/java/org/springframework/integration/amqp/config/AmqpOutboundChannelAdapterParserTests-context.xml b/spring-integration-amqp/src/test/java/org/springframework/integration/amqp/config/AmqpOutboundChannelAdapterParserTests-context.xml
index cc359f6bd4..0d3cb3947d 100644
--- a/spring-integration-amqp/src/test/java/org/springframework/integration/amqp/config/AmqpOutboundChannelAdapterParserTests-context.xml
+++ b/spring-integration-amqp/src/test/java/org/springframework/integration/amqp/config/AmqpOutboundChannelAdapterParserTests-context.xml
@@ -22,5 +22,10 @@
mapped-request-headers="foo*"/>
-
+
+
+
+
+
+
diff --git a/spring-integration-amqp/src/test/java/org/springframework/integration/amqp/config/AmqpOutboundChannelAdapterParserTests.java b/spring-integration-amqp/src/test/java/org/springframework/integration/amqp/config/AmqpOutboundChannelAdapterParserTests.java
index 6a2e752d6d..e273dbb21f 100644
--- a/spring-integration-amqp/src/test/java/org/springframework/integration/amqp/config/AmqpOutboundChannelAdapterParserTests.java
+++ b/spring-integration-amqp/src/test/java/org/springframework/integration/amqp/config/AmqpOutboundChannelAdapterParserTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2011 the original author or authors.
+ * Copyright 2002-2012 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.
@@ -17,6 +17,7 @@
package org.springframework.integration.amqp.config;
import java.lang.reflect.Field;
+import java.util.List;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -33,6 +34,7 @@ import org.springframework.integration.amqp.outbound.AmqpOutboundEndpoint;
import org.springframework.integration.channel.DirectChannel;
import org.springframework.integration.core.MessageHandler;
import org.springframework.integration.endpoint.EventDrivenConsumer;
+import org.springframework.integration.handler.MessageHandlerChain;
import org.springframework.integration.support.MessageBuilder;
import org.springframework.integration.test.util.TestUtils;
import org.springframework.test.context.ContextConfiguration;
@@ -47,6 +49,7 @@ import static junit.framework.Assert.assertEquals;
* @author Mark Fisher
* @author Oleg Zhurakousky
* @author Gary Russell
+ * @author Artem Bilan
* @since 2.1
*/
@ContextConfiguration
@@ -99,4 +102,35 @@ public class AmqpOutboundChannelAdapterParserTests {
Mockito.verify(amqpTemplate, Mockito.times(1)).send(Mockito.any(String.class), Mockito.any(String.class), Mockito.any(org.springframework.amqp.core.Message.class));
}
+ @SuppressWarnings("rawtypes")
+ @Test
+ public void amqpOutboundChannelAdapterWithinChain() {
+ Object eventDrivernConsumer = context.getBean("chainWithRabbitOutbound");
+
+ List chainHandlers = TestUtils.getPropertyValue(eventDrivernConsumer, "handler.handlers", List.class);
+
+ AmqpOutboundEndpoint endpoint = (AmqpOutboundEndpoint) chainHandlers.get(0);
+
+ Field amqpTemplateField = ReflectionUtils.findField(AmqpOutboundEndpoint.class, "amqpTemplate");
+ amqpTemplateField.setAccessible(true);
+ RabbitTemplate amqpTemplate = TestUtils.getPropertyValue(endpoint, "amqpTemplate", RabbitTemplate.class);
+ amqpTemplate = Mockito.spy(amqpTemplate);
+
+ Mockito.doAnswer(new Answer() {
+ public Object answer(InvocationOnMock invocation) {
+ Object[] args = invocation.getArguments();
+ org.springframework.amqp.core.Message amqpReplyMessage = (org.springframework.amqp.core.Message) args[2];
+ assertEquals("hello", new String(amqpReplyMessage.getBody()));
+ return null;
+ }})
+ .when(amqpTemplate).send(Mockito.any(String.class), Mockito.any(String.class), Mockito.any(org.springframework.amqp.core.Message.class));
+ ReflectionUtils.setField(amqpTemplateField, endpoint, amqpTemplate);
+
+
+ MessageChannel requestChannel = context.getBean("amqpOutboundChannelAdapterWithinChain", MessageChannel.class);
+ Message> message = MessageBuilder.withPayload("hello").build();
+ requestChannel.send(message);
+ Mockito.verify(amqpTemplate, Mockito.times(1)).send(Mockito.any(String.class), Mockito.any(String.class), Mockito.any(org.springframework.amqp.core.Message.class));
+ }
+
}
diff --git a/spring-integration-core/src/main/java/org/springframework/integration/config/xml/AbstractChannelAdapterParser.java b/spring-integration-core/src/main/java/org/springframework/integration/config/xml/AbstractChannelAdapterParser.java
index 04c19e58a6..fcb0ab5f76 100644
--- a/spring-integration-core/src/main/java/org/springframework/integration/config/xml/AbstractChannelAdapterParser.java
+++ b/spring-integration-core/src/main/java/org/springframework/integration/config/xml/AbstractChannelAdapterParser.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2008 the original author or authors.
+ * Copyright 2002-2012 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.
@@ -25,18 +25,28 @@ import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
import org.springframework.beans.factory.xml.AbstractBeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
+import org.springframework.integration.channel.DirectChannel;
import org.springframework.util.StringUtils;
/**
* Base parser for Channel Adapters.
- *
+ *
+ * Includes logic to determine {@link org.springframework.integration.MessageChannel}:
+ * if 'channel' attribute is defined - uses its value as 'channelName';
+ * if 'id' attribute is defined - creates {@link DirectChannel} at runtime and uses id's value as 'channelName';
+ * if current component is defined as nested element inside any other components e.g. <chain>
+ * 'id' and 'channel' attributes will be ignored and this component will not be parsed as
+ * {@link org.springframework.integration.endpoint.AbstractEndpoint}.
+ *
* @author Mark Fisher
+ * @author Artem Bilan
*/
public abstract class AbstractChannelAdapterParser extends AbstractBeanDefinitionParser {
@Override
- protected final String resolveId(Element element, AbstractBeanDefinition definition, ParserContext parserContext) throws BeanDefinitionStoreException {
- String id = element.getAttribute("id");
+ protected final String resolveId(Element element, AbstractBeanDefinition definition, ParserContext parserContext)
+ throws BeanDefinitionStoreException {
+ String id = element.getAttribute(ID_ATTRIBUTE);
if (!element.hasAttribute("channel")) {
// the created channel will get the 'id', so the adapter's bean name includes a suffix
id = id + ".adapter";
@@ -57,13 +67,15 @@ public abstract class AbstractChannelAdapterParser extends AbstractBeanDefinitio
}
private String createDirectChannel(Element element, ParserContext parserContext) {
- String channelId = element.getAttribute("id");
+ if (parserContext.isNested()) {
+ return null;
+ }
+ String channelId = element.getAttribute(ID_ATTRIBUTE);
if (!StringUtils.hasText(channelId)) {
parserContext.getReaderContext().error("The channel-adapter's 'id' attribute is required when no 'channel' "
+ "reference has been provided, because that 'id' would be used for the created channel.", element);
}
- BeanDefinitionBuilder channelBuilder = BeanDefinitionBuilder.genericBeanDefinition(
- IntegrationNamespaceUtils.BASE_PACKAGE + ".channel.DirectChannel");
+ BeanDefinitionBuilder channelBuilder = BeanDefinitionBuilder.genericBeanDefinition(DirectChannel.class);
BeanDefinitionHolder holder = new BeanDefinitionHolder(channelBuilder.getBeanDefinition(), channelId);
BeanDefinitionReaderUtils.registerBeanDefinition(holder, parserContext.getRegistry());
return channelId;
@@ -72,7 +84,7 @@ public abstract class AbstractChannelAdapterParser extends AbstractBeanDefinitio
/**
* Subclasses must implement this method to parse the adapter element.
* The name of the MessageChannel bean is provided.
- */
+ */
protected abstract AbstractBeanDefinition doParse(Element element, ParserContext parserContext, String channelName);
}
diff --git a/spring-integration-core/src/main/java/org/springframework/integration/config/xml/AbstractOutboundChannelAdapterParser.java b/spring-integration-core/src/main/java/org/springframework/integration/config/xml/AbstractOutboundChannelAdapterParser.java
index 86b8b5d786..fe23621d39 100644
--- a/spring-integration-core/src/main/java/org/springframework/integration/config/xml/AbstractOutboundChannelAdapterParser.java
+++ b/spring-integration-core/src/main/java/org/springframework/integration/config/xml/AbstractOutboundChannelAdapterParser.java
@@ -23,22 +23,31 @@ import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
import org.springframework.beans.factory.xml.ParserContext;
+import org.springframework.integration.config.ConsumerEndpointFactoryBean;
import org.springframework.util.StringUtils;
import org.springframework.util.xml.DomUtils;
/**
* Base class for outbound Channel Adapter parsers.
+ *
+ * If this component is defined as the top-level element in the Spring application context it will produce
+ * an {@link org.springframework.integration.endpoint.AbstractEndpoint} depending on the channel type.
+ * If this component is defined as nested element (e.g., inside of the chain) it will produce
+ * a {@link org.springframework.integration.core.MessageHandler}.
*
* @author Mark Fisher
* @author Gary Russell
+ * @author Artem Bilan
*/
public abstract class AbstractOutboundChannelAdapterParser extends AbstractChannelAdapterParser {
@Override
protected AbstractBeanDefinition doParse(Element element, ParserContext parserContext, String channelName) {
+ if (parserContext.isNested()) {
+ return this.parseConsumer(element, parserContext);
+ }
+ BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(ConsumerEndpointFactoryBean.class);
Element pollerElement = DomUtils.getChildElementByTagName(element, "poller");
- BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(
- IntegrationNamespaceUtils.BASE_PACKAGE + ".config.ConsumerEndpointFactoryBean");
builder.addPropertyReference("handler", this.parseAndRegisterConsumer(element, parserContext));
if (pollerElement != null) {
if (!StringUtils.hasText(channelName)) {
@@ -60,15 +69,13 @@ public abstract class AbstractOutboundChannelAdapterParser extends AbstractChann
protected String parseAndRegisterConsumer(Element element, ParserContext parserContext) {
AbstractBeanDefinition definition = this.parseConsumer(element, parserContext);
if (definition == null) {
- parserContext.getReaderContext().error(
- "Consumer parsing must return a BeanComponentDefinition.", element);
+ parserContext.getReaderContext().error("Consumer parsing must return an AbstractBeanDefinition.", element);
}
- String order = element.getAttribute("order");
+ String order = element.getAttribute(IntegrationNamespaceUtils.ORDER);
if (StringUtils.hasText(order)) {
- definition.getPropertyValues().addPropertyValue("order", order);
+ definition.getPropertyValues().addPropertyValue(IntegrationNamespaceUtils.ORDER, order);
}
- String beanName = BeanDefinitionReaderUtils.generateBeanName(
- definition, parserContext.getRegistry());
+ String beanName = BeanDefinitionReaderUtils.generateBeanName(definition, parserContext.getRegistry());
parserContext.registerBeanComponent(new BeanComponentDefinition(definition, beanName));
return beanName;
}
diff --git a/spring-integration-core/src/main/java/org/springframework/integration/config/xml/DefaultOutboundChannelAdapterParser.java b/spring-integration-core/src/main/java/org/springframework/integration/config/xml/DefaultOutboundChannelAdapterParser.java
index 43fc0feed4..2c3031c391 100644
--- a/spring-integration-core/src/main/java/org/springframework/integration/config/xml/DefaultOutboundChannelAdapterParser.java
+++ b/spring-integration-core/src/main/java/org/springframework/integration/config/xml/DefaultOutboundChannelAdapterParser.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2011 the original author or authors.
+ * Copyright 2002-2012 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.
@@ -18,16 +18,14 @@ package org.springframework.integration.config.xml;
import org.w3c.dom.Element;
-import org.springframework.beans.factory.parsing.BeanComponentDefinition;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
-import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
import org.springframework.beans.factory.support.RootBeanDefinition;
+import org.springframework.beans.factory.parsing.BeanComponentDefinition;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.integration.config.ExpressionFactoryBean;
import org.springframework.integration.handler.ExpressionEvaluatingMessageHandler;
import org.springframework.integration.handler.MethodInvokingMessageHandler;
-import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
/**
@@ -39,7 +37,8 @@ import org.springframework.util.StringUtils;
*/
public class DefaultOutboundChannelAdapterParser extends AbstractOutboundChannelAdapterParser {
- protected String parseAndRegisterConsumer(Element element, ParserContext parserContext) {
+ @Override
+ protected AbstractBeanDefinition parseConsumer(Element element, ParserContext parserContext) {
BeanComponentDefinition innerConsumerDefinition = IntegrationNamespaceUtils.parseInnerHandlerDefinition(element, parserContext);
String consumerRef = element.getAttribute(IntegrationNamespaceUtils.REF_ATTRIBUTE);
@@ -61,42 +60,27 @@ public class DefaultOutboundChannelAdapterParser extends AbstractOutboundChannel
"The 'method' attribute cannot be used with the 'expression' attribute.", element);
}
- if (hasMethod | isExpression) {
- BeanDefinitionBuilder consumerBuilder = null;
- if (hasMethod) {
- consumerBuilder = BeanDefinitionBuilder.genericBeanDefinition(MethodInvokingMessageHandler.class);
- if (isRef) {
- consumerBuilder.addConstructorArgReference(consumerRef);
- }
- else {
- consumerBuilder.addConstructorArgValue(innerConsumerDefinition);
- }
- consumerBuilder.addConstructorArgValue(methodName);
+ BeanDefinitionBuilder consumerBuilder = null;
+
+ if (isExpression) {
+ consumerBuilder = BeanDefinitionBuilder.genericBeanDefinition(ExpressionEvaluatingMessageHandler.class);
+ RootBeanDefinition expressionDef = new RootBeanDefinition(ExpressionFactoryBean.class);
+ expressionDef.getConstructorArgumentValues().addGenericArgumentValue(consumerExpressionString);
+ consumerBuilder.addConstructorArgValue(expressionDef);
+ }
+ else {
+ consumerBuilder = BeanDefinitionBuilder.genericBeanDefinition(MethodInvokingMessageHandler.class);
+ if (isRef) {
+ consumerBuilder.addConstructorArgReference(consumerRef);
}
else {
- consumerBuilder = BeanDefinitionBuilder.genericBeanDefinition(ExpressionEvaluatingMessageHandler.class);
- RootBeanDefinition expressionDef = new RootBeanDefinition(ExpressionFactoryBean.class);
- expressionDef.getConstructorArgumentValues().addGenericArgumentValue(consumerExpressionString);
- consumerBuilder.addConstructorArgValue(expressionDef);
+ consumerBuilder.addConstructorArgValue(innerConsumerDefinition);
}
-
- consumerBuilder.addPropertyValue("componentType", "outbound-channel-adapter");
- String order = element.getAttribute(IntegrationNamespaceUtils.ORDER);
- if (StringUtils.hasText(order)) {
- consumerBuilder.addPropertyValue(IntegrationNamespaceUtils.ORDER, order);
- }
- consumerRef = BeanDefinitionReaderUtils.registerWithGeneratedName(consumerBuilder.getBeanDefinition(), parserContext.getRegistry());
+ consumerBuilder.addConstructorArgValue(hasMethod ? methodName : "handleMessage");
}
- else if (isInnerConsumer) {
- consumerRef = innerConsumerDefinition.getBeanName();
- }
- Assert.hasText(consumerRef, "cannot determine consumer for 'outbound-channel-adapter'");
- return consumerRef;
- }
- @Override
- protected AbstractBeanDefinition parseConsumer(Element element, ParserContext parserContext) {
- throw new UnsupportedOperationException();
+ consumerBuilder.addPropertyValue("componentType", "outbound-channel-adapter");
+ return consumerBuilder.getBeanDefinition();
}
}
diff --git a/spring-integration-core/src/main/java/org/springframework/integration/handler/MessageHandlerChain.java b/spring-integration-core/src/main/java/org/springframework/integration/handler/MessageHandlerChain.java
index 8b16287230..7f2ee38f91 100644
--- a/spring-integration-core/src/main/java/org/springframework/integration/handler/MessageHandlerChain.java
+++ b/spring-integration-core/src/main/java/org/springframework/integration/handler/MessageHandlerChain.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2011 the original author or authors.
+ * Copyright 2002-2012 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,11 +16,9 @@
package org.springframework.integration.handler;
-import java.util.HashSet;
-import java.util.List;
-
import org.springframework.aop.framework.Advised;
import org.springframework.aop.support.AopUtils;
+import org.springframework.beans.DirectFieldAccessor;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.core.Ordered;
import org.springframework.integration.Message;
@@ -34,6 +32,9 @@ import org.springframework.integration.support.channel.BeanFactoryChannelResolve
import org.springframework.integration.support.channel.ChannelResolver;
import org.springframework.util.Assert;
+import java.util.HashSet;
+import java.util.List;
+
/**
* A composite {@link MessageHandler} implementation that invokes a chain of
* MessageHandler instances in order.
@@ -65,8 +66,9 @@ import org.springframework.util.Assert;
* @author Mark Fisher
* @author Iwein Fuld
* @author Gary Russell
+ * @author Artem Bilan
*/
-public class MessageHandlerChain extends AbstractMessageHandler implements MessageProducer, Ordered {
+public class MessageHandlerChain extends AbstractMessageHandler implements MessageProducer {
private volatile List handlers;
@@ -79,8 +81,6 @@ public class MessageHandlerChain extends AbstractMessageHandler implements Messa
*/
private volatile Long sendTimeout = null;
- private volatile int order = Ordered.LOWEST_PRECEDENCE;
-
private volatile ChannelResolver channelResolver;
private volatile boolean initialized;
@@ -100,15 +100,6 @@ public class MessageHandlerChain extends AbstractMessageHandler implements Messa
this.sendTimeout = sendTimeout;
}
- public void setOrder(int order) {
- this.order = order;
- }
-
- public int getOrder() {
- return this.order;
- }
-
-
@Override
public String getComponentType() {
return "chain";
@@ -156,6 +147,13 @@ public class MessageHandlerChain extends AbstractMessageHandler implements Messa
}
};
((MessageProducer) handler).setOutputChannel(nextChannel);
+
+ // If this 'handler' is a nested non-last <chain>, it is necessary
+ // to 'force' re-init it for check its configuration in conjunction with current MessageHandlerChain.
+ if (handler instanceof MessageHandlerChain) {
+ new DirectFieldAccessor(handler).setPropertyValue("initialized", false);
+ ((MessageHandlerChain) handler).afterPropertiesSet();
+ }
}
else if (handler instanceof MessageProducer) {
MessageChannel replyChannel = new ReplyForwardingMessageChannel();
diff --git a/spring-integration-core/src/main/resources/org/springframework/integration/config/xml/spring-integration-2.2.xsd b/spring-integration-core/src/main/resources/org/springframework/integration/config/xml/spring-integration-2.2.xsd
index 7c9a16caa3..39574a0fcd 100644
--- a/spring-integration-core/src/main/resources/org/springframework/integration/config/xml/spring-integration-2.2.xsd
+++ b/spring-integration-core/src/main/resources/org/springframework/integration/config/xml/spring-integration-2.2.xsd
@@ -789,7 +789,7 @@
-
+
Defines a Channel Adapter that receives from a MessageChannel and passes to
@@ -797,89 +797,75 @@
MessageHandler.
-
-
-
-
-
-
- Specifies the order for invocation when this endpoint is connected as a
-subscriber to a channel. This is particularly relevant when that channel
-is using a "failover" dispatching strategy. It has no effect when this
-endpoint itself is a Polling Consumer for a channel with a queue.
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Provide a name for the logger. This is useful when there are multiple logging Channel Adapters configured,
- and you would like to differentiate them within the actual log. By default the logger name will be the
- fully qualified class name of the LoggingHandler implementation.
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Provide a name for the logger. This is useful when there are multiple logging Channel Adapters configured,
+ and you would like to differentiate them within the actual log. By default the logger name will be the
+ fully qualified class name of the LoggingHandler implementation.
+
+
+
+
+
+
-
-
-
-
-
+
+
+
+
-
-
-
-
-
- Specifies the order for invocation when this endpoint is connected as a
- subscriber to a channel. This is particularly relevant when that channel
- is using a "failover" dispatching strategy. It has no effect when this
- endpoint itself is a Polling Consumer for a channel with a queue.
-
-
-
-
-
-
-
+
+
+
@@ -945,18 +931,42 @@ endpoint itself is a Polling Consumer for a channel with a queue.
-
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+ Specifies the order for invocation when this endpoint is connected as a
+ subscriber to a channel. This is particularly relevant when that channel
+ is using a "failover" dispatching strategy. It has no effect when this
+ endpoint itself is a Polling Consumer for a channel with a queue.
+
+
+
+
+
+
+
+
+
@@ -1369,38 +1379,44 @@ endpoint itself is a Polling Consumer for a channel with a queue.
-
-
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/spring-integration-core/src/test/java/org/springframework/integration/config/ChainParserTests-context.xml b/spring-integration-core/src/test/java/org/springframework/integration/config/ChainParserTests-context.xml
index 5ab6d03d37..09fc426c63 100644
--- a/spring-integration-core/src/test/java/org/springframework/integration/config/ChainParserTests-context.xml
+++ b/spring-integration-core/src/test/java/org/springframework/integration/config/ChainParserTests-context.xml
@@ -96,6 +96,17 @@
+
+
+
+
+
+
+
+
+
+
+
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 1c684d9b79..5c7860cea5 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-2010 the original author or authors.
+ * Copyright 2002-2012 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,22 +16,17 @@
package org.springframework.integration.config;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertThat;
-
-import java.util.List;
-
import org.hamcrest.Factory;
import org.hamcrest.Matcher;
import org.junit.Test;
import org.junit.runner.RunWith;
-
+import org.springframework.beans.BeansException;
import org.springframework.beans.DirectFieldAccessor;
+import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.ApplicationContext;
+import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.integration.Message;
import org.springframework.integration.MessageChannel;
import org.springframework.integration.core.PollableChannel;
@@ -43,6 +38,15 @@ import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.util.StringUtils;
+import java.io.ByteArrayOutputStream;
+import java.io.OutputStream;
+import java.io.PrintStream;
+import java.util.List;
+
+import static org.junit.Assert.*;
+import static org.junit.matchers.JUnitMatchers.both;
+import static org.junit.matchers.JUnitMatchers.containsString;
+
/**
* @author Mark Fisher
* @author Iwein Fuld
@@ -94,9 +98,19 @@ public class ChainParserTests {
@Autowired
private MessageChannel headerValueRouterWithMappingInput;
+ @Autowired
+ private MessageChannel loggingChannelAdapterChannel;
+
+ @Autowired
+ private MessageChannel outboundChannelAdapterChannel;
+
+ @Autowired
+ private TestConsumer testConsumer;
+
@Autowired
@Qualifier("claimCheckInput")
private MessageChannel claimCheckInput;
+
@Autowired
@Qualifier("claimCheckOutput")
private PollableChannel claimCheckOutput;
@@ -241,6 +255,40 @@ public class ChainParserTests {
assertEquals(message.getPayload(), reply.getPayload());
}
+ @Test //INT-2275
+ public void chainWithOutboundChannelAdapter() {
+ this.outboundChannelAdapterChannel.send(successMessage);
+ assertSame(successMessage, testConsumer.getLastMessage());
+ }
+
+ @Test //INT-2275
+ public void chainWithLoggingChannelAdapter() {
+ Message> message = MessageBuilder.withPayload("test").build();
+ PrintStream realOut = System.out;
+ try {
+ OutputStream out = new ByteArrayOutputStream();
+ System.setOut(new PrintStream(out));
+ this.loggingChannelAdapterChannel.send(message);
+ assertEquals("LoggingHandler: TEST", out.toString().trim());
+ }
+ finally {
+ System.setOut(realOut);
+ }
+ }
+
+ @Test(expected = BeanCreationException.class) //INT-2275
+ public void invalidNestedChainWithLoggingChannelAdapter() {
+ try {
+ new ClassPathXmlApplicationContext("invalidNestedChainWithOutboundChannelAdapter-context.xml", this.getClass());
+ fail("BeanCreationException is expected!");
+ }
+ catch (BeansException e) {
+ assertEquals(IllegalArgumentException.class, e.getCause().getClass());
+ assertThat(e.getMessage(), both(containsString("output channel was provided")).and(containsString("does not implement the MessageProducer")));
+ throw e;
+ }
+ }
+
public static class StubHandler extends AbstractReplyProducingMessageHandler {
@Override
protected Object handleRequestMessage(Message> requestMessage) {
diff --git a/spring-integration-core/src/test/java/org/springframework/integration/config/invalidNestedChainWithOutboundChannelAdapter-context.xml b/spring-integration-core/src/test/java/org/springframework/integration/config/invalidNestedChainWithOutboundChannelAdapter-context.xml
new file mode 100644
index 0000000000..8777987fa3
--- /dev/null
+++ b/spring-integration-core/src/test/java/org/springframework/integration/config/invalidNestedChainWithOutboundChannelAdapter-context.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/spring-integration-core/src/test/java/org/springframework/integration/config/xml/MethodInvokingOutboundChannelAdapterParserTests-context.xml b/spring-integration-core/src/test/java/org/springframework/integration/config/xml/DefaultOutboundChannelAdapterParserTests-context.xml
similarity index 76%
rename from spring-integration-core/src/test/java/org/springframework/integration/config/xml/MethodInvokingOutboundChannelAdapterParserTests-context.xml
rename to spring-integration-core/src/test/java/org/springframework/integration/config/xml/DefaultOutboundChannelAdapterParserTests-context.xml
index 4edcba37be..fa3a430b79 100644
--- a/spring-integration-core/src/test/java/org/springframework/integration/config/xml/MethodInvokingOutboundChannelAdapterParserTests-context.xml
+++ b/spring-integration-core/src/test/java/org/springframework/integration/config/xml/DefaultOutboundChannelAdapterParserTests-context.xml
@@ -13,16 +13,22 @@
+
+
+ class="org.springframework.integration.config.xml.DefaultOutboundChannelAdapterParserTests$TestBean"/>
-
+
+
+
+
+
diff --git a/spring-integration-core/src/test/java/org/springframework/integration/config/xml/MethodInvokingOutboundChannelAdapterParserTests.java b/spring-integration-core/src/test/java/org/springframework/integration/config/xml/DefaultOutboundChannelAdapterParserTests.java
similarity index 71%
rename from spring-integration-core/src/test/java/org/springframework/integration/config/xml/MethodInvokingOutboundChannelAdapterParserTests.java
rename to spring-integration-core/src/test/java/org/springframework/integration/config/xml/DefaultOutboundChannelAdapterParserTests.java
index fdf8b8f7d4..52d82e0b8e 100644
--- a/spring-integration-core/src/test/java/org/springframework/integration/config/xml/MethodInvokingOutboundChannelAdapterParserTests.java
+++ b/spring-integration-core/src/test/java/org/springframework/integration/config/xml/DefaultOutboundChannelAdapterParserTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2009 the original author or authors.
+ * Copyright 2002-2012 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.
@@ -25,6 +25,7 @@ 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.config.TestConsumer;
import org.springframework.integration.handler.MethodInvokingMessageHandler;
import org.springframework.integration.test.util.TestUtils;
import org.springframework.test.context.ContextConfiguration;
@@ -32,10 +33,11 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/**
* @author Mark Fisher
+ * @author Artem Bilan
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
-public class MethodInvokingOutboundChannelAdapterParserTests {
+public class DefaultOutboundChannelAdapterParserTests {
@Autowired
private ApplicationContext context;
@@ -44,21 +46,29 @@ public class MethodInvokingOutboundChannelAdapterParserTests {
@Test
public void checkConfig() {
Object adapter = context.getBean("adapter");
+ assertEquals(Boolean.FALSE, TestUtils.getPropertyValue(adapter, "autoStartup"));
Object handler = TestUtils.getPropertyValue(adapter, "handler");
assertEquals(MethodInvokingMessageHandler.class, handler.getClass());
- DirectFieldAccessor handlerAccessor = new DirectFieldAccessor(handler);
- assertEquals(99, handlerAccessor.getPropertyValue("order"));
- assertEquals(Boolean.FALSE, TestUtils.getPropertyValue(adapter, "autoStartup"));
+ assertEquals(99, TestUtils.getPropertyValue(handler, "order"));
}
@Test
public void checkConfigWithInnerBeanAndPoller() {
Object adapter = context.getBean("adapterB");
+ assertEquals(Boolean.FALSE, TestUtils.getPropertyValue(adapter, "autoStartup"));
Object handler = TestUtils.getPropertyValue(adapter, "handler");
assertEquals(MethodInvokingMessageHandler.class, handler.getClass());
- DirectFieldAccessor handlerAccessor = new DirectFieldAccessor(handler);
- assertEquals(99, handlerAccessor.getPropertyValue("order"));
- assertEquals(Boolean.FALSE, TestUtils.getPropertyValue(adapter, "autoStartup"));
+ assertEquals(99, TestUtils.getPropertyValue(handler, "order"));
+ }
+
+ @Test
+ public void checkConfigWithInnerMessageHandler() {
+ Object adapter = context.getBean("adapterC");
+ Object handler = TestUtils.getPropertyValue(adapter, "handler");
+ assertEquals(MethodInvokingMessageHandler.class, handler.getClass());
+ assertEquals(99, TestUtils.getPropertyValue(handler, "order"));
+ Object targetObject = TestUtils.getPropertyValue(handler, "processor.delegate.targetObject");
+ assertEquals(TestConsumer.class, targetObject.getClass());
}
@@ -68,4 +78,5 @@ public class MethodInvokingOutboundChannelAdapterParserTests {
}
}
+
}
diff --git a/spring-integration-event/src/test/java/org/springframework/integration/event/config/EventOutboundChannelAdapterParserTests-context.xml b/spring-integration-event/src/test/java/org/springframework/integration/event/config/EventOutboundChannelAdapterParserTests-context.xml
index b6aaa66efb..88903e44cd 100644
--- a/spring-integration-event/src/test/java/org/springframework/integration/event/config/EventOutboundChannelAdapterParserTests-context.xml
+++ b/spring-integration-event/src/test/java/org/springframework/integration/event/config/EventOutboundChannelAdapterParserTests-context.xml
@@ -8,7 +8,12 @@
http://www.springframework.org/schema/integration/event http://www.springframework.org/schema/integration/event/spring-integration-event.xsd">
-
+
+
+
+
+
+
diff --git a/spring-integration-event/src/test/java/org/springframework/integration/event/config/EventOutboundChannelAdapterParserTests.java b/spring-integration-event/src/test/java/org/springframework/integration/event/config/EventOutboundChannelAdapterParserTests.java
index caa379e49f..5e64e9dfc6 100644
--- a/spring-integration-event/src/test/java/org/springframework/integration/event/config/EventOutboundChannelAdapterParserTests.java
+++ b/spring-integration-event/src/test/java/org/springframework/integration/event/config/EventOutboundChannelAdapterParserTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2010 the original author or authors.
+ * Copyright 2002-2012 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,14 +16,9 @@
package org.springframework.integration.event.config;
-import java.util.concurrent.BrokenBarrierException;
-import java.util.concurrent.CyclicBarrier;
-
import junit.framework.Assert;
-
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.ApplicationEvent;
@@ -40,8 +35,12 @@ import org.springframework.integration.message.GenericMessage;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+import java.util.concurrent.BrokenBarrierException;
+import java.util.concurrent.CyclicBarrier;
+
/**
* @author Oleg Zhurakousky
+ * @author Artem Bilan
* @since 2.0
*/
@RunWith(SpringJUnit4ClassRunner.class)
@@ -83,6 +82,25 @@ public class EventOutboundChannelAdapterParserTests {
Assert.assertTrue(receivedEvent);
}
+ @Test //INT-2275
+ public void testInsideChain() {
+ ApplicationListener> listener = new ApplicationListener() {
+ public void onApplicationEvent(ApplicationEvent event) {
+ Object source = event.getSource();
+ if (source instanceof Message){
+ String payload = (String) ((Message>) source).getPayload();
+ if (payload.equals("foobar")) {
+ receivedEvent = true;
+ }
+ }
+ }
+ };
+ context.addApplicationListener(listener);
+ DirectChannel channel = context.getBean("inputChain", DirectChannel.class);
+ channel.send(new GenericMessage("foo"));
+ Assert.assertTrue(receivedEvent);
+ }
+
@Test(timeout=2000)
public void validateUsageWithPollableChannel() throws Exception {
ConfigurableApplicationContext context = new ClassPathXmlApplicationContext("EventOutboundChannelAdapterParserTestsWithPollable-context.xml", EventOutboundChannelAdapterParserTests.class);
diff --git a/spring-integration-file/src/main/java/org/springframework/integration/file/FileWritingMessageHandler.java b/spring-integration-file/src/main/java/org/springframework/integration/file/FileWritingMessageHandler.java
index e413ba9fb9..2fcb37f956 100644
--- a/spring-integration-file/src/main/java/org/springframework/integration/file/FileWritingMessageHandler.java
+++ b/spring-integration-file/src/main/java/org/springframework/integration/file/FileWritingMessageHandler.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2010 the original author or authors.
+ * Copyright 2002-2012 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.
@@ -54,6 +54,7 @@ import java.nio.charset.Charset;
* @author Iwein Fuld
* @author Alex Peters
* @author Oleg Zhurakousky
+ * @author Artem Bilan
*/
public class FileWritingMessageHandler extends AbstractReplyProducingMessageHandler {
@@ -71,6 +72,7 @@ public class FileWritingMessageHandler extends AbstractReplyProducingMessageHand
private volatile Charset charset = Charset.defaultCharset();
+ private volatile boolean expectReply = true;
public FileWritingMessageHandler(File destinationDirectory) {
Assert.notNull(destinationDirectory, "Destination directory must not be null.");
@@ -92,7 +94,15 @@ public class FileWritingMessageHandler extends AbstractReplyProducingMessageHand
public void setTemporaryFileSuffix(String temporaryFileSuffix) {
this.temporaryFileSuffix = temporaryFileSuffix;
}
-
+
+ /**
+ * Specify whether a reply Message is expected. If not, this handler will simply return null for a
+ * successful response or throw an Exception for a non-successful response. The default is true.
+ */
+ public void setExpectReply(boolean expectReply) {
+ this.expectReply = expectReply;
+ }
+
protected String getTemporaryFileSuffix() {
return temporaryFileSuffix;
}
@@ -169,6 +179,11 @@ public class FileWritingMessageHandler extends AbstractReplyProducingMessageHand
catch (Exception e) {
throw new MessageHandlingException(requestMessage, "failed to write Message payload to file", e);
}
+
+ if (!this.expectReply) {
+ return null;
+ }
+
if (resultFile != null) {
if (originalFileFromHeader == null && payload instanceof File) {
return MessageBuilder.withPayload(resultFile)
diff --git a/spring-integration-file/src/main/java/org/springframework/integration/file/config/FileOutboundChannelAdapterParser.java b/spring-integration-file/src/main/java/org/springframework/integration/file/config/FileOutboundChannelAdapterParser.java
index db6fac3281..591b7de360 100644
--- a/spring-integration-file/src/main/java/org/springframework/integration/file/config/FileOutboundChannelAdapterParser.java
+++ b/spring-integration-file/src/main/java/org/springframework/integration/file/config/FileOutboundChannelAdapterParser.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2010 the original author or authors.
+ * Copyright 2002-2012 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,8 +22,6 @@ import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.integration.config.xml.AbstractOutboundChannelAdapterParser;
-import org.springframework.integration.context.IntegrationContextUtils;
-import org.springframework.util.StringUtils;
/**
* Parser for the <outbound-channel-adapter/> element of the 'file'
@@ -32,36 +30,14 @@ import org.springframework.util.StringUtils;
* @author Mark Fisher
* @author Iwein Fuld
* @author Oleg Zhurakousky
+ * @author Artem Bilan
*/
public class FileOutboundChannelAdapterParser extends AbstractOutboundChannelAdapterParser {
@Override
protected AbstractBeanDefinition parseConsumer(Element element, ParserContext parserContext) {
- BeanDefinitionBuilder handlerBuilder = FileWritingMessageHandlerBeanDefinitionBuilder.configure(
- element, IntegrationContextUtils.NULL_CHANNEL_BEAN_NAME, parserContext);
- if (handlerBuilder != null){
- String remoteFileNameGenerator = element.getAttribute("filename-generator");
- String remoteFileNameGeneratorExpression = element.getAttribute("filename-generator-expression");
- boolean hasRemoteFileNameGenerator = StringUtils.hasText(remoteFileNameGenerator);
- boolean hasRemoteFileNameGeneratorExpression = StringUtils.hasText(remoteFileNameGeneratorExpression);
- if (hasRemoteFileNameGenerator || hasRemoteFileNameGeneratorExpression) {
- if (hasRemoteFileNameGenerator && hasRemoteFileNameGeneratorExpression) {
- parserContext.getReaderContext().error("at most one of 'filename-generator-expression' or 'filename-generator' " +
- "is allowed on file outbound adapter/gateway", element);
- }
- if (hasRemoteFileNameGenerator) {
- handlerBuilder.addPropertyReference("fileNameGenerator", remoteFileNameGenerator);
- }
- else {
- BeanDefinitionBuilder fileNameGeneratorBuilder = BeanDefinitionBuilder.genericBeanDefinition(
- "org.springframework.integration.file.DefaultFileNameGenerator");
- fileNameGeneratorBuilder.addPropertyValue("expression", remoteFileNameGeneratorExpression);
- handlerBuilder.addPropertyValue("fileNameGenerator", fileNameGeneratorBuilder.getBeanDefinition());
- }
- }
- }
-
- return (handlerBuilder != null ? handlerBuilder.getBeanDefinition() : null);
+ BeanDefinitionBuilder handlerBuilder = FileWritingMessageHandlerBeanDefinitionBuilder.configure(element, false, parserContext);
+ return handlerBuilder.getBeanDefinition();
}
}
diff --git a/spring-integration-file/src/main/java/org/springframework/integration/file/config/FileOutboundGatewayParser.java b/spring-integration-file/src/main/java/org/springframework/integration/file/config/FileOutboundGatewayParser.java
index 4166304bdc..c89e28420a 100644
--- a/spring-integration-file/src/main/java/org/springframework/integration/file/config/FileOutboundGatewayParser.java
+++ b/spring-integration-file/src/main/java/org/springframework/integration/file/config/FileOutboundGatewayParser.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2010 the original author or authors.
+ * Copyright 2002-2012 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,18 +16,19 @@
package org.springframework.integration.file.config;
+import org.springframework.integration.config.xml.IntegrationNamespaceUtils;
import org.w3c.dom.Element;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.integration.config.xml.AbstractConsumerEndpointParser;
-import org.springframework.util.StringUtils;
/**
* Parser for the 'outbound-gateway' element of the file namespace.
*
* @author Mark Fisher
* @author Oleg Zhurakousky
+ * @author Artem Bilan
* @since 1.0.3
*/
public class FileOutboundGatewayParser extends AbstractConsumerEndpointParser {
@@ -39,31 +40,8 @@ public class FileOutboundGatewayParser extends AbstractConsumerEndpointParser {
@Override
protected BeanDefinitionBuilder parseHandler(Element element, ParserContext parserContext) {
- String replyChannel = element.getAttribute("reply-channel");
-
- BeanDefinitionBuilder handlerBuilder =
- FileWritingMessageHandlerBeanDefinitionBuilder.configure(element, replyChannel, parserContext);
-
- String remoteFileNameGenerator = element.getAttribute("filename-generator");
- String remoteFileNameGeneratorExpression = element.getAttribute("filename-generator-expression");
- boolean hasRemoteFileNameGenerator = StringUtils.hasText(remoteFileNameGenerator);
- boolean hasRemoteFileNameGeneratorExpression = StringUtils.hasText(remoteFileNameGeneratorExpression);
- if (hasRemoteFileNameGenerator || hasRemoteFileNameGeneratorExpression) {
- if (hasRemoteFileNameGenerator && hasRemoteFileNameGeneratorExpression) {
- parserContext.getReaderContext().error("at most one of 'filename-generator-expression' or 'filename-generator' " +
- "is allowed on file outbound adapter/gateway", element) ;
- }
- if (hasRemoteFileNameGenerator) {
- handlerBuilder.addPropertyReference("fileNameGenerator", remoteFileNameGenerator);
- }
- else {
- BeanDefinitionBuilder fileNameGeneratorBuilder = BeanDefinitionBuilder.genericBeanDefinition(
- "org.springframework.integration.file.DefaultFileNameGenerator");
- fileNameGeneratorBuilder.addPropertyValue("expression", remoteFileNameGeneratorExpression);
- handlerBuilder.addPropertyValue("fileNameGenerator", fileNameGeneratorBuilder.getBeanDefinition());
- }
- }
-
+ BeanDefinitionBuilder handlerBuilder = FileWritingMessageHandlerBeanDefinitionBuilder.configure(element, true, parserContext);
+ IntegrationNamespaceUtils.setReferenceIfAttributeDefined(handlerBuilder, element, "reply-channel", "outputChannel");
return handlerBuilder;
}
diff --git a/spring-integration-file/src/main/java/org/springframework/integration/file/config/FileWritingMessageHandlerBeanDefinitionBuilder.java b/spring-integration-file/src/main/java/org/springframework/integration/file/config/FileWritingMessageHandlerBeanDefinitionBuilder.java
index 716ea5043e..0efd972686 100644
--- a/spring-integration-file/src/main/java/org/springframework/integration/file/config/FileWritingMessageHandlerBeanDefinitionBuilder.java
+++ b/spring-integration-file/src/main/java/org/springframework/integration/file/config/FileWritingMessageHandlerBeanDefinitionBuilder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2010 the original author or authors.
+ * Copyright 2002-2012 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,7 @@
package org.springframework.integration.file.config;
+import org.springframework.integration.file.DefaultFileNameGenerator;
import org.w3c.dom.Element;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
@@ -29,32 +30,42 @@ import org.springframework.util.StringUtils;
* {@link org.springframework.integration.file.FileWritingMessageHandler}.
*
* @author Mark Fisher
+ * @author Artem Bilan
* @since 1.0.3
*/
abstract class FileWritingMessageHandlerBeanDefinitionBuilder {
- static BeanDefinitionBuilder configure(Element element, String outputChannelBeanName, ParserContext parserContext) {
- if (outputChannelBeanName == null) {
- parserContext.getReaderContext().error("outputChannelBeanName must not be null", element);
- return null;
- }
+ static BeanDefinitionBuilder configure(Element element, boolean expectReply, ParserContext parserContext) {
+
String directory = element.getAttribute("directory");
if (!StringUtils.hasText(directory)) {
parserContext.getReaderContext().error("directory is required", element);
}
- BeanDefinitionBuilder builder = BeanDefinitionBuilder
- .genericBeanDefinition("org.springframework.integration.file.config.FileWritingMessageHandlerFactoryBean");
+ BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(FileWritingMessageHandlerFactoryBean.class);
builder.addPropertyValue("directory", directory);
- if (StringUtils.hasText(outputChannelBeanName)) {
- builder.addPropertyReference("outputChannel", outputChannelBeanName);
- }
+ builder.addPropertyValue("expectReply", expectReply);
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "auto-create-directory");
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "delete-source-files");
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "temporary-file-suffix");
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "charset");
- String fileNameGenerator = element.getAttribute("filename-generator");
- if (StringUtils.hasText(fileNameGenerator)) {
- builder.addPropertyReference("fileNameGenerator", fileNameGenerator);
+ String remoteFileNameGenerator = element.getAttribute("filename-generator");
+ String remoteFileNameGeneratorExpression = element.getAttribute("filename-generator-expression");
+ boolean hasRemoteFileNameGenerator = StringUtils.hasText(remoteFileNameGenerator);
+ boolean hasRemoteFileNameGeneratorExpression = StringUtils.hasText(remoteFileNameGeneratorExpression);
+ if (hasRemoteFileNameGenerator || hasRemoteFileNameGeneratorExpression) {
+ if (hasRemoteFileNameGenerator && hasRemoteFileNameGeneratorExpression) {
+ parserContext.getReaderContext().error("at most one of 'filename-generator-expression' or 'filename-generator' " +
+ "is allowed on file outbound adapter/gateway", element);
+ }
+ if (hasRemoteFileNameGenerator) {
+ builder.addPropertyReference("fileNameGenerator", remoteFileNameGenerator);
+ }
+ else {
+ BeanDefinitionBuilder fileNameGeneratorBuilder = BeanDefinitionBuilder
+ .genericBeanDefinition(DefaultFileNameGenerator.class);
+ fileNameGeneratorBuilder.addPropertyValue("expression", remoteFileNameGeneratorExpression);
+ builder.addPropertyValue("fileNameGenerator", fileNameGeneratorBuilder.getBeanDefinition());
+ }
}
return builder;
}
diff --git a/spring-integration-file/src/main/java/org/springframework/integration/file/config/FileWritingMessageHandlerFactoryBean.java b/spring-integration-file/src/main/java/org/springframework/integration/file/config/FileWritingMessageHandlerFactoryBean.java
index 03ac945f39..d4823c62dd 100644
--- a/spring-integration-file/src/main/java/org/springframework/integration/file/config/FileWritingMessageHandlerFactoryBean.java
+++ b/spring-integration-file/src/main/java/org/springframework/integration/file/config/FileWritingMessageHandlerFactoryBean.java
@@ -29,6 +29,7 @@ import org.springframework.integration.file.FileWritingMessageHandler;
* @author Iwein Fuld
* @author Oleg Zhurakousky
* @author Gary Russell
+ * @author Artem Bilan
* @since 1.0.3
*/
public class FileWritingMessageHandlerFactoryBean extends AbstractSimpleMessageHandlerFactoryBean{
@@ -48,7 +49,9 @@ public class FileWritingMessageHandlerFactoryBean extends AbstractSimpleMessageH
private volatile Long sendTimeout;
private volatile String temporaryFileSuffix;
-
+
+ private volatile boolean expectReply = true;
+
public void setDirectory(File directory) {
this.directory = directory;
}
@@ -80,7 +83,11 @@ public class FileWritingMessageHandlerFactoryBean extends AbstractSimpleMessageH
public void setTemporaryFileSuffix(String temporaryFileSuffix) {
this.temporaryFileSuffix = temporaryFileSuffix;
}
-
+
+ public void setExpectReply(boolean expectReply) {
+ this.expectReply = expectReply;
+ }
+
@Override
protected FileWritingMessageHandler createHandler() {
FileWritingMessageHandler handler = new FileWritingMessageHandler(this.directory);
@@ -105,6 +112,7 @@ public class FileWritingMessageHandlerFactoryBean extends AbstractSimpleMessageH
if (this.temporaryFileSuffix != null) {
handler.setTemporaryFileSuffix(this.temporaryFileSuffix);
}
+ handler.setExpectReply(this.expectReply);
return handler;
}
}
diff --git a/spring-integration-file/src/test/java/org/springframework/integration/file/FileOutboundChannelAdapterInsideChainTests-context.xml b/spring-integration-file/src/test/java/org/springframework/integration/file/FileOutboundChannelAdapterInsideChainTests-context.xml
new file mode 100644
index 0000000000..79aca33f36
--- /dev/null
+++ b/spring-integration-file/src/test/java/org/springframework/integration/file/FileOutboundChannelAdapterInsideChainTests-context.xml
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/spring-integration-file/src/test/java/org/springframework/integration/file/FileOutboundChannelAdapterInsideChainTests.java b/spring-integration-file/src/test/java/org/springframework/integration/file/FileOutboundChannelAdapterInsideChainTests.java
new file mode 100644
index 0000000000..0696d6faba
--- /dev/null
+++ b/spring-integration-file/src/test/java/org/springframework/integration/file/FileOutboundChannelAdapterInsideChainTests.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2002-2012 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.file;
+
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.integration.Message;
+import org.springframework.integration.MessageChannel;
+import org.springframework.integration.support.MessageBuilder;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+import org.springframework.util.FileCopyUtils;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Properties;
+
+import static org.junit.Assert.*;
+
+/**
+ * //INT-2275
+ *
+ * @author Artem Bilan
+ */
+@ContextConfiguration
+@RunWith(SpringJUnit4ClassRunner.class)
+public class FileOutboundChannelAdapterInsideChainTests {
+
+ public static final String TEST_FILE_NAME = FileOutboundChannelAdapterInsideChainTests.class.getSimpleName();
+
+ public static final String WORK_DIR_NAME = System.getProperty("java.io.tmpdir") + "/" + FileOutboundChannelAdapterInsideChainTests.class.getSimpleName() + "Dir";
+
+ public static final String SAMPLE_CONTENT = "test";
+
+ public static Properties placeholderProperties = new Properties();
+
+ static {
+ placeholderProperties.put("test.file", TEST_FILE_NAME);
+ placeholderProperties.put("work.dir", WORK_DIR_NAME);
+ }
+
+ @Autowired
+ private MessageChannel outboundChainChannel;
+
+ private static File workDir;
+
+ @BeforeClass
+ public static void setupClass() {
+ workDir = new File(WORK_DIR_NAME);
+ workDir.mkdir();
+ workDir.deleteOnExit();
+ }
+
+ @AfterClass
+ public static void cleanUp() {
+ if (workDir != null && workDir.exists()) {
+ for (File file : workDir.listFiles()) {
+ file.delete();
+ }
+ }
+ workDir.delete();
+ }
+
+ @Test //INT-2275
+ public void testFileOutboundChannelAdapterWithinChain() throws IOException {
+ Message message = MessageBuilder.withPayload(SAMPLE_CONTENT).build();
+ outboundChainChannel.send(message);
+ File testFile = new File(workDir, TEST_FILE_NAME);
+ assertTrue(testFile.exists());
+ byte[] testFileContent = FileCopyUtils.copyToByteArray(testFile);
+ assertEquals(new String(testFileContent), SAMPLE_CONTENT);
+ }
+
+}
diff --git a/spring-integration-ftp/src/test/java/org/springframework/integration/ftp/outbound/FtpOutboundChannelAdapterInsideChainTests-context.xml b/spring-integration-ftp/src/test/java/org/springframework/integration/ftp/outbound/FtpOutboundChannelAdapterInsideChainTests-context.xml
new file mode 100644
index 0000000000..95e2cc9aa5
--- /dev/null
+++ b/spring-integration-ftp/src/test/java/org/springframework/integration/ftp/outbound/FtpOutboundChannelAdapterInsideChainTests-context.xml
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/spring-integration-ftp/src/test/java/org/springframework/integration/ftp/outbound/FtpSendingMessageHandlerTests.java b/spring-integration-ftp/src/test/java/org/springframework/integration/ftp/outbound/FtpSendingMessageHandlerTests.java
index cd7ef2f395..4845782a53 100644
--- a/spring-integration-ftp/src/test/java/org/springframework/integration/ftp/outbound/FtpSendingMessageHandlerTests.java
+++ b/spring-integration-ftp/src/test/java/org/springframework/integration/ftp/outbound/FtpSendingMessageHandlerTests.java
@@ -32,8 +32,11 @@ import org.junit.Test;
import org.mockito.Mockito;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.expression.common.LiteralExpression;
import org.springframework.integration.Message;
+import org.springframework.integration.MessageChannel;
import org.springframework.integration.file.FileNameGenerator;
import org.springframework.integration.file.remote.handler.FileTransferringMessageHandler;
import org.springframework.integration.ftp.session.AbstractFtpSessionFactory;
@@ -42,6 +45,7 @@ import org.springframework.util.FileCopyUtils;
/**
* @author Oleg Zhurakousky
+ * @author Artem Bilan
*/
public class FtpSendingMessageHandlerTests {
@@ -120,6 +124,25 @@ public class FtpSendingMessageHandlerTests {
assertTrue("destination file was not created", destFile.exists());
}
+ @Test //INT-2275
+ public void testFtpOutboundChannelAdapterInsideChain() throws Exception {
+ File targetDir = new File("remote-target-dir");
+ assertTrue("target directory does not exist: " + targetDir.getName(), targetDir.exists());
+
+ File srcFile = File.createTempFile("testHandleFileMessage", ".tmp");
+ srcFile.deleteOnExit();
+
+ File destFile = new File(targetDir, srcFile.getName());
+ destFile.deleteOnExit();
+
+ ApplicationContext context = new ClassPathXmlApplicationContext("FtpOutboundChannelAdapterInsideChainTests-context.xml", getClass());
+
+ MessageChannel channel = context.getBean("outboundChainChannel", MessageChannel.class);
+
+ channel.send(new GenericMessage(srcFile));
+ assertTrue("destination file was not created", destFile.exists());
+ }
+
public static class TestFtpSessionFactory extends AbstractFtpSessionFactory {
diff --git a/spring-integration-gemfire/src/test/java/org/springframework/integration/gemfire/outbound/GemfireOutboundChannelAdapterTests-context.xml b/spring-integration-gemfire/src/test/java/org/springframework/integration/gemfire/outbound/GemfireOutboundChannelAdapterTests-context.xml
index 967e2c7858..f671560599 100644
--- a/spring-integration-gemfire/src/test/java/org/springframework/integration/gemfire/outbound/GemfireOutboundChannelAdapterTests-context.xml
+++ b/spring-integration-gemfire/src/test/java/org/springframework/integration/gemfire/outbound/GemfireOutboundChannelAdapterTests-context.xml
@@ -22,5 +22,9 @@
-
+
+
+
+
+
diff --git a/spring-integration-gemfire/src/test/java/org/springframework/integration/gemfire/outbound/GemfireOutboundChannelAdapterTests.java b/spring-integration-gemfire/src/test/java/org/springframework/integration/gemfire/outbound/GemfireOutboundChannelAdapterTests.java
index 5b26ad7b9b..783b19eaee 100644
--- a/spring-integration-gemfire/src/test/java/org/springframework/integration/gemfire/outbound/GemfireOutboundChannelAdapterTests.java
+++ b/spring-integration-gemfire/src/test/java/org/springframework/integration/gemfire/outbound/GemfireOutboundChannelAdapterTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2011 the original author or authors.
+ * Copyright 2002-2012 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
@@ -31,6 +31,7 @@ import com.gemstone.gemfire.internal.cache.DistributedRegion;
/**
* @author David Turanski
+ * @author Artem Bilan
* @since 2.1
*/
@@ -40,7 +41,7 @@ public class GemfireOutboundChannelAdapterTests {
@Autowired
MessageChannel cacheChannel1;
-
+
@Autowired
DistributedRegion region1;
@@ -49,7 +50,11 @@ public class GemfireOutboundChannelAdapterTests {
@Autowired
DistributedRegion region2;
-
+
+ @Autowired
+ MessageChannel cacheChainChannel;
+
+
@Before
public void setUp() {
region1.clear();
@@ -75,4 +80,16 @@ public class GemfireOutboundChannelAdapterTests {
assertEquals("hello",region2.get("HELLO"));
assertEquals("bar",region2.get("foo"));
}
+
+ @Test //INT-2275
+ public void testWriteWithinChain() {
+ Map map = new HashMap();
+ map.put("foo","bar");
+
+ Message> message = MessageBuilder.withPayload(map).build();
+ cacheChainChannel.send(message);
+ assertEquals(1,region1.size());
+ assertEquals("bar",region1.get("foo"));
+ }
+
}
diff --git a/spring-integration-http/src/test/java/org/springframework/integration/http/outbound/HttpOutboundChannelAdapterWithinChainTests-context.xml b/spring-integration-http/src/test/java/org/springframework/integration/http/outbound/HttpOutboundChannelAdapterWithinChainTests-context.xml
new file mode 100644
index 0000000000..1ad869df32
--- /dev/null
+++ b/spring-integration-http/src/test/java/org/springframework/integration/http/outbound/HttpOutboundChannelAdapterWithinChainTests-context.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/spring-integration-http/src/test/java/org/springframework/integration/http/outbound/HttpRequestExecutingMessageHandlerTests.java b/spring-integration-http/src/test/java/org/springframework/integration/http/outbound/HttpRequestExecutingMessageHandlerTests.java
index de03d2ff01..951abb7621 100644
--- a/spring-integration-http/src/test/java/org/springframework/integration/http/outbound/HttpRequestExecutingMessageHandlerTests.java
+++ b/spring-integration-http/src/test/java/org/springframework/integration/http/outbound/HttpRequestExecutingMessageHandlerTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2010 the original author or authors.
+ * Copyright 2002-2012 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.
@@ -32,13 +32,16 @@ import javax.xml.transform.Source;
import org.junit.Test;
import org.springframework.beans.DirectFieldAccessor;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpMethod;
+import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.integration.Message;
+import org.springframework.integration.MessageChannel;
import org.springframework.integration.channel.QueueChannel;
-import org.springframework.integration.http.outbound.HttpRequestExecutingMessageHandler;
import org.springframework.integration.support.MessageBuilder;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestClientException;
@@ -47,6 +50,7 @@ import org.springframework.web.client.RestTemplate;
/**
* @author Mark Fisher
* @author Oleg Zhurakousky
+ * @author Artem Bilan
*/
public class HttpRequestExecutingMessageHandlerTests {
@@ -639,7 +643,15 @@ public class HttpRequestExecutingMessageHandlerTests {
assertNull(request.getHeaders().getContentType());
*/
}
-
+
+ @Test //INT-2275
+ public void testOutboundChannelAdapterWithinChain() {
+ ApplicationContext ctx = new ClassPathXmlApplicationContext("HttpOutboundChannelAdapterWithinChainTests-context.xml", this.getClass());
+ MessageChannel channel = ctx.getBean("httpOutboundChannelAdapterWithinChain", MessageChannel.class);
+ channel.send(MessageBuilder.withPayload("test").build());
+// It's just enough if it was sent successfully from chain without any failures
+ }
+
public static class City{
private String name;
public City(String name){
@@ -661,4 +673,15 @@ public class HttpRequestExecutingMessageHandlerTests {
throw new RuntimeException("intentional");
}
}
+
+ private static class MockRestTemplate2 extends RestTemplate {
+
+ @Override
+ public ResponseEntity exchange(String url, HttpMethod method, HttpEntity> requestEntity,
+ Class responseType, Map uriVariables) throws RestClientException {
+ return new ResponseEntity(HttpStatus.OK);
+ }
+ }
+
+
}
diff --git a/spring-integration-ip/src/test/java/org/springframework/integration/ip/tcp/TcpOutboundChannelAdapterWithinTests-context.xml b/spring-integration-ip/src/test/java/org/springframework/integration/ip/tcp/TcpOutboundChannelAdapterWithinTests-context.xml
new file mode 100644
index 0000000000..abe18b3580
--- /dev/null
+++ b/spring-integration-ip/src/test/java/org/springframework/integration/ip/tcp/TcpOutboundChannelAdapterWithinTests-context.xml
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/spring-integration-ip/src/test/java/org/springframework/integration/ip/tcp/TcpSendingMessageHandlerTests.java b/spring-integration-ip/src/test/java/org/springframework/integration/ip/tcp/TcpSendingMessageHandlerTests.java
index aa0eb3e0e4..597292f9fe 100644
--- a/spring-integration-ip/src/test/java/org/springframework/integration/ip/tcp/TcpSendingMessageHandlerTests.java
+++ b/spring-integration-ip/src/test/java/org/springframework/integration/ip/tcp/TcpSendingMessageHandlerTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2011 the original author or authors.
+ * Copyright 2002-2012 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.
@@ -43,10 +43,15 @@ import javax.net.ServerSocketFactory;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.junit.Test;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.core.serializer.DefaultDeserializer;
import org.springframework.core.serializer.DefaultSerializer;
import org.springframework.integration.Message;
+import org.springframework.integration.MessageChannel;
import org.springframework.integration.channel.QueueChannel;
+import org.springframework.integration.core.PollableChannel;
+import org.springframework.integration.ip.IpHeaders;
import org.springframework.integration.ip.tcp.connection.AbstractConnectionFactory;
import org.springframework.integration.ip.tcp.connection.HelloWorldInterceptorFactory;
import org.springframework.integration.ip.tcp.connection.TcpConnectionInterceptorFactory;
@@ -57,10 +62,12 @@ import org.springframework.integration.ip.tcp.serializer.ByteArrayCrLfSerializer
import org.springframework.integration.ip.tcp.serializer.ByteArrayLengthHeaderSerializer;
import org.springframework.integration.ip.tcp.serializer.ByteArrayStxEtxSerializer;
import org.springframework.integration.ip.util.SocketTestUtils;
+import org.springframework.integration.message.GenericMessage;
import org.springframework.integration.support.MessageBuilder;
/**
* @author Gary Russell
+ * @author Artem Bilan
* @since 2.0
*/
public class TcpSendingMessageHandlerTests {
@@ -1055,4 +1062,20 @@ public class TcpSendingMessageHandlerTests {
done.set(true);
}
+ @Test
+ public void testOutboundChannelAdapterWithinChain() throws Exception {
+ ApplicationContext ctx = new ClassPathXmlApplicationContext(
+ "TcpOutboundChannelAdapterWithinTests-context.xml", this.getClass());
+ AbstractConnectionFactory ccf = ctx.getBean("ccf", AbstractConnectionFactory.class);
+// TODO Lifecycle#start() isn't invoked within chain...
+ ccf.start();
+ MessageChannel channelAdapterWithinChain = ctx.getBean("tcpOutboundChannelAdapterWithinChain", MessageChannel.class);
+ PollableChannel inbound = ctx.getBean("inbound", PollableChannel.class);
+ String testPayload = "Hello, world!";
+ channelAdapterWithinChain.send(new GenericMessage(testPayload));
+ Message> m = inbound.receive(1000);
+ assertNotNull(m);
+ assertEquals(testPayload, new String((byte[]) m.getPayload()));
+ }
+
}
diff --git a/spring-integration-ip/src/test/java/org/springframework/integration/ip/udp/UdpUnicastEndToEndTests.java b/spring-integration-ip/src/test/java/org/springframework/integration/ip/udp/UdpUnicastEndToEndTests.java
index 4d9f76462f..b296805624 100644
--- a/spring-integration-ip/src/test/java/org/springframework/integration/ip/udp/UdpUnicastEndToEndTests.java
+++ b/spring-integration-ip/src/test/java/org/springframework/integration/ip/udp/UdpUnicastEndToEndTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2010 the original author or authors.
+ * Copyright 2002-2012 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.
@@ -26,6 +26,7 @@ import java.util.Properties;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
+import org.junit.Before;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.AbstractApplicationContext;
@@ -49,6 +50,7 @@ import org.springframework.integration.test.util.TestUtils;
* received in the other context (and written back to the console).
*
* @author Gary Russell
+ * @author Artem Bilan
* @since 2.0
*/
public class UdpUnicastEndToEndTests implements Runnable {
@@ -67,7 +69,18 @@ public class UdpUnicastEndToEndTests implements Runnable {
private CountDownLatch readyToReceive = new CountDownLatch(1);
- private static long hangAroundFor = 0;
+ private static long hangAroundFor = 10;
+
+ @Before
+ public void setup() {
+ this.testingIpText = null;
+ this.finalMessage = null;
+ this.sentFirst = new CountDownLatch(1);
+ this.firstReceived = new CountDownLatch(1);
+ this.doneProcessing = new CountDownLatch(1);
+ this.okToRun = true;
+ this.readyToReceive = new CountDownLatch(1);
+ }
@Test
public void runIt() throws Exception {
@@ -80,6 +93,17 @@ public class UdpUnicastEndToEndTests implements Runnable {
applicationContext.stop();
}
+ @Test
+ public void tesUudpOutboundChannelAdapterWithinChain() throws Exception {
+ UdpUnicastEndToEndTests launcher = new UdpUnicastEndToEndTests();
+ Thread t = new Thread(launcher);
+ t.start(); // launch the receiver
+ AbstractApplicationContext applicationContext = new ClassPathXmlApplicationContext(
+ "testIp-out-within-chain-context.xml", UdpUnicastEndToEndTests.class);
+ launcher.launchSender(applicationContext);
+ applicationContext.stop();
+ }
+
public void launchSender(ApplicationContext applicationContext) throws Exception {
ChannelResolver channelResolver = new BeanFactoryChannelResolver(applicationContext);
@@ -159,6 +183,7 @@ public class UdpUnicastEndToEndTests implements Runnable {
public static void main(String[] args) throws Exception {
hangAroundFor = 120000;
new UdpUnicastEndToEndTests().runIt();
+ new UdpUnicastEndToEndTests().tesUudpOutboundChannelAdapterWithinChain();
}
}
diff --git a/spring-integration-ip/src/test/java/org/springframework/integration/ip/udp/testIp-out-within-chain-context.xml b/spring-integration-ip/src/test/java/org/springframework/integration/ip/udp/testIp-out-within-chain-context.xml
new file mode 100644
index 0000000000..b2e696b4e0
--- /dev/null
+++ b/spring-integration-ip/src/test/java/org/springframework/integration/ip/udp/testIp-out-within-chain-context.xml
@@ -0,0 +1,42 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/spring-integration-jdbc/src/main/resources/org/springframework/integration/jdbc/config/spring-integration-jdbc-2.2.xsd b/spring-integration-jdbc/src/main/resources/org/springframework/integration/jdbc/config/spring-integration-jdbc-2.2.xsd
index ef2d80a345..c50026a692 100644
--- a/spring-integration-jdbc/src/main/resources/org/springframework/integration/jdbc/config/spring-integration-jdbc-2.2.xsd
+++ b/spring-integration-jdbc/src/main/resources/org/springframework/integration/jdbc/config/spring-integration-jdbc-2.2.xsd
@@ -705,17 +705,6 @@
-
-
-
- Indicates whether this procedure's return value
- should be included.
-
-
-
-
-
-
@@ -1313,4 +1302,4 @@
-
\ No newline at end of file
+
diff --git a/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/StoredProcOutboundChannelAdapterWithinChainTests-context.xml b/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/StoredProcOutboundChannelAdapterWithinChainTests-context.xml
new file mode 100644
index 0000000000..cf586e4aee
--- /dev/null
+++ b/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/StoredProcOutboundChannelAdapterWithinChainTests-context.xml
@@ -0,0 +1,29 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/StoredProcOutboundChannelAdapterWithinChainTests.java b/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/StoredProcOutboundChannelAdapterWithinChainTests.java
new file mode 100644
index 0000000000..b677945480
--- /dev/null
+++ b/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/StoredProcOutboundChannelAdapterWithinChainTests.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2002-2012 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.jdbc;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.support.AbstractApplicationContext;
+import org.springframework.integration.Message;
+import org.springframework.integration.MessageChannel;
+import org.springframework.integration.jdbc.storedproc.User;
+import org.springframework.integration.support.MessageBuilder;
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+
+import java.util.Map;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * @author Artem Bilan
+ * @since 2.2
+ */
+@ContextConfiguration
+@RunWith(SpringJUnit4ClassRunner.class)
+public class StoredProcOutboundChannelAdapterWithinChainTests {
+
+ @Autowired
+ private AbstractApplicationContext context;
+
+ @Autowired
+ private JdbcTemplate jdbcTemplate;
+
+ @Autowired
+ private MessageChannel jdbcStoredProcOutboundChannelAdapterWithinChain;
+
+
+ @Test
+ public void test() {
+ Message message = MessageBuilder.withPayload(new User("username", "password", "email")).build();
+ this.jdbcStoredProcOutboundChannelAdapterWithinChain.send(message);
+
+ Map map = this.jdbcTemplate.queryForMap("SELECT * FROM USERS WHERE USERNAME=?", "username");
+
+ assertEquals("Wrong username", "username", map.get("USERNAME"));
+ assertEquals("Wrong password", "password", map.get("PASSWORD"));
+ assertEquals("Wrong email", "email", map.get("EMAIL"));
+// embeddedDatabase can be in working state. So other tests with the same embeddedDatabase beanId, type and init scripts
+// may be failed with Exception like: object in the DB already exists
+ this.context.destroy();
+ }
+
+}
diff --git a/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/config/JdbcMessageHandlerParserTests.java b/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/config/JdbcMessageHandlerParserTests.java
index 62e21c04c6..afd4ed0299 100644
--- a/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/config/JdbcMessageHandlerParserTests.java
+++ b/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/config/JdbcMessageHandlerParserTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2011 the original author or authors.
+ * Copyright 2002-2012 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
@@ -38,6 +38,7 @@ import org.springframework.jdbc.core.JdbcTemplate;
* @author Mark Fisher
* @author Oleg Zhurakousky
* @author Gary Russell
+ * @author Artem Bilan
* @since 2.0
*
*/
@@ -115,6 +116,16 @@ public class JdbcMessageHandlerParserTests {
assertEquals("Wrong id", "foo", map.get("name"));
}
+ @Test
+ public void testOutboundChannelAdapterWithinChain(){
+ setUp("handlingJdbcOutboundChannelAdapterWithinChainTest.xml", getClass());
+ Message> message = MessageBuilder.withPayload("foo").setHeader("business.key", "FOO").build();
+ channel.send(message);
+ Map map = this.jdbcTemplate.queryForMap("SELECT * from FOOS");
+ assertEquals("Wrong id", "FOO", map.get("ID"));
+ assertEquals("Wrong id", "foo", map.get("name"));
+ }
+
@After
public void tearDown(){
if(context != null){
diff --git a/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/config/handlingJdbcOutboundChannelAdapterWithinChainTest.xml b/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/config/handlingJdbcOutboundChannelAdapterWithinChainTest.xml
new file mode 100644
index 0000000000..318d63fa56
--- /dev/null
+++ b/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/config/handlingJdbcOutboundChannelAdapterWithinChainTest.xml
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/spring-integration-jms/src/test/java/org/springframework/integration/jms/JmsOutboundInsideChainTests-context.xml b/spring-integration-jms/src/test/java/org/springframework/integration/jms/JmsOutboundInsideChainTests-context.xml
new file mode 100644
index 0000000000..27c827d8a0
--- /dev/null
+++ b/spring-integration-jms/src/test/java/org/springframework/integration/jms/JmsOutboundInsideChainTests-context.xml
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/spring-integration-jms/src/test/java/org/springframework/integration/jms/JmsOutboundInsideChainTests.java b/spring-integration-jms/src/test/java/org/springframework/integration/jms/JmsOutboundInsideChainTests.java
new file mode 100644
index 0000000000..3cbe61cb31
--- /dev/null
+++ b/spring-integration-jms/src/test/java/org/springframework/integration/jms/JmsOutboundInsideChainTests.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2002-2012 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.jms;
+
+import org.junit.Test;
+import org.springframework.context.support.ClassPathXmlApplicationContext;
+import org.springframework.integration.Message;
+import org.springframework.integration.MessageChannel;
+import org.springframework.integration.core.PollableChannel;
+import org.springframework.integration.support.MessageBuilder;
+
+import static org.junit.Assert.*;
+
+/**
+ * //INT-2275
+ *
+ * @author Artem Bilan
+ */
+public class JmsOutboundInsideChainTests {
+
+ @Test
+ public void testJmsOutboundChannelInsideChain(){
+ ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("JmsOutboundInsideChainTests-context.xml", getClass());
+ PollableChannel receiveChannel = context.getBean("receiveChannel", PollableChannel.class);
+ MessageChannel outboundChainChannel = context.getBean("outboundChainChannel", MessageChannel.class);
+ String testString = "test";
+ Message shippedMessage = MessageBuilder.withPayload(testString).build();
+ outboundChainChannel.send(shippedMessage);
+ Message> receivedMessage = receiveChannel.receive();
+ assertEquals(testString, receivedMessage.getPayload());
+ context.close();
+ }
+
+}
diff --git a/spring-integration-jmx/src/test/java/org/springframework/integration/jmx/config/NotificationPublishingChannelAdapterParserTests-context.xml b/spring-integration-jmx/src/test/java/org/springframework/integration/jmx/config/NotificationPublishingChannelAdapterParserTests-context.xml
index cddfbbeebb..d8b1f8c8db 100644
--- a/spring-integration-jmx/src/test/java/org/springframework/integration/jmx/config/NotificationPublishingChannelAdapterParserTests-context.xml
+++ b/spring-integration-jmx/src/test/java/org/springframework/integration/jmx/config/NotificationPublishingChannelAdapterParserTests-context.xml
@@ -24,6 +24,13 @@
object-name="test.publisher:name=publisher"
default-notification-type="default.type"/>
+
+
+
+
+
diff --git a/spring-integration-jmx/src/test/java/org/springframework/integration/jmx/config/NotificationPublishingChannelAdapterParserTests.java b/spring-integration-jmx/src/test/java/org/springframework/integration/jmx/config/NotificationPublishingChannelAdapterParserTests.java
index 7c6cc8b408..b3dc8b303d 100644
--- a/spring-integration-jmx/src/test/java/org/springframework/integration/jmx/config/NotificationPublishingChannelAdapterParserTests.java
+++ b/spring-integration-jmx/src/test/java/org/springframework/integration/jmx/config/NotificationPublishingChannelAdapterParserTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2010 the original author or authors.
+ * Copyright 2002-2012 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.
@@ -35,6 +35,7 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/**
* @author Mark Fisher
+ * @author Artem Bilan
* @since 2.0
*/
@ContextConfiguration
@@ -47,6 +48,9 @@ public class NotificationPublishingChannelAdapterParserTests {
@Autowired
private TestListener listener;
+ @Autowired
+ private MessageChannel publishingWithinChainChannel;
+
@After
public void clearListener() {
listener.lastNotification = null;
@@ -54,7 +58,7 @@ public class NotificationPublishingChannelAdapterParserTests {
@Test
- public void publishStringMessag() throws Exception {
+ public void publishStringMessage() throws Exception {
assertNull(listener.lastNotification);
Message> message = MessageBuilder.withPayload("XYZ")
.setHeader(JmxHeaders.NOTIFICATION_TYPE, "test.type").build();
@@ -90,7 +94,18 @@ public class NotificationPublishingChannelAdapterParserTests {
assertEquals("default.type", notification.getType());
}
-
+ @Test //INT-2275
+ public void publishStringMessageWithinChain() throws Exception {
+ assertNull(listener.lastNotification);
+ Message> message = MessageBuilder.withPayload("XYZ")
+ .setHeader(JmxHeaders.NOTIFICATION_TYPE, "test.type").build();
+ publishingWithinChainChannel.send(message);
+ assertNotNull(listener.lastNotification);
+ Notification notification = listener.lastNotification;
+ assertEquals("XYZ", notification.getMessage());
+ assertEquals("test.type", notification.getType());
+ assertNull(notification.getUserData());
+ }
private static class TestData {
}
diff --git a/spring-integration-jmx/src/test/java/org/springframework/integration/jmx/config/OperationInvokingChannelAdapterParserTests-context.xml b/spring-integration-jmx/src/test/java/org/springframework/integration/jmx/config/OperationInvokingChannelAdapterParserTests-context.xml
index 5efd68bbcc..642f15d064 100644
--- a/spring-integration-jmx/src/test/java/org/springframework/integration/jmx/config/OperationInvokingChannelAdapterParserTests-context.xml
+++ b/spring-integration-jmx/src/test/java/org/springframework/integration/jmx/config/OperationInvokingChannelAdapterParserTests-context.xml
@@ -20,6 +20,22 @@
object-name="org.springframework.integration.jmx.config:type=TestBean,name=testBeanAdapter"
operation-name="test"/>
+
+
+
+
+
+
+
+
+
+
diff --git a/spring-integration-jmx/src/test/java/org/springframework/integration/jmx/config/OperationInvokingChannelAdapterParserTests.java b/spring-integration-jmx/src/test/java/org/springframework/integration/jmx/config/OperationInvokingChannelAdapterParserTests.java
index 9f80459618..97c9b5ce46 100644
--- a/spring-integration-jmx/src/test/java/org/springframework/integration/jmx/config/OperationInvokingChannelAdapterParserTests.java
+++ b/spring-integration-jmx/src/test/java/org/springframework/integration/jmx/config/OperationInvokingChannelAdapterParserTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2010 the original author or authors.
+ * Copyright 2002-2012 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.
@@ -17,6 +17,8 @@
package org.springframework.integration.jmx.config;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
import org.junit.After;
import org.junit.Test;
@@ -24,6 +26,7 @@ import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.integration.Message;
import org.springframework.integration.MessageChannel;
+import org.springframework.integration.MessagingException;
import org.springframework.integration.jmx.JmxHeaders;
import org.springframework.integration.message.GenericMessage;
import org.springframework.integration.support.MessageBuilder;
@@ -33,6 +36,7 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/**
* @author Mark Fisher
* @author Oleg Zhurakousky
+ * @author Artem Bilan
* @since 2.0
*/
@ContextConfiguration
@@ -42,6 +46,15 @@ public class OperationInvokingChannelAdapterParserTests {
@Autowired
private MessageChannel input;
+ @Autowired
+ private MessageChannel operationWithNonNullReturn;
+
+ @Autowired
+ private MessageChannel operationInvokingWithinChain;
+
+ @Autowired
+ private MessageChannel operationWithinChainWithNonNullReturn;
+
@Autowired
private TestBean testBean;
@@ -59,7 +72,19 @@ public class OperationInvokingChannelAdapterParserTests {
input.send(new GenericMessage("test3"));
assertEquals(3, testBean.messages.size());
}
-
+
+ @Test
+ public void testOutboundAdapterWithNonNullReturn() throws Exception {
+ try {
+ operationWithNonNullReturn.send(new GenericMessage("test1"));
+ fail("Expect MessagingException about non-null return");
+ }
+ catch (Exception e) {
+ assertTrue(e instanceof MessagingException);
+// TODO Add check exception's message about 'must have a void return' after refactoring
+ }
+ }
+
@Test
// Headers should be ignored
public void adapterWitJmxHeaders() throws Exception {
@@ -69,7 +94,25 @@ public class OperationInvokingChannelAdapterParserTests {
input.send(this.createMessage("3"));
assertEquals(3, testBean.messages.size());
}
-
+
+ @Test //INT-2275
+ public void testInvokeOperationWithinChain() throws Exception {
+ operationInvokingWithinChain.send(new GenericMessage("test1"));
+ assertEquals(1, testBean.messages.size());
+ }
+
+ @Test //INT-2275
+ public void testOperationWithinChainWithNonNullReturn() throws Exception {
+ try {
+ operationWithinChainWithNonNullReturn.send(new GenericMessage("test1"));
+ fail("Expect MessagingException about non-null return");
+ }
+ catch (Exception e) {
+ assertTrue(e instanceof MessagingException);
+// TODO Add check exception's message about 'must have a void return' after refactoring
+ }
+ }
+
private Message> createMessage(String payload){
return MessageBuilder.withPayload(payload)
.setHeader(JmxHeaders.OBJECT_NAME, "org.springframework.integration.jmx.config:type=TestBean,name=foo")
diff --git a/spring-integration-jmx/src/test/java/org/springframework/integration/jmx/config/TestListener.java b/spring-integration-jmx/src/test/java/org/springframework/integration/jmx/config/TestListener.java
index d02745a6cd..1c8b6261b4 100644
--- a/spring-integration-jmx/src/test/java/org/springframework/integration/jmx/config/TestListener.java
+++ b/spring-integration-jmx/src/test/java/org/springframework/integration/jmx/config/TestListener.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2010 the original author or authors.
+ * Copyright 2002-2012 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.
@@ -26,6 +26,7 @@ import org.springframework.jmx.support.ObjectNameManager;
/**
* @author Mark Fisher
+ * @author Artem Bilan
* @since 2.0
*/
public class TestListener implements NotificationListener, BeanFactoryAware {
@@ -37,6 +38,8 @@ public class TestListener implements NotificationListener, BeanFactoryAware {
try {
server.addNotificationListener(
ObjectNameManager.getInstance("test.publisher:name=publisher"), this, null, null);
+ server.addNotificationListener(
+ ObjectNameManager.getInstance("test.publisher:name=publisher-chain"), this, null, null);
}
catch (Exception e) {
throw new IllegalArgumentException(e);
diff --git a/spring-integration-mail/src/test/java/org/springframework/integration/mail/MailSendingMessageHandlerContextTests.java b/spring-integration-mail/src/test/java/org/springframework/integration/mail/MailSendingMessageHandlerContextTests.java
index 12bdc273ee..e690b785a9 100644
--- a/spring-integration-mail/src/test/java/org/springframework/integration/mail/MailSendingMessageHandlerContextTests.java
+++ b/spring-integration-mail/src/test/java/org/springframework/integration/mail/MailSendingMessageHandlerContextTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2010 the original author or authors.
+ * Copyright 2002-2012 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.
@@ -31,6 +31,7 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.integration.MessageChannel;
import org.springframework.integration.mapping.MessageMappingException;
import org.springframework.integration.message.GenericMessage;
import org.springframework.integration.support.MessageBuilder;
@@ -40,6 +41,7 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/**
* @author Marius Bogoevici
+ * @author Artem Bilan
*/
@RunWith(value = SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:/org/springframework/integration/mail/mailSendingMessageHandlerContextTests.xml"})
@@ -51,6 +53,9 @@ public class MailSendingMessageHandlerContextTests {
@Autowired
private StubJavaMailSender mailSender;
+ @Autowired
+ private MessageChannel sendMailOutboundChainChannel;
+
@Before
public void reset() {
@@ -99,4 +104,13 @@ public class MailSendingMessageHandlerContextTests {
this.handler.handleMessage(new GenericMessage(payload));
}
+ @Test //INT-2275
+ public void mailOutboundChannelAdapterWithinChain() {
+ this.sendMailOutboundChainChannel.send(MailTestsHelper.createIntegrationMessage());
+ SimpleMailMessage mailMessage = MailTestsHelper.createSimpleMailMessage();
+ assertEquals("no mime message should have been sent", 0, this.mailSender.getSentMimeMessages().size());
+ assertEquals("only one simple message must be sent", 1, this.mailSender.getSentSimpleMailMessages().size());
+ assertEquals("message content different from expected", mailMessage, this.mailSender.getSentSimpleMailMessages().get(0));
+ }
+
}
diff --git a/spring-integration-mail/src/test/java/org/springframework/integration/mail/mailSendingMessageHandlerContextTests.xml b/spring-integration-mail/src/test/java/org/springframework/integration/mail/mailSendingMessageHandlerContextTests.xml
index dc1d8b70e2..391caa3b20 100644
--- a/spring-integration-mail/src/test/java/org/springframework/integration/mail/mailSendingMessageHandlerContextTests.xml
+++ b/spring-integration-mail/src/test/java/org/springframework/integration/mail/mailSendingMessageHandlerContextTests.xml
@@ -1,16 +1,18 @@
+ xmlns:int="http://www.springframework.org/schema/integration"
+ xmlns:int-mail="http://www.springframework.org/schema/integration/mail"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ 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
+ http://www.springframework.org/schema/integration/mail http://www.springframework.org/schema/integration/mail/spring-integration-mail.xsd">
-
+
+
+
@@ -19,4 +21,8 @@
-
\ No newline at end of file
+
+
+
+
+
diff --git a/spring-integration-redis/src/test/java/org/springframework/integration/redis/config/RedisOutboundChannelAdapterParserTests-context.xml b/spring-integration-redis/src/test/java/org/springframework/integration/redis/config/RedisOutboundChannelAdapterParserTests-context.xml
index 4e0b77dd9e..620a792ee6 100644
--- a/spring-integration-redis/src/test/java/org/springframework/integration/redis/config/RedisOutboundChannelAdapterParserTests-context.xml
+++ b/spring-integration-redis/src/test/java/org/springframework/integration/redis/config/RedisOutboundChannelAdapterParserTests-context.xml
@@ -26,4 +26,8 @@
+
+
+
+
diff --git a/spring-integration-redis/src/test/java/org/springframework/integration/redis/config/RedisOutboundChannelAdapterParserTests.java b/spring-integration-redis/src/test/java/org/springframework/integration/redis/config/RedisOutboundChannelAdapterParserTests.java
index 7e92fe2f0c..ada5daccf9 100644
--- a/spring-integration-redis/src/test/java/org/springframework/integration/redis/config/RedisOutboundChannelAdapterParserTests.java
+++ b/spring-integration-redis/src/test/java/org/springframework/integration/redis/config/RedisOutboundChannelAdapterParserTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2011 the original author or authors.
+ * Copyright 2002-2012 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.
@@ -38,6 +38,7 @@ import static junit.framework.Assert.assertEquals;
/**
* @author Oleg Zhurakousky
* @author Mark Fisher
+ * @author Artem Bilan
*/
@ContextConfiguration
@RunWith(SpringJUnit4ClassRunner.class)
@@ -69,6 +70,16 @@ public class RedisOutboundChannelAdapterParserTests extends RedisAvailableTests{
assertEquals("Hello Redis", receiveChannel.receive(1000).getPayload());
}
+ @Test //INT-2275
+ @RedisAvailable
+ public void testOutboundChannelAdapterWithinChain() throws Exception{
+ MessageChannel sendChannel = context.getBean("redisOutboudChain", MessageChannel.class);
+ sendChannel.send(new GenericMessage("Hello Redis from chain"));
+ Thread.sleep(1000);
+ QueueChannel receiveChannel = context.getBean("receiveChannel", QueueChannel.class);
+ assertEquals("Hello Redis from chain", receiveChannel.receive(1000).getPayload());
+ }
+
@SuppressWarnings("unused")
private static class TestMessageConverter extends SimpleMessageConverter {
diff --git a/spring-integration-sftp/src/test/java/org/springframework/integration/sftp/outbound/SftpOutboundChannelAdapterInsideChainTests-context.xml b/spring-integration-sftp/src/test/java/org/springframework/integration/sftp/outbound/SftpOutboundChannelAdapterInsideChainTests-context.xml
new file mode 100644
index 0000000000..2a097e15bc
--- /dev/null
+++ b/spring-integration-sftp/src/test/java/org/springframework/integration/sftp/outbound/SftpOutboundChannelAdapterInsideChainTests-context.xml
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/spring-integration-sftp/src/test/java/org/springframework/integration/sftp/outbound/SftpSendingMessageHandlerTests.java b/spring-integration-sftp/src/test/java/org/springframework/integration/sftp/outbound/SftpSendingMessageHandlerTests.java
index 87574469d7..15d7510883 100644
--- a/spring-integration-sftp/src/test/java/org/springframework/integration/sftp/outbound/SftpSendingMessageHandlerTests.java
+++ b/spring-integration-sftp/src/test/java/org/springframework/integration/sftp/outbound/SftpSendingMessageHandlerTests.java
@@ -30,7 +30,10 @@ import org.mockito.Mockito;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.expression.common.LiteralExpression;
+import org.springframework.integration.MessageChannel;
import org.springframework.integration.file.DefaultFileNameGenerator;
import org.springframework.integration.file.remote.handler.FileTransferringMessageHandler;
import org.springframework.integration.file.remote.session.Session;
@@ -106,6 +109,24 @@ public class SftpSendingMessageHandlerTests {
assertTrue(new File("remote-target-dir", "foo.txt").exists());
}
+ @Test //INT-2275
+ public void testSftpOutboundChannelAdapterInsideChain() throws Exception {
+ File targetDir = new File("remote-target-dir");
+ assertTrue("target directory does not exist: " + targetDir.getName(), targetDir.exists());
+
+ File srcFile = File.createTempFile("testHandleFileMessage", ".tmp");
+ srcFile.deleteOnExit();
+
+ File destFile = new File(targetDir, srcFile.getName());
+ destFile.deleteOnExit();
+
+ ApplicationContext context = new ClassPathXmlApplicationContext("SftpOutboundChannelAdapterInsideChainTests-context.xml", getClass());
+
+ MessageChannel channel = context.getBean("outboundChainChannel", MessageChannel.class);
+
+ channel.send(new GenericMessage(srcFile));
+ assertTrue("destination file was not created", destFile.exists());
+ }
public static class TestSftpSessionFactory extends DefaultSftpSessionFactory {
diff --git a/spring-integration-stream/src/test/java/org/springframework/integration/stream/config/ConsoleOutboundChannelAdapterParserTests.java b/spring-integration-stream/src/test/java/org/springframework/integration/stream/config/ConsoleOutboundChannelAdapterParserTests.java
index f8f02d586f..13e17b20e0 100644
--- a/spring-integration-stream/src/test/java/org/springframework/integration/stream/config/ConsoleOutboundChannelAdapterParserTests.java
+++ b/spring-integration-stream/src/test/java/org/springframework/integration/stream/config/ConsoleOutboundChannelAdapterParserTests.java
@@ -24,20 +24,22 @@ import java.io.OutputStreamWriter;
import java.io.PrintStream;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
+
import java.nio.charset.Charset;
import org.junit.Before;
import org.junit.Test;
-
import org.springframework.beans.DirectFieldAccessor;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.context.support.ClassPathXmlApplicationContext;
+import org.springframework.integration.channel.DirectChannel;
import org.springframework.integration.message.GenericMessage;
import org.springframework.integration.stream.CharacterStreamWritingMessageHandler;
/**
* @author Mark Fisher
* @author Gary Russell
+ * @author Artem Bilan
*/
public class ConsoleOutboundChannelAdapterParserTests {
@@ -156,4 +158,13 @@ public class ConsoleOutboundChannelAdapterParserTests {
assertEquals("foo" + System.getProperty("line.separator"), out.toString());
}
+ @Test //INT-2275
+ public void stdoutInsideNestedChain() {
+ ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
+ "consoleOutboundChannelAdapterParserTests.xml", ConsoleOutboundChannelAdapterParserTests.class);
+ DirectChannel channel = context.getBean("stdoutInsideNestedChain", DirectChannel.class);
+ this.resetStreams();
+ channel.send(new GenericMessage("foo"));
+ assertEquals("foobar", out.toString());
+ }
}
diff --git a/spring-integration-stream/src/test/java/org/springframework/integration/stream/config/consoleOutboundChannelAdapterParserTests.xml b/spring-integration-stream/src/test/java/org/springframework/integration/stream/config/consoleOutboundChannelAdapterParserTests.xml
index 95492bb297..f70f1c265e 100644
--- a/spring-integration-stream/src/test/java/org/springframework/integration/stream/config/consoleOutboundChannelAdapterParserTests.xml
+++ b/spring-integration-stream/src/test/java/org/springframework/integration/stream/config/consoleOutboundChannelAdapterParserTests.xml
@@ -20,4 +20,11 @@
-
\ No newline at end of file
+
+
+
+
+
+
+
+
diff --git a/spring-integration-twitter/src/test/java/org/springframework/integration/twitter/ignored/TestSendingDMsUsingNamespace-context.xml b/spring-integration-twitter/src/test/java/org/springframework/integration/twitter/ignored/TestSendingDMsUsingNamespace-context.xml
index 107348a91f..95b36add49 100644
--- a/spring-integration-twitter/src/test/java/org/springframework/integration/twitter/ignored/TestSendingDMsUsingNamespace-context.xml
+++ b/spring-integration-twitter/src/test/java/org/springframework/integration/twitter/ignored/TestSendingDMsUsingNamespace-context.xml
@@ -33,6 +33,10 @@
+
+
+
+
diff --git a/spring-integration-twitter/src/test/java/org/springframework/integration/twitter/ignored/TestSendingDMsUsingNamespace.java b/spring-integration-twitter/src/test/java/org/springframework/integration/twitter/ignored/TestSendingDMsUsingNamespace.java
index c5a0a743d7..13dec1e9dd 100644
--- a/spring-integration-twitter/src/test/java/org/springframework/integration/twitter/ignored/TestSendingDMsUsingNamespace.java
+++ b/spring-integration-twitter/src/test/java/org/springframework/integration/twitter/ignored/TestSendingDMsUsingNamespace.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2010 the original author or authors.
+ * Copyright 2002-2012 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.
@@ -31,14 +31,19 @@ import org.springframework.util.StringUtils;
/**
* @author Josh Long
* @author Oleg Zhurakouksy
+ * @author Artem Bilan
*/
@ContextConfiguration
public class TestSendingDMsUsingNamespace extends AbstractJUnit4SpringContextTests {
@Autowired
@Qualifier("inputChannel")
+
private MessageChannel inputChannel;
-
+ @Autowired
+ @Qualifier("dmOutboundWithinChain")
+ private MessageChannel dmOutboundWithinChain;
+
@Test
@Ignore
public void testSendigRealDirectMessage() throws Throwable {
@@ -52,4 +57,16 @@ public class TestSendingDMsUsingNamespace extends AbstractJUnit4SpringContextTes
inputChannel.send(mb.build());
}
+ @Test
+ @Ignore
+ public void testSendigDirectMessageFromChain() throws Throwable {
+ String dmUsr = "z_oleg";
+ MessageBuilder mb = MessageBuilder.withPayload("Hello world!");
+
+ if (StringUtils.hasText(dmUsr)) {
+ mb.setHeader(TwitterHeaders.DM_TARGET_USER_ID, dmUsr);
+ }
+ dmOutboundWithinChain.send(mb.build());
+ }
+
}
diff --git a/spring-integration-twitter/src/test/java/org/springframework/integration/twitter/ignored/TestSendingUpdatesUsingNamespace-context.xml b/spring-integration-twitter/src/test/java/org/springframework/integration/twitter/ignored/TestSendingUpdatesUsingNamespace-context.xml
index 26465a48c2..a5c4a2b599 100644
--- a/spring-integration-twitter/src/test/java/org/springframework/integration/twitter/ignored/TestSendingUpdatesUsingNamespace-context.xml
+++ b/spring-integration-twitter/src/test/java/org/springframework/integration/twitter/ignored/TestSendingUpdatesUsingNamespace-context.xml
@@ -32,7 +32,11 @@
-
+
+
+
+
+
diff --git a/spring-integration-twitter/src/test/java/org/springframework/integration/twitter/ignored/TestSendingUpdatesUsingNamespace.java b/spring-integration-twitter/src/test/java/org/springframework/integration/twitter/ignored/TestSendingUpdatesUsingNamespace.java
index d26146f8a7..80d5aa832b 100644
--- a/spring-integration-twitter/src/test/java/org/springframework/integration/twitter/ignored/TestSendingUpdatesUsingNamespace.java
+++ b/spring-integration-twitter/src/test/java/org/springframework/integration/twitter/ignored/TestSendingUpdatesUsingNamespace.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2010 the original author or authors
+ * Copyright 2002-2012 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.
@@ -21,6 +21,8 @@ import java.util.Date;
import org.junit.Ignore;
import org.junit.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.integration.Message;
import org.springframework.integration.MessageChannel;
@@ -31,6 +33,7 @@ import org.springframework.test.context.junit4.AbstractJUnit4SpringContextTests;
/**
* @author Josh Long
+ * @author Artem Bilan
*/
@ContextConfiguration
public class TestSendingUpdatesUsingNamespace extends AbstractJUnit4SpringContextTests {
@@ -39,6 +42,10 @@ public class TestSendingUpdatesUsingNamespace extends AbstractJUnit4SpringContex
@Value("#{out}") private MessageChannel channel;
+ @Autowired
+ @Qualifier("outFromChain")
+ private MessageChannel outFromChain;
+
@Test
@Ignore
public void testSendingATweet() throws Throwable {
@@ -48,4 +55,11 @@ public class TestSendingUpdatesUsingNamespace extends AbstractJUnit4SpringContex
this.messagingTemplate.send(this.channel, m);
}
+ @Test
+ @Ignore
+ public void testSendingATweetFromChain() throws Throwable {
+ Message m = MessageBuilder.withPayload("Early start today" + new Date(System.currentTimeMillis())).build();
+ this.outFromChain.send(m);
+ }
+
}
diff --git a/spring-integration-xmpp/src/test/java/org/springframework/integration/xmpp/config/ChatMessageOutboundChannelAdapterParserTests-context.xml b/spring-integration-xmpp/src/test/java/org/springframework/integration/xmpp/config/ChatMessageOutboundChannelAdapterParserTests-context.xml
index 31347bce2e..beffa34209 100644
--- a/spring-integration-xmpp/src/test/java/org/springframework/integration/xmpp/config/ChatMessageOutboundChannelAdapterParserTests-context.xml
+++ b/spring-integration-xmpp/src/test/java/org/springframework/integration/xmpp/config/ChatMessageOutboundChannelAdapterParserTests-context.xml
@@ -43,4 +43,8 @@
xmpp-connection="testConnection">
+
+
+
+
diff --git a/spring-integration-xmpp/src/test/java/org/springframework/integration/xmpp/config/ChatMessageOutboundChannelAdapterParserTests.java b/spring-integration-xmpp/src/test/java/org/springframework/integration/xmpp/config/ChatMessageOutboundChannelAdapterParserTests.java
index 8c05e0a667..73fc340b86 100644
--- a/spring-integration-xmpp/src/test/java/org/springframework/integration/xmpp/config/ChatMessageOutboundChannelAdapterParserTests.java
+++ b/spring-integration-xmpp/src/test/java/org/springframework/integration/xmpp/config/ChatMessageOutboundChannelAdapterParserTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2011 the original author or authors.
+ * Copyright 2002-2012 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.
@@ -49,6 +49,7 @@ import static org.mockito.Mockito.verify;
/**
* @author Oleg Zhurakousky
* @author Mark Fisher
+ * @author Artem Bilan
*/
@ContextConfiguration
@RunWith(SpringJUnit4ClassRunner.class)
@@ -104,7 +105,6 @@ public class ChatMessageOutboundChannelAdapterParserTests {
org.jivesoftware.smack.packet.Message xmppMessage = (org.jivesoftware.smack.packet.Message) args[0];
assertEquals("oleg", xmppMessage.getTo());
assertEquals("foobar", xmppMessage.getProperty("foobar"));
- assertEquals("oleg", xmppMessage.getTo());
return null;
}})
.when(connection).sendPacket(Mockito.any(org.jivesoftware.smack.packet.Message.class));
@@ -112,6 +112,29 @@ public class ChatMessageOutboundChannelAdapterParserTests {
channel.send(message);
verify(connection, times(1)).sendPacket(Mockito.any(org.jivesoftware.smack.packet.Message.class));
+ Mockito.reset(connection);
+ }
+
+ @SuppressWarnings("rawtypes")
+ @Test //INT-2275
+ public void testOutboundChannelAdapterInsideChain() throws Exception{
+ MessageChannel channel = context.getBean("outboundChainChannel", MessageChannel.class);
+ Message> message = MessageBuilder.withPayload("hello").setHeader(XmppHeaders.TO, "artem").build();
+ XMPPConnection connection = context.getBean("testConnection", XMPPConnection.class);
+ Mockito.doAnswer(new Answer() {
+ public Object answer(InvocationOnMock invocation) {
+ Object[] args = invocation.getArguments();
+ org.jivesoftware.smack.packet.Message xmppMessage = (org.jivesoftware.smack.packet.Message) args[0];
+ assertEquals("artem", xmppMessage.getTo());
+ assertEquals("hello", xmppMessage.getBody());
+ return null;
+ }})
+ .when(connection).sendPacket(Mockito.any(org.jivesoftware.smack.packet.Message.class));
+
+ channel.send(message);
+
+ verify(connection, times(1)).sendPacket(Mockito.any(org.jivesoftware.smack.packet.Message.class));
+ Mockito.reset(connection);
}
}
diff --git a/src/reference/docbook/chain.xml b/src/reference/docbook/chain.xml
index 6e7dd385aa..edc3c7062d 100644
--- a/src/reference/docbook/chain.xml
+++ b/src/reference/docbook/chain.xml
@@ -57,7 +57,7 @@
The <chain> element provides an input-channel attribute, and if the last element in the chain is capable
of producing reply messages (optional), it also supports an output-channel attribute. The sub-elements are then
- filters, transformers, splitters, and service-activators. The last element may also be a router.
+ filters, transformers, splitters, and service-activators. The last element may also be a router or an outbound-channel-adapter.
@@ -72,7 +72,18 @@
that touches only header values. You could obtain the same result by implementing a MessageHandler that did the
header modifications and wiring that as a bean, but the header-enricher is obviously a simpler option.
-
+
+ The <chain> can be configured as the last 'black-box' consumer of the message flow. For this solution it is
+ enough to put at the end of the <chain> some <outbound-channel-adapter>:
+
+
+
+
+
+
+
+ ]]>
+
Sometimes you need to make a nested call to another chain from within a chain and then come
back and continue execution within the original chain.