diff --git a/basic/sftp/.gitignore b/basic/sftp/.gitignore index d6ef0695..139fb7c9 100644 --- a/basic/sftp/.gitignore +++ b/basic/sftp/.gitignore @@ -1,3 +1,4 @@ /local-dir /target -/src/test/resources/META-INF/keys/sftp_rsa +hostkey.ser +si.sftp.sample diff --git a/basic/sftp/README.md b/basic/sftp/README.md index 00132577..dfc9b472 100644 --- a/basic/sftp/README.md +++ b/basic/sftp/README.md @@ -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 diff --git a/basic/sftp/remote-source-dir/a.txt b/basic/sftp/remote-source-dir/a.txt deleted file mode 100644 index 8c7e5a66..00000000 --- a/basic/sftp/remote-source-dir/a.txt +++ /dev/null @@ -1 +0,0 @@ -A \ No newline at end of file diff --git a/basic/sftp/remote-source-dir/b.txt b/basic/sftp/remote-source-dir/b.txt deleted file mode 100644 index 7371f47a..00000000 --- a/basic/sftp/remote-source-dir/b.txt +++ /dev/null @@ -1 +0,0 @@ -B \ No newline at end of file diff --git a/basic/sftp/remote-source-dir/c.bar b/basic/sftp/remote-source-dir/c.bar deleted file mode 100644 index 96d80cd6..00000000 --- a/basic/sftp/remote-source-dir/c.bar +++ /dev/null @@ -1 +0,0 @@ -C \ No newline at end of file diff --git a/basic/sftp/remote-target-dir/.nothing b/basic/sftp/remote-target-dir/.nothing deleted file mode 100644 index e69de29b..00000000 diff --git a/basic/sftp/src/test/java/org/springframework/integration/samples/sftp/EmbeddedSftpServer.java b/basic/sftp/src/test/java/org/springframework/integration/samples/sftp/EmbeddedSftpServer.java new file mode 100644 index 00000000..3dbb4388 --- /dev/null +++ b/basic/sftp/src/test/java/org/springframework/integration/samples/sftp/EmbeddedSftpServer.java @@ -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.>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; + } + +} diff --git a/basic/sftp/src/test/java/org/springframework/integration/samples/sftp/SftpInboundReceiveSample.java b/basic/sftp/src/test/java/org/springframework/integration/samples/sftp/SftpInboundReceiveSample.java index 77900a4f..3ab71349 100644 --- a/basic/sftp/src/test/java/org/springframework/integration/samples/sftp/SftpInboundReceiveSample.java +++ b/basic/sftp/src/test/java/org/springframework/integration/samples/sftp/SftpInboundReceiveSample.java @@ -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 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 sessionFactory = context.getBean(CachingSessionFactory.class); + template = new RemoteFileTemplate(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()); + } } + } diff --git a/basic/sftp/src/test/java/org/springframework/integration/samples/sftp/SftpOutboundGatewaySample.java b/basic/sftp/src/test/java/org/springframework/integration/samples/sftp/SftpOutboundGatewaySample.java index 9745c8be..ca8f33de 100644 --- a/basic/sftp/src/test/java/org/springframework/integration/samples/sftp/SftpOutboundGatewaySample.java +++ b/basic/sftp/src/test/java/org/springframework/integration/samples/sftp/SftpOutboundGatewaySample.java @@ -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 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 sessionFactory = ctx.getBean(CachingSessionFactory.class); + template = new RemoteFileTemplate(sessionFactory); + SftpTestUtils.createTestFiles(template, file1, file2); // execute the flow (ls, get, rm, aggregate results) - List rmResults = toFtpFlow.lsGetAndRmFiles(dir.getAbsolutePath()); + List 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()); } } + } diff --git a/basic/sftp/src/test/java/org/springframework/integration/samples/sftp/SftpOutboundTransferSample.java b/basic/sftp/src/test/java/org/springframework/integration/samples/sftp/SftpOutboundTransferSample.java index 28e0e7db..c9ddc96d 100644 --- a/basic/sftp/src/test/java/org/springframework/integration/samples/sftp/SftpOutboundTransferSample.java +++ b/basic/sftp/src/test/java/org/springframework/integration/samples/sftp/SftpOutboundTransferSample.java @@ -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 sessionFactory = ac.getBean(CachingSessionFactory.class); + RemoteFileTemplate template = new RemoteFileTemplate(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 message = MessageBuilder.withPayload(file).build(); - final MessageChannel inputChannel = ac.getBean("inputChannel", MessageChannel.class); + final Message 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(); + } } } diff --git a/basic/sftp/src/test/java/org/springframework/integration/samples/sftp/SftpTestUtils.java b/basic/sftp/src/test/java/org/springframework/integration/samples/sftp/SftpTestUtils.java new file mode 100644 index 00000000..c1a1d4c0 --- /dev/null +++ b/basic/sftp/src/test/java/org/springframework/integration/samples/sftp/SftpTestUtils.java @@ -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 template, final String... fileNames) { + if (template != null) { + final ByteArrayInputStream stream = new ByteArrayInputStream("foo".getBytes()); + template.execute(new SessionCallback() { + + @Override + public Void doInSession(Session 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 template, final String... fileNames) { + if (template != null) { + template.execute(new SessionCallback() { + + @Override + public Void doInSession(Session 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 template, final String... fileNames) { + if (template != null) { + return template.execute(new SessionCallback() { + + @Override + public Boolean doInSession(Session 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; + } + } + +} diff --git a/basic/sftp/src/test/resources/META-INF/keys/sftp_rsa b/basic/sftp/src/test/resources/META-INF/keys/sftp_rsa index 05a66c80..59c7bab7 100644 --- a/basic/sftp/src/test/resources/META-INF/keys/sftp_rsa +++ b/basic/sftp/src/test/resources/META-INF/keys/sftp_rsa @@ -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----- diff --git a/basic/sftp/src/test/resources/META-INF/keys/sftp_rsa.pub b/basic/sftp/src/test/resources/META-INF/keys/sftp_rsa.pub new file mode 100644 index 00000000..e790fbc5 --- /dev/null +++ b/basic/sftp/src/test/resources/META-INF/keys/sftp_rsa.pub @@ -0,0 +1 @@ +AAAAB3NzaC1yc2EAAAADAQABAAABAQDMQB/vTCY6QEF+/P73ZQZzgj5LBUG8gKPbAXdWcE/X0g3jgsPpxb7+NGiqNpP+oVIQsL9Q7TBsv1/X7xc6sd6SmM/UTP8LF0zlf0GSvEehC2BT98GCiDqI8BKpZjG6O8+pPEBY8M5iGOLtDUSzlhzyV7kPcADYLHl/z1fssU+x2UML7BoSmgh0XPc2u+Gv6+58SVk2ipAZOmaWZDyzWAc3sczz/DkQeR/cpj047HVc1Zb/M5a4ajYI18Ka+mVhKeiQnHc3NKwE6ZxcwlacbVK/feypfperHQOlj6Ee6f6huhnVx9x42V11A41Toh98WI2EVDequ4EcTxHHJntJhpbd diff --git a/basic/sftp/src/test/resources/META-INF/spring/integration/SftpInboundReceiveSample-context.xml b/basic/sftp/src/test/resources/META-INF/spring/integration/SftpInboundReceiveSample-context.xml index 13372772..4743fe8f 100644 --- a/basic/sftp/src/test/resources/META-INF/spring/integration/SftpInboundReceiveSample-context.xml +++ b/basic/sftp/src/test/resources/META-INF/spring/integration/SftpInboundReceiveSample-context.xml @@ -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"> - + - - - + + + + + + + - - + + diff --git a/basic/sftp/src/test/resources/META-INF/spring/integration/SftpOutboundGatewaySample-context.xml b/basic/sftp/src/test/resources/META-INF/spring/integration/SftpOutboundGatewaySample-context.xml index c939e0c6..d22cf30b 100644 --- a/basic/sftp/src/test/resources/META-INF/spring/integration/SftpOutboundGatewaySample-context.xml +++ b/basic/sftp/src/test/resources/META-INF/spring/integration/SftpOutboundGatewaySample-context.xml @@ -1,26 +1,28 @@ + http://www.springframework.org/schema/integration/sftp http://www.springframework.org/schema/integration/sftp/spring-integration-sftp.xsd"> - + - + + + + - + - - + + + expression="payload.remoteDirectory + payload.filename"/> diff --git a/basic/sftp/src/test/resources/META-INF/spring/integration/SftpOutboundTransferSample-context.xml b/basic/sftp/src/test/resources/META-INF/spring/integration/SftpOutboundTransferSample-context.xml index 82ab8481..ea53f696 100644 --- a/basic/sftp/src/test/resources/META-INF/spring/integration/SftpOutboundTransferSample-context.xml +++ b/basic/sftp/src/test/resources/META-INF/spring/integration/SftpOutboundTransferSample-context.xml @@ -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"> - + - - - + + + + + + + - - + + @@ -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"/> diff --git a/basic/sftp/src/test/resources/META-INF/spring/integration/SftpSampleCommon.xml b/basic/sftp/src/test/resources/META-INF/spring/integration/SftpSampleCommon.xml new file mode 100644 index 00000000..065f6c15 --- /dev/null +++ b/basic/sftp/src/test/resources/META-INF/spring/integration/SftpSampleCommon.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + diff --git a/basic/sftp/src/test/resources/user.properties b/basic/sftp/src/test/resources/user.properties index 3780ad08..ece0bb29 100644 --- a/basic/sftp/src/test/resources/user.properties +++ b/basic/sftp/src/test/resources/user.properties @@ -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=<> diff --git a/build.gradle b/build.gradle index 92ecc1f0..0b76df18 100644 --- a/build.gradle +++ b/build.gradle @@ -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" } }