GH-8800: Fix SMB Gateway for recursive MGET
Fixes: gh-8800 The `SmbFile.getName()` returns plain file name, not with a sub-directory as it is expected by the `AbstractRemoteFileOutboundGateway` for (S)FTP protocols * Introduce `AbstractRemoteFileOutboundGateway.getFullFileName()` with dir and file name concatenation by default (as it was before) and override it in the `SmbOutboundGateway` to return the full path according this protocol. * Fix `SmbOutboundGateway.enhanceNameWithSubDirectory()` to return an `SmbFile` instance since it has all the info about remote file, include requested directory * Fix `SmbOutboundGateway.getFilename()` to remove the trailing `/` in the dir name since this is not what expected by the `AbstractRemoteFileOutboundGateway` logic **Cherry-pick to `6.1.x`**
This commit is contained in:
committed by
Christian Tzolov
parent
45a32cf13c
commit
0531832a0e
@@ -1036,6 +1036,10 @@ public abstract class AbstractRemoteFileOutboundGateway<F> extends AbstractReply
|
||||
return;
|
||||
}
|
||||
String fileName = getFilename(fileToAdd);
|
||||
// Some remote file protocols don't include sub-dir into file name.
|
||||
if (StringUtils.hasText(subDirectory) && !fileName.startsWith(subDirectory)) {
|
||||
fileName = subDirectory + fileName;
|
||||
}
|
||||
final boolean isDirectory = isDirectory(file);
|
||||
boolean isDots = hasDots(fileName);
|
||||
if ((this.options.contains(Option.SUBDIRS) || !isDirectory)
|
||||
@@ -1276,10 +1280,7 @@ public abstract class AbstractRemoteFileOutboundGateway<F> extends AbstractReply
|
||||
private File getRemoteFileForMget(Message<?> message, Session<F> session, String remoteDirectory,
|
||||
AbstractFileInfo<F> lsEntry) throws IOException {
|
||||
|
||||
String fullFileName =
|
||||
remoteDirectory != null
|
||||
? remoteDirectory + getFilename(lsEntry)
|
||||
: getFilename(lsEntry);
|
||||
String fullFileName = getFullFileName(remoteDirectory, lsEntry.getFileInfo());
|
||||
/*
|
||||
* With recursion, the filename might contain subdirectory information
|
||||
* normalize each file separately.
|
||||
@@ -1289,6 +1290,20 @@ public abstract class AbstractRemoteFileOutboundGateway<F> extends AbstractReply
|
||||
return get(message, session, actualRemoteDirectory, fullFileName, fileName, lsEntry.getFileInfo());
|
||||
}
|
||||
|
||||
/**
|
||||
* By default, this method contacts the remote directory with the remote file name
|
||||
* to build a full remote file path.
|
||||
* The remote file protocol-specific implementation may override this method for other approach.
|
||||
* @param remoteDirectory the directory remote file belongs.
|
||||
* @param remoteFile the remote file to take a name and adjust its path according provided remote directory.
|
||||
* @return the full path for the remote file
|
||||
*/
|
||||
protected String getFullFileName(String remoteDirectory, F remoteFile) {
|
||||
return remoteDirectory != null
|
||||
? remoteDirectory + getFilename(remoteFile)
|
||||
: getFilename(remoteFile);
|
||||
}
|
||||
|
||||
private String getRemoteDirectory(String remoteFilePath, String remoteFilename) {
|
||||
String remoteDir = remoteFilePath.substring(0, remoteFilePath.lastIndexOf(remoteFilename));
|
||||
if (remoteDir.length() == 0) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2022 the original author or authors.
|
||||
* Copyright 2022-2023 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.
|
||||
@@ -16,8 +16,6 @@
|
||||
|
||||
package org.springframework.integration.smb.outbound;
|
||||
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
@@ -145,13 +143,14 @@ public class SmbOutboundGateway extends AbstractRemoteFileOutboundGateway<SmbFil
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getFilename(SmbFile file) {
|
||||
return file.getName();
|
||||
protected String getFilename(AbstractFileInfo<SmbFile> file) {
|
||||
return getFilename(file.getFileInfo());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getFilename(AbstractFileInfo<SmbFile> file) {
|
||||
return file.getFilename();
|
||||
protected String getFilename(SmbFile file) {
|
||||
String name = file.getName();
|
||||
return name.endsWith("/") ? name.substring(0, name.length() - 1) : name;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -170,14 +169,12 @@ public class SmbOutboundGateway extends AbstractRemoteFileOutboundGateway<SmbFil
|
||||
|
||||
@Override
|
||||
protected SmbFile enhanceNameWithSubDirectory(SmbFile file, String directory) {
|
||||
try {
|
||||
file.renameTo(new SmbFile(file, directory), true);
|
||||
return file;
|
||||
}
|
||||
catch (SmbException | MalformedURLException | UnknownHostException e) {
|
||||
logger.error("Unable to enhance file name with a sub directory path", e);
|
||||
return null;
|
||||
}
|
||||
return file;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getFullFileName(String remoteDirectory, SmbFile smbFile) {
|
||||
return smbFile.getLocator().getURLPath().substring(1).replaceFirst(smbFile.getShare() + "/?", "");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2022 the original author or authors.
|
||||
* Copyright 2022-2023 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.
|
||||
@@ -291,15 +291,14 @@ public class SmbTests extends SmbTestSupport {
|
||||
Smb.outboundGateway(sessionFactory(), AbstractRemoteFileOutboundGateway.Command.MGET, "payload")
|
||||
.options(AbstractRemoteFileOutboundGateway.Option.RECURSIVE)
|
||||
.fileExistsMode(FileExistsMode.IGNORE)
|
||||
.filterExpression("name matches 'subSmbSource|.*.txt'")
|
||||
.filterExpression("name matches 'smbSource/|subSmbSource/|subSmbSource\\d\\.txt'")
|
||||
.localDirectoryExpression("'" + getTargetLocalDirectoryName() + "' + #remoteDirectory")
|
||||
.localFilenameExpression("#remoteFileName.replaceFirst('smbSource', 'localTarget')")
|
||||
.localFilenameExpression("#remoteFileName.replaceFirst('subSmbSource', 'localTarget')")
|
||||
.charset(StandardCharsets.UTF_8.name())
|
||||
.useTemporaryFileName(true))
|
||||
.channel(out);
|
||||
IntegrationFlowRegistration registration = this.flowContext.registration(flow).register();
|
||||
String dir = "smbSource/subSmbSource/";
|
||||
registration.getInputChannel().send(new GenericMessage<>(dir + "*"));
|
||||
registration.getInputChannel().send(new GenericMessage<>("*"));
|
||||
Message<?> result = out.receive(10_000);
|
||||
assertThat(result).isNotNull();
|
||||
|
||||
@@ -307,12 +306,10 @@ public class SmbTests extends SmbTestSupport {
|
||||
assertThat(localFiles).as("unexpected local files " + localFiles).hasSize(2);
|
||||
|
||||
for (File file : localFiles) {
|
||||
assertThat(file.getPath().replaceAll(Matcher.quoteReplacement(File.separator), "/")).contains(dir);
|
||||
assertThat(file.getPath().replaceAll(Matcher.quoteReplacement(File.separator), "/"))
|
||||
.matches(".*smbSource/subSmbSource/localTarget\\d.txt");
|
||||
}
|
||||
|
||||
assertThat(localFiles.get(1).getPath().replaceAll(Matcher.quoteReplacement(File.separator), "/"))
|
||||
.contains(dir + "subSmbSource");
|
||||
|
||||
registration.destroy();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user