INT-4015: Streaming Remote File Inbound Adapter
JIRA: https://jira.spring.io/browse/INT-4015 https://jira.spring.io/browse/INT-3854 Initial commit. Reworked to emit an input stream and use the file splitter. Add StreamTransformer. Add CLOSABLE_RESOURCE header so we can close the session automatically. Implement INT-3854, FTP, SFTP (S)FTP Namespace Changes Docs - also fixes a PDF overflow Polishing - PR Comments checkstyle fixes Polishing - Add Namespace for StreamParser Polishing - PR Comments
This commit is contained in:
committed by
Artem Bilan
parent
6b6a38f8cb
commit
287d924fc0
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* Copyright 2016 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;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Collections;
|
||||
|
||||
import org.apache.sshd.SshServer;
|
||||
import org.apache.sshd.common.NamedFactory;
|
||||
import org.apache.sshd.common.file.virtualfs.VirtualFileSystemFactory;
|
||||
import org.apache.sshd.server.Command;
|
||||
import org.apache.sshd.server.PasswordAuthenticator;
|
||||
import org.apache.sshd.server.keyprovider.SimpleGeneratorHostKeyProvider;
|
||||
import org.apache.sshd.server.sftp.SftpSubsystem;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.BeforeClass;
|
||||
|
||||
import org.springframework.integration.file.remote.RemoteFileTestSupport;
|
||||
import org.springframework.integration.file.remote.session.CachingSessionFactory;
|
||||
import org.springframework.integration.file.remote.session.SessionFactory;
|
||||
import org.springframework.integration.sftp.session.DefaultSftpSessionFactory;
|
||||
|
||||
import com.jcraft.jsch.ChannelSftp.LsEntry;
|
||||
|
||||
/**
|
||||
* Provides an embedded SFTP Server for test cases.
|
||||
*
|
||||
* @author David Turanski
|
||||
* @author Gary Russell
|
||||
* @since 4.3
|
||||
*/
|
||||
public class SftpTestSupport extends RemoteFileTestSupport {
|
||||
|
||||
private static SshServer server;
|
||||
|
||||
public String getTargetLocalDirectoryName() {
|
||||
return targetLocalDirectory.getAbsolutePath() + File.separator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String prefix() {
|
||||
return "sftp";
|
||||
}
|
||||
|
||||
@BeforeClass
|
||||
public static void createServer() throws Exception {
|
||||
server = SshServer.setUpDefaultServer();
|
||||
server.setPasswordAuthenticator(new PasswordAuthenticator() {
|
||||
|
||||
@Override
|
||||
public boolean authenticate(String username, String password,
|
||||
org.apache.sshd.server.session.ServerSession session) {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
server.setPort(0);
|
||||
server.setKeyPairProvider(new SimpleGeneratorHostKeyProvider("hostkey.ser"));
|
||||
server.setSubsystemFactories(Collections.<NamedFactory<Command>>singletonList(new SftpSubsystem.Factory()));
|
||||
server.setFileSystemFactory(new VirtualFileSystemFactory(remoteTemporaryFolder.getRoot().getAbsolutePath()));
|
||||
server.start();
|
||||
port = server.getPort();
|
||||
}
|
||||
|
||||
public static SessionFactory<LsEntry> sessionFactory() {
|
||||
DefaultSftpSessionFactory factory = new DefaultSftpSessionFactory(true);
|
||||
factory.setHost("localhost");
|
||||
factory.setPort(port);
|
||||
factory.setUser("foo");
|
||||
factory.setPassword("foo");
|
||||
factory.setAllowUnknownKeys(true);
|
||||
return new CachingSessionFactory<LsEntry>(factory);
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void stopServer() throws Exception {
|
||||
server.stop();
|
||||
File hostkey = new File("hostkey.ser");
|
||||
if (hostkey.exists()) {
|
||||
hostkey.delete();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,186 +0,0 @@
|
||||
/*
|
||||
* Copyright 2014-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* 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;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
|
||||
import org.apache.sshd.SshServer;
|
||||
import org.apache.sshd.common.NamedFactory;
|
||||
import org.apache.sshd.common.file.virtualfs.VirtualFileSystemFactory;
|
||||
import org.apache.sshd.server.Command;
|
||||
import org.apache.sshd.server.PasswordAuthenticator;
|
||||
import org.apache.sshd.server.keyprovider.SimpleGeneratorHostKeyProvider;
|
||||
import org.apache.sshd.server.session.ServerSession;
|
||||
import org.apache.sshd.server.sftp.SftpSubsystem;
|
||||
import org.junit.rules.TemporaryFolder;
|
||||
|
||||
import org.springframework.beans.factory.DisposableBean;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.integration.file.remote.session.CachingSessionFactory;
|
||||
import org.springframework.integration.sftp.session.DefaultSftpSessionFactory;
|
||||
|
||||
import com.jcraft.jsch.ChannelSftp.LsEntry;
|
||||
|
||||
/**
|
||||
* @author Gary Russell
|
||||
* @author Artem Bilan
|
||||
* @since 4.1
|
||||
*
|
||||
*/
|
||||
public class TestSftpServer implements InitializingBean, DisposableBean {
|
||||
|
||||
private final SshServer server = SshServer.setUpDefaultServer();
|
||||
|
||||
private final TemporaryFolder sftpFolder;
|
||||
|
||||
private final TemporaryFolder localFolder;
|
||||
|
||||
private volatile File sftpRootFolder;
|
||||
|
||||
private volatile File sourceSftpDirectory;
|
||||
|
||||
private volatile File targetSftpDirectory;
|
||||
|
||||
private volatile File sourceLocalDirectory;
|
||||
|
||||
private volatile File targetLocalDirectory;
|
||||
|
||||
public TestSftpServer() {
|
||||
this.sftpFolder = new TemporaryFolder() {
|
||||
|
||||
@Override
|
||||
public void create() throws IOException {
|
||||
super.create();
|
||||
sftpRootFolder = this.newFolder("test");
|
||||
sourceSftpDirectory = new File(sftpRootFolder, "sftpSource");
|
||||
sourceSftpDirectory.mkdir();
|
||||
File file = new File(sourceSftpDirectory, "sftpSource1.txt");
|
||||
file.createNewFile();
|
||||
FileOutputStream fos = new FileOutputStream(file);
|
||||
fos.write("source1".getBytes());
|
||||
fos.close();
|
||||
file = new File(sourceSftpDirectory, "sftpSource2.txt");
|
||||
file.createNewFile();
|
||||
fos = new FileOutputStream(file);
|
||||
fos.write("source2".getBytes());
|
||||
fos.close();
|
||||
|
||||
File subSourceFtpDirectory = new File(sourceSftpDirectory, "subSftpSource");
|
||||
subSourceFtpDirectory.mkdir();
|
||||
file = new File(subSourceFtpDirectory, "subSftpSource1.txt");
|
||||
file.createNewFile();
|
||||
fos = new FileOutputStream(file);
|
||||
fos.write("subSource1".getBytes());
|
||||
fos.close();
|
||||
|
||||
targetSftpDirectory = new File(sftpRootFolder, "sftpTarget");
|
||||
targetSftpDirectory.mkdir();
|
||||
}
|
||||
};
|
||||
this.localFolder = new TemporaryFolder() {
|
||||
|
||||
@Override
|
||||
public void create() throws IOException {
|
||||
super.create();
|
||||
File rootFolder = this.newFolder("test");
|
||||
sourceLocalDirectory = new File(rootFolder, "localSource");
|
||||
sourceLocalDirectory.mkdirs();
|
||||
File file = new File(sourceLocalDirectory, "localSource1.txt");
|
||||
file.createNewFile();
|
||||
file = new File(sourceLocalDirectory, "localSource2.txt");
|
||||
file.createNewFile();
|
||||
|
||||
File subSourceLocalDirectory = new File(sourceLocalDirectory, "subLocalSource");
|
||||
subSourceLocalDirectory.mkdir();
|
||||
file = new File(subSourceLocalDirectory, "subLocalSource1.txt");
|
||||
file.createNewFile();
|
||||
|
||||
targetLocalDirectory = new File(rootFolder, "slocalTarget");
|
||||
targetLocalDirectory.mkdir();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
this.sftpFolder.create();
|
||||
this.localFolder.create();
|
||||
server.setPasswordAuthenticator(new PasswordAuthenticator() {
|
||||
|
||||
@Override
|
||||
public boolean authenticate(String arg0, String arg1, ServerSession arg2) {
|
||||
return true;
|
||||
}
|
||||
|
||||
});
|
||||
server.setPort(0);
|
||||
server.setKeyPairProvider(new SimpleGeneratorHostKeyProvider("hostkey.ser"));
|
||||
this.server.setSubsystemFactories(Collections.<NamedFactory<Command>>singletonList(new SftpSubsystem.Factory()));
|
||||
this.server.setFileSystemFactory(new VirtualFileSystemFactory(sftpRootFolder.getAbsolutePath()));
|
||||
server.start();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() throws Exception {
|
||||
this.server.stop(true);
|
||||
this.sftpFolder.delete();
|
||||
this.localFolder.delete();
|
||||
}
|
||||
|
||||
public File getSourceLocalDirectory() {
|
||||
return this.sourceLocalDirectory;
|
||||
}
|
||||
|
||||
public File getTargetLocalDirectory() {
|
||||
return this.targetLocalDirectory;
|
||||
}
|
||||
|
||||
public String getTargetLocalDirectoryName() {
|
||||
return this.targetLocalDirectory.getAbsolutePath() + File.separator;
|
||||
}
|
||||
|
||||
public File getTargetSftpDirectory() {
|
||||
return this.targetSftpDirectory;
|
||||
}
|
||||
|
||||
public void recursiveDelete(File file) {
|
||||
File[] files = file.listFiles();
|
||||
if (files != null) {
|
||||
for (File each : files) {
|
||||
recursiveDelete(each);
|
||||
}
|
||||
}
|
||||
if (!(file.equals(this.targetSftpDirectory) || file.equals(this.targetLocalDirectory))) {
|
||||
file.delete();
|
||||
}
|
||||
}
|
||||
|
||||
public CachingSessionFactory<LsEntry> getSessionFactory() {
|
||||
DefaultSftpSessionFactory factory = new DefaultSftpSessionFactory(true);
|
||||
factory.setHost("localhost");
|
||||
factory.setPort(this.server.getPort());
|
||||
factory.setUser("foo");
|
||||
factory.setPassword("foo");
|
||||
factory.setAllowUnknownKeys(true);
|
||||
return new CachingSessionFactory<LsEntry>(factory);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
/*
|
||||
* Copyright 2014-2016 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;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.integration.file.remote.session.CachingSessionFactory;
|
||||
|
||||
import com.jcraft.jsch.ChannelSftp.LsEntry;
|
||||
|
||||
/**
|
||||
* @author Gary Russell
|
||||
* @since 4.1
|
||||
*
|
||||
*/
|
||||
@Configuration
|
||||
public class TestSftpServerConfig {
|
||||
|
||||
@Bean
|
||||
public TestSftpServer sftpServer() {
|
||||
return new TestSftpServer();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public CachingSessionFactory<LsEntry> sftpSessionFactory(TestSftpServer server) {
|
||||
return sftpServer().getSessionFactory();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:int="http://www.springframework.org/schema/integration"
|
||||
xmlns:int-sftp="http://www.springframework.org/schema/integration/sftp"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd
|
||||
http://www.springframework.org/schema/integration/sftp http://www.springframework.org/schema/integration/sftp/spring-integration-sftp.xsd">
|
||||
|
||||
<bean id="sftpSessionFactory"
|
||||
class="org.springframework.integration.sftp.config.SftpStreamingInboundChannelAdapterParserTests$TestSessionFactoryBean"/>
|
||||
|
||||
<bean id="csf" class="org.springframework.integration.file.remote.session.CachingSessionFactory">
|
||||
<constructor-arg ref="sftpSessionFactory"/>
|
||||
</bean>
|
||||
|
||||
<int-sftp:inbound-streaming-channel-adapter id="sftpInbound"
|
||||
channel="sftpChannel"
|
||||
session-factory="csf"
|
||||
auto-startup="false"
|
||||
phase="23"
|
||||
filename-pattern="*.txt"
|
||||
remote-file-separator="X"
|
||||
comparator="comparator"
|
||||
remote-directory-expression="'foo/bar'">
|
||||
<int:poller fixed-rate="1000" />
|
||||
</int-sftp:inbound-streaming-channel-adapter>
|
||||
|
||||
<int:channel id="sftpChannel">
|
||||
<int:queue/>
|
||||
</int:channel>
|
||||
|
||||
<bean id="comparator" class="org.mockito.Mockito" factory-method="mock">
|
||||
<constructor-arg value="java.util.Comparator"/>
|
||||
</bean>
|
||||
|
||||
<int-sftp:inbound-streaming-channel-adapter id="contextLoadsWithNoComparator"
|
||||
channel="sftpChannel"
|
||||
session-factory="csf"
|
||||
auto-startup="false"
|
||||
phase="23"
|
||||
filename-pattern="*.txt"
|
||||
remote-file-separator="X"
|
||||
remote-directory-expression="'foo/bar'">
|
||||
<int:poller fixed-rate="1000" />
|
||||
</int-sftp:inbound-streaming-channel-adapter>
|
||||
|
||||
</beans>
|
||||
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* Copyright 2016 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.config;
|
||||
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.instanceOf;
|
||||
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.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.integration.endpoint.SourcePollingChannelAdapter;
|
||||
import org.springframework.integration.file.remote.session.CachingSessionFactory;
|
||||
import org.springframework.integration.sftp.filters.SftpSimplePatternFileListFilter;
|
||||
import org.springframework.integration.sftp.inbound.SftpStreamingMessageSource;
|
||||
import org.springframework.integration.sftp.session.DefaultSftpSessionFactory;
|
||||
import org.springframework.integration.sftp.session.SftpSession;
|
||||
import org.springframework.integration.test.util.TestUtils;
|
||||
import org.springframework.messaging.MessageChannel;
|
||||
import org.springframework.test.annotation.DirtiesContext;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
|
||||
/**
|
||||
* @author Gary Russell
|
||||
*/
|
||||
@ContextConfiguration
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@DirtiesContext
|
||||
public class SftpStreamingInboundChannelAdapterParserTests {
|
||||
|
||||
@Autowired
|
||||
private SourcePollingChannelAdapter sftpInbound;
|
||||
|
||||
@Autowired
|
||||
private MessageChannel sftpChannel;
|
||||
|
||||
@Autowired
|
||||
private CachingSessionFactory<?> csf;
|
||||
|
||||
@Test
|
||||
public void testFtpInboundChannelAdapterComplete() throws Exception {
|
||||
assertFalse(TestUtils.getPropertyValue(this.sftpInbound, "autoStartup", Boolean.class));
|
||||
assertEquals("sftpInbound", this.sftpInbound.getComponentName());
|
||||
assertEquals("sftp:inbound-streaming-channel-adapter", this.sftpInbound.getComponentType());
|
||||
assertSame(this.sftpChannel, TestUtils.getPropertyValue(this.sftpInbound, "outputChannel"));
|
||||
SftpStreamingMessageSource source = TestUtils.getPropertyValue(sftpInbound, "source",
|
||||
SftpStreamingMessageSource.class);
|
||||
|
||||
assertNotNull(TestUtils.getPropertyValue(source, "comparator"));
|
||||
assertThat(TestUtils.getPropertyValue(source, "remoteFileSeparator", String.class), equalTo("X"));
|
||||
assertThat(TestUtils.getPropertyValue(source, "filter"), instanceOf(SftpSimplePatternFileListFilter.class));
|
||||
assertSame(this.csf, TestUtils.getPropertyValue(source, "remoteFileTemplate.sessionFactory"));
|
||||
}
|
||||
|
||||
public static class TestSessionFactoryBean implements FactoryBean<DefaultSftpSessionFactory> {
|
||||
|
||||
@Override
|
||||
public DefaultSftpSessionFactory getObject() throws Exception {
|
||||
DefaultSftpSessionFactory factory = mock(DefaultSftpSessionFactory.class);
|
||||
SftpSession session = mock(SftpSession.class);
|
||||
when(factory.getSession()).thenReturn(session);
|
||||
return factory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getObjectType() {
|
||||
return DefaultSftpSessionFactory.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSingleton() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -7,13 +7,15 @@
|
||||
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="extraConfig" class="org.springframework.integration.sftp.inbound.RollbackLocalFilterTests$Config" />
|
||||
|
||||
<int-sftp:inbound-channel-adapter id="sftpAdapterAutoCreate"
|
||||
session-factory="sftpSessionFactory"
|
||||
channel="requestChannel"
|
||||
remote-directory-expression="'/sftpSource'"
|
||||
local-directory="file:local-test-dir/rollback"
|
||||
auto-create-local-directory="true"
|
||||
filename-pattern="sftpSource1.txt"
|
||||
filename-pattern="sftpSource2.txt"
|
||||
local-filter="acceptOnceFilter">
|
||||
<int:poller fixed-rate="1000" max-messages-per-poll="2" error-channel="nullChannel">
|
||||
<int:transactional synchronization-factory="syncFactory" />
|
||||
@@ -34,6 +36,4 @@
|
||||
|
||||
<bean id="transactionManager" class="org.springframework.integration.transaction.PseudoTransactionManager" />
|
||||
|
||||
<bean id="sftpServerConfig" class="org.springframework.integration.sftp.TestSftpServerConfig" />
|
||||
|
||||
</beans>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
* Copyright 2015-2016 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.
|
||||
@@ -30,10 +30,15 @@ import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.integration.file.remote.session.SessionFactory;
|
||||
import org.springframework.integration.sftp.SftpTestSupport;
|
||||
import org.springframework.test.annotation.DirtiesContext;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
|
||||
import com.jcraft.jsch.ChannelSftp.LsEntry;
|
||||
|
||||
/**
|
||||
* @author Gary Russell
|
||||
* @author Artem Bilan
|
||||
@@ -43,12 +48,12 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
@ContextConfiguration
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@DirtiesContext
|
||||
public class RollbackLocalFilterTests {
|
||||
public class RollbackLocalFilterTests extends SftpTestSupport {
|
||||
|
||||
@BeforeClass
|
||||
@AfterClass
|
||||
public static void clean() {
|
||||
new File("local-test-dir/rollback/sftpSource1.txt").delete();
|
||||
new File("local-test-dir/rollback/sftpSource2.txt").delete();
|
||||
}
|
||||
|
||||
@Autowired
|
||||
@@ -57,7 +62,7 @@ public class RollbackLocalFilterTests {
|
||||
@Test
|
||||
public void testRollback() throws Exception {
|
||||
assertTrue(this.crash.getLatch().await(10, TimeUnit.SECONDS));
|
||||
assertEquals("sftpSource1.txt", this.crash.getFile().getName());
|
||||
assertEquals("sftpSource2.txt", this.crash.getFile().getName());
|
||||
}
|
||||
|
||||
public static class Crash {
|
||||
@@ -86,4 +91,13 @@ public class RollbackLocalFilterTests {
|
||||
}
|
||||
}
|
||||
|
||||
public static class Config {
|
||||
|
||||
@Bean
|
||||
public SessionFactory<LsEntry> sftpSessionFactory() {
|
||||
return RollbackLocalFilterTests.sessionFactory();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
* Copyright 2016 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.inbound;
|
||||
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.integration.annotation.InboundChannelAdapter;
|
||||
import org.springframework.integration.annotation.Transformer;
|
||||
import org.springframework.integration.channel.QueueChannel;
|
||||
import org.springframework.integration.config.EnableIntegration;
|
||||
import org.springframework.integration.core.MessageSource;
|
||||
import org.springframework.integration.file.remote.session.SessionFactory;
|
||||
import org.springframework.integration.scheduling.PollerMetadata;
|
||||
import org.springframework.integration.sftp.SftpTestSupport;
|
||||
import org.springframework.integration.sftp.session.SftpRemoteFileTemplate;
|
||||
import org.springframework.integration.transformer.StreamTransformer;
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.messaging.PollableChannel;
|
||||
import org.springframework.scheduling.support.PeriodicTrigger;
|
||||
import org.springframework.test.annotation.DirtiesContext;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
|
||||
import com.jcraft.jsch.ChannelSftp.LsEntry;
|
||||
|
||||
/**
|
||||
* @author Gary Russell
|
||||
* @since 4.3
|
||||
*
|
||||
*/
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@DirtiesContext
|
||||
public class SftpStreamingMessageSourceTests extends SftpTestSupport {
|
||||
|
||||
@Autowired
|
||||
public PollableChannel data;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test
|
||||
public void testAllContents() {
|
||||
Message<byte[]> received = (Message<byte[]>) this.data.receive(10000);
|
||||
assertNotNull(received);
|
||||
assertThat(new String(received.getPayload()), equalTo("source1"));
|
||||
received = (Message<byte[]>) this.data.receive(10000);
|
||||
assertNotNull(received);
|
||||
assertThat(new String(received.getPayload()), equalTo("source2"));
|
||||
assertNull(this.data.receive(0));
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableIntegration
|
||||
public static class Config {
|
||||
|
||||
@Bean
|
||||
public QueueChannel data() {
|
||||
return new QueueChannel();
|
||||
}
|
||||
|
||||
@Bean(name = PollerMetadata.DEFAULT_POLLER)
|
||||
public PollerMetadata defaultPoller() {
|
||||
PollerMetadata pollerMetadata = new PollerMetadata();
|
||||
pollerMetadata.setTrigger(new PeriodicTrigger(500));
|
||||
pollerMetadata.setMaxMessagesPerPoll(2000);
|
||||
return pollerMetadata;
|
||||
}
|
||||
|
||||
@Bean
|
||||
@InboundChannelAdapter(channel = "stream")
|
||||
public MessageSource<InputStream> ftpMessageSource() {
|
||||
SftpStreamingMessageSource messageSource = new SftpStreamingMessageSource(template(), null);
|
||||
messageSource.setRemoteDirectory("sftpSource/");
|
||||
return messageSource;
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Transformer(inputChannel = "stream", outputChannel = "data")
|
||||
public org.springframework.integration.transformer.Transformer transformer() {
|
||||
return new StreamTransformer();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public SftpRemoteFileTemplate template() {
|
||||
return new SftpRemoteFileTemplate(ftpSessionFactory());
|
||||
}
|
||||
|
||||
@Bean
|
||||
public SessionFactory<LsEntry> ftpSessionFactory() {
|
||||
return SftpStreamingMessageSourceTests.sessionFactory();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -9,6 +9,8 @@
|
||||
http://www.springframework.org/schema/integration/file http://www.springframework.org/schema/integration/file/spring-integration-file.xsd
|
||||
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd">
|
||||
|
||||
<bean id="extraConfig" class="org.springframework.integration.sftp.outbound.SftpServerOutboundTests$Config" />
|
||||
|
||||
<int:channel id="output">
|
||||
<int:queue/>
|
||||
</int:channel>
|
||||
@@ -19,7 +21,7 @@
|
||||
request-channel="inboundGet"
|
||||
command="get"
|
||||
expression="payload"
|
||||
local-directory-expression="@sftpServer.targetLocalDirectoryName + #remoteDirectory.toUpperCase()"
|
||||
local-directory-expression="@extraConfig.targetLocalDirectoryName + #remoteDirectory.toUpperCase()"
|
||||
local-filename-generator-expression="#remoteFileName.replaceFirst('sftpSource', 'localTarget')"
|
||||
reply-channel="output"/>
|
||||
|
||||
@@ -38,7 +40,7 @@
|
||||
request-channel="inboundMGet"
|
||||
command="mget"
|
||||
expression="payload"
|
||||
local-directory-expression="@sftpServer.targetLocalDirectoryName + #remoteDirectory"
|
||||
local-directory-expression="@extraConfig.targetLocalDirectoryName + #remoteDirectory"
|
||||
local-filename-generator-expression="#remoteFileName.replaceFirst('sftpSource', 'localTarget')"
|
||||
reply-channel="output"/>
|
||||
|
||||
@@ -49,7 +51,7 @@
|
||||
command="mget"
|
||||
expression="payload"
|
||||
command-options="-R"
|
||||
local-directory-expression="@sftpServer.targetLocalDirectoryName + #remoteDirectory"
|
||||
local-directory-expression="@extraConfig.targetLocalDirectoryName + #remoteDirectory"
|
||||
local-filename-generator-expression="#remoteFileName.replaceFirst('sftpSource', 'localTarget')"
|
||||
reply-channel="output"/>
|
||||
|
||||
@@ -61,7 +63,7 @@
|
||||
expression="payload"
|
||||
command-options="-R"
|
||||
filename-regex="(subSftpSource|.*1.txt)"
|
||||
local-directory-expression="@sftpServer.targetLocalDirectoryName + #remoteDirectory"
|
||||
local-directory-expression="@extraConfig.targetLocalDirectoryName + #remoteDirectory"
|
||||
local-filename-generator-expression="#remoteFileName.replaceFirst('sftpSource', 'localTarget')"
|
||||
reply-channel="output"/>
|
||||
|
||||
@@ -104,8 +106,6 @@
|
||||
|
||||
<int:channel id="appending" />
|
||||
|
||||
<bean id="sftpServerConfig" class="org.springframework.integration.sftp.TestSftpServerConfig" />
|
||||
|
||||
<int-sftp:outbound-channel-adapter id="appender"
|
||||
session-factory="sftpSessionFactory"
|
||||
channel="appending"
|
||||
|
||||
@@ -40,20 +40,20 @@ import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.hamcrest.Matchers;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.DirectFieldAccessor;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.integration.channel.DirectChannel;
|
||||
import org.springframework.integration.file.FileHeaders;
|
||||
import org.springframework.integration.file.remote.MessageSessionCallback;
|
||||
import org.springframework.integration.file.remote.SessionCallback;
|
||||
import org.springframework.integration.file.remote.session.Session;
|
||||
import org.springframework.integration.file.remote.session.SessionFactory;
|
||||
import org.springframework.integration.sftp.TestSftpServer;
|
||||
import org.springframework.integration.sftp.SftpTestSupport;
|
||||
import org.springframework.integration.sftp.session.SftpRemoteFileTemplate;
|
||||
import org.springframework.integration.support.MessageBuilder;
|
||||
import org.springframework.integration.test.util.TestUtils;
|
||||
@@ -69,24 +69,13 @@ import com.jcraft.jsch.ChannelSftp;
|
||||
import com.jcraft.jsch.ChannelSftp.LsEntry;
|
||||
|
||||
/**
|
||||
* Runs against an embedded SFTP Server with the following directory tree:
|
||||
*
|
||||
* <pre class="code">
|
||||
* $ tree sftpSource/
|
||||
* sftpSource/
|
||||
* ??? sftpSource1.txt - contains 'source1'
|
||||
* ??? sftpSource2.txt - contains 'source2'
|
||||
* ??? subSftpSource
|
||||
* ??? subSftpSource1.txt - contains 'subSource1'
|
||||
* </pre>
|
||||
*
|
||||
* @author Artem Bilan
|
||||
* @author Gary Russell
|
||||
* @since 3.0
|
||||
*/
|
||||
@ContextConfiguration
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
public class SftpServerOutboundTests {
|
||||
public class SftpServerOutboundTests extends SftpTestSupport {
|
||||
|
||||
@Autowired
|
||||
private PollableChannel output;
|
||||
@@ -127,27 +116,25 @@ public class SftpServerOutboundTests {
|
||||
@Autowired
|
||||
private DirectChannel failing;
|
||||
|
||||
@Autowired
|
||||
private TestSftpServer sftpServer;
|
||||
|
||||
@Autowired
|
||||
private DirectChannel inboundGetStream;
|
||||
|
||||
@Autowired
|
||||
private DirectChannel inboundCallback;
|
||||
|
||||
@Autowired
|
||||
private Config config;
|
||||
|
||||
@Before
|
||||
@After
|
||||
public void setup() {
|
||||
this.sftpServer.recursiveDelete(sftpServer.getTargetLocalDirectory());
|
||||
this.sftpServer.recursiveDelete(sftpServer.getTargetSftpDirectory());
|
||||
this.config.targetLocalDirectoryName = getTargetLocalDirectoryName();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInt2866LocalDirectoryExpressionGET() {
|
||||
Session<?> session = this.sessionFactory.getSession();
|
||||
String dir = "sftpSource/";
|
||||
this.inboundGet.send(new GenericMessage<Object>(dir + "sftpSource1.txt"));
|
||||
this.inboundGet.send(new GenericMessage<Object>(dir + " sftpSource1.txt"));
|
||||
Message<?> result = this.output.receive(1000);
|
||||
assertNotNull(result);
|
||||
File localFile = (File) result.getPayload();
|
||||
@@ -169,7 +156,7 @@ public class SftpServerOutboundTests {
|
||||
@Test
|
||||
public void testInt2866InvalidLocalDirectoryExpression() {
|
||||
try {
|
||||
this.invalidDirExpression.send(new GenericMessage<Object>("sftpSource/sftpSource1.txt"));
|
||||
this.invalidDirExpression.send(new GenericMessage<Object>("sftpSource/ sftpSource1.txt"));
|
||||
fail("Exception expected.");
|
||||
}
|
||||
catch (Exception e) {
|
||||
@@ -257,7 +244,7 @@ public class SftpServerOutboundTests {
|
||||
public void testInt3100RawGET() throws Exception {
|
||||
Session<?> session = this.sessionFactory.getSession();
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
FileCopyUtils.copy(session.readRaw("sftpSource/sftpSource1.txt"), baos);
|
||||
FileCopyUtils.copy(session.readRaw("sftpSource/ sftpSource1.txt"), baos);
|
||||
assertTrue(session.finalizeRaw());
|
||||
assertEquals("source1", new String(baos.toByteArray()));
|
||||
|
||||
@@ -341,7 +328,7 @@ public class SftpServerOutboundTests {
|
||||
while (output.receive(0) != null) {
|
||||
// drain
|
||||
}
|
||||
this.inboundMPut.send(new GenericMessage<File>(this.sftpServer.getSourceLocalDirectory()));
|
||||
this.inboundMPut.send(new GenericMessage<File>(getSourceLocalDirectory()));
|
||||
@SuppressWarnings("unchecked")
|
||||
Message<List<String>> out = (Message<List<String>>) this.output.receive(1000);
|
||||
assertNotNull(out);
|
||||
@@ -365,7 +352,7 @@ public class SftpServerOutboundTests {
|
||||
while (output.receive(0) != null) {
|
||||
// drain
|
||||
}
|
||||
this.inboundMPutRecursive.send(new GenericMessage<File>(this.sftpServer.getSourceLocalDirectory()));
|
||||
this.inboundMPutRecursive.send(new GenericMessage<File>(getSourceLocalDirectory()));
|
||||
@SuppressWarnings("unchecked")
|
||||
Message<List<String>> out = (Message<List<String>>) this.output.receive(1000);
|
||||
assertNotNull(out);
|
||||
@@ -393,7 +380,7 @@ public class SftpServerOutboundTests {
|
||||
while (output.receive(0) != null) {
|
||||
// drain
|
||||
}
|
||||
this.inboundMPutRecursiveFiltered.send(new GenericMessage<File>(this.sftpServer.getSourceLocalDirectory()));
|
||||
this.inboundMPutRecursiveFiltered.send(new GenericMessage<File>(getSourceLocalDirectory()));
|
||||
@SuppressWarnings("unchecked")
|
||||
Message<List<String>> out = (Message<List<String>>) this.output.receive(1000);
|
||||
assertNotNull(out);
|
||||
@@ -439,12 +426,12 @@ public class SftpServerOutboundTests {
|
||||
session.close();
|
||||
|
||||
String dir = "sftpSource/";
|
||||
this.inboundGetStream.send(new GenericMessage<Object>(dir + "sftpSource1.txt"));
|
||||
this.inboundGetStream.send(new GenericMessage<Object>(dir + " sftpSource1.txt"));
|
||||
Message<?> result = this.output.receive(1000);
|
||||
assertNotNull(result);
|
||||
assertEquals("source1", result.getPayload());
|
||||
assertEquals("sftpSource/", result.getHeaders().get(FileHeaders.REMOTE_DIRECTORY));
|
||||
assertEquals("sftpSource1.txt", result.getHeaders().get(FileHeaders.REMOTE_FILE));
|
||||
assertEquals(" sftpSource1.txt", result.getHeaders().get(FileHeaders.REMOTE_FILE));
|
||||
verify(session).close();
|
||||
}
|
||||
|
||||
@@ -479,4 +466,19 @@ public class SftpServerOutboundTests {
|
||||
|
||||
}
|
||||
|
||||
public static class Config {
|
||||
|
||||
private volatile String targetLocalDirectoryName;
|
||||
|
||||
@Bean
|
||||
public SessionFactory<LsEntry> sftpSessionFactory() {
|
||||
return SftpServerOutboundTests.sessionFactory();
|
||||
}
|
||||
|
||||
public String getTargetLocalDirectoryName() {
|
||||
return this.targetLocalDirectoryName;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -22,12 +22,12 @@ import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.expression.common.LiteralExpression;
|
||||
import org.springframework.integration.file.DefaultFileNameGenerator;
|
||||
import org.springframework.integration.file.remote.ClientCallbackWithoutResult;
|
||||
@@ -35,8 +35,8 @@ import org.springframework.integration.file.remote.SessionCallback;
|
||||
import org.springframework.integration.file.remote.SessionCallbackWithoutResult;
|
||||
import org.springframework.integration.file.remote.session.CachingSessionFactory;
|
||||
import org.springframework.integration.file.remote.session.Session;
|
||||
import org.springframework.integration.sftp.TestSftpServer;
|
||||
import org.springframework.integration.sftp.TestSftpServerConfig;
|
||||
import org.springframework.integration.file.remote.session.SessionFactory;
|
||||
import org.springframework.integration.sftp.SftpTestSupport;
|
||||
import org.springframework.messaging.support.GenericMessage;
|
||||
import org.springframework.test.annotation.DirtiesContext;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
@@ -52,24 +52,14 @@ import com.jcraft.jsch.SftpException;
|
||||
* @since 4.1
|
||||
*
|
||||
*/
|
||||
@ContextConfiguration(classes = TestSftpServerConfig.class)
|
||||
@ContextConfiguration
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@DirtiesContext
|
||||
public class SftpRemoteFileTemplateTests {
|
||||
|
||||
@Autowired
|
||||
private TestSftpServer sftpServer;
|
||||
public class SftpRemoteFileTemplateTests extends SftpTestSupport {
|
||||
|
||||
@Autowired
|
||||
private CachingSessionFactory<LsEntry> sessionFactory;
|
||||
|
||||
@Before
|
||||
@After
|
||||
public void setup() {
|
||||
this.sftpServer.recursiveDelete(sftpServer.getTargetLocalDirectory());
|
||||
this.sftpServer.recursiveDelete(sftpServer.getTargetSftpDirectory());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testINT3412AppendStatRmdir() {
|
||||
SftpRemoteFileTemplate template = new SftpRemoteFileTemplate(sessionFactory);
|
||||
@@ -117,4 +107,14 @@ public class SftpRemoteFileTemplateTests {
|
||||
assertFalse(template.exists("foo"));
|
||||
}
|
||||
|
||||
@Configuration
|
||||
public static class Config {
|
||||
|
||||
@Bean
|
||||
public SessionFactory<LsEntry> ftpSessionFactory() {
|
||||
return SftpRemoteFileTemplateTests.sessionFactory();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user