diff --git a/spring-integration-file/src/main/java/org/springframework/integration/file/config/RemoteFileOutboundChannelAdapterParser.java b/spring-integration-file/src/main/java/org/springframework/integration/file/config/RemoteFileOutboundChannelAdapterParser.java index cdc9a78fc5..d8033f3bb8 100644 --- a/spring-integration-file/src/main/java/org/springframework/integration/file/config/RemoteFileOutboundChannelAdapterParser.java +++ b/spring-integration-file/src/main/java/org/springframework/integration/file/config/RemoteFileOutboundChannelAdapterParser.java @@ -47,6 +47,7 @@ public class RemoteFileOutboundChannelAdapterParser extends AbstractOutboundChan "org.springframework.integration.file.remote.handler.FileTransferringMessageHandler"); handlerBuilder.addConstructorArgValue(sessionFactoryBuilder.getBeanDefinition()); IntegrationNamespaceUtils.setValueIfAttributeDefined(handlerBuilder, element, "temporary-file-suffix"); + IntegrationNamespaceUtils.setValueIfAttributeDefined(handlerBuilder, element, "auto-create-directory"); // configure remote directory expression String remoteDirectory = element.getAttribute("remote-directory"); diff --git a/spring-integration-file/src/main/java/org/springframework/integration/file/remote/handler/FileTransferringMessageHandler.java b/spring-integration-file/src/main/java/org/springframework/integration/file/remote/handler/FileTransferringMessageHandler.java index 5494608f1e..55bc7754f8 100644 --- a/spring-integration-file/src/main/java/org/springframework/integration/file/remote/handler/FileTransferringMessageHandler.java +++ b/spring-integration-file/src/main/java/org/springframework/integration/file/remote/handler/FileTransferringMessageHandler.java @@ -48,6 +48,8 @@ public class FileTransferringMessageHandler extends AbstractMessageHandler { public volatile String temporaryFileSuffix =".writing"; private final SessionFactory sessionFactory; + + private volatile boolean autoCreateDirectory = false; private volatile ExpressionEvaluatingMessageProcessor directoryExpressionProcessor; @@ -65,7 +67,10 @@ public class FileTransferringMessageHandler extends AbstractMessageHandler { this.sessionFactory = sessionFactory; } - + public void setAutoCreateDirectory(boolean autoCreateDirectory) { + this.autoCreateDirectory = autoCreateDirectory; + } + public void setRemoteFileSeparator(String remoteFileSeparator) { Assert.hasText(remoteFileSeparator, "'remoteFileSeparator' must not be empty"); this.remoteFileSeparator = remoteFileSeparator; @@ -185,10 +190,32 @@ public class FileTransferringMessageHandler extends AbstractMessageHandler { String remoteFilePath = remoteDirectory + fileName; // write remote file first with .writing extension String tempFilePath = remoteFilePath + this.temporaryFileSuffix; + + if (this.autoCreateDirectory){ + this.ensureDirectoryExists(session, remoteDirectory, remoteDirectory); + } + session.write(fileInputStream, tempFilePath); fileInputStream.close(); // then rename it to its final name session.rename(tempFilePath, remoteFilePath); } + private void ensureDirectoryExists(Session session, String remoteDirectory, String originalRemoteDirectory){ + try { + session.list(remoteDirectory); + String missingDirectoryPath = originalRemoteDirectory.substring(remoteDirectory.length()); + String[] directories = StringUtils.tokenizeToStringArray(missingDirectoryPath, this.remoteFileSeparator); + String directory = remoteDirectory + this.remoteFileSeparator; + for (String directorySegment : directories) { + directory += directorySegment+this.remoteFileSeparator; + logger.debug("Creating '" + directory + "'"); + session.mkdir(directory); + } + } catch (IOException e) { + logger.debug("Directory '" + remoteDirectory + "' does not exist"); + remoteDirectory = remoteDirectory.substring(0, remoteDirectory.lastIndexOf(this.remoteFileSeparator)); + this.ensureDirectoryExists(session, remoteDirectory, originalRemoteDirectory); + } + } } diff --git a/spring-integration-file/src/main/java/org/springframework/integration/file/remote/session/CachingSessionFactory.java b/spring-integration-file/src/main/java/org/springframework/integration/file/remote/session/CachingSessionFactory.java index 1948dc7bcf..bb67b4efaa 100644 --- a/spring-integration-file/src/main/java/org/springframework/integration/file/remote/session/CachingSessionFactory.java +++ b/spring-integration-file/src/main/java/org/springframework/integration/file/remote/session/CachingSessionFactory.java @@ -148,6 +148,10 @@ public class CachingSessionFactory implements SessionFactory, DisposableBean { public void rename(String pathFrom, String pathTo) throws IOException { this.targetSession.rename(pathFrom, pathTo); } + + public void mkdir(String directory) throws IOException { + this.targetSession.mkdir(directory); + } } } diff --git a/spring-integration-file/src/main/java/org/springframework/integration/file/remote/session/Session.java b/spring-integration-file/src/main/java/org/springframework/integration/file/remote/session/Session.java index 5a8d45af4b..09408ddc01 100644 --- a/spring-integration-file/src/main/java/org/springframework/integration/file/remote/session/Session.java +++ b/spring-integration-file/src/main/java/org/springframework/integration/file/remote/session/Session.java @@ -39,6 +39,8 @@ public interface Session { void write(InputStream inputStream, String destination) throws IOException; + void mkdir(String directory) throws IOException; + void rename(String pathFrom, String pathTo) throws IOException; void close(); diff --git a/spring-integration-ftp/src/main/java/org/springframework/integration/ftp/session/FtpSession.java b/spring-integration-ftp/src/main/java/org/springframework/integration/ftp/session/FtpSession.java index 55d727e007..5ddd3f2c4a 100644 --- a/spring-integration-ftp/src/main/java/org/springframework/integration/ftp/session/FtpSession.java +++ b/spring-integration-ftp/src/main/java/org/springframework/integration/ftp/session/FtpSession.java @@ -113,4 +113,15 @@ class FtpSession implements Session { } logger.info("File have been successfully renamed from: " + pathFrom + " to " + pathTo); } + + public void mkdir(String directory) throws IOException { + try { + this.client.makeDirectory(directory); + } + catch (Exception e) { + if (logger.isWarnEnabled()) { + logger.warn("failed to create directory '" + directory + "'", e); + } + } + } } diff --git a/spring-integration-sftp/src/main/java/org/springframework/integration/sftp/session/SftpSession.java b/spring-integration-sftp/src/main/java/org/springframework/integration/sftp/session/SftpSession.java index d61a99b0d1..27faf75261 100644 --- a/spring-integration-sftp/src/main/java/org/springframework/integration/sftp/session/SftpSession.java +++ b/spring-integration-sftp/src/main/java/org/springframework/integration/sftp/session/SftpSession.java @@ -140,4 +140,12 @@ class SftpSession implements Session { } } + public void mkdir(String directory) throws IOException { + try { + this.channel.mkdir(directory); + } catch (SftpException e) { + throw new NestedIOException("failed to create remote directory '" + directory + "'.", e); + } + } + } diff --git a/spring-integration-sftp/src/main/resources/org/springframework/integration/sftp/config/spring-integration-sftp-2.0.xsd b/spring-integration-sftp/src/main/resources/org/springframework/integration/sftp/config/spring-integration-sftp-2.0.xsd index 04588bc9cc..f25a5df072 100644 --- a/spring-integration-sftp/src/main/resources/org/springframework/integration/sftp/config/spring-integration-sftp-2.0.xsd +++ b/spring-integration-sftp/src/main/resources/org/springframework/integration/sftp/config/spring-integration-sftp-2.0.xsd @@ -77,6 +77,14 @@ + + + + + Specify whether to automatically create the remote target directory if it doesn't exist. + + + diff --git a/spring-integration-sftp/src/test/java/org/springframework/integration/sftp/config/SftpInboundOutboundSanitySample.java b/spring-integration-sftp/src/test/java/org/springframework/integration/sftp/config/SftpInboundOutboundSanitySample.java index c9b97bcf96..d5d64a454d 100644 --- a/spring-integration-sftp/src/test/java/org/springframework/integration/sftp/config/SftpInboundOutboundSanitySample.java +++ b/spring-integration-sftp/src/test/java/org/springframework/integration/sftp/config/SftpInboundOutboundSanitySample.java @@ -64,7 +64,7 @@ public class SftpInboundOutboundSanitySample { } @Test - @Ignore + //@Ignore public void testOutbound() throws Exception{ ApplicationContext ac = new ClassPathXmlApplicationContext("SftpOutboundTransferSample-ignored.xml", this.getClass()); diff --git a/spring-integration-sftp/src/test/java/org/springframework/integration/sftp/config/SftpOutboundTransferSample-ignored.xml b/spring-integration-sftp/src/test/java/org/springframework/integration/sftp/config/SftpOutboundTransferSample-ignored.xml index 9e68173bc5..37f1494558 100644 --- a/spring-integration-sftp/src/test/java/org/springframework/integration/sftp/config/SftpOutboundTransferSample-ignored.xml +++ b/spring-integration-sftp/src/test/java/org/springframework/integration/sftp/config/SftpOutboundTransferSample-ignored.xml @@ -24,6 +24,7 @@ charset="UTF-8" temporary-file-suffix=".foo" remote-filename-generator-expression="payload.getName() + '-foo'" - remote-directory="/Users/ozhurakousky/workspace-sts-2.3.3.M2/si/spring-integration/spring-integration-sftp/remote-target-dir"/> + auto-create-directory="true" + remote-directory="/Users/ozhurakousky/workspace-sts-2.3.3.M2/si/spring-integration/spring-integration-sftp/remote-target-dir/foo/bar/baz"/>