INT-4046: Add FtpRemoteFileTemplate.ExistsMode
JIRA: https://jira.spring.io/browse/INT-4046 Since not all FTP servers provide proper `STAT` command implementation, plus the `NLIST` doesn't work properly for directories cases, introduce the `FtpRemoteFileTemplate.ExistsMode` to let: * to perform `STAT` by default (previous) behavior; * to switch to `NLIST` for `FtpRemoteFileTemplate` internal use; * perform the full `NLIST` and `FTPClient.changeWorkingDirectory()` algorithm if needed. * Improve (S)Ftp components to use proper `RemoteFileTemplate` for internal instantiation * Introduce `FtpMessageHandler` to wrap `FtpRemoteFileTemplate` with the proper `NLIST` `ExistsMode` * Cover `NLIST` switching from the `FtpOutboundChannelAdapterParser` and `FtpOutboundGatewayParser` * Document the `FtpRemoteFileTemplate.ExistsMode` * Fix typo in the recently introduced `RemoteFileOperations.getSession()` method name * Add JavaDoc to `Session.exists()` * Add `NLIST` support for the `FtpSession.exists()` to meet the API requirements **Cherry-pick to 4.2.x and 4.1.x** Addressing PR comments Doc Polishing Conflicts: spring-integration-file/src/main/java/org/springframework/integration/file/remote/AbstractRemoteFileStreamingMessageSource.java spring-integration-file/src/main/java/org/springframework/integration/file/remote/RemoteFileOperations.java spring-integration-file/src/main/java/org/springframework/integration/file/remote/RemoteFileTemplate.java spring-integration-ftp/src/main/java/org/springframework/integration/ftp/session/FtpSession.java spring-integration-ftp/src/test/java/org/springframework/integration/ftp/config/FtpOutboundChannelAdapterParserTests.java spring-integration-sftp/src/main/java/org/springframework/integration/sftp/gateway/SftpOutboundGateway.java spring-integration-sftp/src/main/java/org/springframework/integration/sftp/outbound/SftpMessageHandler.java spring-integration-sftp/src/main/java/org/springframework/integration/sftp/outbound/package-info.java
This commit is contained in:
@@ -84,9 +84,14 @@ public abstract class AbstractRemoteFileOutboundGatewayParser extends AbstractCo
|
||||
builder.addPropertyValue("localFilenameGeneratorExpression", localFileGeneratorExpressionBuilder.getBeanDefinition());
|
||||
}
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "mode", "fileExistsMode");
|
||||
postProcessBuilder(builder, element);
|
||||
return builder;
|
||||
}
|
||||
|
||||
protected void postProcessBuilder(BeanDefinitionBuilder builder, Element element) {
|
||||
// no-op
|
||||
}
|
||||
|
||||
protected void configureFilter(BeanDefinitionBuilder builder, Element element, ParserContext parserContext,
|
||||
String filterAttribute, String patternPrefix, String propertyName) {
|
||||
String filter = element.getAttribute(filterAttribute);
|
||||
|
||||
@@ -38,7 +38,7 @@ public abstract class RemoteFileOutboundChannelAdapterParser extends AbstractOut
|
||||
|
||||
@Override
|
||||
protected AbstractBeanDefinition parseConsumer(Element element, ParserContext parserContext) {
|
||||
BeanDefinitionBuilder handlerBuilder = BeanDefinitionBuilder.genericBeanDefinition(FileTransferringMessageHandler.class);
|
||||
BeanDefinitionBuilder handlerBuilder = BeanDefinitionBuilder.genericBeanDefinition(handlerClass());
|
||||
|
||||
BeanDefinition templateDefinition = FileParserUtils.parseRemoteFileTemplate(element, parserContext, true,
|
||||
getTemplateClass());
|
||||
@@ -48,9 +48,18 @@ public abstract class RemoteFileOutboundChannelAdapterParser extends AbstractOut
|
||||
if (StringUtils.hasText(mode)) {
|
||||
handlerBuilder.addConstructorArgValue(mode);
|
||||
}
|
||||
postProcessBuilder(handlerBuilder, element);
|
||||
return handlerBuilder.getBeanDefinition();
|
||||
}
|
||||
|
||||
protected Class<?> handlerClass() {
|
||||
return FileTransferringMessageHandler.class;
|
||||
}
|
||||
|
||||
protected void postProcessBuilder(BeanDefinitionBuilder builder, Element element) {
|
||||
// no-op
|
||||
}
|
||||
|
||||
protected abstract Class<? extends RemoteFileOperations<?>> getTemplateClass();
|
||||
|
||||
}
|
||||
|
||||
@@ -340,8 +340,14 @@ public class RemoteFileTemplate<F> implements RemoteFileOperations<F>, Initializ
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean exists(String path) {
|
||||
throw new UnsupportedOperationException("exists() is not supported by the generic template");
|
||||
public boolean exists(final String path) {
|
||||
return this.execute(new SessionCallback<F, Boolean>() {
|
||||
|
||||
@Override
|
||||
public Boolean doInSession(Session<F> session) throws IOException {
|
||||
return session.exists(path);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -65,7 +65,7 @@ import org.springframework.util.StringUtils;
|
||||
*/
|
||||
public abstract class AbstractRemoteFileOutboundGateway<F> extends AbstractReplyProducingMessageHandler {
|
||||
|
||||
private final RemoteFileTemplate<F> remoteFileTemplate;
|
||||
protected final RemoteFileTemplate<F> remoteFileTemplate;
|
||||
|
||||
protected final Command command;
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ import org.springframework.util.Assert;
|
||||
*/
|
||||
public class FileTransferringMessageHandler<F> extends AbstractMessageHandler {
|
||||
|
||||
private final RemoteFileTemplate<F> remoteFileTemplate;
|
||||
protected final RemoteFileTemplate<F> remoteFileTemplate;
|
||||
|
||||
private final FileExistsMode mode;
|
||||
|
||||
|
||||
@@ -66,6 +66,12 @@ public interface Session<F> {
|
||||
|
||||
boolean isOpen();
|
||||
|
||||
/**
|
||||
* Check if the remote file or directory exists.
|
||||
* @param path the remote path.
|
||||
* @return {@code true} or {@code false} if remote path exists or not.
|
||||
* @throws IOException an IO exception during remote interaction.
|
||||
*/
|
||||
boolean exists(String path) throws IOException;
|
||||
|
||||
String[] listNames(String path) throws IOException;
|
||||
|
||||
@@ -23,9 +23,15 @@ import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import org.hamcrest.Matchers;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.TemporaryFolder;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.expression.common.LiteralExpression;
|
||||
import org.springframework.integration.file.remote.session.Session;
|
||||
@@ -34,13 +40,6 @@ import org.springframework.integration.file.support.FileExistsMode;
|
||||
import org.springframework.messaging.MessagingException;
|
||||
import org.springframework.messaging.support.GenericMessage;
|
||||
|
||||
import org.hamcrest.Matchers;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.TemporaryFolder;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
/**
|
||||
* @author Gary Russell
|
||||
* @since 4.1.7
|
||||
@@ -61,19 +60,7 @@ public class RemoteFileTemplateTests {
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
SessionFactory<Object> sessionFactory = mock(SessionFactory.class);
|
||||
this.template = new RemoteFileTemplate<Object>(sessionFactory) {
|
||||
|
||||
@Override
|
||||
public boolean exists(String path) {
|
||||
try {
|
||||
return sessionFactory.getSession().exists(path);
|
||||
}
|
||||
catch (IOException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
this.template = new RemoteFileTemplate<Object>(sessionFactory);
|
||||
this.template.setRemoteDirectoryExpression(new LiteralExpression("/foo"));
|
||||
this.template.setBeanFactory(mock(BeanFactory.class));
|
||||
this.template.afterPropertiesSet();
|
||||
|
||||
@@ -15,22 +15,46 @@
|
||||
*/
|
||||
package org.springframework.integration.ftp.config;
|
||||
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.integration.file.config.RemoteFileOutboundChannelAdapterParser;
|
||||
import org.springframework.integration.file.remote.RemoteFileOperations;
|
||||
import org.springframework.integration.ftp.outbound.FtpMessageHandler;
|
||||
import org.springframework.integration.ftp.session.FtpRemoteFileTemplate;
|
||||
|
||||
/**
|
||||
* Parser for FTP Outbound Channel Adapters.
|
||||
*
|
||||
* @author Gary Russell
|
||||
* @author Artem Bilan
|
||||
* @since 4.1
|
||||
*
|
||||
*/
|
||||
public class FtpOutboundChannelAdapterParser extends RemoteFileOutboundChannelAdapterParser {
|
||||
|
||||
@Override
|
||||
protected Class<?> handlerClass() {
|
||||
return FtpMessageHandler.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<? extends RemoteFileOperations<?>> getTemplateClass() {
|
||||
return FtpRemoteFileTemplate.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void postProcessBuilder(BeanDefinitionBuilder builder, Element element) {
|
||||
BeanDefinition templateDefinition = (BeanDefinition) builder.getRawBeanDefinition()
|
||||
.getConstructorArgumentValues()
|
||||
.getIndexedArgumentValues()
|
||||
.values()
|
||||
.iterator()
|
||||
.next()
|
||||
.getValue();
|
||||
templateDefinition.getPropertyValues()
|
||||
.add("existsMode", FtpRemoteFileTemplate.ExistsMode.NLST);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -15,6 +15,10 @@
|
||||
*/
|
||||
package org.springframework.integration.ftp.config;
|
||||
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.integration.file.config.AbstractRemoteFileOutboundGatewayParser;
|
||||
import org.springframework.integration.file.remote.RemoteFileOperations;
|
||||
import org.springframework.integration.ftp.filters.FtpRegexPatternFileListFilter;
|
||||
@@ -50,4 +54,17 @@ public class FtpOutboundGatewayParser extends AbstractRemoteFileOutboundGatewayP
|
||||
return FtpRemoteFileTemplate.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void postProcessBuilder(BeanDefinitionBuilder builder, Element element) {
|
||||
BeanDefinition templateDefinition = (BeanDefinition) builder.getRawBeanDefinition()
|
||||
.getConstructorArgumentValues()
|
||||
.getIndexedArgumentValues()
|
||||
.values()
|
||||
.iterator()
|
||||
.next()
|
||||
.getValue();
|
||||
templateDefinition.getPropertyValues()
|
||||
.add("existsMode", FtpRemoteFileTemplate.ExistsMode.NLST);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ import org.springframework.integration.file.remote.RemoteFileTemplate;
|
||||
import org.springframework.integration.file.remote.gateway.AbstractRemoteFileOutboundGateway;
|
||||
import org.springframework.integration.file.remote.session.SessionFactory;
|
||||
import org.springframework.integration.ftp.session.FtpFileInfo;
|
||||
import org.springframework.integration.ftp.session.FtpRemoteFileTemplate;
|
||||
|
||||
/**
|
||||
* Outbound Gateway for performing remote file operations via FTP/FTPS.
|
||||
@@ -46,7 +47,8 @@ public class FtpOutboundGateway extends AbstractRemoteFileOutboundGateway<FTPFil
|
||||
*/
|
||||
public FtpOutboundGateway(SessionFactory<FTPFile> sessionFactory,
|
||||
MessageSessionCallback<FTPFile, ?> messageSessionCallback) {
|
||||
super(sessionFactory, messageSessionCallback);
|
||||
this(new FtpRemoteFileTemplate(sessionFactory), messageSessionCallback);
|
||||
((FtpRemoteFileTemplate) this.remoteFileTemplate).setExistsMode(FtpRemoteFileTemplate.ExistsMode.NLST);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -68,7 +70,8 @@ public class FtpOutboundGateway extends AbstractRemoteFileOutboundGateway<FTPFil
|
||||
* @param expression the filename expression.
|
||||
*/
|
||||
public FtpOutboundGateway(SessionFactory<FTPFile> sessionFactory, String command, String expression) {
|
||||
super(sessionFactory, command, expression);
|
||||
this(new FtpRemoteFileTemplate(sessionFactory), command, expression);
|
||||
((FtpRemoteFileTemplate) this.remoteFileTemplate).setExistsMode(FtpRemoteFileTemplate.ExistsMode.NLST);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* 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.ftp.outbound;
|
||||
|
||||
import org.apache.commons.net.ftp.FTPFile;
|
||||
|
||||
import org.springframework.integration.file.remote.RemoteFileTemplate;
|
||||
import org.springframework.integration.file.remote.handler.FileTransferringMessageHandler;
|
||||
import org.springframework.integration.file.remote.session.SessionFactory;
|
||||
import org.springframework.integration.file.support.FileExistsMode;
|
||||
import org.springframework.integration.ftp.session.FtpRemoteFileTemplate;
|
||||
|
||||
/**
|
||||
* The FTP specific {@link FileTransferringMessageHandler} extension.
|
||||
* Based on the {@link FtpRemoteFileTemplate}.
|
||||
*
|
||||
* @author Artem Bilan
|
||||
* @since 4.1.9
|
||||
* @see FtpRemoteFileTemplate
|
||||
*/
|
||||
public class FtpMessageHandler extends FileTransferringMessageHandler<FTPFile> {
|
||||
|
||||
public FtpMessageHandler(SessionFactory<FTPFile> sessionFactory) {
|
||||
this(new FtpRemoteFileTemplate(sessionFactory));
|
||||
((FtpRemoteFileTemplate) this.remoteFileTemplate).setExistsMode(FtpRemoteFileTemplate.ExistsMode.NLST);
|
||||
}
|
||||
|
||||
public FtpMessageHandler(FtpRemoteFileTemplate remoteFileTemplate) {
|
||||
super(remoteFileTemplate);
|
||||
}
|
||||
|
||||
public FtpMessageHandler(RemoteFileTemplate<FTPFile> remoteFileTemplate, FileExistsMode mode) {
|
||||
super(remoteFileTemplate, mode);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* Provides classes for the FTP outbound channel adapter.
|
||||
*/
|
||||
package org.springframework.integration.ftp.outbound;
|
||||
@@ -26,17 +26,22 @@ 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.messaging.MessagingException;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* FTP version of {@code RemoteFileTemplate} providing type-safe access to
|
||||
* the underlying FTPClient object.
|
||||
*
|
||||
* @author Gary Russell
|
||||
* @author Artem Bilan
|
||||
* @since 4.1
|
||||
*
|
||||
*/
|
||||
public class FtpRemoteFileTemplate extends RemoteFileTemplate<FTPFile> {
|
||||
|
||||
private ExistsMode existsMode = ExistsMode.STAT;
|
||||
|
||||
public FtpRemoteFileTemplate(SessionFactory<FTPFile> sessionFactory) {
|
||||
super(sessionFactory);
|
||||
}
|
||||
@@ -47,6 +52,19 @@ public class FtpRemoteFileTemplate extends RemoteFileTemplate<FTPFile> {
|
||||
return doExecuteWithClient((ClientCallback<FTPClient, T>) callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify an {@link ExistsMode} for {@link #exists(String)} operation.
|
||||
* Defaults to {@link ExistsMode#STAT}.
|
||||
* When used internally by framework components for file operation,
|
||||
* switched to {@link ExistsMode#NLST}.
|
||||
* @param existsMode the {@link ExistsMode} to use.
|
||||
* @since 4.1.9
|
||||
*/
|
||||
public void setExistsMode(ExistsMode existsMode) {
|
||||
Assert.notNull(existsMode, "'existsMode' must not be null.");
|
||||
this.existsMode = existsMode;
|
||||
}
|
||||
|
||||
protected <T> T doExecuteWithClient(final ClientCallback<FTPClient, T> callback) {
|
||||
return execute(new SessionCallback<FTPFile, T>() {
|
||||
|
||||
@@ -57,21 +75,76 @@ public class FtpRemoteFileTemplate extends RemoteFileTemplate<FTPFile> {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* This particular FTP implementation is based on the {@link FTPClient#getStatus(String)}
|
||||
* by default, but since not all FTP servers properly implement the {@code STAT} command,
|
||||
* the framework internal {@link FtpRemoteFileTemplate} instances are switched to the
|
||||
* {@link FTPClient#listNames(String)} for only files operations.
|
||||
* <p> The mode can be switched with the {@link #setExistsMode(ExistsMode)} property.
|
||||
* <p> Any custom implementation can be done in an extension of the {@link FtpRemoteFileTemplate}.
|
||||
* @param path the remote file path to check.
|
||||
* @return true or false if remote file exists or not.
|
||||
*/
|
||||
@Override
|
||||
public boolean exists(final String path) {
|
||||
return executeWithClient(new ClientCallback<FTPClient, Boolean>() {
|
||||
return doExecuteWithClient(new ClientCallback<FTPClient, Boolean>() {
|
||||
|
||||
@Override
|
||||
public Boolean doWithClient(FTPClient client) {
|
||||
try {
|
||||
return client.getStatus(path) != null;
|
||||
switch (FtpRemoteFileTemplate.this.existsMode) {
|
||||
|
||||
case STAT:
|
||||
return client.getStatus(path) != null;
|
||||
|
||||
case NLST:
|
||||
String[] names = client.listNames(path);
|
||||
return !ObjectUtils.isEmpty(names);
|
||||
|
||||
case NLST_AND_DIRS:
|
||||
return FtpRemoteFileTemplate.this.sessionFactory.getSession().exists(path);
|
||||
|
||||
default:
|
||||
throw new IllegalStateException("Unsupported 'existsMode': " +
|
||||
FtpRemoteFileTemplate.this.existsMode);
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new MessagingException("Failed to stat " + path, e);
|
||||
throw new MessagingException("Failed to check the remote path for " + path, e);
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* The {@link #exists(String)} operation mode.
|
||||
* @since 4.1.9
|
||||
*/
|
||||
public enum ExistsMode {
|
||||
|
||||
/**
|
||||
* Perform the {@code STAT} FTP command.
|
||||
* Default.
|
||||
*/
|
||||
STAT,
|
||||
|
||||
/**
|
||||
* Perform the {@code NLST} FTP command.
|
||||
* Used as default internally by framework components for files only operations.
|
||||
*/
|
||||
NLST,
|
||||
|
||||
/**
|
||||
* Perform the {@code NLST} FTP command and fall back to
|
||||
* {@link FTPClient#changeWorkingDirectory(String)}.
|
||||
* <p> This technique is required when you want to check if a directory exists
|
||||
* and the server does not support {@code STAT} - it requires 4 requests/replies.
|
||||
* <p> If you are only checking for an existing file, {@code NLST} is preferred
|
||||
* (unless {@code STAT} is supported).
|
||||
* @see FtpSession#exists(String)
|
||||
*/
|
||||
NLST_AND_DIRS
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ import org.apache.commons.net.ftp.FTPReply;
|
||||
|
||||
import org.springframework.integration.file.remote.session.Session;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* Implementation of {@link Session} for FTP.
|
||||
@@ -195,17 +196,21 @@ public class FtpSession implements Session<FTPFile> {
|
||||
public boolean exists(String path) throws IOException{
|
||||
Assert.hasText(path, "'path' must not be empty");
|
||||
|
||||
String currentWorkingPath = this.client.printWorkingDirectory();
|
||||
Assert.state(currentWorkingPath != null, "working directory cannot be determined, therefore exists check can not be completed");
|
||||
boolean exists = false;
|
||||
String[] names = this.client.listNames(path);
|
||||
boolean exists = !ObjectUtils.isEmpty(names);
|
||||
|
||||
try {
|
||||
if (this.client.changeWorkingDirectory(path)) {
|
||||
exists = true;
|
||||
if (!exists) {
|
||||
String currentWorkingPath = this.client.printWorkingDirectory();
|
||||
Assert.state(currentWorkingPath != null,
|
||||
"working directory cannot be determined; exists check can not be completed");
|
||||
|
||||
try {
|
||||
exists = this.client.changeWorkingDirectory(path);
|
||||
}
|
||||
}
|
||||
finally {
|
||||
this.client.changeWorkingDirectory(currentWorkingPath);
|
||||
finally {
|
||||
this.client.changeWorkingDirectory(currentWorkingPath);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return exists;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-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.
|
||||
@@ -38,6 +38,7 @@ import org.springframework.integration.file.remote.handler.FileTransferringMessa
|
||||
import org.springframework.integration.file.remote.session.CachingSessionFactory;
|
||||
import org.springframework.integration.file.support.FileExistsMode;
|
||||
import org.springframework.integration.ftp.session.DefaultFtpSessionFactory;
|
||||
import org.springframework.integration.ftp.session.FtpRemoteFileTemplate;
|
||||
import org.springframework.integration.handler.ExpressionEvaluatingMessageProcessor;
|
||||
import org.springframework.integration.handler.advice.AbstractRequestHandlerAdvice;
|
||||
import org.springframework.integration.support.MessageBuilder;
|
||||
@@ -91,7 +92,8 @@ public class FtpOutboundChannelAdapterParserTests {
|
||||
assertEquals(ftpChannel, TestUtils.getPropertyValue(ftpOutbound, "inputChannel"));
|
||||
assertEquals("ftpOutbound", ftpOutbound.getComponentName());
|
||||
FileTransferringMessageHandler<?> handler = TestUtils.getPropertyValue(ftpOutbound, "handler", FileTransferringMessageHandler.class);
|
||||
String remoteFileSeparator = (String) TestUtils.getPropertyValue(handler, "remoteFileTemplate.remoteFileSeparator");
|
||||
String remoteFileSeparator = (String) TestUtils.getPropertyValue(handler,
|
||||
"remoteFileTemplate.remoteFileSeparator");
|
||||
assertNotNull(remoteFileSeparator);
|
||||
assertEquals(".foo", TestUtils.getPropertyValue(handler, "remoteFileTemplate.temporaryFileSuffix", String.class));
|
||||
assertEquals("", remoteFileSeparator);
|
||||
@@ -99,6 +101,8 @@ public class FtpOutboundChannelAdapterParserTests {
|
||||
assertEquals("UTF-8", TestUtils.getPropertyValue(handler, "remoteFileTemplate.charset"));
|
||||
assertNotNull(TestUtils.getPropertyValue(handler, "remoteFileTemplate.directoryExpressionProcessor"));
|
||||
assertNotNull(TestUtils.getPropertyValue(handler, "remoteFileTemplate.temporaryDirectoryExpressionProcessor"));
|
||||
assertEquals(FtpRemoteFileTemplate.ExistsMode.NLST,
|
||||
TestUtils.getPropertyValue(handler, "remoteFileTemplate.existsMode"));
|
||||
Object sfProperty = TestUtils.getPropertyValue(handler, "remoteFileTemplate.sessionFactory");
|
||||
assertEquals(DefaultFtpSessionFactory.class, sfProperty.getClass());
|
||||
DefaultFtpSessionFactory sessionFactory = (DefaultFtpSessionFactory) sfProperty;
|
||||
|
||||
@@ -41,6 +41,7 @@ import org.springframework.integration.file.remote.gateway.AbstractRemoteFileOut
|
||||
import org.springframework.integration.file.remote.session.CachingSessionFactory;
|
||||
import org.springframework.integration.file.support.FileExistsMode;
|
||||
import org.springframework.integration.ftp.gateway.FtpOutboundGateway;
|
||||
import org.springframework.integration.ftp.session.FtpRemoteFileTemplate;
|
||||
import org.springframework.integration.handler.ExpressionEvaluatingMessageProcessor;
|
||||
import org.springframework.integration.handler.advice.AbstractRequestHandlerAdvice;
|
||||
import org.springframework.integration.support.MessageBuilder;
|
||||
@@ -93,7 +94,7 @@ public class FtpOutboundGatewayParserTests {
|
||||
assertNotNull(TestUtils.getPropertyValue(gateway, "remoteFileTemplate.sessionFactory"));
|
||||
assertNotNull(TestUtils.getPropertyValue(gateway, "outputChannel"));
|
||||
assertEquals("local-test-dir", TestUtils.getPropertyValue(gateway, "localDirectoryExpression.literalValue"));
|
||||
assertFalse((Boolean) TestUtils.getPropertyValue(gateway, "autoCreateLocalDirectory"));
|
||||
assertFalse(TestUtils.getPropertyValue(gateway, "autoCreateLocalDirectory", Boolean.class));
|
||||
assertNotNull(TestUtils.getPropertyValue(gateway, "filter"));
|
||||
assertEquals(Command.LS, TestUtils.getPropertyValue(gateway, "command"));
|
||||
|
||||
@@ -105,7 +106,8 @@ public class FtpOutboundGatewayParserTests {
|
||||
Long sendTimeout = TestUtils.getPropertyValue(gateway, "messagingTemplate.sendTimeout", Long.class);
|
||||
assertEquals(Long.valueOf(777), sendTimeout);
|
||||
assertTrue(TestUtils.getPropertyValue(gateway, "requiresReply", Boolean.class));
|
||||
assertThat(TestUtils.getPropertyValue(gateway, "mputFilter"), Matchers.instanceOf(RegexPatternFileListFilter.class));
|
||||
assertThat(TestUtils.getPropertyValue(gateway, "mputFilter"),
|
||||
Matchers.instanceOf(RegexPatternFileListFilter.class));
|
||||
assertEquals(FileExistsMode.APPEND, TestUtils.getPropertyValue(gateway, "fileExistsMode"));
|
||||
}
|
||||
|
||||
@@ -115,10 +117,13 @@ public class FtpOutboundGatewayParserTests {
|
||||
"handler", FtpOutboundGateway.class);
|
||||
assertEquals("X", TestUtils.getPropertyValue(gateway, "remoteFileTemplate.remoteFileSeparator"));
|
||||
assertNotNull(TestUtils.getPropertyValue(gateway, "remoteFileTemplate.sessionFactory"));
|
||||
assertTrue(TestUtils.getPropertyValue(gateway, "remoteFileTemplate.sessionFactory") instanceof CachingSessionFactory);
|
||||
assertThat(TestUtils.getPropertyValue(gateway, "remoteFileTemplate.sessionFactory"),
|
||||
Matchers.instanceOf(CachingSessionFactory.class));
|
||||
assertEquals(FtpRemoteFileTemplate.ExistsMode.NLST,
|
||||
TestUtils.getPropertyValue(gateway, "remoteFileTemplate.existsMode"));
|
||||
assertNotNull(TestUtils.getPropertyValue(gateway, "outputChannel"));
|
||||
assertEquals("local-test-dir", TestUtils.getPropertyValue(gateway, "localDirectoryExpression.literalValue"));
|
||||
assertFalse((Boolean) TestUtils.getPropertyValue(gateway, "autoCreateLocalDirectory"));
|
||||
assertFalse(TestUtils.getPropertyValue(gateway, "autoCreateLocalDirectory", Boolean.class));
|
||||
assertEquals(Command.GET, TestUtils.getPropertyValue(gateway, "command"));
|
||||
@SuppressWarnings("unchecked")
|
||||
Set<String> options = TestUtils.getPropertyValue(gateway, "options", Set.class);
|
||||
|
||||
@@ -348,13 +348,14 @@ public class FtpServerOutboundTests {
|
||||
|
||||
@Test
|
||||
public void testInt3412FileMode() {
|
||||
FtpRemoteFileTemplate template = new FtpRemoteFileTemplate(ftpSessionFactory);
|
||||
assertFalse(template.exists("ftpTarget/appending.txt"));
|
||||
Message<String> m = MessageBuilder.withPayload("foo")
|
||||
.setHeader(FileHeaders.FILENAME, "appending.txt")
|
||||
.build();
|
||||
appending.send(m);
|
||||
appending.send(m);
|
||||
|
||||
FtpRemoteFileTemplate template = new FtpRemoteFileTemplate(ftpSessionFactory);
|
||||
assertLength6(template);
|
||||
|
||||
ignoring.send(m);
|
||||
|
||||
@@ -71,7 +71,7 @@ public class FtpRemoteFileTemplateTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testINT3412AppendStatRmdir() {
|
||||
public void testINT3412AppendStatRmdir() throws IOException {
|
||||
FtpRemoteFileTemplate template = new FtpRemoteFileTemplate(sessionFactory);
|
||||
DefaultFileNameGenerator fileNameGenerator = new DefaultFileNameGenerator();
|
||||
fileNameGenerator.setExpression("'foobar.txt'");
|
||||
@@ -114,7 +114,7 @@ public class FtpRemoteFileTemplateTests {
|
||||
assertTrue(session.rmdir("foo/"));
|
||||
}
|
||||
});
|
||||
assertFalse(template.exists("foo"));
|
||||
assertFalse(sessionFactory.getSession().exists("foo"));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014 the original author or authors.
|
||||
* 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.
|
||||
@@ -17,6 +17,7 @@ package org.springframework.integration.sftp.config;
|
||||
|
||||
import org.springframework.integration.file.config.RemoteFileOutboundChannelAdapterParser;
|
||||
import org.springframework.integration.file.remote.RemoteFileOperations;
|
||||
import org.springframework.integration.sftp.outbound.SftpMessageHandler;
|
||||
import org.springframework.integration.sftp.session.SftpRemoteFileTemplate;
|
||||
|
||||
/**
|
||||
@@ -28,6 +29,12 @@ import org.springframework.integration.sftp.session.SftpRemoteFileTemplate;
|
||||
*/
|
||||
public class SftpOutboundChannelAdapterParser extends RemoteFileOutboundChannelAdapterParser {
|
||||
|
||||
|
||||
@Override
|
||||
protected Class<?> handlerClass() {
|
||||
return SftpMessageHandler.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<? extends RemoteFileOperations<?>> getTemplateClass() {
|
||||
return SftpRemoteFileTemplate.class;
|
||||
|
||||
@@ -27,6 +27,7 @@ import org.springframework.integration.file.remote.RemoteFileTemplate;
|
||||
import org.springframework.integration.file.remote.gateway.AbstractRemoteFileOutboundGateway;
|
||||
import org.springframework.integration.file.remote.session.SessionFactory;
|
||||
import org.springframework.integration.sftp.session.SftpFileInfo;
|
||||
import org.springframework.integration.sftp.session.SftpRemoteFileTemplate;
|
||||
|
||||
import com.jcraft.jsch.ChannelSftp.LsEntry;
|
||||
|
||||
@@ -47,7 +48,7 @@ public class SftpOutboundGateway extends AbstractRemoteFileOutboundGateway<LsEnt
|
||||
*/
|
||||
public SftpOutboundGateway(SessionFactory<LsEntry> sessionFactory,
|
||||
MessageSessionCallback<LsEntry, ?> messageSessionCallback) {
|
||||
super(sessionFactory, messageSessionCallback);
|
||||
this(new SftpRemoteFileTemplate(sessionFactory), messageSessionCallback);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -69,7 +70,7 @@ public class SftpOutboundGateway extends AbstractRemoteFileOutboundGateway<LsEnt
|
||||
* @param expression the filename expression.
|
||||
*/
|
||||
public SftpOutboundGateway(SessionFactory<LsEntry> sessionFactory, String command, String expression) {
|
||||
super(sessionFactory, command, expression);
|
||||
this(new SftpRemoteFileTemplate(sessionFactory), command, expression);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* 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.outbound;
|
||||
|
||||
import org.springframework.integration.file.remote.handler.FileTransferringMessageHandler;
|
||||
import org.springframework.integration.file.remote.session.SessionFactory;
|
||||
import org.springframework.integration.file.support.FileExistsMode;
|
||||
import org.springframework.integration.sftp.session.SftpRemoteFileTemplate;
|
||||
|
||||
import com.jcraft.jsch.ChannelSftp.LsEntry;
|
||||
|
||||
/**
|
||||
* Subclass of {@link FileTransferringMessageHandler} for SFTP.
|
||||
*
|
||||
* @author Gary Russell
|
||||
* @since 4.3
|
||||
*
|
||||
*/
|
||||
public class SftpMessageHandler extends FileTransferringMessageHandler<LsEntry> {
|
||||
|
||||
/**
|
||||
* @param remoteFileTemplate the template.
|
||||
* @see FileTransferringMessageHandler#FileTransferringMessageHandler
|
||||
* (org.springframework.integration.file.remote.RemoteFileTemplate)
|
||||
*/
|
||||
public SftpMessageHandler(SftpRemoteFileTemplate remoteFileTemplate) {
|
||||
super(remoteFileTemplate);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param remoteFileTemplate the template.
|
||||
* @param mode the file exists mode.
|
||||
* @see FileTransferringMessageHandler#FileTransferringMessageHandler
|
||||
* (org.springframework.integration.file.remote.RemoteFileTemplate, FileExistsMode)
|
||||
*/
|
||||
public SftpMessageHandler(SftpRemoteFileTemplate remoteFileTemplate, FileExistsMode mode) {
|
||||
super(remoteFileTemplate, mode);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param sessionFactory the session factory.
|
||||
* @see FileTransferringMessageHandler#FileTransferringMessageHandler
|
||||
* (SessionFactory)
|
||||
*/
|
||||
public SftpMessageHandler(SessionFactory<LsEntry> sessionFactory) {
|
||||
this(new SftpRemoteFileTemplate(sessionFactory));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* Provides classes for the SFTP outbound channel adapter.
|
||||
*/
|
||||
package org.springframework.integration.sftp.outbound;
|
||||
@@ -25,7 +25,6 @@ import org.springframework.integration.file.remote.session.SessionFactory;
|
||||
|
||||
import com.jcraft.jsch.ChannelSftp;
|
||||
import com.jcraft.jsch.ChannelSftp.LsEntry;
|
||||
import com.jcraft.jsch.SftpException;
|
||||
|
||||
/**
|
||||
* SFTP version of {@code RemoteFileTemplate} providing type-safe access to
|
||||
@@ -57,22 +56,4 @@ public class SftpRemoteFileTemplate extends RemoteFileTemplate<LsEntry> {
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean exists(final String path) {
|
||||
return executeWithClient(new ClientCallback<ChannelSftp, Boolean>() {
|
||||
|
||||
@Override
|
||||
public Boolean doWithClient(ChannelSftp client) {
|
||||
try {
|
||||
return client.stat(path) != null;
|
||||
}
|
||||
catch (SftpException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user