Merge remote-tracking branch 'upstream/master' into 4.0.0-WIP

Conflicts:
	spring-integration-core/src/main/java/org/springframework/integration/gateway/MessagingGatewaySupport.java
	spring-integration-core/src/main/java/org/springframework/integration/support/channel/BeanFactoryChannelResolver.java
	spring-integration-core/src/main/java/org/springframework/integration/util/MessagingMethodInvokerHelper.java
	spring-integration-core/src/test/java/org/springframework/integration/config/AggregatorParserTests.java
	spring-integration-core/src/test/java/org/springframework/integration/config/annotation/AggregatorAnnotationTests.java
	spring-integration-core/src/test/java/org/springframework/integration/config/xml/ControlBusTests.java
	spring-integration-file/src/main/java/org/springframework/integration/file/DefaultFileNameGenerator.java
	spring-integration-file/src/main/java/org/springframework/integration/file/remote/handler/FileTransferringMessageHandler.java
	spring-integration-file/src/test/java/org/springframework/integration/file/remote/gateway/RemoteFileOutboundGatewayTests.java
	spring-integration-ftp/src/test/java/org/springframework/integration/ftp/config/FtpOutboundGatewayParserTests.java
	spring-integration-ftp/src/test/java/org/springframework/integration/ftp/inbound/FtpInboundRemoteFileSystemSynchronizerTests.java
	spring-integration-ftp/src/test/java/org/springframework/integration/ftp/outbound/FtpServerOutboundTests.java
	spring-integration-groovy/src/main/java/org/springframework/integration/groovy/GroovyScriptExecutingMessageProcessor.java
	spring-integration-http/src/test/java/org/springframework/integration/http/outbound/UriVariableExpressionTests.java
	spring-integration-ip/src/test/java/org/springframework/integration/ip/tcp/connection/HelloWorldInterceptor.java
	spring-integration-jpa/src/test/java/org/springframework/integration/jpa/outbound/JpaOutboundGatewayIntegrationTests.java
	spring-integration-mongodb/src/test/java/org/springframework/integration/mongodb/store/MongoDbMessageGroupStoreTests.java
	spring-integration-mongodb/src/test/java/org/springframework/integration/mongodb/store/MongoDbMessageStoreTests.java
	spring-integration-redis/src/test/java/org/springframework/integration/redis/config/RedisOutboundChannelAdapterParserTests.java
	spring-integration-sftp/src/test/java/org/springframework/integration/sftp/config/SftpOutboundGatewayParserTests.java
	spring-integration-sftp/src/test/java/org/springframework/integration/sftp/inbound/SftpInboundRemoteFileSystemSynchronizerTests.java
	spring-integration-sftp/src/test/java/org/springframework/integration/sftp/outbound/SftpServerOutboundTests.java

Resolved.
This commit is contained in:
Gary Russell
2013-11-25 17:59:51 -05:00
191 changed files with 8774 additions and 2707 deletions

View File

@@ -0,0 +1,51 @@
/*
* Copyright 2013 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.sftp.filters;
import org.springframework.integration.file.filters.AbstractPersistentAcceptOnceFileListFilter;
import org.springframework.integration.metadata.MetadataStore;
import com.jcraft.jsch.ChannelSftp.LsEntry;
/**
* Since the super class deems files as 'not seen' if the timestamp is different, remote file
* users should use the adapter's preserve-timestamp option. Otherwise if a file is re-fetched
* it will have a new timestamp.
*
* @author Gary Russell
* @since 3.0
*
*/
public class SftpPersistentAcceptOnceFileListFilter extends AbstractPersistentAcceptOnceFileListFilter<LsEntry> {
public SftpPersistentAcceptOnceFileListFilter(MetadataStore store, String prefix) {
super(store, prefix);
}
@Override
protected long modified(LsEntry file) {
return ((long) file.getAttrs().getMTime()) * 1000;
}
@Override
protected String fileName(LsEntry file) {
return file.getLongname();
}
}

View File

@@ -22,6 +22,7 @@ import java.util.List;
import org.springframework.beans.DirectFieldAccessor;
import org.springframework.integration.file.remote.AbstractFileInfo;
import org.springframework.integration.file.remote.RemoteFileTemplate;
import org.springframework.integration.file.remote.gateway.AbstractRemoteFileOutboundGateway;
import org.springframework.integration.file.remote.session.SessionFactory;
import org.springframework.integration.sftp.session.SftpFileInfo;
@@ -36,15 +37,15 @@ import com.jcraft.jsch.ChannelSftp.LsEntry;
*/
public class SftpOutboundGateway extends AbstractRemoteFileOutboundGateway<LsEntry> {
/**
* @param sessionFactory
* @param command
* @param expression
*/
public SftpOutboundGateway(SessionFactory<LsEntry> sessionFactory, String command, String expression) {
super(sessionFactory, command, expression);
}
private SftpOutboundGateway(RemoteFileTemplate<LsEntry> remoteFileTemplate, String command, String expression) {
super(remoteFileTemplate, command, expression);
}
@Override
protected boolean isDirectory(LsEntry file) {
return file.getAttrs().isDir();

View File

@@ -26,74 +26,6 @@
<xsd:all>
<xsd:element name="request-handler-advice-chain" type="integration:adviceChainType" minOccurs="0" maxOccurs="1" />
</xsd:all>
<xsd:attribute name="remote-directory-expression"
type="xsd:string">
<xsd:annotation>
<xsd:documentation>
Allows you to provide a SpEL expression which
will compute the directory
path
where files will be transferred to
(e.g., "headers.['remote_dir'] +
'/myTransfers'");
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="temporary-remote-directory-expression"
type="xsd:string">
<xsd:annotation>
<xsd:documentation>
Allows you to provide a SpEL expression which
will compute the temporary directory
path where files will be transferred to before they are moved to the remote-directory
(e.g., "headers.['remote_dir'] +
'/temp/myTransfers'");
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="auto-create-directory" type="xsd:string"
default="false">
<xsd:annotation>
<xsd:documentation>
Specify whether to automatically create the
remote target directory if
it doesn't exist.
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="remote-filename-generator" type="xsd:string">
<xsd:annotation>
<xsd:documentation>
Allows you to specify a reference to
[org.springframework.integration.file.FileNameGenerator] bean.
</xsd:documentation>
<xsd:appinfo>
<tool:annotation kind="ref">
<tool:expected-type
type="org.springframework.integration.file.FileNameGenerator" />
</tool:annotation>
</xsd:appinfo>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="remote-filename-generator-expression"
type="xsd:string">
<xsd:annotation>
<xsd:documentation>
Allows you to provide SpEL expression which
will compute file name of
the remote file (e.g., assuming payload
is java.io.File
"payload.getName() + '.transfered'");
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="use-temporary-file-name" type="xsd:string" default="true">
<xsd:annotation>
<xsd:documentation>
Allows you to suppress using a temporary file name while writing the file.
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="order" type="xsd:string">
<xsd:annotation>
<xsd:documentation>
@@ -114,6 +46,7 @@
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attributeGroup ref="int-file:remoteOutboundAttributeGroup" />
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
@@ -269,7 +202,7 @@
</xsd:annotation>
<xsd:complexType>
<xsd:complexContent>
<xsd:extension base="base-adapter-type">
<xsd:extension base="base-sftp-adapter-type">
<xsd:all>
<xsd:element name="request-handler-advice-chain" type="integration:adviceChainType" minOccurs="0" maxOccurs="1" />
</xsd:all>
@@ -379,7 +312,9 @@
<xsd:documentation>
Allows you to specify a reference to
[org.springframework.integration.file.filters.FileListFilter]
bean.
bean. This filter acts against the remote server view when using the 'ls'
or 'mget' commands.
Only one of 'filter', 'filename-pattern', or 'filename-regex' is allowed.
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
@@ -387,9 +322,11 @@
<xsd:annotation>
<xsd:documentation>
Allows you to provide file name pattern to
determine the file names retrieved by the ls command
determine the file names retrieved by the 'ls' and 'mget' commands
and is based
on simple pattern matching algorithm (e.g., "*.txt, fo*.txt" etc.)
on simple pattern matching algorithm (e.g., "*.txt, fo*.txt"
etc.)
Only one of 'filter', 'filename-pattern', or 'filename-regex' is allowed.
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
@@ -397,9 +334,49 @@
<xsd:annotation>
<xsd:documentation>
Allows you to provide Regular Expression to
determine the file names retrieved by the ls command.
determine the file names retrieved by the 'ls' and 'mget' commands.
(e.g.,
"f[o]+\.txt" etc.)
Only one of 'filter', 'filename-pattern', or 'filename-regex' is allowed.
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="mput-filter" type="xsd:string">
<xsd:annotation>
<xsd:appinfo>
<tool:annotation kind="ref">
<tool:expected-type
type="org.springframework.integration.file.filters.FileListFilter" />
</tool:annotation>
</xsd:appinfo>
<xsd:documentation>
Allows you to specify a reference to
[org.springframework.integration.file.filters.FileListFilter]
bean. This filter acts on the local file system when using the 'mput' command.
Only one of 'mput-filter', 'mput-pattern', or 'mput-regex' is allowed.
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="mput-pattern" type="xsd:string">
<xsd:annotation>
<xsd:documentation>
Allows you to provide file name pattern to
determine the file names sent by the 'mput' command
and is based
on simple pattern matching algorithm (e.g., "*.txt, fo*.txt"
etc.)
Only one of 'mput-filter', 'mput-pattern', or 'mput-regex' is allowed.
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="mput-regex" type="xsd:string">
<xsd:annotation>
<xsd:documentation>
Allows you to provide Regular Expression to
determine the file names sent by the 'mput' command
(e.g.,
"f[o]+\.txt" etc.)
Only one of 'mput-filter', 'mput-pattern', or 'mput-regex' is allowed.
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
@@ -483,6 +460,7 @@
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attributeGroup ref="int-file:remoteOutboundAttributeGroup" />
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>

View File

@@ -46,7 +46,7 @@ public class InboundChannelAdapterParserCachingTests {
@Test
public void cachingAdapter() {
Object sessionFactory = TestUtils.getPropertyValue(cachingAdapter, "source.synchronizer.sessionFactory");
Object sessionFactory = TestUtils.getPropertyValue(cachingAdapter, "source.synchronizer.remoteFileTemplate.sessionFactory");
assertEquals(CachingSessionFactory.class, sessionFactory.getClass());
Properties sessionConfig = TestUtils.getPropertyValue(sessionFactory, "sessionFactory.sessionConfig", Properties.class);
assertNotNull(sessionConfig);
@@ -55,7 +55,7 @@ public class InboundChannelAdapterParserCachingTests {
@Test
public void nonCachingAdapter() {
Object sessionFactory = TestUtils.getPropertyValue(nonCachingAdapter, "source.synchronizer.sessionFactory");
Object sessionFactory = TestUtils.getPropertyValue(nonCachingAdapter, "source.synchronizer.remoteFileTemplate.sessionFactory");
assertEquals(DefaultSftpSessionFactory.class, sessionFactory.getClass());
}

View File

@@ -44,13 +44,13 @@ public class OutboundChannelAdapterParserCachingTests {
@Test
public void cachingAdapter() {
Object sessionFactory = TestUtils.getPropertyValue(cachingAdapter, "handler.sessionFactory");
Object sessionFactory = TestUtils.getPropertyValue(cachingAdapter, "handler.remoteFileTemplate.sessionFactory");
assertEquals(CachingSessionFactory.class, sessionFactory.getClass());
}
@Test
public void nonCachingAdapter() {
Object sessionFactory = TestUtils.getPropertyValue(nonCachingAdapter, "handler.sessionFactory");
Object sessionFactory = TestUtils.getPropertyValue(nonCachingAdapter, "handler.remoteFileTemplate.sessionFactory");
assertEquals(DefaultSftpSessionFactory.class, sessionFactory.getClass());
}

View File

@@ -7,7 +7,7 @@
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">
<bean id="sftpSessionFactory" class="org.springframework.integration.sftp.session.SimpleSftpSessionFactory">
<bean id="sftpSessionFactory" class="org.springframework.integration.sftp.session.DefaultSftpSessionFactory">
<property name="host" value="localhost"/>
<property name="knownHosts" value="local, foo.com, bar.foo"/>
<property name="privateKey" value="classpath:org/springframework/integration/sftp/config/sftpTest"/>

View File

@@ -21,11 +21,14 @@ import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.util.Iterator;
import java.util.Set;
import org.hamcrest.Matchers;
import org.junit.Test;
import org.springframework.beans.factory.BeanDefinitionStoreException;
@@ -66,17 +69,17 @@ public class OutboundChannelAdapterParserTests {
assertEquals(channel, TestUtils.getPropertyValue(consumer, "inputChannel"));
assertEquals("sftpOutboundAdapter", ((EventDrivenConsumer)consumer).getComponentName());
FileTransferringMessageHandler<?> handler = TestUtils.getPropertyValue(consumer, "handler", FileTransferringMessageHandler.class);
String remoteFileSeparator = (String) TestUtils.getPropertyValue(handler, "remoteFileSeparator");
String remoteFileSeparator = (String) TestUtils.getPropertyValue(handler, "remoteFileTemplate.remoteFileSeparator");
assertNotNull(remoteFileSeparator);
assertEquals(".", remoteFileSeparator);
assertEquals(".bar", TestUtils.getPropertyValue(handler, "temporaryFileSuffix", String.class));
Expression remoteDirectoryExpression = (Expression) TestUtils.getPropertyValue(handler, "directoryExpressionProcessor.expression");
assertEquals(".bar", TestUtils.getPropertyValue(handler, "remoteFileTemplate.temporaryFileSuffix", String.class));
Expression remoteDirectoryExpression = (Expression) TestUtils.getPropertyValue(handler, "remoteFileTemplate.directoryExpressionProcessor.expression");
assertNotNull(remoteDirectoryExpression);
assertTrue(remoteDirectoryExpression instanceof LiteralExpression);
assertNotNull(TestUtils.getPropertyValue(handler, "temporaryDirectoryExpressionProcessor"));
assertEquals(context.getBean("fileNameGenerator"), TestUtils.getPropertyValue(handler, "fileNameGenerator"));
assertEquals("UTF-8", TestUtils.getPropertyValue(handler, "charset"));
CachingSessionFactory<?> sessionFactory = TestUtils.getPropertyValue(handler, "sessionFactory", CachingSessionFactory.class);
assertNotNull(TestUtils.getPropertyValue(handler, "remoteFileTemplate.temporaryDirectoryExpressionProcessor"));
assertEquals(context.getBean("fileNameGenerator"), TestUtils.getPropertyValue(handler, "remoteFileTemplate.fileNameGenerator"));
assertEquals("UTF-8", TestUtils.getPropertyValue(handler, "remoteFileTemplate.charset"));
CachingSessionFactory<?> sessionFactory = TestUtils.getPropertyValue(handler, "remoteFileTemplate.sessionFactory", CachingSessionFactory.class);
DefaultSftpSessionFactory clientFactory = TestUtils.getPropertyValue(sessionFactory, "sessionFactory", DefaultSftpSessionFactory.class);
assertEquals("localhost", TestUtils.getPropertyValue(clientFactory, "host"));
assertEquals(2222, TestUtils.getPropertyValue(clientFactory, "port"));
@@ -101,14 +104,15 @@ public class OutboundChannelAdapterParserTests {
assertEquals(context.getBean("inputChannel"), TestUtils.getPropertyValue(consumer, "inputChannel"));
assertEquals("sftpOutboundAdapterWithExpression", ((EventDrivenConsumer)consumer).getComponentName());
FileTransferringMessageHandler<?> handler = TestUtils.getPropertyValue(consumer, "handler", FileTransferringMessageHandler.class);
SpelExpression remoteDirectoryExpression = (SpelExpression) TestUtils.getPropertyValue(handler, "directoryExpressionProcessor.expression");
SpelExpression remoteDirectoryExpression = (SpelExpression) TestUtils.getPropertyValue(handler, "remoteFileTemplate.directoryExpressionProcessor.expression");
assertNotNull(remoteDirectoryExpression);
assertEquals("'foo' + '/' + 'bar'", remoteDirectoryExpression.getExpressionString());
FileNameGenerator generator = (FileNameGenerator) TestUtils.getPropertyValue(handler, "fileNameGenerator");
String fileNameGeneratorExpression = (String) TestUtils.getPropertyValue(generator, "expression");
assertEquals("payload.getName() + '-foo'", fileNameGeneratorExpression);
assertEquals("UTF-8", TestUtils.getPropertyValue(handler, "charset"));
assertNull(TestUtils.getPropertyValue(handler, "temporaryDirectoryExpressionProcessor"));
FileNameGenerator generator = (FileNameGenerator) TestUtils.getPropertyValue(handler, "remoteFileTemplate.fileNameGenerator");
Expression fileNameGeneratorExpression = TestUtils.getPropertyValue(generator, "expression", Expression.class);
assertNotNull(fileNameGeneratorExpression);
assertEquals("payload.getName() + '-foo'", fileNameGeneratorExpression.getExpressionString());
assertEquals("UTF-8", TestUtils.getPropertyValue(handler, "remoteFileTemplate.charset"));
assertNull(TestUtils.getPropertyValue(handler, "remoteFileTemplate.temporaryDirectoryExpressionProcessor"));
}
@@ -118,7 +122,7 @@ public class OutboundChannelAdapterParserTests {
new ClassPathXmlApplicationContext("OutboundChannelAdapterParserTests-context.xml", this.getClass());
Object consumer = context.getBean("sftpOutboundAdapterWithNoTemporaryFileName");
FileTransferringMessageHandler<?> handler = TestUtils.getPropertyValue(consumer, "handler", FileTransferringMessageHandler.class);
assertFalse((Boolean)TestUtils.getPropertyValue(handler,"useTemporaryFileName"));
assertFalse((Boolean)TestUtils.getPropertyValue(handler,"remoteFileTemplate.useTemporaryFileName"));
}
@Test
@@ -131,9 +135,15 @@ public class OutboundChannelAdapterParserTests {
assertEquals(1, adviceCalled);
}
@Test(expected=BeanDefinitionStoreException.class)
@Test
public void testFailWithRemoteDirAndExpression(){
new ClassPathXmlApplicationContext("OutboundChannelAdapterParserTests-context-fail.xml", this.getClass());
try {
new ClassPathXmlApplicationContext("OutboundChannelAdapterParserTests-context-fail.xml", this.getClass());
fail("Exception expected");
}
catch (BeanDefinitionStoreException e) {
assertThat(e.getMessage(), Matchers.containsString("Only one of 'remote-directory'"));
}
}

View File

@@ -29,6 +29,7 @@
command-options="-1 -f"
expression="payload"
order="1"
mput-regex=".*"
/>
<bean id="fooString" class="java.lang.String">
@@ -49,6 +50,7 @@
order="2"
requires-reply="false"
local-filename-generator-expression="#remoteFileName.toUpperCase() + '.a' + @fooString"
mput-pattern="*"
/>
<int-sftp:outbound-gateway id="gateway3"
@@ -61,6 +63,30 @@
order="1"
/>
<int-sftp:outbound-gateway id="gateway4"
session-factory="csf"
request-channel="inbound1"
reply-channel="outbound"
command="mput"
expression="payload"
remote-directory="/foo"
remote-file-separator="X"
auto-create-directory="true"
remote-filename-generator="fileNameGenerator"
temporary-remote-directory="/bar"
rename-expression="'foo'"
order="1"
mput-filter="mputFilter"
/>
<bean id="fileNameGenerator" class="org.mockito.Mockito" factory-method="mock">
<constructor-arg value="org.springframework.integration.file.FileNameGenerator"/>
</bean>
<bean id="mputFilter" class="org.springframework.integration.file.filters.RegexPatternFileListFilter">
<constructor-arg value="(.*1.txt|sub*)"/>
</bean>
<int-sftp:outbound-gateway id="advised"
local-directory="local-test-dir"
session-factory="sf"

View File

@@ -18,26 +18,32 @@ package org.springframework.integration.sftp.config;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import java.io.File;
import java.lang.reflect.Method;
import java.util.Set;
import java.util.concurrent.atomic.AtomicReference;
import org.hamcrest.Matchers;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.Message;
import org.springframework.expression.Expression;
import org.springframework.integration.endpoint.AbstractEndpoint;
import org.springframework.integration.file.FileNameGenerator;
import org.springframework.integration.file.filters.RegexPatternFileListFilter;
import org.springframework.integration.file.filters.SimplePatternFileListFilter;
import org.springframework.integration.file.remote.gateway.AbstractRemoteFileOutboundGateway.Command;
import org.springframework.integration.file.remote.gateway.AbstractRemoteFileOutboundGateway.Option;
import org.springframework.integration.file.remote.session.CachingSessionFactory;
import org.springframework.integration.handler.advice.AbstractRequestHandlerAdvice;
import org.springframework.messaging.support.GenericMessage;
import org.springframework.integration.sftp.gateway.SftpOutboundGateway;
import org.springframework.integration.test.util.TestUtils;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.GenericMessage;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.util.ReflectionUtils;
@@ -63,17 +69,23 @@ public class SftpOutboundGatewayParserTests {
@Autowired
AbstractEndpoint gateway3;
@Autowired
AbstractEndpoint gateway4;
@Autowired
AbstractEndpoint advised;
@Autowired
FileNameGenerator generator;
private static volatile int adviceCalled;
@Test
public void testGateway1() {
SftpOutboundGateway gateway = TestUtils.getPropertyValue(gateway1,
"handler", SftpOutboundGateway.class);
assertEquals("X", TestUtils.getPropertyValue(gateway, "remoteFileSeparator"));
assertNotNull(TestUtils.getPropertyValue(gateway, "sessionFactory"));
assertEquals("X", TestUtils.getPropertyValue(gateway, "remoteFileTemplate.remoteFileSeparator"));
assertNotNull(TestUtils.getPropertyValue(gateway, "remoteFileTemplate.sessionFactory"));
assertNotNull(TestUtils.getPropertyValue(gateway, "outputChannel"));
assertEquals("local-test-dir", TestUtils.getPropertyValue(gateway, "localDirectoryExpression.literalValue"));
assertFalse((Boolean) TestUtils.getPropertyValue(gateway, "autoCreateLocalDirectory"));
@@ -87,15 +99,16 @@ public class SftpOutboundGatewayParserTests {
Long sendTimeout = TestUtils.getPropertyValue(gateway, "messagingTemplate.sendTimeout", Long.class);
assertEquals(Long.valueOf(777), sendTimeout);
assertThat(TestUtils.getPropertyValue(gateway, "mputFilter"), Matchers.instanceOf(RegexPatternFileListFilter.class));
}
@Test
public void testGateway2() throws Exception {
SftpOutboundGateway gateway = TestUtils.getPropertyValue(gateway2,
"handler", SftpOutboundGateway.class);
assertEquals("X", TestUtils.getPropertyValue(gateway, "remoteFileSeparator"));
assertNotNull(TestUtils.getPropertyValue(gateway, "sessionFactory"));
assertTrue(TestUtils.getPropertyValue(gateway, "sessionFactory") instanceof CachingSessionFactory);
assertEquals("X", TestUtils.getPropertyValue(gateway, "remoteFileTemplate.remoteFileSeparator"));
assertNotNull(TestUtils.getPropertyValue(gateway, "remoteFileTemplate.sessionFactory"));
assertTrue(TestUtils.getPropertyValue(gateway, "remoteFileTemplate.sessionFactory") instanceof CachingSessionFactory);
assertNotNull(TestUtils.getPropertyValue(gateway, "outputChannel"));
assertEquals("local-test-dir", TestUtils.getPropertyValue(gateway, "localDirectoryExpression.literalValue"));
assertFalse((Boolean) TestUtils.getPropertyValue(gateway, "autoCreateLocalDirectory"));
@@ -119,18 +132,37 @@ public class SftpOutboundGatewayParserTests {
}
});
assertEquals("FOO.afoo", genMethod.get().invoke(gateway, new GenericMessage<String>(""), "foo"));
assertThat(TestUtils.getPropertyValue(gateway, "mputFilter"), Matchers.instanceOf(SimplePatternFileListFilter.class));
}
@Test
public void testGatewayMv() {
SftpOutboundGateway gateway = TestUtils.getPropertyValue(gateway3,
"handler", SftpOutboundGateway.class);
assertNotNull(TestUtils.getPropertyValue(gateway, "sessionFactory"));
assertNotNull(TestUtils.getPropertyValue(gateway, "remoteFileTemplate.sessionFactory"));
assertNotNull(TestUtils.getPropertyValue(gateway, "outputChannel"));
assertEquals(Command.MV, TestUtils.getPropertyValue(gateway, "command"));
assertEquals("'foo'", TestUtils.getPropertyValue(gateway, "renameProcessor.expression.expression"));
}
@Test
public void testGatewayMPut() {
SftpOutboundGateway gateway = TestUtils.getPropertyValue(gateway4,
"handler", SftpOutboundGateway.class);
assertNotNull(TestUtils.getPropertyValue(gateway, "remoteFileTemplate.sessionFactory"));
assertNotNull(TestUtils.getPropertyValue(gateway, "outputChannel"));
assertEquals(Command.MPUT, TestUtils.getPropertyValue(gateway, "command"));
assertEquals("'foo'", TestUtils.getPropertyValue(gateway, "renameProcessor.expression.expression"));
assertThat(TestUtils.getPropertyValue(gateway, "mputFilter"), Matchers.instanceOf(RegexPatternFileListFilter.class));
assertSame(generator, TestUtils.getPropertyValue(gateway, "remoteFileTemplate.fileNameGenerator"));
assertEquals("/foo",
TestUtils.getPropertyValue(gateway, "remoteFileTemplate.directoryExpressionProcessor.expression", Expression.class)
.getExpressionString());
assertEquals("/bar",
TestUtils.getPropertyValue(gateway, "remoteFileTemplate.temporaryDirectoryExpressionProcessor.expression", Expression.class)
.getExpressionString());
}
@Test
public void advised() {
SftpOutboundGateway gateway = TestUtils.getPropertyValue(advised,

View File

@@ -30,18 +30,27 @@ import static org.mockito.Mockito.when;
import java.io.File;
import java.io.FileInputStream;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import java.util.Queue;
import java.util.Vector;
import org.hamcrest.Matchers;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.springframework.integration.expression.ExpressionUtils;
import org.springframework.integration.file.filters.CompositeFileListFilter;
import org.springframework.integration.file.filters.FileListFilter;
import org.springframework.integration.file.remote.session.Session;
import org.springframework.integration.metadata.PropertiesPersistingMetadataStore;
import org.springframework.integration.sftp.filters.SftpPersistentAcceptOnceFileListFilter;
import org.springframework.integration.sftp.filters.SftpRegexPatternFileListFilter;
import org.springframework.integration.sftp.session.DefaultSftpSessionFactory;
import org.springframework.integration.sftp.session.SftpTestSessionFactory;
import org.springframework.integration.test.util.TestUtils;
import org.springframework.messaging.Message;
import com.jcraft.jsch.ChannelSftp;
@@ -59,6 +68,7 @@ public class SftpInboundRemoteFileSystemSynchronizerTests {
private static com.jcraft.jsch.Session jschSession = mock(com.jcraft.jsch.Session.class);
@Before
@After
public void cleanup(){
File file = new File("test");
@@ -87,7 +97,16 @@ public class SftpInboundRemoteFileSystemSynchronizerTests {
synchronizer.setDeleteRemoteFiles(true);
synchronizer.setPreserveTimestamp(true);
synchronizer.setRemoteDirectory("remote-test-dir");
synchronizer.setFilter(new SftpRegexPatternFileListFilter(".*\\.test$"));
SftpRegexPatternFileListFilter patternFilter = new SftpRegexPatternFileListFilter(".*\\.test$");
PropertiesPersistingMetadataStore store = new PropertiesPersistingMetadataStore();
store.setBaseDirectory("test");
SftpPersistentAcceptOnceFileListFilter persistFilter =
new SftpPersistentAcceptOnceFileListFilter(store, "foo");
List<FileListFilter<LsEntry>> filters = new ArrayList<FileListFilter<LsEntry>>();
filters.add(persistFilter);
filters.add(patternFilter);
CompositeFileListFilter<LsEntry> filter = new CompositeFileListFilter<LsEntry>(filters);
synchronizer.setFilter(filter);
synchronizer.setIntegrationEvaluationContext(ExpressionUtils.createStandardEvaluationContext());
SftpInboundFileSynchronizingMessageSource ms =
@@ -115,28 +134,48 @@ public class SftpInboundRemoteFileSystemSynchronizerTests {
assertTrue(new File("test/a.test").exists());
assertTrue(new File("test/b.test").exists());
TestUtils.getPropertyValue(ms, "localFileListFilter.seen", Queue.class).clear();
new File("test/a.test").delete();
new File("test/b.test").delete();
// the remote filter should prevent a re-fetch
nothing = ms.receive();
assertNull(nothing);
}
public static class TestSftpSessionFactory extends DefaultSftpSessionFactory {
private final Vector<LsEntry> sftpEntries = new Vector<LsEntry>();
private void init() {
String[] files = new File("remote-test-dir").list();
for (String fileName : files) {
LsEntry lsEntry = mock(LsEntry.class);
SftpATTRS attributes = mock(SftpATTRS.class);
when(lsEntry.getAttrs()).thenReturn(attributes);
Calendar calendar = Calendar.getInstance();
calendar.add(Calendar.DATE, 1);
when(lsEntry.getAttrs().getMTime()).thenReturn(new Long(calendar.getTimeInMillis() / 1000).intValue());
when(lsEntry.getFilename()).thenReturn(fileName);
when(lsEntry.getLongname()).thenReturn(fileName);
sftpEntries.add(lsEntry);
}
}
@Override
public Session<LsEntry> getSession() {
if (this.sftpEntries.size() == 0) {
this.init();
}
try {
ChannelSftp channel = mock(ChannelSftp.class);
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);
Calendar calendar = Calendar.getInstance();
calendar.add(Calendar.DATE, 1);
when(lsEntry.getAttrs().getMTime()).thenReturn(new Long(calendar.getTimeInMillis() / 1000).intValue());
when(lsEntry.getFilename()).thenReturn(fileName);
sftpEntries.add(lsEntry);
when(channel.get("remote-test-dir/"+fileName)).thenReturn(new FileInputStream("remote-test-dir/" + fileName));
}
when(channel.ls("remote-test-dir")).thenReturn(sftpEntries);
@@ -148,4 +187,5 @@ public class SftpInboundRemoteFileSystemSynchronizerTests {
}
}
}
}

View File

@@ -64,6 +64,42 @@
local-filename-generator-expression="#remoteFileName.replaceFirst('ftpSource', 'localTarget')"
reply-channel="output"/>
<int:channel id="inboundMPut"/>
<int-sftp:outbound-gateway session-factory="ftpSessionFactory"
request-channel="inboundMPut"
command="mput"
auto-create-directory="true"
filename-pattern="*.txt"
expression="payload"
remote-directory="sftpTarget"
reply-channel="output"/>
<int:channel id="inboundMPutRecursive"/>
<int-sftp:outbound-gateway session-factory="ftpSessionFactory"
request-channel="inboundMPutRecursive"
command="mput"
command-options="-R"
auto-create-directory="true"
filename-pattern="*.txt"
expression="payload"
remote-directory="sftpTarget"
reply-channel="output"/>
<int:channel id="inboundMPutRecursiveFiltered"/>
<int-sftp:outbound-gateway session-factory="ftpSessionFactory"
request-channel="inboundMPutRecursiveFiltered"
command="mput"
command-options="-R"
mput-regex="(.*1.txt|sub.*)"
auto-create-directory="true"
filename-pattern="*.txt"
expression="payload"
remote-directory="sftpTarget"
reply-channel="output"/>
<bean id="ftpSessionFactory" class="org.mockito.Mockito" factory-method="mock">
<constructor-arg value="org.springframework.integration.file.remote.session.SessionFactory" />
</bean>

View File

@@ -16,6 +16,9 @@
package org.springframework.integration.sftp.outbound;
import static org.hamcrest.Matchers.anyOf;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.not;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertSame;
@@ -46,10 +49,13 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.integration.channel.DirectChannel;
import org.springframework.integration.file.remote.session.Session;
import org.springframework.integration.file.remote.session.SessionFactory;
import org.springframework.integration.sftp.session.SftpFileInfo;
import org.springframework.integration.test.util.TestUtils;
import org.springframework.messaging.Message;
import org.springframework.messaging.PollableChannel;
import org.springframework.messaging.support.GenericMessage;
import org.springframework.test.annotation.IfProfileValue;
import org.springframework.test.annotation.ProfileValueUtils;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.util.FileCopyUtils;
@@ -98,7 +104,16 @@ public class SftpServerOutboundTests {
private DirectChannel inboundMGetRecursiveFiltered;
@Autowired
private SessionFactory<?> sessionFactory;
private DirectChannel inboundMPut;
@Autowired
private DirectChannel inboundMPutRecursive;
@Autowired
private DirectChannel inboundMPutRecursiveFiltered;
@Autowired
private SessionFactory<SftpFileInfo> sessionFactory;
@Before
public void setup() throws Exception {
@@ -108,7 +123,9 @@ public class SftpServerOutboundTests {
@SuppressWarnings({ "rawtypes", "unchecked" })
private void setUpMocksIfNeeded() throws IOException {
if (sessionFactory.toString().startsWith("Mock for")) {
String profile = ProfileValueUtils.retrieveProfileValueSource(this.getClass()).get("spring.profiles.active");
boolean usingMocks = profile == null || ! profile.startsWith("realSSH");
if (usingMocks) {
Session session = mock(Session.class);
when(sessionFactory.getSession()).thenReturn(session);
LsEntry entry1 = mock(LsEntry.class);
@@ -275,82 +292,151 @@ public class SftpServerOutboundTests {
* Only runs with a real server (see class javadocs).
*/
@Test
@IfProfileValue(name="spring.profiles.active", value="realSSH")
public void testInt3100RawGET() throws Exception {
if (!sessionFactory.toString().startsWith("Mock for")) {
Session<?> session = this.sessionFactory.getSession();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
FileCopyUtils.copy(session.readRaw("sftpSource/sftpSource1.txt"), baos);
assertTrue(session.finalizeRaw());
assertEquals("source1", new String(baos.toByteArray()));
Session<?> session = this.sessionFactory.getSession();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
FileCopyUtils.copy(session.readRaw("sftpSource/sftpSource1.txt"), baos);
assertTrue(session.finalizeRaw());
assertEquals("source1", new String(baos.toByteArray()));
baos = new ByteArrayOutputStream();
FileCopyUtils.copy(session.readRaw("sftpSource/sftpSource2.txt"), baos);
assertTrue(session.finalizeRaw());
assertEquals("source2", new String(baos.toByteArray()));
baos = new ByteArrayOutputStream();
FileCopyUtils.copy(session.readRaw("sftpSource/sftpSource2.txt"), baos);
assertTrue(session.finalizeRaw());
assertEquals("source2", new String(baos.toByteArray()));
session.close();
}
session.close();
}
@Test
@IfProfileValue(name="spring.profiles.active", value="realSSHSharedSession")
public void testInt3047ConcurrentSharedSession() throws Exception {
if ("realSSHSharedSession".equals(System.getProperty("spring.profiles.active"))) {
final Session<?> session1 = this.sessionFactory.getSession();
final Session<?> session2 = this.sessionFactory.getSession();
final PipedInputStream pipe1 = new PipedInputStream();
PipedOutputStream out1 = new PipedOutputStream(pipe1);
final PipedInputStream pipe2 = new PipedInputStream();
PipedOutputStream out2 = new PipedOutputStream(pipe2);
final CountDownLatch latch1 = new CountDownLatch(1);
final CountDownLatch latch2 = new CountDownLatch(1);
Executors.newSingleThreadExecutor().execute(new Runnable() {
final Session<?> session1 = this.sessionFactory.getSession();
final Session<?> session2 = this.sessionFactory.getSession();
final PipedInputStream pipe1 = new PipedInputStream();
PipedOutputStream out1 = new PipedOutputStream(pipe1);
final PipedInputStream pipe2 = new PipedInputStream();
PipedOutputStream out2 = new PipedOutputStream(pipe2);
final CountDownLatch latch1 = new CountDownLatch(1);
final CountDownLatch latch2 = new CountDownLatch(1);
Executors.newSingleThreadExecutor().execute(new Runnable() {
@Override
public void run() {
try {
session1.write(pipe1, "foo.txt");
}
catch (IOException e) {
e.printStackTrace();
}
latch1.countDown();
@Override
public void run() {
try {
session1.write(pipe1, "foo.txt");
}
});
Executors.newSingleThreadExecutor().execute(new Runnable() {
@Override
public void run() {
try {
session2.write(pipe2, "bar.txt");
}
catch (IOException e) {
e.printStackTrace();
}
latch2.countDown();
catch (IOException e) {
e.printStackTrace();
}
});
latch1.countDown();
}
});
Executors.newSingleThreadExecutor().execute(new Runnable() {
out1.write('a');
out2.write('b');
out1.write('c');
out2.write('d');
out1.write('e');
out2.write('f');
out1.close();
out2.close();
assertTrue(latch1.await(10, TimeUnit.SECONDS));
assertTrue(latch2.await(10, TimeUnit.SECONDS));
ByteArrayOutputStream bos1 = new ByteArrayOutputStream();
ByteArrayOutputStream bos2 = new ByteArrayOutputStream();
session1.read("foo.txt", bos1);
session2.read("bar.txt", bos2);
assertEquals("ace", new String(bos1.toByteArray()));
assertEquals("bdf", new String(bos2.toByteArray()));
session1.remove("foo.txt");
session2.remove("bar.txt");
session1.close();
session2.close();
}
@Override
public void run() {
try {
session2.write(pipe2, "bar.txt");
}
catch (IOException e) {
e.printStackTrace();
}
latch2.countDown();
}
});
out1.write('a');
out2.write('b');
out1.write('c');
out2.write('d');
out1.write('e');
out2.write('f');
out1.close();
out2.close();
assertTrue(latch1.await(10, TimeUnit.SECONDS));
assertTrue(latch2.await(10, TimeUnit.SECONDS));
ByteArrayOutputStream bos1 = new ByteArrayOutputStream();
ByteArrayOutputStream bos2 = new ByteArrayOutputStream();
session1.read("foo.txt", bos1);
session2.read("bar.txt", bos2);
assertEquals("ace", new String(bos1.toByteArray()));
assertEquals("bdf", new String(bos2.toByteArray()));
session1.remove("foo.txt");
session2.remove("bar.txt");
session1.close();
session2.close();
}
@Test
@IfProfileValue(name="spring.profiles.active", value="realSSH")
public void testInt3088MPutNotRecursive() {
String dir = "sftpSource/";
this.inboundMGetRecursive.send(new GenericMessage<Object>(dir + "*"));
while (output.receive(0) != null) { }
this.inboundMPut.send(new GenericMessage<File>(new File("/tmp/sftpOutboundTests/sftpSource")));
@SuppressWarnings("unchecked")
Message<List<String>> out = (Message<List<String>>) this.output.receive(1000);
assertNotNull(out);
assertEquals(2, out.getPayload().size());
assertThat(out.getPayload().get(0),
not(equalTo(out.getPayload().get(1))));
assertThat(
out.getPayload().get(0),
anyOf(equalTo("sftpTarget/slocalTarget1.txt"), equalTo("sftpTarget/slocalTarget2.txt")));
assertThat(
out.getPayload().get(1),
anyOf(equalTo("sftpTarget/slocalTarget1.txt"), equalTo("sftpTarget/slocalTarget2.txt")));
}
@Test
@IfProfileValue(name="spring.profiles.active", value="realSSH")
public void testInt3088MPutRecursive() {
String dir = "sftpSource/";
this.inboundMGetRecursive.send(new GenericMessage<Object>(dir + "*"));
while (output.receive(0) != null) { }
this.inboundMPutRecursive.send(new GenericMessage<File>(new File("/tmp/sftpOutboundTests/sftpSource")));
@SuppressWarnings("unchecked")
Message<List<String>> out = (Message<List<String>>) this.output.receive(1000);
assertNotNull(out);
assertEquals(3, out.getPayload().size());
assertThat(out.getPayload().get(0),
not(equalTo(out.getPayload().get(1))));
assertThat(
out.getPayload().get(0),
anyOf(equalTo("sftpTarget/slocalTarget1.txt"), equalTo("sftpTarget/slocalTarget2.txt"),
equalTo("sftpTarget/subSftpSource/subSlocalTarget1.txt")));
assertThat(
out.getPayload().get(1),
anyOf(equalTo("sftpTarget/slocalTarget1.txt"), equalTo("sftpTarget/slocalTarget2.txt"),
equalTo("sftpTarget/subSftpSource/subSlocalTarget1.txt")));
assertThat(
out.getPayload().get(2),
anyOf(equalTo("sftpTarget/slocalTarget1.txt"), equalTo("sftpTarget/slocalTarget2.txt"),
equalTo("sftpTarget/subSftpSource/subSlocalTarget1.txt")));
}
@Test
@IfProfileValue(name="spring.profiles.active", value="realSSH")
public void testInt3088MPutRecursiveFiltered() {
String dir = "sftpSource/";
this.inboundMGetRecursive.send(new GenericMessage<Object>(dir + "*"));
while (output.receive(0) != null) { }
this.inboundMPutRecursiveFiltered.send(new GenericMessage<File>(new File("/tmp/sftpOutboundTests/sftpSource")));
@SuppressWarnings("unchecked")
Message<List<String>> out = (Message<List<String>>) this.output.receive(1000);
assertNotNull(out);
assertEquals(2, out.getPayload().size());
assertThat(out.getPayload().get(0),
not(equalTo(out.getPayload().get(1))));
assertThat(
out.getPayload().get(0),
anyOf(equalTo("sftpTarget/slocalTarget1.txt"), equalTo("sftpTarget/slocalTarget2.txt"),
equalTo("sftpTarget/subSftpSource/subSlocalTarget1.txt")));
assertThat(
out.getPayload().get(1),
anyOf(equalTo("sftpTarget/slocalTarget1.txt"), equalTo("sftpTarget/slocalTarget2.txt"),
equalTo("sftpTarget/subSftpSource/subSlocalTarget1.txt")));
}
}