INT-2275: any outbound-channel-adapter in <chain>
Add re-init logic for nested chains Add logic about nested element for AbstractChannelAdapterParser Refactor of DefaultOutboundChannelAdapterParser Test for non-last nested chain with some outbound-channel-adapter Improve XSD for chain-type Manual outbound-channel-adapter ability for chain Integration tests for all outbound-channel-adapter within <chain> Remove redundant 'return-value-required' attribute from <stored-proc-outbound-channel-adapter> Add support 'expectReply' for FileWritingMessageHandler INT-2275 polishing & refactor FileOutbound*Parser HttpRequestExecutingMessageHandlerTests polishing INT-2275: polishing JavaDoc
This commit is contained in:
committed by
Oleg Zhurakousky
parent
4d5b8d5be1
commit
45c429ee2b
@@ -22,5 +22,10 @@
|
||||
mapped-request-headers="foo*"/>
|
||||
|
||||
<int:channel id="requestChannel"/>
|
||||
|
||||
|
||||
<int:chain id="chainWithRabbitOutbound" input-channel="amqpOutboundChannelAdapterWithinChain">
|
||||
<amqp:outbound-channel-adapter exchange-name="outboundchanneladapter.test.1"/>
|
||||
</int:chain>
|
||||
|
||||
|
||||
</beans>
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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<MessageHandler> 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();
|
||||
|
||||
@@ -789,7 +789,7 @@
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
|
||||
<xsd:element name="outbound-channel-adapter">
|
||||
<xsd:element name="outbound-channel-adapter" type="methodInvokingChannelAdapterType">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
Defines a Channel Adapter that receives from a MessageChannel and passes to
|
||||
@@ -797,89 +797,75 @@
|
||||
MessageHandler.
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
<xsd:complexType>
|
||||
<xsd:complexContent>
|
||||
<xsd:extension base="methodInvokingChannelAdapterType">
|
||||
<xsd:attribute name="order">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
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.
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
</xsd:extension>
|
||||
</xsd:complexContent>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
|
||||
<xsd:element name="logging-channel-adapter">
|
||||
<xsd:complexType>
|
||||
<xsd:complexContent>
|
||||
<xsd:extension base="channelAdapterType">
|
||||
<xsd:attribute name="level" default="INFO">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
<xsd:extension base="outboundChannelAdapterType">
|
||||
<xsd:attributeGroup ref="loggingChannelAdapterAttributes"/>
|
||||
</xsd:extension>
|
||||
</xsd:complexContent>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
|
||||
<xsd:complexType name="loggingChannelAdapterTypeChain">
|
||||
<xsd:complexContent>
|
||||
<xsd:extension base="outboundChannelAdapterTypeChain">
|
||||
<xsd:attributeGroup ref="loggingChannelAdapterAttributes"/>
|
||||
</xsd:extension>
|
||||
</xsd:complexContent>
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:attributeGroup name="loggingChannelAdapterAttributes">
|
||||
<xsd:attribute name="level" default="INFO">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
Specify the log level.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
<xsd:simpleType>
|
||||
<xsd:restriction base="xsd:string">
|
||||
<xsd:enumeration value="FATAL" />
|
||||
<xsd:enumeration value="ERROR" />
|
||||
<xsd:enumeration value="WARN" />
|
||||
<xsd:enumeration value="INFO" />
|
||||
<xsd:enumeration value="DEBUG" />
|
||||
<xsd:enumeration value="TRACE" />
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="logger-name" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
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.
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="expression">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
</xsd:annotation>
|
||||
<xsd:simpleType>
|
||||
<xsd:restriction base="xsd:string">
|
||||
<xsd:enumeration value="FATAL" />
|
||||
<xsd:enumeration value="ERROR" />
|
||||
<xsd:enumeration value="WARN" />
|
||||
<xsd:enumeration value="INFO" />
|
||||
<xsd:enumeration value="DEBUG" />
|
||||
<xsd:enumeration value="TRACE" />
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="logger-name" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
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.
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="expression">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
Provide a SpEL expression to be evaluated against the Message as the root object. For example,
|
||||
the default behavior is equivalent to an expression of "payload", or an expression may evaluate
|
||||
against the payload itself ("payload.address.city") or headers ("headers.foo"). This attribute and
|
||||
the 'log-full-message' attribute are mutually exclusive. See the documentation on the
|
||||
'log-full-message' attribute for more information.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="log-full-message">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="log-full-message">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
Specify whether to log the full message. This attribute and the 'expression' attribute are
|
||||
mutually exclusive. Setting this to true is equivalent to setting an expression value of "#root"
|
||||
since the Message is the root object against which the expression will be evaluated. If no
|
||||
'expression' is provided, and this value is false (the default), only the payload will be logged.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="order">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
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.
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
</xsd:extension>
|
||||
</xsd:complexContent>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
</xsd:attributeGroup>
|
||||
|
||||
<xsd:attributeGroup name="methodInvokingOrExpressionEvaluatingAttributes">
|
||||
<xsd:attribute name="ref" type="xsd:string">
|
||||
@@ -945,18 +931,42 @@ endpoint itself is a Polling Consumer for a channel with a queue.
|
||||
|
||||
<xsd:complexType name="methodInvokingChannelAdapterType">
|
||||
<xsd:complexContent>
|
||||
<xsd:extension base="channelAdapterType">
|
||||
<xsd:extension base="outboundChannelAdapterType">
|
||||
<xsd:attributeGroup ref="methodInvokingOrExpressionEvaluatingAttributes" />
|
||||
</xsd:extension>
|
||||
</xsd:complexContent>
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:complexType name="channelAdapterType">
|
||||
<xsd:complexType name="methodInvokingChannelAdapterTypeChain">
|
||||
<xsd:complexContent>
|
||||
<xsd:extension base="outboundChannelAdapterTypeChain">
|
||||
<xsd:attributeGroup ref="methodInvokingOrExpressionEvaluatingAttributes" />
|
||||
</xsd:extension>
|
||||
</xsd:complexContent>
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:complexType name="outboundChannelAdapterType">
|
||||
<xsd:all>
|
||||
<xsd:element name="poller" type="basePollerType" minOccurs="0" maxOccurs="1" />
|
||||
<xsd:element ref="beans:bean" minOccurs="0" maxOccurs="1" />
|
||||
</xsd:all>
|
||||
<xsd:attributeGroup ref="channelAdapterAttributes" />
|
||||
<xsd:attribute name="order">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
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.
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:complexType name="outboundChannelAdapterTypeChain">
|
||||
<xsd:all>
|
||||
<xsd:element ref="beans:bean" minOccurs="0" maxOccurs="1" />
|
||||
</xsd:all>
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:element name="service-activator">
|
||||
@@ -1369,38 +1379,44 @@ endpoint itself is a Polling Consumer for a channel with a queue.
|
||||
</xsd:element>
|
||||
|
||||
<xsd:complexType name="chain-type">
|
||||
<xsd:choice minOccurs="1" maxOccurs="unbounded">
|
||||
<xsd:any processContents="strict" namespace="##other" minOccurs="0" maxOccurs="unbounded" />
|
||||
<xsd:sequence>
|
||||
<xsd:choice minOccurs="0" maxOccurs="unbounded">
|
||||
<xsd:any processContents="strict" namespace="##other" minOccurs="0" maxOccurs="unbounded"/>
|
||||
|
||||
<xsd:element name="service-activator" type="expressionOrInnerEndpointDefinitionAware" />
|
||||
<xsd:element name="splitter" type="splitter-type" />
|
||||
<xsd:element name="transformer" type="expressionOrInnerEndpointDefinitionAware" />
|
||||
<xsd:element name="header-enricher" type="header-enricher-type" />
|
||||
<xsd:element name="header-filter" type="header-filter-type" />
|
||||
<xsd:element name="enricher" type="enricher-type" />
|
||||
<xsd:element name="filter" type="filter-type" />
|
||||
<xsd:element name="aggregator" type="aggregator-type" />
|
||||
<xsd:element name="resequencer" type="resequencer-type" />
|
||||
<xsd:element name="router" type="routerTypeChain" />
|
||||
<xsd:element name="payload-type-router" type="payloadTypeRouterTypeChain" />
|
||||
<xsd:element name="recipient-list-router" type="recipientListRouterTypeChain" />
|
||||
<xsd:element name="exception-type-router" type="exceptionTypeRouterTypeChain" />
|
||||
<xsd:element name="header-value-router" type="headerValueRouterTypeChain" />
|
||||
<xsd:element name="delayer" type="delayer-type" />
|
||||
<xsd:element name="gateway" type="innerGatewayType" />
|
||||
<xsd:element name="poller" type="basePollerType" />
|
||||
<xsd:element name="payload-serializing-transformer" type="payload-serializing-transformer-type" />
|
||||
<xsd:element name="payload-deserializing-transformer" type="payload-deserializing-transformer-type" />
|
||||
<xsd:element name="object-to-string-transformer" type="specialized-transformer-type" />
|
||||
<xsd:element name="object-to-map-transformer" type="specialized-transformer-type" />
|
||||
<xsd:element name="map-to-object-transformer" type="map-to-object-transformer-type" />
|
||||
<xsd:element name="object-to-json-transformer" type="object-to-json-transformer-type" />
|
||||
<xsd:element name="json-to-object-transformer" type="json-to-object-transformer-type" />
|
||||
<xsd:element name="claim-check-in" type="claimCheckInTypeChain" />
|
||||
<xsd:element name="claim-check-out" type="claimCheckOutTypeChain" />
|
||||
<xsd:element name="control-bus" type="control-bus-type" />
|
||||
<xsd:element name="chain" type="chain-type" />
|
||||
</xsd:choice>
|
||||
<xsd:element name="service-activator" type="expressionOrInnerEndpointDefinitionAware"/>
|
||||
<xsd:element name="splitter" type="splitter-type"/>
|
||||
<xsd:element name="transformer" type="expressionOrInnerEndpointDefinitionAware"/>
|
||||
<xsd:element name="header-enricher" type="header-enricher-type"/>
|
||||
<xsd:element name="header-filter" type="header-filter-type"/>
|
||||
<xsd:element name="enricher" type="enricher-type"/>
|
||||
<xsd:element name="filter" type="filter-type"/>
|
||||
<xsd:element name="aggregator" type="aggregator-type"/>
|
||||
<xsd:element name="resequencer" type="resequencer-type"/>
|
||||
<xsd:element name="router" type="routerTypeChain"/>
|
||||
<xsd:element name="payload-type-router" type="payloadTypeRouterTypeChain"/>
|
||||
<xsd:element name="recipient-list-router" type="recipientListRouterTypeChain"/>
|
||||
<xsd:element name="exception-type-router" type="exceptionTypeRouterTypeChain"/>
|
||||
<xsd:element name="header-value-router" type="headerValueRouterTypeChain"/>
|
||||
<xsd:element name="delayer" type="delayer-type"/>
|
||||
<xsd:element name="gateway" type="innerGatewayType"/>
|
||||
<xsd:element name="poller" type="basePollerType"/>
|
||||
<xsd:element name="payload-serializing-transformer" type="payload-serializing-transformer-type"/>
|
||||
<xsd:element name="payload-deserializing-transformer" type="payload-deserializing-transformer-type"/>
|
||||
<xsd:element name="object-to-string-transformer" type="specialized-transformer-type"/>
|
||||
<xsd:element name="object-to-map-transformer" type="specialized-transformer-type"/>
|
||||
<xsd:element name="map-to-object-transformer" type="map-to-object-transformer-type"/>
|
||||
<xsd:element name="object-to-json-transformer" type="object-to-json-transformer-type"/>
|
||||
<xsd:element name="json-to-object-transformer" type="json-to-object-transformer-type"/>
|
||||
<xsd:element name="claim-check-in" type="claimCheckInTypeChain"/>
|
||||
<xsd:element name="claim-check-out" type="claimCheckOutTypeChain"/>
|
||||
<xsd:element name="control-bus" type="control-bus-type"/>
|
||||
<xsd:element name="chain" type="chain-type"/>
|
||||
</xsd:choice>
|
||||
<xsd:choice minOccurs="0">
|
||||
<xsd:element name="outbound-channel-adapter" type="methodInvokingChannelAdapterTypeChain"/>
|
||||
<xsd:element name="logging-channel-adapter" type="loggingChannelAdapterTypeChain"/>
|
||||
</xsd:choice>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:element name="poller">
|
||||
|
||||
@@ -96,6 +96,17 @@
|
||||
<service-activator ref="testHandler" />
|
||||
</chain>
|
||||
|
||||
<chain input-channel="outboundChannelAdapterChannel">
|
||||
<outbound-channel-adapter ref="testConsumer"/>
|
||||
</chain>
|
||||
|
||||
<chain input-channel="loggingChannelAdapterChannel">
|
||||
<transformer expression="payload.toUpperCase()"/>
|
||||
<logging-channel-adapter level="WARN"/>
|
||||
</chain>
|
||||
|
||||
<beans:bean id="testConsumer" class="org.springframework.integration.config.TestConsumer" />
|
||||
|
||||
<channel id="strings">
|
||||
<queue/>
|
||||
</channel>
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans:beans xmlns="http://www.springframework.org/schema/integration"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:beans="http://www.springframework.org/schema/beans"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans
|
||||
http://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://www.springframework.org/schema/integration
|
||||
http://www.springframework.org/schema/integration/spring-integration.xsd">
|
||||
|
||||
<chain input-channel="invalidNestedChain">
|
||||
<chain>
|
||||
<logging-channel-adapter/>
|
||||
</chain>
|
||||
<logging-channel-adapter/>
|
||||
</chain>
|
||||
|
||||
</beans:beans>
|
||||
@@ -13,16 +13,22 @@
|
||||
<queue capacity="2"/>
|
||||
</channel>
|
||||
|
||||
<channel id="channelC"/>
|
||||
|
||||
<outbound-channel-adapter id="adapter" channel="channel" ref="bean" method="out" order="99" auto-startup="false"/>
|
||||
|
||||
<beans:bean id="bean"
|
||||
class="org.springframework.integration.config.xml.MethodInvokingOutboundChannelAdapterParserTests$TestBean"/>
|
||||
class="org.springframework.integration.config.xml.DefaultOutboundChannelAdapterParserTests$TestBean"/>
|
||||
|
||||
<outbound-channel-adapter id="adapterB" channel="channelB" method="out" order="99" auto-startup="false">
|
||||
<beans:bean class="org.springframework.integration.config.xml.MethodInvokingOutboundChannelAdapterParserTests$TestBean"/>
|
||||
<beans:bean class="org.springframework.integration.config.xml.DefaultOutboundChannelAdapterParserTests$TestBean"/>
|
||||
<poller task-executor="executor" max-messages-per-poll="5" fixed-delay="20" />
|
||||
</outbound-channel-adapter>
|
||||
|
||||
<task:executor id="executor" pool-size="5" />
|
||||
|
||||
<outbound-channel-adapter id="adapterC" channel="channelC" order="99">
|
||||
<beans:bean class="org.springframework.integration.config.TestConsumer"/>
|
||||
</outbound-channel-adapter>
|
||||
|
||||
</beans:beans>
|
||||
@@ -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 {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -8,7 +8,12 @@
|
||||
http://www.springframework.org/schema/integration/event http://www.springframework.org/schema/integration/event/spring-integration-event.xsd">
|
||||
|
||||
<int:channel id="input"/>
|
||||
|
||||
|
||||
<int-event:outbound-channel-adapter id="eventAdapter" channel="input"/>
|
||||
|
||||
<int:chain input-channel="inputChain">
|
||||
<int:transformer expression="payload + 'bar'"/>
|
||||
<int-event:outbound-channel-adapter/>
|
||||
</int:chain>
|
||||
|
||||
</beans>
|
||||
|
||||
@@ -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<ApplicationEvent>() {
|
||||
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<String>("foo"));
|
||||
Assert.assertTrue(receivedEvent);
|
||||
}
|
||||
|
||||
@Test(timeout=2000)
|
||||
public void validateUsageWithPollableChannel() throws Exception {
|
||||
ConfigurableApplicationContext context = new ClassPathXmlApplicationContext("EventOutboundChannelAdapterParserTestsWithPollable-context.xml", EventOutboundChannelAdapterParserTests.class);
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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<FileWritingMessageHandler>{
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:context="http://www.springframework.org/schema/context"
|
||||
xmlns:si="http://www.springframework.org/schema/integration"
|
||||
xmlns:file="http://www.springframework.org/schema/integration/file"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans
|
||||
http://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://www.springframework.org/schema/context
|
||||
http://www.springframework.org/schema/context/spring-context.xsd
|
||||
http://www.springframework.org/schema/integration
|
||||
http://www.springframework.org/schema/integration/spring-integration.xsd
|
||||
http://www.springframework.org/schema/integration/file
|
||||
http://www.springframework.org/schema/integration/file/spring-integration-file.xsd">
|
||||
|
||||
|
||||
<si:chain input-channel="outboundChainChannel">
|
||||
<si:header-enricher>
|
||||
<si:header name="#{T(org.springframework.integration.file.FileHeaders).FILENAME}" value="${test.file}"/>
|
||||
</si:header-enricher>
|
||||
<file:outbound-channel-adapter directory="${work.dir}"/>
|
||||
</si:chain>
|
||||
|
||||
<bean id="placeholderProperties" class="org.springframework.beans.factory.config.PropertiesFactoryBean">
|
||||
<property name="properties" value="#{T(org.springframework.integration.file.FileOutboundChannelAdapterInsideChainTests).placeholderProperties}"/>
|
||||
</bean>
|
||||
|
||||
<context:property-placeholder properties-ref="placeholderProperties"/>
|
||||
|
||||
</beans>
|
||||
@@ -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<String> 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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:context="http://www.springframework.org/schema/context"
|
||||
xmlns:si="http://www.springframework.org/schema/integration"
|
||||
xmlns:ftp="http://www.springframework.org/schema/integration/ftp"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans
|
||||
http://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://www.springframework.org/schema/context
|
||||
http://www.springframework.org/schema/context/spring-context.xsd
|
||||
http://www.springframework.org/schema/integration
|
||||
http://www.springframework.org/schema/integration/spring-integration.xsd
|
||||
http://www.springframework.org/schema/integration/ftp
|
||||
http://www.springframework.org/schema/integration/ftp/spring-integration-ftp.xsd">
|
||||
|
||||
|
||||
<si:chain input-channel="outboundChainChannel">
|
||||
<ftp:outbound-channel-adapter
|
||||
auto-create-directory="true"
|
||||
session-factory="ftpSessionFactory"
|
||||
remote-directory="remote-target-dir"/>
|
||||
</si:chain>
|
||||
|
||||
<bean id="ftpSessionFactory"
|
||||
class="org.springframework.integration.ftp.outbound.FtpSendingMessageHandlerTests$TestFtpSessionFactory">
|
||||
<property name="username" value="kermit"/>
|
||||
<property name="password" value="frog"/>
|
||||
<property name="host" value="foo.com"/>
|
||||
</bean>
|
||||
</beans>
|
||||
@@ -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<File>(srcFile));
|
||||
assertTrue("destination file was not created", destFile.exists());
|
||||
}
|
||||
|
||||
|
||||
public static class TestFtpSessionFactory extends AbstractFtpSessionFactory<FTPClient> {
|
||||
|
||||
|
||||
@@ -22,5 +22,9 @@
|
||||
<entry key="'foo'" value="'bar'"/>
|
||||
</int-gfe:cache-entries>
|
||||
</int-gfe:outbound-channel-adapter>
|
||||
|
||||
|
||||
<int:chain input-channel="cacheChainChannel">
|
||||
<int-gfe:outbound-channel-adapter region="region1"/>
|
||||
</int:chain>
|
||||
|
||||
</beans>
|
||||
|
||||
@@ -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<String,String> map = new HashMap<String,String>();
|
||||
map.put("foo","bar");
|
||||
|
||||
Message<?> message = MessageBuilder.withPayload(map).build();
|
||||
cacheChainChannel.send(message);
|
||||
assertEquals(1,region1.size());
|
||||
assertEquals("bar",region1.get("foo"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans:beans
|
||||
xmlns="http://www.springframework.org/schema/integration/http"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:beans="http://www.springframework.org/schema/beans"
|
||||
xmlns:si="http://www.springframework.org/schema/integration"
|
||||
xmlns:util="http://www.springframework.org/schema/util"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/integration/http http://www.springframework.org/schema/integration/http/spring-integration-http.xsd
|
||||
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd
|
||||
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">
|
||||
|
||||
<si:chain input-channel="httpOutboundChannelAdapterWithinChain">
|
||||
<outbound-channel-adapter url="http://localhost/test1" rest-template="restTemplate"/>
|
||||
</si:chain>
|
||||
|
||||
<beans:bean id="restTemplate" class="org.springframework.integration.http.outbound.HttpRequestExecutingMessageHandlerTests$MockRestTemplate2"/>
|
||||
|
||||
</beans:beans>
|
||||
@@ -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 <T> ResponseEntity<T> exchange(String url, HttpMethod method, HttpEntity<?> requestEntity,
|
||||
Class<T> responseType, Map<String, ?> uriVariables) throws RestClientException {
|
||||
return new ResponseEntity<T>(HttpStatus.OK);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:int-ip="http://www.springframework.org/schema/integration/ip"
|
||||
xmlns:int="http://www.springframework.org/schema/integration"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/integration/ip http://www.springframework.org/schema/integration/ip/spring-integration-ip.xsd
|
||||
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd
|
||||
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
|
||||
|
||||
<bean id="tcpIpUtils" class="org.springframework.integration.ip.util.SocketTestUtils" />
|
||||
|
||||
<int-ip:tcp-connection-factory
|
||||
id="scf"
|
||||
type="server"
|
||||
so-timeout="60000"
|
||||
deserializer=""
|
||||
port="#{tcpIpUtils.findAvailableServerSocket(7000)}"/>
|
||||
|
||||
<int-ip:tcp-inbound-channel-adapter
|
||||
connection-factory="scf"
|
||||
channel="inbound"/>
|
||||
|
||||
<int:channel id="inbound">
|
||||
<int:queue/>
|
||||
</int:channel>
|
||||
|
||||
<int-ip:tcp-connection-factory
|
||||
id="ccf"
|
||||
type="client"
|
||||
host="localhost"
|
||||
port="#{scf.port}"
|
||||
single-use="true"
|
||||
so-timeout="60000"/>
|
||||
|
||||
<int:chain input-channel="tcpOutboundChannelAdapterWithinChain">
|
||||
<int-ip:tcp-outbound-channel-adapter connection-factory="ccf"/>
|
||||
</int:chain>
|
||||
|
||||
|
||||
</beans>
|
||||
@@ -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<String>(testPayload));
|
||||
Message<?> m = inbound.receive(1000);
|
||||
assertNotNull(m);
|
||||
assertEquals(testPayload, new String((byte[]) m.getPayload()));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans:beans xmlns="http://www.springframework.org/schema/integration"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:beans="http://www.springframework.org/schema/beans"
|
||||
xmlns:stream="http://www.springframework.org/schema/integration/stream"
|
||||
xmlns:ip="http://www.springframework.org/schema/integration/ip"
|
||||
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/stream
|
||||
http://www.springframework.org/schema/integration/stream/spring-integration-stream.xsd
|
||||
http://www.springframework.org/schema/integration/ip
|
||||
http://www.springframework.org/schema/integration/ip/spring-integration-ip.xsd">
|
||||
|
||||
<stream:stdin-channel-adapter id="stdin" channel="outputChannel" >
|
||||
<poller fixed-delay="100"/>
|
||||
</stream:stdin-channel-adapter>
|
||||
|
||||
<channel id="inputChannel"/>
|
||||
|
||||
<channel id="outputChannel" />
|
||||
|
||||
<service-activator input-channel="inputChannel"
|
||||
output-channel="outputChannel"
|
||||
ref="testIp"
|
||||
method="testIp"/>
|
||||
|
||||
<chain input-channel="outputChannel">
|
||||
<ip:udp-outbound-channel-adapter host="localhost"
|
||||
port="11111"
|
||||
check-length="true"
|
||||
acknowledge="true"
|
||||
ack-host="localhost"
|
||||
ack-port="22223"
|
||||
ack-timeout="10000"/>
|
||||
</chain>
|
||||
|
||||
|
||||
<beans:import resource="testIp-common-context.xml" />
|
||||
|
||||
</beans:beans>
|
||||
@@ -705,17 +705,6 @@
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="return-value-required" default="false">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
Indicates whether this procedure's return value
|
||||
should be included.
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
<xsd:simpleType>
|
||||
<xsd:union memberTypes="xsd:boolean xsd:string" />
|
||||
</xsd:simpleType>
|
||||
</xsd:attribute>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
|
||||
@@ -1313,4 +1302,4 @@
|
||||
<xsd:enumeration value="INOUT"/>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
</xsd:schema>
|
||||
</xsd:schema>
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:int="http://www.springframework.org/schema/integration"
|
||||
xmlns:jdbc="http://www.springframework.org/schema/jdbc"
|
||||
xmlns:int-jdbc="http://www.springframework.org/schema/integration/jdbc"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc.xsd
|
||||
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd
|
||||
http://www.springframework.org/schema/integration/jdbc http://www.springframework.org/schema/integration/jdbc/spring-integration-jdbc.xsd
|
||||
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
|
||||
|
||||
<jdbc:embedded-database id="dataSource" type="DERBY">
|
||||
<jdbc:script location="classpath:derby-stored-procedures.sql"/>
|
||||
</jdbc:embedded-database>
|
||||
|
||||
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
|
||||
<constructor-arg ref="dataSource" />
|
||||
</bean>
|
||||
|
||||
<int:chain input-channel="jdbcStoredProcOutboundChannelAdapterWithinChain">
|
||||
<int-jdbc:stored-proc-outbound-channel-adapter stored-procedure-name="CREATE_USER" data-source="dataSource">
|
||||
<int-jdbc:parameter name="username" expression="payload.username"/>
|
||||
<int-jdbc:parameter name="password" expression="payload.password"/>
|
||||
<int-jdbc:parameter name="email" expression="payload.email"/>
|
||||
</int-jdbc:stored-proc-outbound-channel-adapter>
|
||||
</int:chain>
|
||||
|
||||
|
||||
</beans>
|
||||
@@ -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<User> message = MessageBuilder.withPayload(new User("username", "password", "email")).build();
|
||||
this.jdbcStoredProcOutboundChannelAdapterWithinChain.send(message);
|
||||
|
||||
Map<String, Object> 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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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<String, Object> 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){
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans:beans xmlns="http://www.springframework.org/schema/integration/jdbc"
|
||||
xmlns:si="http://www.springframework.org/schema/integration"
|
||||
xmlns:beans="http://www.springframework.org/schema/beans"
|
||||
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/jdbc
|
||||
http://www.springframework.org/schema/integration/jdbc/spring-integration-jdbc.xsd">
|
||||
|
||||
<si:chain input-channel="target">
|
||||
<outbound-channel-adapter
|
||||
query="insert into foos (id, status, name) values (:headers[business.key], 0, :payload)"
|
||||
jdbc-operations="jdbcTemplate"/>
|
||||
</si:chain>
|
||||
|
||||
<beans:import resource="jdbcOutboundChannelAdapterCommonConfig.xml" />
|
||||
|
||||
</beans:beans>
|
||||
@@ -0,0 +1,31 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:int="http://www.springframework.org/schema/integration"
|
||||
xmlns:jms="http://www.springframework.org/schema/integration/jms"
|
||||
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/jms
|
||||
http://www.springframework.org/schema/integration/jms/spring-integration-jms.xsd">
|
||||
|
||||
<int:channel id="receiveChannel">
|
||||
<int:queue/>
|
||||
</int:channel>
|
||||
|
||||
<int:chain input-channel="outboundChainChannel">
|
||||
<jms:outbound-channel-adapter destination="testQueue"/>
|
||||
</int:chain>
|
||||
|
||||
<jms:message-driven-channel-adapter destination="testQueue" channel="receiveChannel"/>
|
||||
|
||||
<bean id="testQueue" class="org.apache.activemq.command.ActiveMQQueue">
|
||||
<constructor-arg value="test.queue"/>
|
||||
</bean>
|
||||
|
||||
<bean id="connectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">
|
||||
<property name="brokerURL" value="vm://localhost?broker.persistent=false"/>
|
||||
</bean>
|
||||
|
||||
</beans>
|
||||
@@ -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<String> shippedMessage = MessageBuilder.withPayload(testString).build();
|
||||
outboundChainChannel.send(shippedMessage);
|
||||
Message<?> receivedMessage = receiveChannel.receive();
|
||||
assertEquals(testString, receivedMessage.getPayload());
|
||||
context.close();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -24,6 +24,13 @@
|
||||
object-name="test.publisher:name=publisher"
|
||||
default-notification-type="default.type"/>
|
||||
|
||||
|
||||
<si:chain input-channel="publishingWithinChainChannel">
|
||||
<jmx:notification-publishing-channel-adapter
|
||||
object-name="test.publisher:name=publisher-chain"
|
||||
default-notification-type="default.type"/>
|
||||
</si:chain>
|
||||
|
||||
<bean id="testListener" class="org.springframework.integration.jmx.config.TestListener"/>
|
||||
|
||||
</beans>
|
||||
|
||||
@@ -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 {
|
||||
}
|
||||
|
||||
@@ -20,6 +20,22 @@
|
||||
object-name="org.springframework.integration.jmx.config:type=TestBean,name=testBeanAdapter"
|
||||
operation-name="test"/>
|
||||
|
||||
<jmx:operation-invoking-channel-adapter id="operationWithNonNullReturn"
|
||||
object-name="org.springframework.integration.jmx.config:type=TestBean,name=testBeanAdapter"
|
||||
operation-name="testWithReturn"/>
|
||||
|
||||
<bean id="testBeanAdapter" class="org.springframework.integration.jmx.config.TestBean"/>
|
||||
|
||||
<si:chain input-channel="operationInvokingWithinChain">
|
||||
<jmx:operation-invoking-channel-adapter
|
||||
object-name="org.springframework.integration.jmx.config:type=TestBean,name=testBeanAdapter"
|
||||
operation-name="test"/>
|
||||
</si:chain>
|
||||
|
||||
<si:chain input-channel="operationWithinChainWithNonNullReturn">
|
||||
<jmx:operation-invoking-channel-adapter
|
||||
object-name="org.springframework.integration.jmx.config:type=TestBean,name=testBeanAdapter"
|
||||
operation-name="testWithReturn"/>
|
||||
</si:chain>
|
||||
|
||||
</beans>
|
||||
|
||||
@@ -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<String>("test3"));
|
||||
assertEquals(3, testBean.messages.size());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testOutboundAdapterWithNonNullReturn() throws Exception {
|
||||
try {
|
||||
operationWithNonNullReturn.send(new GenericMessage<String>("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 <jmx:operation-invoking-channel-adapter/> 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<String>("test1"));
|
||||
assertEquals(1, testBean.messages.size());
|
||||
}
|
||||
|
||||
@Test //INT-2275
|
||||
public void testOperationWithinChainWithNonNullReturn() throws Exception {
|
||||
try {
|
||||
operationWithinChainWithNonNullReturn.send(new GenericMessage<String>("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 <jmx:operation-invoking-channel-adapter/> refactoring
|
||||
}
|
||||
}
|
||||
|
||||
private Message<?> createMessage(String payload){
|
||||
return MessageBuilder.withPayload(payload)
|
||||
.setHeader(JmxHeaders.OBJECT_NAME, "org.springframework.integration.jmx.config:type=TestBean,name=foo")
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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<byte[]>(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));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,16 +1,18 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:util="http://www.springframework.org/schema/util"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans
|
||||
http://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://www.springframework.org/schema/util
|
||||
http://www.springframework.org/schema/util/spring-util.xsd">
|
||||
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">
|
||||
|
||||
<bean id="javaMailSender" class="org.springframework.integration.mail.StubJavaMailSender">
|
||||
<constructor-arg>
|
||||
<bean class="javax.mail.internet.MimeMessage">
|
||||
<constructor-arg type="javax.mail.Session"><null/></constructor-arg>
|
||||
<constructor-arg type="javax.mail.Session">
|
||||
<null/>
|
||||
</constructor-arg>
|
||||
</bean>
|
||||
</constructor-arg>
|
||||
</bean>
|
||||
@@ -19,4 +21,8 @@
|
||||
<constructor-arg ref="javaMailSender"/>
|
||||
</bean>
|
||||
|
||||
</beans>
|
||||
<int:chain input-channel="sendMailOutboundChainChannel">
|
||||
<int-mail:outbound-channel-adapter mail-sender="javaMailSender"/>
|
||||
</int:chain>
|
||||
|
||||
</beans>
|
||||
|
||||
@@ -26,4 +26,8 @@
|
||||
|
||||
<bean id="testConverter" class="org.springframework.integration.redis.config.RedisOutboundChannelAdapterParserTests$TestMessageConverter"/>
|
||||
|
||||
<int:chain input-channel="redisOutboudChain">
|
||||
<int-redis:outbound-channel-adapter topic="foo"/>
|
||||
</int:chain>
|
||||
|
||||
</beans>
|
||||
|
||||
@@ -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<String>("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 {
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:si="http://www.springframework.org/schema/integration"
|
||||
xmlns:sftp="http://www.springframework.org/schema/integration/sftp"
|
||||
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/sftp
|
||||
http://www.springframework.org/schema/integration/sftp/spring-integration-sftp.xsd">
|
||||
|
||||
|
||||
<si:chain input-channel="outboundChainChannel">
|
||||
<sftp:outbound-channel-adapter
|
||||
auto-create-directory="true"
|
||||
session-factory="sftpSessionFactory"
|
||||
remote-directory="remote-target-dir"/>
|
||||
</si:chain>
|
||||
|
||||
<bean id="sftpSessionFactory"
|
||||
class="org.springframework.integration.sftp.outbound.SftpSendingMessageHandlerTests$TestSftpSessionFactory"/>
|
||||
|
||||
</beans>
|
||||
@@ -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<File>(srcFile));
|
||||
assertTrue("destination file was not created", destFile.exists());
|
||||
}
|
||||
|
||||
public static class TestSftpSessionFactory extends DefaultSftpSessionFactory {
|
||||
|
||||
|
||||
@@ -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<String>("foo"));
|
||||
assertEquals("foobar", out.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,4 +20,11 @@
|
||||
|
||||
<stdout-channel-adapter id="newlineAdapter" append-newline="true" channel="testChannel"/>
|
||||
|
||||
</beans:beans>
|
||||
<integration:chain input-channel="stdoutInsideNestedChain">
|
||||
<integration:transformer expression="payload + 'bar'"/>
|
||||
<integration:chain>
|
||||
<stdout-channel-adapter/>
|
||||
</integration:chain>
|
||||
</integration:chain>
|
||||
|
||||
</beans:beans>
|
||||
|
||||
@@ -33,6 +33,10 @@
|
||||
|
||||
<twitter:dm-outbound-channel-adapter twitter-template="twitterTemplate" channel="inputChannel"/>
|
||||
|
||||
<chain input-channel="dmOutboundWithinChain">
|
||||
<twitter:dm-outbound-channel-adapter twitter-template="twitterTemplate"/>
|
||||
</chain>
|
||||
|
||||
</beans:beans>
|
||||
|
||||
|
||||
|
||||
@@ -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<String> mb = MessageBuilder.withPayload("Hello world!");
|
||||
|
||||
if (StringUtils.hasText(dmUsr)) {
|
||||
mb.setHeader(TwitterHeaders.DM_TARGET_USER_ID, dmUsr);
|
||||
}
|
||||
dmOutboundWithinChain.send(mb.build());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -32,7 +32,11 @@
|
||||
<channel id="out"/>
|
||||
|
||||
<twitter:outbound-channel-adapter twitter-template="twitterTemplate" channel="out"/>
|
||||
|
||||
|
||||
<chain input-channel="outFromChain">
|
||||
<twitter:outbound-channel-adapter twitter-template="twitterTemplate"/>
|
||||
</chain>
|
||||
|
||||
</beans:beans>
|
||||
|
||||
|
||||
|
||||
@@ -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<String> m = MessageBuilder.withPayload("Early start today" + new Date(System.currentTimeMillis())).build();
|
||||
this.outFromChain.send(m);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -43,4 +43,8 @@
|
||||
xmpp-connection="testConnection">
|
||||
</int-xmpp:outbound-channel-adapter>
|
||||
|
||||
<int:chain input-channel="outboundChainChannel">
|
||||
<int-xmpp:outbound-channel-adapter xmpp-connection="testConnection"/>
|
||||
</int:chain>
|
||||
|
||||
</beans>
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -57,7 +57,7 @@
|
||||
<para>
|
||||
The <chain> element provides an <code>input-channel</code> attribute, and if the last element in the chain is capable
|
||||
of producing reply messages (optional), it also supports an <code>output-channel</code> 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.
|
||||
<programlisting language="xml"><![CDATA[ <int:chain input-channel="input" output-channel="output">
|
||||
<int:filter ref="someSelector" throw-exception-on-rejection="true"/>
|
||||
<int:header-enricher>
|
||||
@@ -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.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
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>:
|
||||
<programlisting language="xml"><![CDATA[ <int:chain input-channel="input">
|
||||
<si-xml:marshalling-transformer marshaller="marshaller" result-type="StringResult" />
|
||||
<int:service-activator ref="someService" method="someMethod"/>
|
||||
<int:header-enricher>
|
||||
<int:header name="foo" value="bar"/>
|
||||
</int:header-enricher>
|
||||
<int:logging-channel-adapter level="INFO" log-full-message="true"/>
|
||||
</int:chain>]]></programlisting>
|
||||
</para>
|
||||
<para>
|
||||
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.
|
||||
|
||||
Reference in New Issue
Block a user