INTSAMPLES-134: SFTP: Use Apache SSHD SshServer

JIRA: https://jira.spring.io/browse/INTSAMPLES-134

INTSAMPLES-134: `sun.misc.BASE64Decoder` -> `org.apache.sshd.common.util.Base64`

INTSAMPLES-134: PR comments and fix for Windows

INTSAMPLES-134 Test Samples with Remote Server

- change 'user' property to 'username' to avoid conflict with environment variable.
- create temporary files using the remote file template in 'si.sftp.sample'.
- clean up after test completion.
- use a caching session factory.
This commit is contained in:
Artem Bilan
2014-07-29 15:22:46 +03:00
committed by Gary Russell
parent 35e5156bdb
commit 90d5ee9282
19 changed files with 494 additions and 110 deletions

View File

@@ -1,3 +1,4 @@
/local-dir
/target
/src/test/resources/META-INF/keys/sftp_rsa
hostkey.ser
si.sftp.sample

View File

@@ -6,11 +6,18 @@ This example demonstrates the following aspects of the SFTP support available wi
1. SFTP Inbound Channel Adapter (transfers files from remote to local directory)
2. SFTP Outbound Channel Adapter (transfers files from local to the remote directory)
In order to run this sample you need to:
In order to run this sample for the 'real' SFTP Server you need to:
1. generate private/public keys. Below is simple directions what needs to be done
2. update user.properties file with appropriate values
3. run the sample
By default this sample uses an [Apache MINA](http://mina.apache.org/sshd-project) embedded `SshServer` with predefined
private and public keys.
Note, the embedded Server is started only when the `port` property remains as `-1`. In this case the target port
for the Embedded Server is selected randomly. For a real SFTP server you should specify correct `host/port` properties.
NOTE: The test cases will create/delete a directory `si.sftp.sample`.
## INBOUND CHANNEL ADAPTER

View File

@@ -1 +0,0 @@
A

View File

@@ -1 +0,0 @@
B

View File

@@ -1 +0,0 @@
C

View File

@@ -0,0 +1,168 @@
/*
* Copyright 2014 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.samples.sftp;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigInteger;
import java.nio.ByteBuffer;
import java.security.KeyFactory;
import java.security.PublicKey;
import java.security.spec.RSAPublicKeySpec;
import java.util.Collections;
import org.apache.sshd.SshServer;
import org.apache.sshd.common.NamedFactory;
import org.apache.sshd.common.file.FileSystemView;
import org.apache.sshd.common.file.nativefs.NativeFileSystemFactory;
import org.apache.sshd.common.file.nativefs.NativeFileSystemView;
import org.apache.sshd.common.util.Base64;
import org.apache.sshd.server.Command;
import org.apache.sshd.server.PublickeyAuthenticator;
import org.apache.sshd.server.keyprovider.SimpleGeneratorHostKeyProvider;
import org.apache.sshd.server.session.ServerSession;
import org.apache.sshd.server.sftp.SftpSubsystem;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.SmartLifecycle;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.FileSystemResource;
import org.springframework.util.SocketUtils;
import org.springframework.util.StreamUtils;
/**
* @author Artem Bilan
*/
public class EmbeddedSftpServer implements InitializingBean, SmartLifecycle {
public static final int PORT = SocketUtils.findAvailableTcpPort();
private final SshServer server = SshServer.setUpDefaultServer();
private volatile int port;
private volatile boolean running;
public void setPort(int port) {
this.port = port;
}
@Override
public void afterPropertiesSet() throws Exception {
final PublicKey allowedKey = decodePublicKey();
this.server.setPublickeyAuthenticator(new PublickeyAuthenticator() {
@Override
public boolean authenticate(String username, PublicKey key, ServerSession session) {
return key.equals(allowedKey);
}
});
this.server.setPort(this.port);
this.server.setKeyPairProvider(new SimpleGeneratorHostKeyProvider("hostkey.ser"));
this.server.setSubsystemFactories(Collections.<NamedFactory<Command>>singletonList(new SftpSubsystem.Factory()));
final String virtualDir = new FileSystemResource("").getFile().getAbsolutePath();
this.server.setFileSystemFactory(new NativeFileSystemFactory() {
@Override
public FileSystemView createFileSystemView(org.apache.sshd.common.Session session) {
return new NativeFileSystemView(session.getUsername(), false) {
@Override
public String getVirtualUserDir() {
return virtualDir;
}
};
}
});
}
private PublicKey decodePublicKey() throws Exception {
InputStream stream = new ClassPathResource("META-INF/keys/sftp_rsa.pub").getInputStream();
byte[] decodeBuffer = Base64.decodeBase64(StreamUtils.copyToByteArray(stream));
ByteBuffer bb = ByteBuffer.wrap(decodeBuffer);
int len = bb.getInt();
byte[] type = new byte[len];
bb.get(type);
if ("ssh-rsa".equals(new String(type))) {
BigInteger e = decodeBigInt(bb);
BigInteger m = decodeBigInt(bb);
RSAPublicKeySpec spec = new RSAPublicKeySpec(m, e);
return KeyFactory.getInstance("RSA").generatePublic(spec);
}
else {
throw new IllegalArgumentException("Only supports RSA");
}
}
private BigInteger decodeBigInt(ByteBuffer bb) {
int len = bb.getInt();
byte[] bytes = new byte[len];
bb.get(bytes);
return new BigInteger(bytes);
}
@Override
public boolean isAutoStartup() {
return PORT == this.port;
}
@Override
public int getPhase() {
return Integer.MAX_VALUE;
}
@Override
public void start() {
try {
server.start();
this.running = true;
}
catch (IOException e) {
throw new IllegalStateException(e);
}
}
@Override
public void stop(Runnable callback) {
stop();
callback.run();
}
@Override
public void stop() {
if (this.running) {
try {
server.stop(true);
}
catch (InterruptedException e) {
throw new IllegalStateException(e);
}
finally {
this.running = false;
}
}
}
@Override
public boolean isRunning() {
return this.running;
}
}

View File

@@ -15,24 +15,68 @@
*/
package org.springframework.integration.samples.sftp;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import java.io.File;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.integration.endpoint.SourcePollingChannelAdapter;
import org.springframework.integration.file.remote.RemoteFileTemplate;
import org.springframework.integration.file.remote.session.CachingSessionFactory;
import org.springframework.integration.file.remote.session.SessionFactory;
import org.springframework.messaging.Message;
import org.springframework.messaging.PollableChannel;
import com.jcraft.jsch.ChannelSftp.LsEntry;
/**
* @author Oleg Zhurakousky
* @author Gary Russell
*
*/
public class SftpInboundReceiveSample {
@Test
public void runDemo(){
ApplicationContext context = new ClassPathXmlApplicationContext("/META-INF/spring/integration/SftpInboundReceiveSample-context.xml", this.getClass());
PollableChannel localFileChannel = context.getBean("receiveChannel", PollableChannel.class);
System.out.println("Received first file message: " + localFileChannel.receive());
System.out.println("Received second file message: " + localFileChannel.receive());
System.out.println("No third file was received " + localFileChannel.receive(1000));
ConfigurableApplicationContext context =
new ClassPathXmlApplicationContext("/META-INF/spring/integration/SftpInboundReceiveSample-context.xml", this.getClass());
RemoteFileTemplate<LsEntry> template = null;
String file1 = "a.txt";
String file2 = "b.txt";
String file3 = "c.bar";
new File("local-dir", file1).delete();
new File("local-dir", file2).delete();
try {
PollableChannel localFileChannel = context.getBean("receiveChannel", PollableChannel.class);
@SuppressWarnings("unchecked")
SessionFactory<LsEntry> sessionFactory = context.getBean(CachingSessionFactory.class);
template = new RemoteFileTemplate<LsEntry>(sessionFactory);
SftpTestUtils.createTestFiles(template, file1, file2, file3);
SourcePollingChannelAdapter adapter = context.getBean(SourcePollingChannelAdapter.class);
adapter.start();
Message<?> received = localFileChannel.receive();
assertNotNull("Expected file", received);
System.out.println("Received first file message: " + received);
received = localFileChannel.receive();
assertNotNull("Expected file", received);
System.out.println("Received second file message: " + received);
received = localFileChannel.receive(1000);
assertNull("Expected null", received);
System.out.println("No third file was received as expected");
}
finally {
SftpTestUtils.cleanUp(template, file1, file2, file3);
context.close();
assertTrue("Could note delete retrieved file", new File("local-dir", file1).delete());
assertTrue("Could note delete retrieved file", new File("local-dir", file2).delete());
}
}
}

View File

@@ -20,11 +20,16 @@ import static org.junit.Assert.assertTrue;
import java.io.File;
import java.util.List;
import java.util.Random;
import org.junit.Test;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.integration.file.remote.RemoteFileTemplate;
import org.springframework.integration.file.remote.session.CachingSessionFactory;
import org.springframework.integration.file.remote.session.SessionFactory;
import com.jcraft.jsch.ChannelSftp.LsEntry;
/**
* Demonstrates use of the outbound gateway to use ls, get and rm.
@@ -40,24 +45,23 @@ public class SftpOutboundGatewaySample {
ConfigurableApplicationContext ctx = new ClassPathXmlApplicationContext(
"classpath:/META-INF/spring/integration/SftpOutboundGatewaySample-context.xml");
ToSftpFlowGateway toFtpFlow = ctx.getBean(ToSftpFlowGateway.class);
RemoteFileTemplate<LsEntry> template = null;
String file1 = "1.ftptest";
String file2 = "2.ftptest";
File tmpDir = new File(System.getProperty("java.io.tmpdir"));
try {
String tmpDir = System.getProperty("java.io.tmpdir");
// remove the previous output files if necessary
new File(new File(tmpDir), "1.ftptest").delete();
new File(new File(tmpDir), "2.ftptest").delete();
// create a couple of files in a temp dir
File dir = new File(tmpDir + "/" + new Random().nextInt());
dir.mkdir();
File f1 = new File(dir, "1.ftptest");
f1.createNewFile();
File f2 = new File(dir, "2.ftptest");
f2.createNewFile();
new File(tmpDir, file1).delete();
new File(tmpDir, file2).delete();
@SuppressWarnings("unchecked")
SessionFactory<LsEntry> sessionFactory = ctx.getBean(CachingSessionFactory.class);
template = new RemoteFileTemplate<LsEntry>(sessionFactory);
SftpTestUtils.createTestFiles(template, file1, file2);
// execute the flow (ls, get, rm, aggregate results)
List<Boolean> rmResults = toFtpFlow.lsGetAndRmFiles(dir.getAbsolutePath());
List<Boolean> rmResults = toFtpFlow.lsGetAndRmFiles("si.sftp.sample");
//Check everything went as expected, and clean up
@@ -65,13 +69,16 @@ public class SftpOutboundGatewaySample {
for (Boolean result : rmResults) {
assertTrue(result);
}
assertTrue("Expected remote dir to be empty", dir.delete());
assertTrue("Could note delete retrieved file", new File(new File(tmpDir), "1.ftptest").delete());
assertTrue("Could note delete retrieved file", new File(new File(tmpDir), "2.ftptest").delete());
} finally {
}
finally {
SftpTestUtils.cleanUp(template, file1, file2);
ctx.close();
assertTrue("Could note delete retrieved file", new File(tmpDir, file1).delete());
assertTrue("Could note delete retrieved file", new File(tmpDir, file2).delete());
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2014 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.
@@ -20,15 +20,21 @@ import java.io.File;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.integration.file.remote.RemoteFileTemplate;
import org.springframework.integration.file.remote.session.CachingSessionFactory;
import org.springframework.integration.file.remote.session.SessionFactory;
import org.springframework.integration.support.MessageBuilder;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageChannel;
import org.springframework.integration.support.MessageBuilder;
import org.springframework.util.Assert;
import com.jcraft.jsch.ChannelSftp.LsEntry;
/**
*
* @author Oleg Zhurakousky
* @author Gunnar Hillert
* @author Gary Russell
*
*/
public class SftpOutboundTransferSample {
@@ -38,29 +44,34 @@ public class SftpOutboundTransferSample {
final String sourceFileName = "README.md";
final String destinationFileName = sourceFileName +"_foo";
final String destinationFilePath = "remote-target-dir/" + destinationFileName;
final ClassPathXmlApplicationContext ac =
new ClassPathXmlApplicationContext("/META-INF/spring/integration/SftpOutboundTransferSample-context.xml", SftpOutboundTransferSample.class);
ac.start();
@SuppressWarnings("unchecked")
SessionFactory<LsEntry> sessionFactory = ac.getBean(CachingSessionFactory.class);
RemoteFileTemplate<LsEntry> template = new RemoteFileTemplate<LsEntry>(sessionFactory);
SftpTestUtils.createTestFiles(template); // Just the directory
final File file = new File(sourceFileName);
try {
final File file = new File(sourceFileName);
Assert.isTrue(file.exists(), String.format("File '%s' does not exist.", sourceFileName));
Assert.isTrue(file.exists(), String.format("File '%s' does not exist.", sourceFileName));
final Message<File> message = MessageBuilder.withPayload(file).build();
final MessageChannel inputChannel = ac.getBean("inputChannel", MessageChannel.class);
final Message<File> message = MessageBuilder.withPayload(file).build();
final MessageChannel inputChannel = ac.getBean("inputChannel", MessageChannel.class);
inputChannel.send(message);
Thread.sleep(2000);
inputChannel.send(message);
Thread.sleep(2000);
Assert.isTrue(new File(destinationFilePath).exists(), String.format("File '%s' does not exist.", destinationFilePath));
System.out.println(String.format("Successfully transferred '%s' file to a " +
"remote location under the name '%s'", sourceFileName, destinationFileName));
ac.stop();
Assert.isTrue(SftpTestUtils.fileExists(template, destinationFileName));
System.out.println(String.format("Successfully transferred '%s' file to a " +
"remote location under the name '%s'", sourceFileName, destinationFileName));
}
finally {
SftpTestUtils.cleanUp(template, destinationFileName);
ac.close();
}
}
}

View File

@@ -0,0 +1,124 @@
/*
* Copyright 2014 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.samples.sftp;
import static org.hamcrest.Matchers.containsString;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.fail;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import org.springframework.beans.DirectFieldAccessor;
import org.springframework.integration.file.remote.RemoteFileTemplate;
import org.springframework.integration.file.remote.SessionCallback;
import org.springframework.integration.file.remote.session.Session;
import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.ChannelSftp.LsEntry;
import com.jcraft.jsch.SftpATTRS;
import com.jcraft.jsch.SftpException;
/**
* @author Gary Russell
* @since 4.1
*
*/
public class SftpTestUtils {
public static void createTestFiles(RemoteFileTemplate<LsEntry> template, final String... fileNames) {
if (template != null) {
final ByteArrayInputStream stream = new ByteArrayInputStream("foo".getBytes());
template.execute(new SessionCallback<LsEntry, Void>() {
@Override
public Void doInSession(Session<LsEntry> session) throws IOException {
try {
session.mkdir("si.sftp.sample");
}
catch (Exception e) {
assertThat(e.getMessage(), containsString("failed to create"));
}
for (int i = 0; i < fileNames.length; i++) {
stream.reset();
session.write(stream, "si.sftp.sample/" + fileNames[i]);
}
return null;
}
});
}
}
public static void cleanUp(RemoteFileTemplate<LsEntry> template, final String... fileNames) {
if (template != null) {
template.execute(new SessionCallback<LsEntry, Void>() {
@Override
public Void doInSession(Session<LsEntry> session) throws IOException {
// TODO: avoid DFAs with Spring 4.1 (INT-3412)
ChannelSftp channel = (ChannelSftp) new DirectFieldAccessor(new DirectFieldAccessor(session)
.getPropertyValue("targetSession")).getPropertyValue("channel");
for (int i = 0; i < fileNames.length; i++) {
try {
session.remove("si.sftp.sample/" + fileNames[i]);
}
catch (IOException e) {}
}
try {
// should be empty
channel.rmdir("si.sftp.sample");
}
catch (SftpException e) {
fail("Expected remote directory to be empty " + e.getMessage());
}
return null;
}
});
}
}
public static boolean fileExists(RemoteFileTemplate<LsEntry> template, final String... fileNames) {
if (template != null) {
return template.execute(new SessionCallback<LsEntry, Boolean>() {
@Override
public Boolean doInSession(Session<LsEntry> session) throws IOException {
// TODO: avoid DFAs with Spring 4.1 (INT-3412)
ChannelSftp channel = (ChannelSftp) new DirectFieldAccessor(new DirectFieldAccessor(session)
.getPropertyValue("targetSession")).getPropertyValue("channel");
for (int i = 0; i < fileNames.length; i++) {
try {
SftpATTRS stat = channel.stat("si.sftp.sample/" + fileNames[i]);
if (stat == null) {
System.out.println("stat returned null for " + fileNames[i]);
return false;
}
}
catch (SftpException e) {
System.out.println("Remote file not present: " + e.getMessage() + ": " + fileNames[i]);
return false;
}
}
return true;
}
});
}
else {
return false;
}
}
}

View File

@@ -1,30 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: DES-EDE3-CBC,89FEB82756CA8E56
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
-----END RSA PRIVATE KEY-----

View File

@@ -0,0 +1 @@
AAAAB3NzaC1yc2EAAAADAQABAAABAQDMQB/vTCY6QEF+/P73ZQZzgj5LBUG8gKPbAXdWcE/X0g3jgsPpxb7+NGiqNpP+oVIQsL9Q7TBsv1/X7xc6sd6SmM/UTP8LF0zlf0GSvEehC2BT98GCiDqI8BKpZjG6O8+pPEBY8M5iGOLtDUSzlhzyV7kPcADYLHl/z1fssU+x2UML7BoSmgh0XPc2u+Gv6+58SVk2ipAZOmaWZDyzWAc3sczz/DkQeR/cpj047HVc1Zb/M5a4ajYI18Ka+mVhKeiQnHc3NKwE6ZxcwlacbVK/feypfperHQOlj6Ee6f6huhnVx9x42V11A41Toh98WI2EVDequ4EcTxHHJntJhpbd

View File

@@ -3,29 +3,31 @@
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"
xmlns:task="http://www.springframework.org/schema/task"
xmlns:context="http://www.springframework.org/schema/context"
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/task http://www.springframework.org/schema/task/spring-task.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/integration/sftp http://www.springframework.org/schema/integration/sftp/spring-integration-sftp.xsd">
<context:property-placeholder location="classpath:user.properties"/>
<import resource="SftpSampleCommon.xml"/>
<bean id="sftpSessionFactory" class="org.springframework.integration.sftp.session.DefaultSftpSessionFactory">
<property name="host" value="localhost"/>
<property name="privateKey" value="classpath:META-INF/keys/sftp_rsa"/>
<bean id="sftpSessionFactory" class="org.springframework.integration.file.remote.session.CachingSessionFactory">
<constructor-arg ref="defaultSftpSessionFactory" />
</bean>
<bean id="defaultSftpSessionFactory"
class="org.springframework.integration.sftp.session.DefaultSftpSessionFactory">
<property name="host" value="${host}"/>
<property name="privateKey" value="${private.keyfile}"/>
<property name="privateKeyPassphrase" value="${passphrase}"/>
<property name="port" value="22"/>
<property name="user" value="${user}"/>
<property name="port" value="#{serverPort}"/>
<property name="user" value="${username}"/>
</bean>
<int-sftp:inbound-channel-adapter id="sftpInbondAdapter"
auto-startup="false"
channel="receiveChannel"
session-factory="sftpSessionFactory"
local-directory="file:local-dir"
remote-directory="${remote.directory}"
remote-directory="si.sftp.sample"
auto-create-local-directory="true"
delete-remote-files="false"
filename-regex=".*\.txt$">

View File

@@ -1,26 +1,28 @@
<?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:int="http://www.springframework.org/schema/integration"
xmlns:int-sftp="http://www.springframework.org/schema/integration/sftp"
xsi:schemaLocation="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/integration/sftp http://www.springframework.org/schema/integration/sftp/spring-integration-sftp.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
http://www.springframework.org/schema/integration/sftp http://www.springframework.org/schema/integration/sftp/spring-integration-sftp.xsd">
<context:property-placeholder location="classpath:user.properties"/>
<import resource="SftpSampleCommon.xml"/>
<int:gateway id="gw" service-interface="org.springframework.integration.samples.sftp.ToSftpFlowGateway"
default-request-channel="inbound"/>
<bean id="sftpSessionFactory"
<bean id="sftpSessionFactory" class="org.springframework.integration.file.remote.session.CachingSessionFactory">
<constructor-arg ref="defaultSftpSessionFactory" />
</bean>
<bean id="defaultSftpSessionFactory"
class="org.springframework.integration.sftp.session.DefaultSftpSessionFactory">
<property name="host" value="localhost"/>
<property name="host" value="${host}"/>
<property name="privateKey" value="${private.keyfile}"/>
<property name="privateKeyPassphrase" value="${passphrase}"/>
<property name="port" value="22"/>
<property name="user" value="${user}"/>
<property name="port" value="#{serverPort}"/>
<property name="user" value="${username}"/>
</bean>
<int-sftp:outbound-gateway id="gatewayLS"
@@ -40,11 +42,11 @@
reply-channel="toRm"
command="get"
command-options="-P"
expression="payload.remoteDirectory + '/' + payload.filename"/>
expression="payload.remoteDirectory + payload.filename"/>
<int-sftp:outbound-gateway id="gatewayRM" reply-channel="aggregateResultsChannel"
session-factory="sftpSessionFactory"
expression="headers['file_remoteDirectory'] + '/' + headers['file_remoteFile']"
expression="headers['file_remoteDirectory'] + headers['file_remoteFile']"
request-channel="toRm"
command="rm"/>

View File

@@ -3,20 +3,23 @@
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"
xmlns:context="http://www.springframework.org/schema/context"
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/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/integration/sftp http://www.springframework.org/schema/integration/sftp/spring-integration-sftp.xsd">
<context:property-placeholder location="classpath:user.properties"/>
<import resource="SftpSampleCommon.xml"/>
<bean id="sftpSessionFactory" class="org.springframework.integration.sftp.session.DefaultSftpSessionFactory">
<property name="host" value="localhost"/>
<property name="privateKey" value="classpath:META-INF/keys/sftp_rsa"/>
<bean id="sftpSessionFactory" class="org.springframework.integration.file.remote.session.CachingSessionFactory">
<constructor-arg ref="defaultSftpSessionFactory" />
</bean>
<bean id="defaultSftpSessionFactory"
class="org.springframework.integration.sftp.session.DefaultSftpSessionFactory">
<property name="host" value="${host}"/>
<property name="privateKey" value="${private.keyfile}"/>
<property name="privateKeyPassphrase" value="${passphrase}"/>
<property name="port" value="22"/>
<property name="user" value="${user}"/>
<property name="port" value="#{serverPort}"/>
<property name="user" value="${username}"/>
</bean>
<int:channel id="inputChannel"/>
@@ -25,6 +28,6 @@
session-factory="sftpSessionFactory"
channel="inputChannel"
remote-filename-generator-expression="payload.getName() + '_foo'"
remote-directory="${remote.directory}"/>
remote-directory="si.sftp.sample"/>
</beans>

View File

@@ -0,0 +1,20 @@
<?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"
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">
<context:property-placeholder location="classpath:user.properties"/>
<bean id="serverPort" class="java.lang.String">
<constructor-arg value="#{'${port}' == '-1' ? T(org.springframework.integration.samples.sftp.EmbeddedSftpServer).PORT : '${port}'}"/>
</bean>
<bean class="org.springframework.integration.samples.sftp.EmbeddedSftpServer">
<property name="port" value="#{serverPort}"/>
</bean>
</beans>

View File

@@ -1,5 +1,7 @@
user=
passphrase=
host=localhost
# -1 means the embedded Apache MINA SshServer. Change it to any real port, if you are going to test sample against real SFTP Server
port=-1
username=user
passphrase=password
#private.keyfile=file:/home/someuser/.ssh/id_rsa
private.keyfile=classpath:META-INF/keys/sftp_rsa
remote.directory=<<SPECIFY REMOTE DIRECTORY (e.g., /{workspace}/samples/basic/sftp/remote-target-dir)>>

View File

@@ -150,6 +150,7 @@ subprojects { subproject ->
ext {
activeMqVersion = '5.9.0'
apacheSshdVersion = '0.10.1'
aspectjVersion = '1.8.0'
commonsDigesterVersion = '2.0'
commonsDbcpVersion = '1.2.2'
@@ -652,10 +653,7 @@ project('sftp') {
dependencies {
compile "org.springframework.integration:spring-integration-sftp:$springIntegrationVersion"
}
test {
exclude '**/*Sample*'
compile "org.apache.sshd:sshd-core:$apacheSshdVersion"
}
}