INT-1029: Support for outbound-gateways in chain

XSD refactoring: remove use="required" from 'request-channel' attribute of all 'outbound-gateways'
Tests for all 'outbound-gateways' inside the <chain>
This commit is contained in:
Artem Bilan
2012-06-07 15:03:39 +03:00
committed by Oleg Zhurakousky
parent c3860e14b7
commit 5bc41bc60b
37 changed files with 731 additions and 214 deletions

View File

@@ -135,7 +135,7 @@
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="request-channel" use="required" type="xsd:string">
<xsd:attribute name="request-channel" type="xsd:string">
<xsd:annotation>
<xsd:documentation>
Message Channel to which Messages should be sent in order to have them converted and published to an AMQP Exchange.

View File

@@ -13,44 +13,45 @@
reply-channel="fromRabbit"
exchange-name="si.test.exchange"
routing-key="si.test.binding"
amqp-template="amqpTemplate"
amqp-template="amqpTemplate"
order="5"
return-channel="returnChannel"/>
<rabbit:template id="amqpTemplate" connection-factory="connectionFactory"/>
<bean id="connectionFactory" class="org.mockito.Mockito" factory-method="mock">
<constructor-arg value="org.springframework.amqp.rabbit.connection.ConnectionFactory"/>
</bean>
<int:channel id="toRabbit"/>
<int:channel id="fromRabbit">
<int:queue/>
</int:channel>
<amqp:outbound-gateway id="withHeaderMapperCustomRequestResponse" request-channel="toRabbit"
reply-channel="fromRabbit"
exchange-name="si.test.exchange"
routing-key="si.test.binding"
amqp-template="amqpTemplate"
amqp-template="amqpTemplate"
order="5"
mapped-request-headers="foo*"
mapped-reply-headers="bar*"/>
<amqp:outbound-gateway id="withHeaderMapperCustomAndStandardResponse" request-channel="toRabbit"
reply-channel="fromRabbit"
exchange-name="si.test.exchange"
routing-key="si.test.binding"
amqp-template="amqpTemplate"
amqp-template="amqpTemplate"
order="5"
mapped-request-headers="foo*"
mapped-reply-headers="bar*, STANDARD_REPLY_HEADERS"/>
<amqp:outbound-gateway id="withHeaderMapperNothingToMap" request-channel="toRabbit"
reply-channel="fromRabbit"
exchange-name="si.test.exchange"
routing-key="si.test.binding"
amqp-template="amqpTemplate"
amqp-template="amqpTemplate"
order="5"
mapped-request-headers=""
mapped-reply-headers=""/>
@@ -59,4 +60,12 @@
<int:queue/>
</int:channel>
<int:chain id="chainWithRabbitOutboundGateway" input-channel="toRabbit" output-channel="fromRabbit">
<amqp:outbound-gateway exchange-name="si.test.exchange"
routing-key="si.test.binding"
amqp-template="amqpTemplate"
mapped-request-headers=""
mapped-reply-headers=""/>
</int:chain>
</beans>

View File

@@ -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,6 +16,7 @@
package org.springframework.integration.amqp.config;
import java.lang.reflect.Field;
import java.util.List;
import org.junit.Test;
import org.mockito.Mockito;
@@ -44,6 +45,7 @@ import static org.junit.Assert.assertTrue;
/**
* @author Oleg Zhurakousky
* @author Gary Russell
* @author Artem Bilan
* @since 2.1
*
*/
@@ -61,20 +63,20 @@ public class AmqpOutboundGatewayParserTests {
MessageChannel returnChannel = context.getBean("returnChannel", MessageChannel.class);
assertSame(returnChannel, TestUtils.getPropertyValue(gateway, "returnChannel"));
}
@SuppressWarnings("rawtypes")
@Test
public void withHeaderMapperCustomRequestResponse() {
ApplicationContext context = new ClassPathXmlApplicationContext("AmqpOutboundGatewayParserTests-context.xml", this.getClass());
Object eventDrivernConsumer = context.getBean("withHeaderMapperCustomRequestResponse");
AmqpOutboundEndpoint endpoint = TestUtils.getPropertyValue(eventDrivernConsumer, "handler", AmqpOutboundEndpoint.class);
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();
@@ -95,9 +97,9 @@ public class AmqpOutboundGatewayParserTests {
MessageChannel requestChannel = context.getBean("toRabbit", MessageChannel.class);
Message<?> message = MessageBuilder.withPayload("hello").setHeader("foo", "foo").build();
requestChannel.send(message);
Mockito.verify(amqpTemplate, Mockito.times(1)).sendAndReceive(Mockito.any(String.class), Mockito.any(String.class), Mockito.any(org.springframework.amqp.core.Message.class));
// verify reply
QueueChannel queueChannel = context.getBean("fromRabbit", QueueChannel.class);
Message<?> replyMessage = queueChannel.receive(0);
@@ -108,20 +110,20 @@ public class AmqpOutboundGatewayParserTests {
assertNull(replyMessage.getHeaders().get(AmqpHeaders.CONTENT_TYPE));
assertNull(replyMessage.getHeaders().get(AmqpHeaders.APP_ID));
}
@SuppressWarnings("rawtypes")
@Test
public void withHeaderMapperCustomAndStandardResponse() {
ApplicationContext context = new ClassPathXmlApplicationContext("AmqpOutboundGatewayParserTests-context.xml", this.getClass());
Object eventDrivernConsumer = context.getBean("withHeaderMapperCustomAndStandardResponse");
AmqpOutboundEndpoint endpoint = TestUtils.getPropertyValue(eventDrivernConsumer, "handler", AmqpOutboundEndpoint.class);
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();
@@ -142,9 +144,9 @@ public class AmqpOutboundGatewayParserTests {
MessageChannel requestChannel = context.getBean("toRabbit", MessageChannel.class);
Message<?> message = MessageBuilder.withPayload("hello").setHeader("foo", "foo").build();
requestChannel.send(message);
Mockito.verify(amqpTemplate, Mockito.times(1)).sendAndReceive(Mockito.any(String.class), Mockito.any(String.class), Mockito.any(org.springframework.amqp.core.Message.class));
// verify reply
QueueChannel queueChannel = context.getBean("fromRabbit", QueueChannel.class);
Message<?> replyMessage = queueChannel.receive(0);
@@ -155,20 +157,20 @@ public class AmqpOutboundGatewayParserTests {
assertNotNull(replyMessage.getHeaders().get(AmqpHeaders.CONTENT_TYPE));
assertNotNull(replyMessage.getHeaders().get(AmqpHeaders.APP_ID));
}
@SuppressWarnings("rawtypes")
@Test
public void withHeaderMapperNothingToMap() {
ApplicationContext context = new ClassPathXmlApplicationContext("AmqpOutboundGatewayParserTests-context.xml", this.getClass());
Object eventDrivernConsumer = context.getBean("withHeaderMapperNothingToMap");
AmqpOutboundEndpoint endpoint = TestUtils.getPropertyValue(eventDrivernConsumer, "handler", AmqpOutboundEndpoint.class);
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();
@@ -189,9 +191,9 @@ public class AmqpOutboundGatewayParserTests {
MessageChannel requestChannel = context.getBean("toRabbit", MessageChannel.class);
Message<?> message = MessageBuilder.withPayload("hello").setHeader("foo", "foo").build();
requestChannel.send(message);
Mockito.verify(amqpTemplate, Mockito.times(1)).sendAndReceive(Mockito.any(String.class), Mockito.any(String.class), Mockito.any(org.springframework.amqp.core.Message.class));
// verify reply
QueueChannel queueChannel = context.getBean("fromRabbit", QueueChannel.class);
Message<?> replyMessage = queueChannel.receive(0);
@@ -202,4 +204,55 @@ public class AmqpOutboundGatewayParserTests {
assertNull(replyMessage.getHeaders().get(AmqpHeaders.CONTENT_TYPE));
assertNull(replyMessage.getHeaders().get(AmqpHeaders.APP_ID));
}
@Test //INT-1029
public void amqpOutboundGatewayWithinChain() {
ApplicationContext context = new ClassPathXmlApplicationContext("AmqpOutboundGatewayParserTests-context.xml", this.getClass());
Object eventDrivernConsumer = context.getBean("chainWithRabbitOutboundGateway");
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 amqpRequestMessage = (org.springframework.amqp.core.Message) args[2];
MessageProperties properties = amqpRequestMessage.getMessageProperties();
assertNull(properties.getHeaders().get("foo"));
// mock reply AMQP message
MessageProperties amqpProperties = new MessageProperties();
amqpProperties.setAppId("test.appId");
amqpProperties.setHeader("foobar", "foobar");
amqpProperties.setHeader("bar", "bar");
return new org.springframework.amqp.core.Message("hello".getBytes(), amqpProperties);
}})
.when(amqpTemplate).sendAndReceive(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("toRabbit", MessageChannel.class);
Message<?> message = MessageBuilder.withPayload("hello").setHeader("foo", "foo").build();
requestChannel.send(message);
Mockito.verify(amqpTemplate, Mockito.times(1)).sendAndReceive(Mockito.any(String.class), Mockito.any(String.class), Mockito.any(org.springframework.amqp.core.Message.class));
// verify reply
QueueChannel queueChannel = context.getBean("fromRabbit", QueueChannel.class);
Message<?> replyMessage = queueChannel.receive(0);
assertEquals("hello", new String((byte[]) replyMessage.getPayload()));
assertNull(replyMessage.getHeaders().get("bar"));
assertEquals("foo", replyMessage.getHeaders().get("foo")); // copied from request Message
assertNull(replyMessage.getHeaders().get("foobar"));
assertNull(replyMessage.getHeaders().get(AmqpHeaders.DELIVERY_MODE));
assertNull(replyMessage.getHeaders().get(AmqpHeaders.CONTENT_TYPE));
assertNull(replyMessage.getHeaders().get(AmqpHeaders.APP_ID));
}
}

View File

@@ -47,7 +47,7 @@
<xsd:attribute name="id" type="xsd:string">
<xsd:annotation>
<xsd:documentation><![CDATA[Identifies the underlying Spring bean definition (SourcePollingChannelAdapter)
Keep in mind that if no "channel" attribute is defined, then the "id" attribute is required.
In that case the "id" attribute's value will be used as the channel name and ".adapter" will be
appended to the "id" value of the underlying bean definition.
@@ -57,9 +57,9 @@
<xsd:attribute name="channel" type="xsd:string">
<xsd:annotation>
<xsd:documentation><![CDATA[Defines the message channel to which the payload shall be forwarded to.
Keep in mind that any Channel Adapter can be created without a "channel" reference in which case
it will implicitly create an instance of DirectChannel. The created channel's name will match
Keep in mind that any Channel Adapter can be created without a "channel" reference in which case
it will implicitly create an instance of DirectChannel. The created channel's name will match
the "id" attribute of the <inbound-channel-adapter/> element. Therefore, if the "channel" attribute
is not provided, then the "id" attribute is required.
]]></xsd:documentation>
@@ -74,7 +74,7 @@
<xsd:annotation>
<xsd:documentation><![CDATA[Specifies the input directory (The directory to poll from) e.g.:
directory="file:/absolute/input" or directory="file:relative/input"]]></xsd:documentation>
</xsd:annotation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="comparator" type="xsd:string">
<xsd:annotation>
@@ -87,11 +87,11 @@
<xsd:attribute name="filter" type="xsd:string">
<xsd:annotation>
<xsd:documentation><![CDATA[
Specify a FileListFilter to be used. By default, an AcceptOnceFileListFilter is used,
Specify a FileListFilter to be used. By default, an AcceptOnceFileListFilter is used,
which ensures files are picked up only once from the directory.
You can also apply multiple filters by referencing a CompositeFileListFilter.
]]></xsd:documentation>
]]></xsd:documentation>
<xsd:appinfo>
<tool:annotation kind="ref">
<tool:expected-type type="org.springframework.integration.file.filters.FileListFilter"/>
@@ -144,7 +144,7 @@ Only files matching this regular expression will be picked up by this adapter.
<xsd:documentation>
Lifecycle attribute signaling if this component should be started during Application Context startup.
</xsd:documentation>
</xsd:annotation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="auto-create-directory" type="xsd:string" default="true">
<xsd:annotation>
@@ -174,7 +174,7 @@ Only files matching this regular expression will be picked up by this adapter.
<xsd:documentation>
Configures an outbound Channel Adapter that writes Message payloads to a File.
</xsd:documentation>
</xsd:annotation>
</xsd:annotation>
<xsd:complexType>
<xsd:complexContent>
<xsd:extension base="outboundFileBaseType">
@@ -199,11 +199,11 @@ Only files matching this regular expression will be picked up by this adapter.
Configures an outbound Gateway that writes request Message payloads to a File and then generates a
reply Message containing the newly written File as its payload.
</xsd:documentation>
</xsd:annotation>
</xsd:annotation>
<xsd:complexType>
<xsd:complexContent>
<xsd:extension base="outboundFileBaseType">
<xsd:attribute name="request-channel" type="xsd:string" use="required">
<xsd:attribute name="request-channel" type="xsd:string">
<xsd:annotation>
<xsd:documentation>The channel through which outgoing messages will arrive.</xsd:documentation>
<xsd:appinfo>
@@ -216,7 +216,7 @@ Only files matching this regular expression will be picked up by this adapter.
<xsd:attribute name="reply-channel" type="xsd:string">
<xsd:annotation>
<xsd:documentation>
<![CDATA[After writing the File, it will be sent to the specified reply channel as the payload of a Message.
<![CDATA[After writing the File, it will be sent to the specified reply channel as the payload of a Message.
Another way of providing the 'reply-channel' is by setting the MessageHeaders.REPLY_CHANNEL Message Header]]>
</xsd:documentation>
<xsd:appinfo>
@@ -244,15 +244,15 @@ Only files matching this regular expression will be picked up by this adapter.
<xsd:annotation>
<xsd:documentation><![CDATA[Specifies the output directory, e.g.:
directory="file:/absolute/output" or directory="file:relative/output"]]></xsd:documentation>
</xsd:annotation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="filename-generator" type="xsd:string">
<xsd:annotation>
<xsd:documentation>
<![CDATA[Allows you to provide a reference to the FileNameGenerator strategy
<![CDATA[Allows you to provide a reference to the FileNameGenerator strategy
to use when generating the destination file's name. If not specified the
DefaultFileNameGenerator is used.]]>
</xsd:documentation>
</xsd:documentation>
<xsd:appinfo>
<tool:annotation kind="ref">
<tool:expected-type type="org.springframework.integration.file.FileNameGenerator"/>
@@ -263,7 +263,7 @@ Only files matching this regular expression will be picked up by this adapter.
<xsd:attribute name="filename-generator-expression" type="xsd:string">
<xsd:annotation>
<xsd:documentation>
Allows you to provide a SpEL expression which will compute the file name of
Allows you to provide a SpEL expression which will compute the file name of
the target file (e.g., assuming payload is java.io.File "payload.name + '.transferred'");
</xsd:documentation>
</xsd:annotation>
@@ -306,18 +306,18 @@ Only files matching this regular expression will be picked up by this adapter.
<xsd:documentation>
<![CDATA[Lifecycle attribute signaling if this component should be started during Application Context startup.]]>
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="charset" type="xsd:string">
<xsd:annotation>
<xsd:documentation>
<![CDATA[Set the charset name to use when writing a File from a String-based
Message payload, e.g. charset="UTF-8". If not set, the default charset of this
<![CDATA[Set the charset name to use when writing a File from a String-based
Message payload, e.g. charset="UTF-8". If not set, the default charset of this
Java virtual machine is used.
]]>
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
</xsd:annotation>
</xsd:attribute>
</xsd:complexType>
<xsd:element name="file-to-string-transformer">
@@ -332,11 +332,11 @@ Only files matching this regular expression will be picked up by this adapter.
<xsd:attribute name="charset" type="xsd:string">
<xsd:annotation>
<xsd:documentation>
<![CDATA[Set the charset name to use when converting a File
payload to a String, e.g. charset="UTF-8". If not set, the default charset of this
<![CDATA[Set the charset name to use when converting a File
payload to a String, e.g. charset="UTF-8". If not set, the default charset of this
Java virtual machine is used.]]>
</xsd:documentation>
</xsd:annotation>
</xsd:annotation>
</xsd:attribute>
</xsd:extension>
</xsd:complexContent>
@@ -348,7 +348,7 @@ Only files matching this regular expression will be picked up by this adapter.
<xsd:documentation>
Creates a Transformer that converts a File payload to an array of bytes.
</xsd:documentation>
</xsd:annotation>
</xsd:annotation>
<xsd:complexType>
<xsd:complexContent>
<xsd:extension base="transformerType"/>
@@ -366,7 +366,7 @@ Only files matching this regular expression will be picked up by this adapter.
<xsd:annotation>
<xsd:documentation>
<![CDATA[The input channel of the transformer.]]>
</xsd:documentation>
</xsd:documentation>
<xsd:appinfo>
<tool:annotation kind="ref">
<tool:expected-type type="org.springframework.integration.MessageChannel"/>
@@ -377,10 +377,10 @@ Only files matching this regular expression will be picked up by this adapter.
<xsd:attribute name="output-channel" type="xsd:string">
<xsd:annotation>
<xsd:documentation>
<![CDATA[The channel to which the transformer will send the transformed message.
Optional, because incoming messages can specify a reply channel using the 'replyChannel'
<![CDATA[The channel to which the transformer will send the transformed message.
Optional, because incoming messages can specify a reply channel using the 'replyChannel'
message header value themselves.]]>
</xsd:documentation>
</xsd:documentation>
<xsd:appinfo>
<tool:annotation kind="ref">
<tool:expected-type type="org.springframework.integration.MessageChannel"/>
@@ -391,27 +391,27 @@ Only files matching this regular expression will be picked up by this adapter.
<xsd:attribute name="delete-files" type="xsd:string">
<xsd:annotation>
<xsd:documentation>
<![CDATA[The delete-files option signals to the transformer that it should delete the
<![CDATA[The delete-files option signals to the transformer that it should delete the
inbound File after the transformation is complete.]]>
</xsd:documentation>
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
</xsd:attribute>
</xsd:complexType>
<xsd:element name="locker">
<xsd:annotation>
<xsd:documentation>
<![CDATA[When multiple processes are reading from the same
directory it can be desirable to lock files to prevent them
<![CDATA[When multiple processes are reading from the same
directory it can be desirable to lock files to prevent them
from being picked up concurrently. To do this you can specify a reference to a FileLocker.]]>
</xsd:documentation>
</xsd:documentation>
</xsd:annotation>
<xsd:complexType>
<xsd:attribute name="ref" type="xsd:string">
<xsd:annotation>
<xsd:documentation>
<![CDATA[The reference to the FileLocker.]]>
</xsd:documentation>
</xsd:documentation>
<xsd:appinfo>
<tool:annotation kind="ref">
<tool:expected-type type="org.springframework.integration.file.FileLocker"/>
@@ -425,8 +425,8 @@ Only files matching this regular expression will be picked up by this adapter.
<xsd:element name="nio-locker">
<xsd:annotation>
<xsd:documentation>
<![CDATA[When multiple processes are reading from the same directory
it can be desirable to lock files to prevent them from being picked up
<![CDATA[When multiple processes are reading from the same directory
it can be desirable to lock files to prevent them from being picked up
concurrently. This is a java.nio based implementation available out of the box.]]>
</xsd:documentation>
</xsd:annotation>

View File

@@ -27,11 +27,15 @@
directory="${java.io.tmpdir}/anyDir" />
<outbound-gateway id="mover"
request-channel="moveInput"
request-channel="moveInput"
reply-channel="output"
directory="${java.io.tmpdir}/anyDir"
directory="${java.io.tmpdir}/anyDir"
delete-source-files="true"/>
<si:chain input-channel="fileOutboundGatewayInsideChain" output-channel="output">
<outbound-gateway directory="${java.io.tmpdir}/anyDir" delete-source-files="true"/>
</si:chain>
<!--suppress SpringModelInspection -->
<context:property-placeholder />

View File

@@ -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.
@@ -47,13 +47,12 @@ import org.springframework.util.FileCopyUtils;
/**
* @author Alex Peters
* @author Mark Fisher
* @author Artem Bilan
*/
@ContextConfiguration
@RunWith(SpringJUnit4ClassRunner.class)
public class FileOutboundGatewayIntegrationTests {
FileWritingMessageHandler handler;
@Qualifier("copyInput")
@Autowired
MessageChannel copyInputChannel;
@@ -62,6 +61,10 @@ public class FileOutboundGatewayIntegrationTests {
@Autowired
MessageChannel moveInputChannel;
@Qualifier("moveInput")
@Autowired
MessageChannel fileOutboundGatewayInsideChain;
@Qualifier("output")
@Autowired
QueueChannel outputChannel;
@@ -145,4 +148,18 @@ public class FileOutboundGatewayIntegrationTests {
assertThat(payloadFile.exists(), is(true));
}
@Test //INT-1029
public void moveInsideTheChain() throws Exception {
fileOutboundGatewayInsideChain.send(message);
List<Message<?>> result = outputChannel.clear();
assertThat(result.size(), is(1));
Message<?> resultMessage = result.get(0);
File payloadFile = (File) resultMessage.getPayload();
assertThat(payloadFile, is(not(sourceFile)));
assertThat(resultMessage.getHeaders().get(FileHeaders.ORIGINAL_FILE, File.class),
is(sourceFile));
assertThat(sourceFile.exists(), is(false));
assertThat(payloadFile.exists(), is(true));
}
}

View File

@@ -115,7 +115,7 @@
<xsd:element name="inbound-channel-adapter">
<xsd:annotation>
<xsd:documentation><![CDATA[
Builds an inbound-channel-adapter that synchronizes a local directory with the contents of a remote FTP endpoint.
Builds an inbound-channel-adapter that synchronizes a local directory with the contents of a remote FTP endpoint.
]]></xsd:documentation>
</xsd:annotation>
<xsd:complexType>
@@ -264,8 +264,7 @@
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="request-channel" use="required"
type="xsd:string">
<xsd:attribute name="request-channel" type="xsd:string">
<xsd:annotation>
<xsd:appinfo>
<tool:annotation kind="ref">
@@ -403,8 +402,8 @@
</tool:annotation>
</xsd:appinfo>
<xsd:documentation>
Identifies channel attached to this adapter. Depending on the type of the adapter
this channel could be the receiving channel (e.g., outbound-channel-adapter) or channel where
Identifies channel attached to this adapter. Depending on the type of the adapter
this channel could be the receiving channel (e.g., outbound-channel-adapter) or channel where
messages will be sent to by this adapter (e.g., inbound-channel-adapter).
</xsd:documentation>
</xsd:annotation>
@@ -419,7 +418,7 @@
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
<xsd:complexType name="base-adapter-type">
<xsd:attribute name="id" type="xsd:string" />
<xsd:attribute name="session-factory" type="xsd:string"
@@ -478,6 +477,6 @@
</xsd:annotation>
</xsd:attribute>
</xsd:complexType>
</xsd:schema>

View File

@@ -1,13 +1,10 @@
<?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
@@ -22,9 +19,21 @@
</si:chain>
<bean id="ftpSessionFactory"
class="org.springframework.integration.ftp.outbound.FtpSendingMessageHandlerTests$TestFtpSessionFactory">
class="org.springframework.integration.ftp.outbound.FtpOutboundTests$TestFtpSessionFactory">
<property name="username" value="kermit"/>
<property name="password" value="frog"/>
<property name="host" value="foo.com"/>
</bean>
<si:channel id="output">
<si:queue/>
</si:channel>
<si:chain input-channel="ftpOutboundGatewayInsideChain" output-channel="output">
<ftp:outbound-gateway session-factory="ftpSessionFactory"
command="ls"
expression="payload"/>
</si:chain>
</beans>

View File

@@ -16,6 +16,7 @@
package org.springframework.integration.ftp.outbound;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertTrue;
import static org.mockito.Mockito.mock;
@@ -24,6 +25,8 @@ import static org.mockito.Mockito.when;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.*;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
@@ -37,21 +40,24 @@ 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.core.PollableChannel;
import org.springframework.integration.file.FileNameGenerator;
import org.springframework.integration.file.remote.FileInfo;
import org.springframework.integration.file.remote.handler.FileTransferringMessageHandler;
import org.springframework.integration.ftp.session.AbstractFtpSessionFactory;
import org.springframework.integration.message.GenericMessage;
import org.springframework.integration.support.MessageBuilder;
import org.springframework.util.FileCopyUtils;
/**
* @author Oleg Zhurakousky
* @author Artem Bilan
*/
public class FtpSendingMessageHandlerTests {
public class FtpOutboundTests {
private static FTPClient ftpClient;
private TestFtpSessionFactory sessionFactory;
@Before
public void prepare(){
ftpClient = mock(FTPClient.class);
@@ -71,7 +77,7 @@ public class FtpSendingMessageHandlerTests {
assertFalse(file.exists());
FileTransferringMessageHandler<FTPFile> handler = new FileTransferringMessageHandler<FTPFile>(sessionFactory);
handler.setRemoteDirectoryExpression(new LiteralExpression("remote-target-dir"));
handler.setFileNameGenerator(new FileNameGenerator() {
handler.setFileNameGenerator(new FileNameGenerator() {
public String generateFileName(Message<?> message) {
return "handlerContent.test";
}
@@ -90,7 +96,7 @@ public class FtpSendingMessageHandlerTests {
assertFalse(file.exists());
FileTransferringMessageHandler<FTPFile> handler = new FileTransferringMessageHandler<FTPFile>(sessionFactory);
handler.setRemoteDirectoryExpression(new LiteralExpression("remote-target-dir"));
handler.setFileNameGenerator(new FileNameGenerator() {
handler.setFileNameGenerator(new FileNameGenerator() {
public String generateFileName(Message<?> message) {
return "handlerContent.test";
}
@@ -99,7 +105,7 @@ public class FtpSendingMessageHandlerTests {
handler.handleMessage(new GenericMessage<byte[]>("hello".getBytes()));
assertTrue(file.exists());
}
@Test
public void testHandleFileMessage() throws Exception {
File targetDir = new File("remote-target-dir");
@@ -135,7 +141,7 @@ public class FtpSendingMessageHandlerTests {
File destFile = new File(targetDir, srcFile.getName());
destFile.deleteOnExit();
ApplicationContext context = new ClassPathXmlApplicationContext("FtpOutboundChannelAdapterInsideChainTests-context.xml", getClass());
ApplicationContext context = new ClassPathXmlApplicationContext("FtpOutboundInsideChainTests-context.xml", getClass());
MessageChannel channel = context.getBean("outboundChainChannel", MessageChannel.class);
@@ -143,6 +149,28 @@ public class FtpSendingMessageHandlerTests {
assertTrue("destination file was not created", destFile.exists());
}
@Test //INT-2275
public void testFtpOutboundGatewayInsideChain() throws Exception {
ApplicationContext context = new ClassPathXmlApplicationContext("FtpOutboundInsideChainTests-context.xml", getClass());
MessageChannel channel = context.getBean("ftpOutboundGatewayInsideChain", MessageChannel.class);
channel.send(MessageBuilder.withPayload("remote-test-dir").build());
PollableChannel output = context.getBean("output", PollableChannel.class);
Message<?> result = output.receive();
Object payload = result.getPayload();
assertTrue(payload instanceof List<?>);
@SuppressWarnings("unchecked")
List<? extends FileInfo> remoteFiles = (List<? extends FileInfo>) payload;
assertEquals(3, remoteFiles.size());
List<String> files = Arrays.asList(new File("remote-test-dir").list());
for (FileInfo remoteFile : remoteFiles) {
assertTrue(files.contains(remoteFile.getFilename()));
}
}
public static class TestFtpSessionFactory extends AbstractFtpSessionFactory<FTPClient> {
@@ -170,6 +198,17 @@ public class FtpSendingMessageHandlerTests {
return true;
}
});
String[] files = new File("remote-test-dir").list();
Collection<Object> ftpFiles = new ArrayList<Object>();
for (String fileName : files) {
FTPFile file = new FTPFile();
file.setName(fileName);
file.setType(FTPFile.FILE_TYPE);
file.setTimestamp(Calendar.getInstance());
ftpFiles.add(file);
when(ftpClient.retrieveFile(Mockito.eq("remote-test-dir/" + fileName) , Mockito.any(OutputStream.class))).thenReturn(true);
}
when(ftpClient.listFiles("remote-test-dir/")).thenReturn(ftpFiles.toArray(new FTPFile[]{}));
return ftpClient;
} catch (Exception e) {
throw new RuntimeException("Failed to create mock client", e);

View File

@@ -163,6 +163,15 @@ The String "HTTP_REQUEST_HEADERS" will match against any of the standard HTTP Re
<xsd:sequence>
<xsd:element name="header" type="headerType" minOccurs="0" maxOccurs="unbounded" />
</xsd:sequence>
<xsd:attribute name="request-channel" type="xsd:string" use="required">
<xsd:annotation>
<xsd:appinfo>
<tool:annotation kind="ref">
<tool:expected-type type="org.springframework.integration.MessageChannel" />
</tool:annotation>
</xsd:appinfo>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="name" type="xsd:string">
<xsd:annotation>
<xsd:documentation>
@@ -491,6 +500,15 @@ The String "HTTP_REQUEST_HEADERS" will match against any of the standard HTTP Re
<xsd:sequence>
<xsd:element name="uri-variable" type="uriVariableType" minOccurs="0" maxOccurs="unbounded" />
</xsd:sequence>
<xsd:attribute name="request-channel" type="xsd:string">
<xsd:annotation>
<xsd:appinfo>
<tool:annotation kind="ref">
<tool:expected-type type="org.springframework.integration.MessageChannel" />
</tool:annotation>
</xsd:appinfo>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="url" type="xsd:string" use="optional">
<xsd:annotation>
<xsd:documentation>
@@ -714,15 +732,6 @@ The String "HTTP_REQUEST_HEADERS" will match against any of the standard HTTP Re
</xsd:documentation>
</xsd:annotation>
<xsd:attribute name="id" type="xsd:string" />
<xsd:attribute name="request-channel" type="xsd:string" use="required">
<xsd:annotation>
<xsd:appinfo>
<tool:annotation kind="ref">
<tool:expected-type type="org.springframework.integration.MessageChannel" />
</tool:annotation>
</xsd:appinfo>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="reply-channel" type="xsd:string">
<xsd:annotation>
<xsd:appinfo>
@@ -734,4 +743,4 @@ The String "HTTP_REQUEST_HEADERS" will match against any of the standard HTTP Re
</xsd:attribute>
</xsd:complexType>
</xsd:schema>
</xsd:schema>

View File

@@ -4,11 +4,9 @@
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">
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<si:chain input-channel="httpOutboundChannelAdapterWithinChain">
<outbound-channel-adapter url="http://localhost/test1" rest-template="restTemplate"/>
@@ -16,4 +14,14 @@
<beans:bean id="restTemplate" class="org.springframework.integration.http.outbound.HttpRequestExecutingMessageHandlerTests$MockRestTemplate2"/>
<si:chain input-channel="httpOutboundGatewayWithinChain" output-channel="replyChannel">
<outbound-gateway url="http://localhost:51235/testApps/httpOutboundGatewayWithinChain"
rest-template="restTemplate"
expected-response-type="java.lang.String"/>
</si:chain>
<si:channel id="replyChannel">
<si:queue/>
</si:channel>
</beans:beans>

View File

@@ -21,6 +21,10 @@ import static junit.framework.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashMap;
@@ -30,6 +34,10 @@ import java.util.concurrent.atomic.AtomicReference;
import javax.xml.transform.Source;
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpServer;
import org.junit.Assert;
import org.junit.Test;
import org.springframework.beans.DirectFieldAccessor;
import org.springframework.context.ApplicationContext;
@@ -43,6 +51,7 @@ 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.core.PollableChannel;
import org.springframework.integration.support.MessageBuilder;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestClientException;
@@ -648,12 +657,24 @@ public class HttpRequestExecutingMessageHandlerTests {
@Test //INT-2275
public void testOutboundChannelAdapterWithinChain() {
ApplicationContext ctx = new ClassPathXmlApplicationContext("HttpOutboundChannelAdapterWithinChainTests-context.xml", this.getClass());
ApplicationContext ctx = new ClassPathXmlApplicationContext("HttpOutboundWithinChainTests-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
}
@Test //INT-1029
public void testHttpOutboundGatewayWithinChain() throws IOException {
ApplicationContext ctx = new ClassPathXmlApplicationContext("HttpOutboundWithinChainTests-context.xml", this.getClass());
MessageChannel channel = ctx.getBean("httpOutboundGatewayWithinChain", MessageChannel.class);
channel.send(MessageBuilder.withPayload("test").build());
PollableChannel output = ctx.getBean("replyChannel", PollableChannel.class);
Message<?> receive = output.receive();
assertEquals(HttpStatus.OK, receive.getPayload());
}
@Test
public void testUriExpression() {
MockRestTemplate restTemplate = new MockRestTemplate();

View File

@@ -311,7 +311,7 @@ task executors such as a WorkManagerTaskExecutor.
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="request-channel" type="xsd:string" use="required">
<xsd:attribute name="request-channel" type="xsd:string">
<xsd:annotation>
<xsd:appinfo>
<tool:annotation kind="ref">

View File

@@ -3,29 +3,47 @@
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:int="http://www.springframework.org/schema/integration"
xmlns:ip="http://www.springframework.org/schema/integration/ip"
xsi:schemaLocation="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/ip
http://www.springframework.org/schema/integration/ip/spring-integration-ip.xsd
http://www.springframework.org/schema/integration
http://www.springframework.org/schema/integration
http://www.springframework.org/schema/integration/spring-integration.xsd">
<import resource="TcpConfigInboundGatewayTests-context.xml" />
<ip:tcp-outbound-gateway id="tcpOutGateway"
<ip:tcp-outbound-gateway id="tcpOutGateway"
connection-factory="crLfClient"
request-channel="requestChannel"
reply-channel="replyChannel"
/>
<ip:tcp-outbound-gateway id="tcpOutGatewayNio"
<ip:tcp-outbound-gateway id="tcpOutGatewayNio"
connection-factory="crLfClientNio"
request-channel="requestChannelNio"
reply-channel="replyChannel"
/>
<ip:tcp-connection-factory id="crLfServer2"
type="server"
port="#{tcpIpUtils.findAvailableServerSocket(7400)}"
serializer="crLfSerializer"
deserializer="crLfSerializer"/>
<ip:tcp-connection-factory id="crLfClient2"
type="client"
host="localhost"
port="#{crLfServer2.port}"
serializer="crLfSerializer"
deserializer="crLfSerializer"/>
<int:chain input-channel="tcpOutboundGatewayInsideChain" output-channel="replyChannel">
<ip:tcp-outbound-gateway connection-factory="crLfClient2"/>
</int:chain>
<int:channel id="replyChannel" >
<int:queue />
</int:channel>
</beans>

View File

@@ -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.
@@ -25,9 +25,11 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.integration.Message;
import org.springframework.integration.MessageChannel;
import org.springframework.integration.core.PollableChannel;
import org.springframework.integration.core.SubscribableChannel;
import org.springframework.integration.ip.tcp.connection.AbstractClientConnectionFactory;
import org.springframework.integration.ip.tcp.connection.AbstractConnectionFactory;
import org.springframework.integration.ip.tcp.connection.AbstractServerConnectionFactory;
import org.springframework.integration.support.MessageBuilder;
import org.springframework.test.context.ContextConfiguration;
@@ -35,6 +37,7 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/**
* @author Gary Russell
* @author Artem Bilan
* @since 2.0
*/
@ContextConfiguration
@@ -45,50 +48,50 @@ public class TcpConfigOutboundGatewayTests {
@Autowired
AbstractApplicationContext ctx;
@Autowired
@Qualifier(value="crLfServer")
AbstractServerConnectionFactory crLfServer;
@Autowired
@Qualifier(value="stxEtxServer")
AbstractServerConnectionFactory stxEtxServer;
@Autowired
@Qualifier(value="lengthHeaderServer")
AbstractServerConnectionFactory lengthHeaderServer;
@Autowired
@Qualifier(value="javaSerialServer")
AbstractServerConnectionFactory javaSerialServer;
@Autowired @Qualifier(value="crLfClient")
AbstractClientConnectionFactory crLfClient;
@Autowired
@Qualifier(value="stxEtxClient")
AbstractClientConnectionFactory stxEtxClient;
@Autowired
@Qualifier(value="lengthHeaderClient")
AbstractClientConnectionFactory lengthHeaderClient;
@Autowired
@Qualifier(value="javaSerialClient")
AbstractClientConnectionFactory javaSerialClient;
@Autowired
@Qualifier(value="gatewayCrLf")
TcpInboundGateway gatewayCrLf;
// @Autowired
// @Qualifier("gatewayCrLf")
// private TcpInboundGateway inboundGatewayCrLf;
@Autowired
@Qualifier("gatewayStxEtx")
private TcpInboundGateway inboundGatewayStxEtx;
@Autowired
@Qualifier("gatewayLength")
private TcpInboundGateway inboundGatewayLength;
@@ -109,6 +112,12 @@ public class TcpConfigOutboundGatewayTests {
@Qualifier("requestChannelNio")
SubscribableChannel requestChannelNio;
@Autowired
AbstractClientConnectionFactory crLfClient2;
@Autowired
MessageChannel tcpOutboundGatewayInsideChain;
@Test
public void testOutboundCrLf() throws Exception {
testOutboundUsingConfig();
@@ -127,7 +136,7 @@ public class TcpConfigOutboundGatewayTests {
throw new Exception("Gateway failed to listen");
}
}
}
@Test
@@ -166,6 +175,17 @@ public class TcpConfigOutboundGatewayTests {
assertEquals("echo:test", new String(bytes));
}
@Test //INT-1029
public void testOutboundInsideChain() throws Exception {
// TODO Lifecycle#start() isn't invoked within chain...
crLfClient2.start();
tcpOutboundGatewayInsideChain.send(MessageBuilder.withPayload("test").build());
byte[] bytes = (byte[]) replyChannel.receive().getPayload();
assertEquals("echo:test", new String(bytes).trim());
}
private void testOutboundUsingConfig() {
Message<String> message = MessageBuilder.withPayload("test").build();
requestChannel.send(message);
@@ -186,7 +206,7 @@ public class TcpConfigOutboundGatewayTests {
staticContext = ctx;
}
}
@AfterClass
public static void shutDown() {
staticContext.close();

View File

@@ -1064,7 +1064,7 @@ public class TcpSendingMessageHandlerTests {
@Test
public void testOutboundChannelAdapterWithinChain() throws Exception {
ApplicationContext ctx = new ClassPathXmlApplicationContext(
"TcpOutboundChannelAdapterWithinTests-context.xml", this.getClass());
"TcpOutboundChannelAdapterWithinChainTests-context.xml", this.getClass());
AbstractConnectionFactory ccf = ctx.getBean("ccf", AbstractConnectionFactory.class);
// TODO Lifecycle#start() isn't invoked within chain...
ccf.start();

View File

@@ -401,7 +401,7 @@
</xsd:appinfo>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="request-channel" type="xsd:string" use="required">
<xsd:attribute name="request-channel" type="xsd:string">
<xsd:annotation>
<xsd:documentation>
The receiving Message Channel of this endpoint.
@@ -865,8 +865,7 @@
<xsd:union memberTypes="xsd:boolean xsd:string" />
</xsd:simpleType>
</xsd:attribute>
<xsd:attribute name="request-channel" type="xsd:string"
use="required">
<xsd:attribute name="request-channel" type="xsd:string">
<xsd:annotation>
<xsd:documentation>
The receiving Message Channel of this endpoint.

View File

@@ -2,17 +2,10 @@
<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"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:p="http://www.springframework.org/schema/p"
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
xsi:schemaLocation="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
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<import resource="classpath:derby-stored-procedures-setup-context.xml"/>
@@ -37,6 +30,7 @@
<int-jdbc:returning-resultset name="out" row-mapper="org.springframework.integration.jdbc.storedproc.UserMapper" />
</int-jdbc:stored-proc-outbound-gateway>
<int:channel id="outputChannel"/>
<int:service-activator id="consumerEndpoint" input-channel="outputChannel" ref="consumer" />
@@ -44,4 +38,20 @@
<int:logging-channel-adapter channel="errorChannel" log-full-message="true"/>
<int:chain input-channel="storedProcOutboundGatewayInsideChain" output-channel="replyChannel">
<int-jdbc:stored-proc-outbound-gateway stored-procedure-name="CREATE_USER_RETURN_ALL" data-source="dataSource"
ignore-column-meta-data="false"
is-function="false"
expect-single-result="true">
<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:returning-resultset name="out" row-mapper="org.springframework.integration.jdbc.storedproc.UserMapper" />
</int-jdbc:stored-proc-outbound-gateway>
</int:chain>
<int:channel id="replyChannel">
<int:queue/>
</int:channel>
</beans>

View File

@@ -33,21 +33,28 @@ 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.annotation.ServiceActivator;
import org.springframework.integration.core.PollableChannel;
import org.springframework.integration.jdbc.storedproc.CreateUser;
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 javax.sql.DataSource;
/**
* @author Gunnar Hillert
* @author Artem Bilan
*/
@ContextConfiguration
@RunWith(SpringJUnit4ClassRunner.class)
public class StoredProcOutboundGatewayWithNamespaceIntegrationTests {
@Autowired
private AbstractApplicationContext context;
DataSource dataSource;
@Autowired
private Consumer consumer;
@@ -55,6 +62,12 @@ public class StoredProcOutboundGatewayWithNamespaceIntegrationTests {
@Autowired
CreateUser createUser;
@Autowired
MessageChannel storedProcOutboundGatewayInsideChain;
@Autowired
PollableChannel replyChannel;
@Test
public void test() throws Exception {
@@ -65,10 +78,38 @@ public class StoredProcOutboundGatewayWithNamespaceIntegrationTests {
received.add(consumer.poll(2000));
Message<Collection<User>> message = received.get(0);
context.stop();
assertNotNull(message);
assertNotNull(message.getPayload());
Collection<User> allUsers = message.getPayload();
assertTrue(allUsers.size() == 1);
User userFromDb = allUsers.iterator().next();
assertEquals("Wrong username", "myUsername", userFromDb.getUsername());
assertEquals("Wrong password", "myPassword", userFromDb.getPassword());
assertEquals("Wrong email", "myEmail", userFromDb.getEmail());
}
@Test //INT-1029
public void testStoredProcOutboundGatewayInsideChain() throws Exception {
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
jdbcTemplate.execute("delete from USERS");
Message<User> requestMessage = MessageBuilder.withPayload(new User("myUsername", "myPassword", "myEmail")).build();
storedProcOutboundGatewayInsideChain.send(requestMessage);
@SuppressWarnings("unchecked")
Message<Collection<User>> message = (Message<Collection<User>>) replyChannel.receive();
assertNotNull(message);
assertNotNull(message.getPayload());
assertNotNull(message.getPayload() instanceof Collection<?>);
Collection<User> allUsers = message.getPayload();

View File

@@ -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
@@ -41,6 +41,7 @@ import org.springframework.jdbc.core.JdbcTemplate;
* @author Dave Syer
* @author Oleg Zhurakousky
* @author Gary Russell
* @author Artem Bilan
* @since 2.0
*
*/
@@ -99,7 +100,7 @@ public class JdbcOutboundGatewayParserTests {
Map<String, ?> payload = (Map<String, ?>) reply.getPayload();
assertEquals(1, payload.get("updated"));
}
@Test
public void testWithPoller() throws Exception{
ApplicationContext ac = new ClassPathXmlApplicationContext("JdbcOutboundGatewayWithPollerTest-context.xml", this.getClass());
@@ -123,21 +124,21 @@ public class JdbcOutboundGatewayParserTests {
setUp("JdbcOutboundGatewayWithPollerTest-context.xml", getClass());
PollingConsumer outboundGateway = this.context.getBean("jdbcOutboundGateway", PollingConsumer.class);
DirectFieldAccessor accessor = new DirectFieldAccessor(outboundGateway);
Object source = accessor.getPropertyValue("handler");
accessor = new DirectFieldAccessor(source);
source = accessor.getPropertyValue("messagingTemplate");
MessagingTemplate messagingTemplate = (MessagingTemplate) source;
accessor = new DirectFieldAccessor(messagingTemplate);
Long sendTimeout = (Long) accessor.getPropertyValue("sendTimeout");
assertEquals("Wrong sendTimeout", Long.valueOf(444L), sendTimeout);
}
@Test
public void testDefaultMaxMessagesPerPollIsSet() throws Exception {
@@ -172,6 +173,21 @@ public class JdbcOutboundGatewayParserTests {
}
@Test //INT-1029
public void testOutboundGatewayInsideChain() {
ConfigurableApplicationContext context = new ClassPathXmlApplicationContext("handlingMapPayloadJdbcOutboundGatewayTest.xml", getClass());
MessageChannel channel = context.getBean("jdbcOutboundGatewayInsideChain", MessageChannel.class);
channel.send(MessageBuilder.withPayload(Collections.singletonMap("foo", "bar")).build());
PollableChannel outbound = context.getBean("replyChannel", PollableChannel.class);
Message<?> reply = outbound.receive();
assertNotNull(reply);
@SuppressWarnings("unchecked")
Map<String, ?> payload = (Map<String, ?>) reply.getPayload();
assertEquals("bar", payload.get("name"));
}
@After
public void tearDown() {
if (context != null) {

View File

@@ -1,10 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/integration/jdbc" xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:si="http://www.springframework.org/schema/integration" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jdbc="http://www.springframework.org/schema/jdbc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
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
@@ -14,9 +12,20 @@
<si:queue />
</si:channel>
<si:channel id="replyChannel">
<si:queue />
</si:channel>
<outbound-gateway id="jdbcGateway" query="select * from foos where id=:headers[id]" update="insert into foos (id, status, name) values (:headers[id], 0, :payload[foo])"
request-channel="target" reply-channel="output" data-source="dataSource" order="23"/>
<si:chain input-channel="jdbcOutboundGatewayInsideChain" output-channel="replyChannel">
<outbound-gateway query="select * from foos where id=:headers[id]"
update="insert into foos (id, status, name) values (:headers[id], 0, :payload[foo])"
data-source="dataSource"/>
</si:chain>
<beans:import resource="jdbcOutboundChannelAdapterCommonConfig.xml" />
</beans:beans>

View File

@@ -42,7 +42,7 @@
<xsd:complexType>
<xsd:complexContent>
<xsd:extension base="operationInvokingType">
<xsd:attribute name="request-channel" type="xsd:string" use="required" />
<xsd:attribute name="request-channel" type="xsd:string" />
<xsd:attribute name="reply-channel" type="xsd:string" use="optional" />
</xsd:extension>
</xsd:complexContent>
@@ -199,4 +199,4 @@
</xsd:attribute>
</xsd:complexType>
</xsd:schema>
</xsd:schema>

View File

@@ -17,18 +17,23 @@
<context:mbean-server/>
<si:channel id="withReplyChannel"/>
<si:channel id="withReplyChannelOutput">
<si:queue/>
</si:channel>
<si:channel id="withNoReplyChannel"/>
<jmx:operation-invoking-outbound-gateway request-channel="withReplyChannel"
reply-channel="withReplyChannelOutput"
object-name="org.springframework.integration.jmx.config:type=TestBean,name=testBeanGateway"
operation-name="testWithReturn"/>
<si:chain input-channel="jmxOutboundGatewayInsideChain" output-channel="withReplyChannelOutput">
<jmx:operation-invoking-outbound-gateway operation-name="testWithReturn"
object-name="org.springframework.integration.jmx.config:type=TestBean,name=testBeanGateway"/>
</si:chain>
<jmx:operation-invoking-outbound-gateway request-channel="withNoReplyChannel"
object-name="org.springframework.integration.jmx.config:type=TestBean,name=testBeanGateway"
operation-name="test"/>

View File

@@ -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.
@@ -28,12 +28,14 @@ import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.integration.MessageChannel;
import org.springframework.integration.core.PollableChannel;
import org.springframework.integration.message.GenericMessage;
import org.springframework.integration.support.MessageBuilder;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/**
* @author Oleg Zhurakousky
*
* @author Artem Bilan
*
*/
@ContextConfiguration
@RunWith(SpringJUnit4ClassRunner.class)
@@ -51,6 +53,9 @@ public class OperationInvokingOutboundGatewayTests {
@Qualifier("withNoReplyChannel")
private MessageChannel withNoReplyChannel;
@Autowired
private MessageChannel jmxOutboundGatewayInsideChain;
@Autowired
private TestBean testBean;
@@ -79,4 +84,14 @@ public class OperationInvokingOutboundGatewayTests {
assertEquals(3, testBean.messages.size());
}
@Test //INT-1029
public void testOutboundGatewayInsideChain() throws Exception {
jmxOutboundGatewayInsideChain.send(MessageBuilder.withPayload("1").build());
assertEquals(1, ((List<?>) withReplyChannelOutput.receive().getPayload()).size());
jmxOutboundGatewayInsideChain.send(MessageBuilder.withPayload("2").build());
assertEquals(2, ((List<?>) withReplyChannelOutput.receive().getPayload()).size());
jmxOutboundGatewayInsideChain.send(MessageBuilder.withPayload("3").build());
assertEquals(3, ((List<?>) withReplyChannelOutput.receive().getPayload()).size());
}
}

View File

@@ -290,7 +290,7 @@
<xsd:union memberTypes="xsd:boolean xsd:string" />
</xsd:simpleType>
</xsd:attribute>
<xsd:attribute name="request-channel" type="xsd:string" use="required">
<xsd:attribute name="request-channel" type="xsd:string">
<xsd:annotation>
<xsd:documentation>
The receiving Message Channel of this endpoint.

View File

@@ -28,16 +28,21 @@
<int:method name="getAllStudents" request-channel="getAllStudentsChannel" />
<int:method name="persistStudent" request-channel="persistStudentChannel" />
<int:method name="persistStudentUsingMerge" request-channel="persistStudentUsingMergeChannel" />
<int:method name="getStudent2" request-channel="retrievingGatewayInsideChain" />
<int:method name="persistStudent2" request-channel="updatingGatewayInsideChain" />
</int:gateway>
<int:channel id="studentReplyChannel"/>
<int:channel id="deleteStudentChannel"/>
<int:channel id="getStudentChannel"/>
<int:channel id="getStudentWithParametersChannel"/>
<int:channel id="getAllStudentsChannel"/>
<int:channel id="persistStudentChannel"/>
<int:channel id="persistStudentUsingMergeChannel"/>
<int:channel id="studentReplyChannel"/>
<int:channel id="getStudentEndpointWithExceptionChannel"/>
<int:channel id="retrievingGatewayInsideChain"/>
<int:channel id="updatingGatewayInsideChain"/>
<bean id="deleteStudentEndpoint"
class="org.springframework.integration.endpoint.EventDrivenConsumer">
@@ -192,4 +197,21 @@
</bean>
</constructor-arg>
</bean>
<int:chain input-channel="retrievingGatewayInsideChain" output-channel="studentReplyChannel">
<jpa:retrieving-outbound-gateway entity-manager="entityManager"
expect-single-result="true"
entity-class="org.springframework.integration.jpa.test.entity.StudentDomain"
jpa-query="from Student s where s.id = :id">
<jpa:parameter name="id" expression="payload"/>
</jpa:retrieving-outbound-gateway>
</int:chain>
<int:chain input-channel="updatingGatewayInsideChain" output-channel="studentReplyChannel">
<!--TODO JPA outbound-gateway must have 'id' inside the chain because
'org.springframework.integration.jpa.outbound.JpaOutboundGatewayFactoryBean#0' isn't registered as bean-->
<jpa:updating-outbound-gateway id="gatewayInsideChain" entity-manager="entityManager"
entity-class="org.springframework.integration.jpa.test.entity.StudentDomain"/>
</int:chain>
</beans>

View File

@@ -16,12 +16,14 @@ import java.util.List;
import junit.framework.Assert;
import org.junit.After;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.integration.MessagingException;
import org.springframework.integration.jpa.test.JpaTestUtils;
import org.springframework.integration.jpa.test.entity.StudentDomain;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@@ -31,6 +33,7 @@ import org.springframework.transaction.annotation.Transactional;
/**
*
* @author Gunnar Hillert
* @author Artem Bilan
* @since 2.2
*
*/
@@ -42,15 +45,22 @@ public class JpaOutboundGatewayTests {
@Autowired
private StudentService studentService;
@Autowired
JdbcTemplate jdbcTemplate;
@After
public void cleanUp() {
this.jdbcTemplate.execute("delete from Student where rollNumber > 1003");
}
@Test
@DirtiesContext
public void getStudent() {
final StudentDomain student = studentService.getStudent(1001L);
Assert.assertNotNull(student);
}
@Test
@DirtiesContext
@Transactional
public void deleteNonExistingStudent() {
@@ -67,7 +77,6 @@ public class JpaOutboundGatewayTests {
}
@Test
@DirtiesContext
public void getStudentWithException() {
try {
studentService.getStudentWithException(1001L);
@@ -82,7 +91,6 @@ public class JpaOutboundGatewayTests {
}
@Test
@DirtiesContext
public void getStudentStudentWithPositionalParameters() {
StudentDomain student = studentService.getStudentWithParameters("First Two");
@@ -92,7 +100,6 @@ public class JpaOutboundGatewayTests {
}
@Test
@DirtiesContext
public void getAllStudents() {
final List<StudentDomain> students = studentService.getAllStudents();
@@ -102,7 +109,6 @@ public class JpaOutboundGatewayTests {
}
@Test
@DirtiesContext
@Transactional
public void persistStudent() {
@@ -116,7 +122,6 @@ public class JpaOutboundGatewayTests {
}
@Test
@DirtiesContext
@Transactional
public void persistStudentUsingMerge() {
@@ -129,4 +134,23 @@ public class JpaOutboundGatewayTests {
}
@Test
public void testRetrievingGatewayInsideChain() {
final StudentDomain student = studentService.getStudent2(1001L);
Assert.assertNotNull(student);
}
@Test
@Transactional
public void testUpdatingGatewayInsideChain() {
final StudentDomain studentToPersist = JpaTestUtils.getTestStudent();
Assert.assertNull(studentToPersist.getRollNumber());
final StudentDomain persistedStudent = studentService.persistStudent2(studentToPersist);
Assert.assertNotNull(persistedStudent);
Assert.assertNotNull(persistedStudent.getRollNumber());
}
}

View File

@@ -35,4 +35,7 @@ public interface StudentService {
StudentDomain getStudentWithParameters(String firstName);
StudentDomain getStudent2(Long id);
StudentDomain persistStudent2(StudentDomain studentToPersist);
}

View File

@@ -28,6 +28,15 @@
</xsd:annotation>
<xsd:complexContent>
<xsd:extension base="gatewayType">
<xsd:attribute name="request-channel" type="xsd:string" use="required">
<xsd:annotation>
<xsd:appinfo>
<tool:annotation kind="ref">
<tool:expected-type type="org.springframework.integration.MessageChannel"/>
</tool:annotation>
</xsd:appinfo>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="expect-reply" type="xsd:string" default="true"/>
<xsd:attribute name="registry-host" type="xsd:string"/>
<xsd:attribute name="registry-port" type="xsd:string"/>
@@ -57,6 +66,15 @@
<xsd:sequence>
<xsd:element ref="integration:poller" minOccurs="0" maxOccurs="1"/>
</xsd:sequence>
<xsd:attribute name="request-channel" type="xsd:string">
<xsd:annotation>
<xsd:appinfo>
<tool:annotation kind="ref">
<tool:expected-type type="org.springframework.integration.MessageChannel"/>
</tool:annotation>
</xsd:appinfo>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="host" type="xsd:string" use="required"/>
<xsd:attribute name="port" type="xsd:string"/>
<xsd:attribute name="remote-channel" type="xsd:string" use="required"/>
@@ -81,15 +99,6 @@
</xsd:annotation>
<xsd:attribute name="id" type="xsd:string"/>
<xsd:attribute name="name" type="xsd:string"/>
<xsd:attribute name="request-channel" type="xsd:string" use="required">
<xsd:annotation>
<xsd:appinfo>
<tool:annotation kind="ref">
<tool:expected-type type="org.springframework.integration.MessageChannel"/>
</tool:annotation>
</xsd:appinfo>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="reply-channel" type="xsd:string">
<xsd:annotation>
<xsd:appinfo>
@@ -104,4 +113,4 @@
<xsd:attribute name="auto-startup" type="xsd:string" default="true"/>
</xsd:complexType>
</xsd:schema>
</xsd:schema>

View File

@@ -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.
@@ -26,14 +26,17 @@ import org.springframework.context.support.ClassPathXmlApplicationContext;
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.message.GenericMessage;
import org.springframework.integration.rmi.RmiInboundGateway;
import org.springframework.integration.rmi.RmiOutboundGateway;
import org.springframework.integration.support.MessageBuilder;
import org.springframework.integration.test.util.TestUtils;
/**
* @author Mark Fisher
* @author Gary Russell
* @author Artem Bilan
*/
public class RmiOutboundGatewayParserTests {
@@ -67,15 +70,27 @@ public class RmiOutboundGatewayParserTests {
assertEquals("test", result.getPayload());
}
@Test
public void endpointInvocation() {
@Test //INT-1029
public void testRmiOutboundGatewayInsideChain() {
ApplicationContext context = new ClassPathXmlApplicationContext(
"rmiOutboundGatewayParserTests.xml", this.getClass());
MessageChannel localChannel = (MessageChannel) context.getBean("localChannel");
localChannel.send(new GenericMessage<String>("test"));
MessageChannel localChannel = context.getBean("rmiOutboundGatewayInsideChain", MessageChannel.class);
localChannel.send(MessageBuilder.withPayload("test").build());
Message<?> result = testChannel.receive(1000);
assertNotNull(result);
assertEquals("test", result.getPayload());
}
@Test //INT-1029
public void testRmiRequestReplyWithinChain() {
ApplicationContext context = new ClassPathXmlApplicationContext(
"rmiOutboundGatewayParserTests.xml", this.getClass());
MessageChannel localChannel = context.getBean("requestReplyRmiWithChainChannel", MessageChannel.class);
localChannel.send(MessageBuilder.withPayload("test").build());
PollableChannel replyChannel = context.getBean("replyChannel", PollableChannel.class);
Message<?> result = replyChannel.receive();
assertNotNull(result);
assertEquals("TEST", result.getPayload());
}
}

View File

@@ -1,9 +1,9 @@
<?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:rmi="http://www.springframework.org/schema/integration/rmi"
xsi:schemaLocation="http://www.springframework.org/schema/beans
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:rmi="http://www.springframework.org/schema/integration/rmi"
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
@@ -13,9 +13,29 @@
<channel id="localChannel"/>
<rmi:outbound-gateway id="gateway"
order="23"
request-channel="localChannel"
remote-channel="testChannel"
host="localhost"/>
order="23"
request-channel="localChannel"
remote-channel="testChannel"
host="localhost"/>
</beans:beans>
<chain input-channel="rmiOutboundGatewayInsideChain">
<rmi:outbound-gateway remote-channel="testChannel" host="localhost"/>
</chain>
<channel id="remoteChannel"/>
<rmi:inbound-gateway request-channel="remoteChannel"/>
<service-activator input-channel="remoteChannel" expression="payload.toUpperCase()"/>
<channel id="replyChannel">
<queue/>
</channel>
<chain input-channel="requestReplyRmiWithChainChannel" output-channel="replyChannel">
<rmi:outbound-gateway remote-channel="remoteChannel" host="localhost"/>
</chain>
</beans:beans>

View File

@@ -268,8 +268,7 @@
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="request-channel" use="required"
type="xsd:string">
<xsd:attribute name="request-channel" type="xsd:string">
<xsd:annotation>
<xsd:appinfo>
<tool:annotation kind="ref">

View File

@@ -11,14 +11,25 @@
http://www.springframework.org/schema/integration/sftp/spring-integration-sftp.xsd">
<si:chain input-channel="outboundChainChannel">
<si:chain input-channel="outboundChannelAdapterInsideChain">
<sftp:outbound-channel-adapter
auto-create-directory="true"
session-factory="sftpSessionFactory"
remote-directory="remote-target-dir"/>
</si:chain>
<si:chain input-channel="outboundGatewayInsideChain" output-channel="replyChannel">
<sftp:outbound-gateway local-directory="/tmp"
session-factory="sftpSessionFactory"
command="ls"
expression="payload"/>
</si:chain>
<si:channel id="replyChannel">
<si:queue/>
</si:channel>
<bean id="sftpSessionFactory"
class="org.springframework.integration.sftp.outbound.SftpSendingMessageHandlerTests$TestSftpSessionFactory"/>
class="org.springframework.integration.sftp.outbound.SftpOutboundTests$TestSftpSessionFactory"/>
</beans>

View File

@@ -16,15 +16,16 @@
package org.springframework.integration.sftp.outbound;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertTrue;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.*;
import java.util.*;
import com.jcraft.jsch.SftpATTRS;
import org.junit.Test;
import org.mockito.Mockito;
import org.mockito.invocation.InvocationOnMock;
@@ -33,14 +34,18 @@ 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.core.PollableChannel;
import org.springframework.integration.file.DefaultFileNameGenerator;
import org.springframework.integration.file.remote.FileInfo;
import org.springframework.integration.file.remote.handler.FileTransferringMessageHandler;
import org.springframework.integration.file.remote.session.Session;
import org.springframework.integration.file.remote.session.SessionFactory;
import org.springframework.integration.message.GenericMessage;
import org.springframework.integration.sftp.session.DefaultSftpSessionFactory;
import org.springframework.integration.sftp.session.SftpTestSessionFactory;
import org.springframework.integration.support.MessageBuilder;
import org.springframework.util.FileCopyUtils;
import com.jcraft.jsch.ChannelSftp;
@@ -49,8 +54,8 @@ import com.jcraft.jsch.ChannelSftp.LsEntry;
/**
* @author Oleg Zhurakousky
*/
public class SftpSendingMessageHandlerTests {
public class SftpOutboundTests {
private static com.jcraft.jsch.Session jschSession = mock(com.jcraft.jsch.Session.class);
@Test
@@ -91,7 +96,7 @@ public class SftpSendingMessageHandlerTests {
handler.handleMessage(new GenericMessage<String>("hello"));
assertTrue(new File("remote-target-dir", "foo.txt").exists());
}
@Test
public void testHandleBytesMessage() throws Exception {
File file = new File("remote-target-dir", "foo.txt");
@@ -120,16 +125,38 @@ public class SftpSendingMessageHandlerTests {
File destFile = new File(targetDir, srcFile.getName());
destFile.deleteOnExit();
ApplicationContext context = new ClassPathXmlApplicationContext("SftpOutboundChannelAdapterInsideChainTests-context.xml", getClass());
ApplicationContext context = new ClassPathXmlApplicationContext("SftpOutboundInsideChainTests-context.xml", getClass());
MessageChannel channel = context.getBean("outboundChainChannel", MessageChannel.class);
MessageChannel channel = context.getBean("outboundChannelAdapterInsideChain", MessageChannel.class);
channel.send(new GenericMessage<File>(srcFile));
assertTrue("destination file was not created", destFile.exists());
}
@Test //INT-2275
public void testFtpOutboundGatewayInsideChain() throws Exception {
ApplicationContext context = new ClassPathXmlApplicationContext("SftpOutboundInsideChainTests-context.xml", getClass());
MessageChannel channel = context.getBean("outboundGatewayInsideChain", MessageChannel.class);
channel.send(MessageBuilder.withPayload("remote-test-dir").build());
PollableChannel output = context.getBean("replyChannel", PollableChannel.class);
Message<?> result = output.receive();
Object payload = result.getPayload();
assertTrue(payload instanceof List<?>);
@SuppressWarnings("unchecked")
List<? extends FileInfo> remoteFiles = (List<? extends FileInfo>) payload;
assertEquals(3, remoteFiles.size());
List<String> files = Arrays.asList(new File("remote-test-dir").list());
for (FileInfo remoteFile : remoteFiles) {
assertTrue(files.contains(remoteFile.getFilename()));
}
}
public static class TestSftpSessionFactory extends DefaultSftpSessionFactory {
@Override
public Session<LsEntry> getSession() {
try {
@@ -137,15 +164,15 @@ public class SftpSendingMessageHandlerTests {
doAnswer(new Answer<Object>() {
public Object answer(InvocationOnMock invocation)
throws Throwable {
throws Throwable {
File file = new File((String)invocation.getArguments()[1]);
assertTrue(file.getName().endsWith(".writing"));
FileCopyUtils.copy((InputStream)invocation.getArguments()[0], new FileOutputStream(file));
return null;
}
}).when(channel).put(Mockito.any(InputStream.class), Mockito.anyString());
doAnswer(new Answer<Object>() {
public Object answer(InvocationOnMock invocation)
throws Throwable {
@@ -155,8 +182,20 @@ public class SftpSendingMessageHandlerTests {
file.renameTo(renameToFile);
return null;
}
}).when(channel).rename(Mockito.anyString(), Mockito.anyString());
String[] files = new File("remote-test-dir").list();
Vector<LsEntry> sftpEntries = new Vector<LsEntry>();
for (String fileName : files) {
LsEntry lsEntry = mock(LsEntry.class);
SftpATTRS attributes = mock(SftpATTRS.class);
when(lsEntry.getAttrs()).thenReturn(attributes);
when(lsEntry.getFilename()).thenReturn(fileName);
sftpEntries.add(lsEntry);
}
when(channel.ls("remote-test-dir/")).thenReturn(sftpEntries);
when(jschSession.openChannel("sftp")).thenReturn(channel);
return SftpTestSessionFactory.createSftpSession(jschSession);
} catch (Exception e) {

View File

@@ -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,29 +16,52 @@
package org.springframework.integration.ws;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.net.URI;
import java.util.concurrent.atomic.AtomicReference;
import javax.xml.transform.TransformerException;
import org.hamcrest.Matchers;
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.integration.Message;
import org.springframework.integration.MessageChannel;
import org.springframework.integration.core.PollableChannel;
import org.springframework.integration.support.MessageBuilder;
import org.springframework.ws.WebServiceMessage;
import org.springframework.ws.WebServiceMessageFactory;
import org.springframework.ws.client.core.WebServiceMessageCallback;
import org.springframework.ws.client.support.destination.DestinationProvider;
import org.springframework.ws.soap.SoapMessage;
import org.springframework.ws.soap.SoapMessageFactory;
import org.springframework.ws.transport.WebServiceConnection;
import org.springframework.ws.transport.WebServiceMessageSender;
import org.springframework.xml.namespace.QNameUtils;
import static org.junit.Assert.*;
/**
* @author Mark Fisher
* @author Artem Bilan
* @since 2.0
*/
public class SimpleWebServiceOutboundGatewayTests {
private static final String response = "<response><name>Test Name</name></response>";
private static final String responseSoapMessage = "<soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\"> " +
"<soap:Body> " +
response +
"</soap:Body> " +
"</soap:Envelope>";
@Test // INT-1051
public void soapActionAndCustomCallback() {
String uri = "http://www.example.org";
@@ -66,6 +89,32 @@ public class SimpleWebServiceOutboundGatewayTests {
}
@Test //INT-1029
public void testWsOutboundGatewayInsideChain() {
ApplicationContext context = new ClassPathXmlApplicationContext("WebServiceOutboundGatewayInsideChainTests-context.xml", this.getClass());
MessageChannel channel = context.getBean("wsOutboundGatewayInsideChain", MessageChannel.class);
channel.send(MessageBuilder.withPayload("<test>foo</test>").build());
PollableChannel replyChannel = context.getBean("replyChannel", PollableChannel.class);
Message<?> replyMessage = replyChannel.receive();
assertThat(replyMessage.getPayload().toString(), Matchers.endsWith(response));
}
public static WebServiceMessageSender createMockMessageSender() throws Exception {
WebServiceMessageSender messageSender = Mockito.mock(WebServiceMessageSender.class);
WebServiceConnection wsConnection = Mockito.mock(WebServiceConnection.class);
Mockito.when(messageSender.createConnection(Mockito.any(URI.class))).thenReturn(wsConnection);
Mockito.when(messageSender.supports(Mockito.any(URI.class))).thenReturn(true);
Mockito.doAnswer(new Answer() {
public Object answer(InvocationOnMock invocation) throws Exception{
Object[] args = invocation.getArguments();
WebServiceMessageFactory factory = (WebServiceMessageFactory) args[0];
return factory.createWebServiceMessage(new ByteArrayInputStream(responseSoapMessage.getBytes()));
}}).when(wsConnection).receive(Mockito.any(WebServiceMessageFactory.class));
return messageSender;
}
private static class TestDestinationProvider implements DestinationProvider {
private final URI uri;

View File

@@ -0,0 +1,25 @@
<?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:ws="http://www.springframework.org/schema/integration/ws"
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/ws
http://www.springframework.org/schema/integration/ws/spring-integration-ws.xsd">
<si:channel id="replyChannel">
<si:queue/>
</si:channel>
<si:chain input-channel="wsOutboundGatewayInsideChain" output-channel="replyChannel">
<ws:outbound-gateway uri="http://test.example.org"
message-sender="mockMessageSender"/>
</si:chain>
<bean id="mockMessageSender" class="org.springframework.integration.ws.SimpleWebServiceOutboundGatewayTests"
factory-method="createMockMessageSender"/>
</beans>