From 0959590d802ce55bfcc8c1d000bbcd54c3a3d35d Mon Sep 17 00:00:00 2001 From: Artem Bilan Date: Wed, 5 Jun 2024 11:03:32 -0400 Subject: [PATCH] GH-9211: Fix `SmbSession.get()` Fixes: #9211 The `AbstractRemoteFileOutboundGateway.get()` uses `Session.list()` for the provided remote file name. The `SmbSession` does not support listing for a single file. * Add logic into `SmbSession.list()` similar to `SftpSession.list()` to list a single remote file on the provided path (cherry picked from commit 91de12c786eb3dc7c937093302c0b8d3afbc4ef6) --- .../integration/smb/session/SmbSession.java | 56 +++++++++++------- .../integration/smb/dsl/SmbTests.java | 59 ++++++++++--------- 2 files changed, 64 insertions(+), 51 deletions(-) diff --git a/spring-integration-smb/src/main/java/org/springframework/integration/smb/session/SmbSession.java b/spring-integration-smb/src/main/java/org/springframework/integration/smb/session/SmbSession.java index c60a9322e0..6212d10dba 100644 --- a/spring-integration-smb/src/main/java/org/springframework/integration/smb/session/SmbSession.java +++ b/spring-integration-smb/src/main/java/org/springframework/integration/smb/session/SmbSession.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2022 the original author or authors. + * Copyright 2012-2024 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 java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.URL; +import java.nio.file.FileSystems; import java.util.Arrays; import jcifs.smb.SmbException; @@ -39,10 +40,10 @@ import org.springframework.util.StringUtils; * Implementation of the {@link Session} interface for Server Message Block (SMB) * also known as Common Internet File System (CIFS). The Samba project set out to * create non-Windows implementations of SMB. Often Samba is thus used synonymously to SMB. - * + *

* SMB is an application-layer network protocol that manages shared access to files, printers * and other networked resources. - * + *

* See Server Message Block * for more details. * @@ -60,7 +61,7 @@ public class SmbSession implements Session { private static final LogAccessor logger = new LogAccessor(SmbSession.class); - private static final String FILE_SEPARATOR = System.getProperty("file.separator"); + private static final String FILE_SEPARATOR = FileSystems.getDefault().getSeparator(); private static final String SMB_FILE_SEPARATOR = "/"; @@ -120,31 +121,42 @@ public class SmbSession implements Session { /** * Return the contents of the specified SMB resource as an array of SmbFile objects. * In case the remote resource does not exist, an empty array is returned. - * @param _path path to a remote directory + * @param remotePath path to a remote directory or remote file path * @return array of SmbFile objects * @throws IOException on error conditions returned by a CIFS server or if the remote resource is not a directory. */ @Override - public SmbFile[] list(String _path) throws IOException { - try { - SmbFile smbDir = createSmbDirectoryObject(_path); - if (!smbDir.exists()) { - logger.warn(() -> "Remote directory [" + _path + "] does not exist. Cannot list resources."); - return new SmbFile[0]; + public SmbFile[] list(String remotePath) throws IOException { + SmbFile[] files; + int lastIndex = StringUtils.hasText(remotePath) ? remotePath.lastIndexOf('/') : 0; + String remoteFileName = lastIndex > 0 ? remotePath.substring(lastIndex + 1) : null; + if (StringUtils.hasText(remoteFileName)) { + SmbFile remoteFile = createSmbFileObject(remotePath); + if (!remoteFile.isFile()) { + throw new IOException("[" + remotePath + "] is not a file."); } - else if (!smbDir.isDirectory()) { - throw new IOException("[" + _path + "] is not a directory. Cannot list resources."); + files = new SmbFile[] {remoteFile}; + } + else { + try { + SmbFile smbDir = createSmbDirectoryObject(remotePath); + if (!smbDir.exists()) { + logger.warn(() -> "Remote directory [" + remotePath + "] does not exist. Cannot list resources."); + return new SmbFile[0]; + } + else if (!smbDir.isDirectory()) { + throw new IOException("[" + remotePath + "] is not a directory. Cannot list resources."); + } + + files = smbDir.listFiles(); + } + catch (SmbException _ex) { + throw new IOException("Failed to list in [" + remotePath + "].", _ex); } - - SmbFile[] files = smbDir.listFiles(); - - logListedFiles(_path, files); - - return files; - } - catch (SmbException _ex) { - throw new IOException("Failed to list in [" + _path + "].", _ex); } + logListedFiles(remotePath, files); + + return files; } /** diff --git a/spring-integration-smb/src/test/java/org/springframework/integration/smb/dsl/SmbTests.java b/spring-integration-smb/src/test/java/org/springframework/integration/smb/dsl/SmbTests.java index cfc4800b70..d1ea9ea548 100644 --- a/spring-integration-smb/src/test/java/org/springframework/integration/smb/dsl/SmbTests.java +++ b/spring-integration-smb/src/test/java/org/springframework/integration/smb/dsl/SmbTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 the original author or authors. + * Copyright 2022-2024 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. @@ -164,7 +164,7 @@ public class SmbTests extends SmbTestSupport { } @Test - public void testSmbOutboundFlow() { + public void testSmbOutboundFlow() throws SmbException { IntegrationFlow flow = f -> f .handle(Smb.outboundAdapter(sessionFactory(), FileExistsMode.REPLACE) .useTemporaryFileName(false) @@ -181,18 +181,13 @@ public class SmbTests extends SmbTestSupport { SmbFile[] files = template.execute(session -> session.list(getTargetRemoteDirectory().getName())); assertThat(files).hasSize(1); - try { - assertThat(files[0].length()).isEqualTo(3); - } - catch (SmbException se) { - se.printStackTrace(); - } + assertThat(files[0].length()).isEqualTo(3); registration.destroy(); } @Test - public void testSmbOutboundFlowWithSmbRemoteTemplate() { + public void testSmbOutboundFlowWithSmbRemoteTemplate() throws SmbException { SmbRemoteFileTemplate smbTemplate = new SmbRemoteFileTemplate(sessionFactory()); IntegrationFlow flow = f -> f .handle(Smb.outboundAdapter(smbTemplate) @@ -209,18 +204,13 @@ public class SmbTests extends SmbTestSupport { SmbFile[] files = smbTemplate.execute(session -> session.list(getTargetRemoteDirectory().getName())); assertThat(files).hasSize(1); - try { - assertThat(files[0].length()).isEqualTo(3); - } - catch (SmbException se) { - se.printStackTrace(); - } + assertThat(files[0].length()).isEqualTo(3); registration.destroy(); } @Test - public void testSmbOutboundFlowWithSmbRemoteTemplateAndMode() { + public void testSmbOutboundFlowWithSmbRemoteTemplateAndMode() throws SmbException { SmbRemoteFileTemplate smbTemplate = new SmbRemoteFileTemplate(sessionFactory()); IntegrationFlow flow = f -> f .handle(Smb.outboundAdapter(smbTemplate, FileExistsMode.APPEND) @@ -242,18 +232,33 @@ public class SmbTests extends SmbTestSupport { SmbFile[] files = smbTemplate.execute(session -> session.list(getTargetRemoteDirectory().getName())); assertThat(files).hasSize(1); - try { - assertThat(files[0].length()).isEqualTo(9); - } - catch (SmbException se) { - se.printStackTrace(); - } + assertThat(files[0].length()).isEqualTo(9); registration.destroy(); } @Test public void testSmbGetFlow() { + QueueChannel out = new QueueChannel(); + IntegrationFlow flow = f -> f + .handle( + Smb.outboundGateway(sessionFactory(), AbstractRemoteFileOutboundGateway.Command.GET, "payload") + .localDirectoryExpression("'" + getTargetLocalDirectoryName() + "'")) + .channel(out); + IntegrationFlowRegistration registration = this.flowContext.registration(flow).register(); + String fileName = "smbSource/subSmbSource/subSmbSource2.txt"; + registration.getInputChannel().send(new GenericMessage<>(fileName)); + Message result = out.receive(10_000); + assertThat(result).isNotNull(); + + File sfis = (File) result.getPayload(); + assertThat(sfis).hasFileName("subSmbSource2.txt"); + + registration.destroy(); + } + + @Test + public void testSmbGetStreamFlow() throws IOException { QueueChannel out = new QueueChannel(); IntegrationFlow flow = f -> f .handle( @@ -271,14 +276,10 @@ public class SmbTests extends SmbTestSupport { Message result = out.receive(10_000); assertThat(result).isNotNull(); - SmbFileInputStream sfis = (SmbFileInputStream) result.getPayload(); - assertThat(sfis).isNotNull(); + try (SmbFileInputStream sfis = (SmbFileInputStream) result.getPayload()) { + assertThat(sfis).isNotNull(); + } - try { - sfis.close(); - } - catch (IOException ioe) { - } registration.destroy(); }