INT-3919: FTP: Allow null for Remote Directory

JIRA: https://jira.spring.io/browse/INT-3919

Since `FtpClient` supports `null` for the `LS` command, treating it as a current `working directory`,
there is no reason to forbid `null` from the FTP adapters end-user perspective.

* Allow `null` for the `FtpSession` `list()` and `listNames()` methods
* Allow `null` in the `remote-directory` for the `<int-ftp:inbound-channel-adapter>`
* Allow `null` in the `expression` for the `FtpOutboundGateway`

Polishing - send error if error on async output

Cover `onFailure()` from `onSuccess()` with the `errorChannel`

Address PR Comments

* Get rid of `null` population for the `remoteDirectoryExpression` in the `AbstractPollingInboundChannelAdapterParser`
* Populate `new LiteralExpression(null)` from the `FtpInboundFileSynchronizer` ctor
* Introduce `buildRemotePath(parent, child)` function in the `AbstractRemoteFileOutboundGateway` with the `null` logic for `parent`
* Rework `mGetWithoutRecursion()` to use `LS` command and allow `null` for the dir.
* Fix tests according the new `mGetWithoutRecursion()` logic

Polishing
This commit is contained in:
Artem Bilan
2016-02-05 16:06:10 -05:00
committed by Gary Russell
parent 2fad35d9b8
commit 7595e4f142
13 changed files with 297 additions and 129 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 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.
@@ -33,6 +33,7 @@ import org.springframework.util.StringUtils;
* @author Oleg Zhurakousky
* @author Mark Fisher
* @author Gary Russell
* @author Artem Bilan
* @since 2.0
*/
public abstract class AbstractRemoteFileInboundChannelAdapterParser extends AbstractPollingInboundChannelAdapterParser {
@@ -46,8 +47,10 @@ public abstract class AbstractRemoteFileInboundChannelAdapterParser extends Abst
// configure the InboundFileSynchronizer properties
BeanDefinition expressionDef = IntegrationNamespaceUtils.createExpressionDefinitionFromValueOrExpression(
"remote-directory", "remote-directory-expression", parserContext, element, true);
synchronizerBuilder.addPropertyValue("remoteDirectoryExpression", expressionDef);
"remote-directory", "remote-directory-expression", parserContext, element, false);
if (expressionDef != null) {
synchronizerBuilder.addPropertyValue("remoteDirectoryExpression", expressionDef);
}
IntegrationNamespaceUtils.setValueIfAttributeDefined(synchronizerBuilder, element, "delete-remote-files");
IntegrationNamespaceUtils.setValueIfAttributeDefined(synchronizerBuilder, element, "preserve-timestamp");
@@ -57,7 +60,8 @@ public abstract class AbstractRemoteFileInboundChannelAdapterParser extends Abst
this.configureFilter(synchronizerBuilder, element, parserContext);
// build the MessageSource
BeanDefinitionBuilder messageSourceBuilder = BeanDefinitionBuilder.genericBeanDefinition(this.getMessageSourceClassname());
BeanDefinitionBuilder messageSourceBuilder =
BeanDefinitionBuilder.genericBeanDefinition(getMessageSourceClassname());
messageSourceBuilder.addConstructorArgValue(synchronizerBuilder.getBeanDefinition());
String comparator = element.getAttribute("comparator");
if (StringUtils.hasText(comparator)) {
@@ -65,17 +69,21 @@ public abstract class AbstractRemoteFileInboundChannelAdapterParser extends Abst
}
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(messageSourceBuilder, element, "local-filter");
IntegrationNamespaceUtils.setValueIfAttributeDefined(messageSourceBuilder, element, "local-directory");
IntegrationNamespaceUtils.setValueIfAttributeDefined(messageSourceBuilder, element, "auto-create-local-directory");
IntegrationNamespaceUtils.setValueIfAttributeDefined(messageSourceBuilder, element,
"auto-create-local-directory");
String localFileGeneratorExpression = element.getAttribute("local-filename-generator-expression");
if (StringUtils.hasText(localFileGeneratorExpression)) {
BeanDefinitionBuilder localFileGeneratorExpressionBuilder = BeanDefinitionBuilder.genericBeanDefinition(ExpressionFactoryBean.class);
BeanDefinitionBuilder localFileGeneratorExpressionBuilder =
BeanDefinitionBuilder.genericBeanDefinition(ExpressionFactoryBean.class);
localFileGeneratorExpressionBuilder.addConstructorArgValue(localFileGeneratorExpression);
synchronizerBuilder.addPropertyValue("localFilenameGeneratorExpression", localFileGeneratorExpressionBuilder.getBeanDefinition());
synchronizerBuilder.addPropertyValue("localFilenameGeneratorExpression",
localFileGeneratorExpressionBuilder.getBeanDefinition());
}
return messageSourceBuilder.getBeanDefinition();
}
private void configureFilter(BeanDefinitionBuilder synchronizerBuilder, Element element, ParserContext parserContext) {
private void configureFilter(BeanDefinitionBuilder synchronizerBuilder, Element element,
ParserContext parserContext) {
String filter = element.getAttribute("filter");
String fileNamePattern = element.getAttribute("filename-pattern");
String fileNameRegex = element.getAttribute("filename-regex");

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2015 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.
@@ -58,7 +58,9 @@ public abstract class AbstractRemoteFileOutboundGatewayParser extends AbstractCo
}
else {
builder.addConstructorArgValue(element.getAttribute("command"));
builder.addConstructorArgValue(element.getAttribute(EXPRESSION_ATTRIBUTE));
if (element.hasAttribute(EXPRESSION_ATTRIBUTE)) {
builder.addConstructorArgValue(element.getAttribute(EXPRESSION_ATTRIBUTE));
}
}
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "command-options", "options");
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "reply-timeout", "sendTimeout");

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2015 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.
@@ -47,7 +47,6 @@ import org.springframework.integration.file.remote.session.SessionFactory;
import org.springframework.integration.file.support.FileExistsMode;
import org.springframework.integration.handler.AbstractReplyProducingMessageHandler;
import org.springframework.integration.handler.ExpressionEvaluatingMessageProcessor;
import org.springframework.integration.support.AbstractIntegrationMessageBuilder;
import org.springframework.integration.support.PartialSuccessException;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageHandlingException;
@@ -65,7 +64,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;
@@ -512,7 +511,7 @@ public abstract class AbstractRemoteFileOutboundGateway<F> extends AbstractReply
private Object doLs(Message<?> requestMessage) {
String dir = this.fileNameProcessor.processMessage(requestMessage);
if (!dir.endsWith(this.remoteFileTemplate.getRemoteFileSeparator())) {
if (dir != null && !dir.endsWith(this.remoteFileTemplate.getRemoteFileSeparator())) {
dir += this.remoteFileTemplate.getRemoteFileSeparator();
}
final String fullDir = dir;
@@ -529,9 +528,9 @@ public abstract class AbstractRemoteFileOutboundGateway<F> extends AbstractReply
}
private Object doGet(final Message<?> requestMessage) {
final String remoteFilePath = this.fileNameProcessor.processMessage(requestMessage);
final String remoteFilename = this.getRemoteFilename(remoteFilePath);
final String remoteDir = this.getRemoteDirectory(remoteFilePath, remoteFilename);
final String remoteFilePath = this.fileNameProcessor.processMessage(requestMessage);
final String remoteFilename = getRemoteFilename(remoteFilePath);
final String remoteDir = getRemoteDirectory(remoteFilePath, remoteFilename);
Session<F> session = null;
Object payload;
if (this.options.contains(Option.STREAM)) {
@@ -550,30 +549,27 @@ public abstract class AbstractRemoteFileOutboundGateway<F> extends AbstractReply
@Override
public File doInSession(Session<F> session) throws IOException {
return AbstractRemoteFileOutboundGateway.this.get(requestMessage, session, remoteDir, remoteFilePath,
remoteFilename, true);
return get(requestMessage, session, remoteDir, remoteFilePath, remoteFilename, true);
}
});
}
AbstractIntegrationMessageBuilder<Object> builder = this.getMessageBuilderFactory().withPayload(payload)
.setHeader(FileHeaders.REMOTE_DIRECTORY, remoteDir)
.setHeader(FileHeaders.REMOTE_FILE, remoteFilename);
if (session != null) {
builder.setHeader(FileHeaders.REMOTE_SESSION, session);
}
return builder.build();
return getMessageBuilderFactory().withPayload(payload)
.setHeader(FileHeaders.REMOTE_DIRECTORY, remoteDir)
.setHeader(FileHeaders.REMOTE_FILE, remoteFilename)
.setHeader(FileHeaders.REMOTE_SESSION, session)
.build();
}
private Object doMget(final Message<?> requestMessage) {
final String remoteFilePath = this.fileNameProcessor.processMessage(requestMessage);
final String remoteFilename = this.getRemoteFilename(remoteFilePath);
final String remoteDir = this.getRemoteDirectory(remoteFilePath, remoteFilename);
final String remoteFilePath = this.fileNameProcessor.processMessage(requestMessage);
final String remoteFilename = getRemoteFilename(remoteFilePath);
final String remoteDir = getRemoteDirectory(remoteFilePath, remoteFilename);
List<File> payload = this.remoteFileTemplate.execute(new SessionCallback<F, List<File>>() {
@Override
public List<File> doInSession(Session<F> session) throws IOException {
return AbstractRemoteFileOutboundGateway.this.mGet(requestMessage, session, remoteDir, remoteFilename);
return mGet(requestMessage, session, remoteDir, remoteFilename);
}
});
return this.getMessageBuilderFactory().withPayload(payload)
@@ -583,10 +579,12 @@ public abstract class AbstractRemoteFileOutboundGateway<F> extends AbstractReply
}
private Object doRm(Message<?> requestMessage) {
final String remoteFilePath = this.fileNameProcessor.processMessage(requestMessage);
String remoteFilename = this.getRemoteFilename(remoteFilePath);
String remoteDir = this.getRemoteDirectory(remoteFilePath, remoteFilename);
final String remoteFilePath = this.fileNameProcessor.processMessage(requestMessage);
String remoteFilename = getRemoteFilename(remoteFilePath);
String remoteDir = getRemoteDirectory(remoteFilePath, remoteFilename);
boolean payload = this.remoteFileTemplate.remove(remoteFilePath);
return this.getMessageBuilderFactory().withPayload(payload)
.setHeader(FileHeaders.REMOTE_DIRECTORY, remoteDir)
.setHeader(FileHeaders.REMOTE_FILE, remoteFilename)
@@ -595,8 +593,8 @@ public abstract class AbstractRemoteFileOutboundGateway<F> extends AbstractReply
private Object doMv(Message<?> requestMessage) {
String remoteFilePath = this.fileNameProcessor.processMessage(requestMessage);
String remoteFilename = this.getRemoteFilename(remoteFilePath);
String remoteDir = this.getRemoteDirectory(remoteFilePath, remoteFilename);
String remoteFilename = getRemoteFilename(remoteFilePath);
String remoteDir = getRemoteDirectory(remoteFilePath, remoteFilename);
String remoteFileNewPath = this.renameProcessor.processMessage(requestMessage);
Assert.hasLength(remoteFileNewPath, "New filename cannot be empty");
@@ -635,8 +633,7 @@ public abstract class AbstractRemoteFileOutboundGateway<F> extends AbstractReply
return this.doPut(requestMessage);
}
else {
List<String> replies = this.putLocalDirectory(requestMessage, file, null);
return replies;
return putLocalDirectory(requestMessage, file, null);
}
}
@@ -717,7 +714,9 @@ public abstract class AbstractRemoteFileOutboundGateway<F> extends AbstractReply
private List<F> listFilesInRemoteDir(Session<F> session, String directory, String subDirectory) throws IOException {
List<F> lsFiles = new ArrayList<F>();
F[] files = session.list(directory + subDirectory);
String remoteDirectory = buildRemotePath(directory, subDirectory);
F[] files = session.list(remoteDirectory);
boolean recursion = this.options.contains(Option.RECURSIVE);
if (!ObjectUtils.isEmpty(files)) {
Collection<F> filteredFiles = this.filterFiles(files);
@@ -742,6 +741,17 @@ public abstract class AbstractRemoteFileOutboundGateway<F> extends AbstractReply
return lsFiles;
}
private String buildRemotePath(String parent, String child) {
String remotePath = null;
if (parent != null) {
remotePath = (parent + child);
}
else if (StringUtils.hasText(child)) {
remotePath = "." + this.remoteFileTemplate.getRemoteFileSeparator() + child;
}
return remotePath;
}
protected final List<F> filterFiles(F[] files) {
return (this.filter != null) ? this.filter.filterFiles(files) : Arrays.asList(files);
}
@@ -784,8 +794,8 @@ public abstract class AbstractRemoteFileOutboundGateway<F> extends AbstractReply
* @return The file.
* @throws IOException Any IOException.
*/
protected File get(Message<?> message, Session<F> session, String remoteDir, String remoteFilePath, String remoteFilename, boolean lsFirst)
throws IOException {
protected File get(Message<?> message, Session<F> session, String remoteDir, String remoteFilePath,
String remoteFilename, boolean lsFirst) throws IOException {
F[] files = null;
if (lsFirst) {
files = session.list(remoteFilePath);
@@ -796,7 +806,8 @@ public abstract class AbstractRemoteFileOutboundGateway<F> extends AbstractReply
throw new MessagingException(remoteFilePath + " is not a file");
}
}
File localFile = new File(this.generateLocalDirectory(message, remoteDir), this.generateLocalFileName(message, remoteFilename));
File localFile =
new File(generateLocalDirectory(message, remoteDir), generateLocalFileName(message, remoteFilename));
FileExistsMode fileExistsMode = this.fileExistsMode;
boolean appending = FileExistsMode.APPEND.equals(fileExistsMode);
boolean replacing = FileExistsMode.REPLACE.equals(fileExistsMode);
@@ -874,37 +885,40 @@ public abstract class AbstractRemoteFileOutboundGateway<F> extends AbstractReply
private List<File> mGetWithoutRecursion(Message<?> message, Session<F> session, String remoteDirectory,
String remoteFilename) throws IOException {
String path = this.generateFullPath(remoteDirectory, remoteFilename);
String[] fileNames = session.listNames(path);
if (fileNames == null) {
fileNames = new String[0];
}
if (fileNames.length == 0 && this.options.contains(Option.EXCEPTION_WHEN_EMPTY)) {
throw new MessagingException("No files found at " + remoteDirectory
List<File> files = new ArrayList<File>();
String remotePath = buildRemotePath(remoteDirectory, remoteFilename);
@SuppressWarnings("unchecked")
List<AbstractFileInfo<F>> remoteFiles = (List<AbstractFileInfo<F>>) ls(session, remotePath);
if (remoteFiles.size() == 0 && this.options.contains(Option.EXCEPTION_WHEN_EMPTY)) {
throw new MessagingException("No files found at "
+ (remoteDirectory != null ? remoteDirectory : "Client Working Directory")
+ " with pattern " + remoteFilename);
}
List<File> files = new ArrayList<File>();
String remoteFileSeparator = this.remoteFileTemplate.getRemoteFileSeparator();
try {
for (String fileName : fileNames) {
File file;
if (fileName.contains(remoteFileSeparator) &&
fileName.startsWith(remoteDirectory)) { // the server returned the full path
file = this.get(message, session, remoteDirectory, fileName,
fileName.substring(fileName.lastIndexOf(remoteFileSeparator)), false);
}
else {
file = this.get(message, session, remoteDirectory,
this.generateFullPath(remoteDirectory, fileName), fileName, false);
for (AbstractFileInfo<F> lsEntry : remoteFiles) {
if (lsEntry.isDirectory()) {
continue;
}
String fullFileName = remoteDirectory != null
? remoteDirectory + getFilename(lsEntry)
: getFilename(lsEntry);
/*
* With recursion, the filename might contain subdirectory information
* normalize each file separately.
*/
String fileName = this.getRemoteFilename(fullFileName);
String actualRemoteDirectory = this.getRemoteDirectory(fullFileName, fileName);
File file = this.get(message, session, actualRemoteDirectory,
fullFileName, fileName, false);
files.add(file);
}
}
catch (Exception e) {
if (files.size() > 0) {
throw new PartialSuccessException(message,
"Partially successful 'mget' operation on " + remoteDirectory, e, files,
Arrays.asList(fileNames));
"Partially successful recursive 'mget' operation on "
+ (remoteDirectory != null ? remoteDirectory : "Client Working Directory"),
e, files, remoteFiles);
}
else if (e instanceof MessagingException) {
throw (MessagingException) e;
@@ -920,14 +934,17 @@ public abstract class AbstractRemoteFileOutboundGateway<F> extends AbstractReply
String remoteFilename) throws IOException {
List<File> files = new ArrayList<File>();
@SuppressWarnings("unchecked")
List<AbstractFileInfo<F>> fileNames = (List<AbstractFileInfo<F>>) this.ls(session, remoteDirectory);
List<AbstractFileInfo<F>> fileNames = (List<AbstractFileInfo<F>>) ls(session, remoteDirectory);
if (fileNames.size() == 0 && this.options.contains(Option.EXCEPTION_WHEN_EMPTY)) {
throw new MessagingException("No files found at " + remoteDirectory
throw new MessagingException("No files found at "
+ (remoteDirectory != null ? remoteDirectory : "Client Working Directory")
+ " with pattern " + remoteFilename);
}
try {
for (AbstractFileInfo<F> lsEntry : fileNames) {
String fullFileName = remoteDirectory + this.getFilename(lsEntry);
String fullFileName = remoteDirectory != null
? remoteDirectory + getFilename(lsEntry)
: getFilename(lsEntry);
/*
* With recursion, the filename might contain subdirectory information
* normalize each file separately.
@@ -942,7 +959,9 @@ public abstract class AbstractRemoteFileOutboundGateway<F> extends AbstractReply
catch (Exception e) {
if (files.size() > 0) {
throw new PartialSuccessException(message,
"Partially successful recursive 'mget' operation on " + remoteDirectory, e, files, fileNames);
"Partially successful recursive 'mget' operation on "
+ (remoteDirectory != null ? remoteDirectory : "Client Working Directory"),
e, files, fileNames);
}
else if (e instanceof MessagingException) {
throw (MessagingException) e;
@@ -957,45 +976,30 @@ public abstract class AbstractRemoteFileOutboundGateway<F> extends AbstractReply
private String getRemoteDirectory(String remoteFilePath, String remoteFilename) {
String remoteDir = remoteFilePath.substring(0, remoteFilePath.lastIndexOf(remoteFilename));
if (remoteDir.length() == 0) {
remoteDir = this.remoteFileTemplate.getRemoteFileSeparator();
return null;
}
return remoteDir;
}
private String generateFullPath(String remoteDirectory, String remoteFilename) {
String path;
String remoteFileSeparator = this.remoteFileTemplate.getRemoteFileSeparator();
if (remoteFileSeparator.equals(remoteDirectory)) {
path = remoteFilename;
}
else if (remoteDirectory.endsWith(remoteFileSeparator)) {
path = remoteDirectory + remoteFilename;
}
else {
path = remoteDirectory + remoteFileSeparator + remoteFilename;
}
return path;
}
/**
* @param remoteFilePath The remote file path.
* @return The remote file name.
*/
protected String getRemoteFilename(String remoteFilePath) {
String remoteFileName;
int index = remoteFilePath.lastIndexOf(this.remoteFileTemplate.getRemoteFileSeparator());
if (index < 0) {
remoteFileName = remoteFilePath;
return remoteFilePath;
}
else {
remoteFileName = remoteFilePath.substring(index + 1);
return remoteFilePath.substring(index + 1);
}
return remoteFileName;
}
private File generateLocalDirectory(Message<?> message, String remoteDirectory) {
EvaluationContext evaluationContext = ExpressionUtils.createStandardEvaluationContext(this.getBeanFactory());
evaluationContext.setVariable("remoteDirectory", remoteDirectory);
EvaluationContext evaluationContext = ExpressionUtils.createStandardEvaluationContext(getBeanFactory());
if (remoteDirectory != null) {
evaluationContext.setVariable("remoteDirectory", remoteDirectory);
}
//TODO see org.springframework.integration.context.CustomConversionServiceFactoryBean
// File localDir = this.localDirectoryExpression.getValue(evaluationContext, message, File.class);
String localDirPath = this.localDirectoryExpression.getValue(evaluationContext, message, String.class);
@@ -1008,7 +1012,7 @@ public abstract class AbstractRemoteFileOutboundGateway<F> extends AbstractReply
private String generateLocalFileName(Message<?> message, String remoteFileName){
if (this.localFilenameGeneratorExpression != null){
EvaluationContext evaluationContext = ExpressionUtils.createStandardEvaluationContext(this.getBeanFactory());
EvaluationContext evaluationContext = ExpressionUtils.createStandardEvaluationContext(getBeanFactory());
evaluationContext.setVariable("remoteFileName", remoteFileName);
return this.localFilenameGeneratorExpression.getValue(evaluationContext, message, String.class);
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2015 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.
@@ -200,6 +200,14 @@ public abstract class AbstractInboundFileSynchronizer<F>
if (this.evaluationContext == null) {
this.evaluationContext = ExpressionUtils.createStandardEvaluationContext(this.beanFactory);
}
doInit();
}
/**
* Subclasses can override to perform initialization - called from
* {@link InitializingBean#afterPropertiesSet()}.
*/
protected void doInit() {
}
protected final List<F> filterFiles(F[] files) {
@@ -271,7 +279,9 @@ public abstract class AbstractInboundFileSynchronizer<F>
Session<F> session) throws IOException {
String remoteFileName = this.getFilename(remoteFile);
String localFileName = this.generateLocalFileName(remoteFileName);
String remoteFilePath = remoteDirectoryPath + remoteFileSeparator + remoteFileName;
String remoteFilePath = remoteDirectoryPath != null
? (remoteDirectoryPath + remoteFileSeparator + remoteFileName)
: remoteFileName;
if (!this.isFile(remoteFile)) {
if (logger.isDebugEnabled()) {
logger.debug("cannot copy, not a file: " + remoteFilePath);

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2015 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.
@@ -23,6 +23,7 @@ import static org.hamcrest.Matchers.instanceOf;
import static org.hamcrest.Matchers.not;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
@@ -188,8 +189,10 @@ public class RemoteFileOutboundGatewayTests {
}
@Override
public String[] listNames(String path) throws IOException {
return new String[] { path1, path2 };
public TestLsEntry[] list(String path) throws IOException {
return new TestLsEntry[] {
new TestLsEntry(path1.replaceFirst("testremote/", ""), 123, false, false, 1234, "-r--r--r--"),
new TestLsEntry(path2.replaceFirst("testremote/", ""), 123, false, false, 1234, "-r--r--r--")};
}
});
@@ -220,8 +223,8 @@ public class RemoteFileOutboundGatewayTests {
}
@Override
public String[] listNames(String path) throws IOException {
return new String[]{"f1"};
public TestLsEntry[] list(String path) throws IOException {
return new TestLsEntry[]{new TestLsEntry("f1", 123, false, false, 1234, "-r--r--r--")};
}
});
@@ -621,10 +624,8 @@ public class RemoteFileOutboundGatewayTests {
assertEquals(outFile, out.getPayload());
assertTrue(outFile.exists());
outFile.delete();
assertEquals("/",
out.getHeaders().get(FileHeaders.REMOTE_DIRECTORY));
assertEquals("f1",
out.getHeaders().get(FileHeaders.REMOTE_FILE));
assertNull(out.getHeaders().get(FileHeaders.REMOTE_DIRECTORY));
assertEquals("f1", out.getHeaders().get(FileHeaders.REMOTE_FILE));
}
@SuppressWarnings("unchecked")