This is an automated email from the ASF dual-hosted git repository.

pvillard pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/nifi.git


The following commit(s) were added to refs/heads/main by this push:
     new 2493d3cef9a NIFI-15345 Avoided calling SFTP stat when attributes not 
configured
2493d3cef9a is described below

commit 2493d3cef9a525394329d2088904fa652b07894e
Author: exceptionfactory <[email protected]>
AuthorDate: Mon Dec 15 13:00:29 2025 -0600

    NIFI-15345 Avoided calling SFTP stat when attributes not configured
    
    - Refactored SFTPTransfer.put() to avoid getting remote file attributes 
when the PutSFTP Processor is not configured to change attributes
    
    Signed-off-by: Pierre Villard <[email protected]>
    
    This closes #10646.
---
 .../processors/standard/util/SFTPTransfer.java     | 122 +++++++++++++++------
 .../nifi/processors/standard/TestPutSFTP.java      |  32 +++++-
 2 files changed, 121 insertions(+), 33 deletions(-)

diff --git 
a/nifi-extension-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/util/SFTPTransfer.java
 
b/nifi-extension-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/util/SFTPTransfer.java
index 45507944281..99d526e8fd6 100644
--- 
a/nifi-extension-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/util/SFTPTransfer.java
+++ 
b/nifi-extension-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/util/SFTPTransfer.java
@@ -747,44 +747,13 @@ public class SFTPTransfer implements FileTransfer {
         }
         final String tempPath = buildFullPath(path, tempFilename);
 
-        final SftpClient.Attributes attributes;
         try {
             sftpClient.put(content, tempPath);
-            attributes = sftpClient.stat(tempPath);
         } catch (final SftpException e) {
             throw new IOException("Failed to transfer content to 
[%s]".formatted(fullPath), e);
         }
 
-        final String permissions = 
ctx.getProperty(PERMISSIONS).evaluateAttributeExpressions(flowFile).getValue();
-        if (StringUtils.isNotEmpty(permissions)) {
-            final int perms = numberPermissions(permissions);
-            attributes.setPermissions(perms);
-        }
-
-        final String lastModifiedTime = 
ctx.getProperty(LAST_MODIFIED_TIME).evaluateAttributeExpressions(flowFile).getValue();
-        if (lastModifiedTime != null && !lastModifiedTime.isBlank()) {
-            final DateTimeFormatter dateTimeFormatter = 
DateTimeFormatter.ofPattern(FILE_MODIFY_DATE_ATTR_FORMAT, Locale.US);
-            final OffsetDateTime offsetDateTime = 
OffsetDateTime.parse(lastModifiedTime, dateTimeFormatter);
-            final FileTime modifyTime = 
FileTime.from(offsetDateTime.toInstant());
-            attributes.setModifyTime(modifyTime);
-        }
-
-        final String owner = 
ctx.getProperty(REMOTE_OWNER).evaluateAttributeExpressions(flowFile).getValue();
-        if (StringUtils.isNotEmpty(owner)) {
-            attributes.setOwner(owner);
-        }
-
-        final String group = 
ctx.getProperty(REMOTE_GROUP).evaluateAttributeExpressions(flowFile).getValue();
-        if (StringUtils.isNotEmpty(group)) {
-            attributes.setGroup(group);
-        }
-
-        // Set Attributes on temporary file path to avoid potential timing 
issues with retrieval and removal of transferred files
-        try {
-            sftpClient.setStat(tempPath, attributes);
-        } catch (final SftpException e) {
-            logger.warn("Failed to set attributes on Remote File [{}]", 
tempPath, e);
-        }
+        setAttributes(flowFile, tempPath);
 
         if (!filename.equals(tempFilename)) {
             try {
@@ -809,6 +778,44 @@ public class SFTPTransfer implements FileTransfer {
         return fullPath;
     }
 
+    private void setAttributes(final FlowFile flowFile, final String 
remotePath) {
+        final AttributesRequested attributesRequested = new 
AttributesRequested();
+
+        final String permissions = 
ctx.getProperty(PERMISSIONS).evaluateAttributeExpressions(flowFile).getValue();
+        if (StringUtils.isNotEmpty(permissions)) {
+            final int perms = numberPermissions(permissions);
+            attributesRequested.setPermissions(perms);
+        }
+
+        final String lastModifiedTime = 
ctx.getProperty(LAST_MODIFIED_TIME).evaluateAttributeExpressions(flowFile).getValue();
+        if (StringUtils.isNotBlank(lastModifiedTime)) {
+            final DateTimeFormatter dateTimeFormatter = 
DateTimeFormatter.ofPattern(FILE_MODIFY_DATE_ATTR_FORMAT, Locale.US);
+            final OffsetDateTime offsetDateTime = 
OffsetDateTime.parse(lastModifiedTime, dateTimeFormatter);
+            final FileTime modifyTime = 
FileTime.from(offsetDateTime.toInstant());
+            attributesRequested.setModifyTime(modifyTime);
+        }
+
+        final String owner = 
ctx.getProperty(REMOTE_OWNER).evaluateAttributeExpressions(flowFile).getValue();
+        if (StringUtils.isNotEmpty(owner)) {
+            attributesRequested.setOwner(owner);
+        }
+
+        final String group = 
ctx.getProperty(REMOTE_GROUP).evaluateAttributeExpressions(flowFile).getValue();
+        if (StringUtils.isNotEmpty(group)) {
+            attributesRequested.setGroup(group);
+        }
+
+        if (attributesRequested.isConfigured()) {
+            try {
+                final SftpClient.Attributes attributes = 
sftpClient.stat(remotePath);
+                attributesRequested.setAttributes(attributes);
+                sftpClient.setStat(remotePath, attributes);
+            } catch (final IOException e) {
+                logger.warn("Failed to set attributes on Remote File [{}] for 
{}", remotePath, flowFile, e);
+            }
+        }
+    }
+
     @Override
     public void rename(final FlowFile flowFile, final String source, final 
String target) throws IOException {
         final SftpClient sftpClient = getSFTPClient(flowFile);
@@ -868,4 +875,55 @@ public class SFTPTransfer implements FileTransfer {
         }
         return number;
     }
+
+    private static class AttributesRequested {
+        private boolean configured;
+
+        private Integer permissions;
+
+        private FileTime modifyTime;
+
+        private String owner;
+
+        private String group;
+
+        void setPermissions(final int permissions) {
+            this.permissions = permissions;
+            this.configured = true;
+        }
+
+        void setModifyTime(final FileTime modifyTime) {
+            this.modifyTime = modifyTime;
+            this.configured = true;
+        }
+
+        void setOwner(final String owner) {
+            this.owner = owner;
+            this.configured = true;
+        }
+
+        void setGroup(final String group) {
+            this.group = group;
+            this.configured = true;
+        }
+
+        boolean isConfigured() {
+            return configured;
+        }
+
+        void setAttributes(final SftpClient.Attributes attributes) {
+            if (permissions != null) {
+                attributes.setPermissions(permissions);
+            }
+            if (modifyTime != null) {
+                attributes.setModifyTime(modifyTime);
+            }
+            if (StringUtils.isNotBlank(owner)) {
+                attributes.setOwner(owner);
+            }
+            if (StringUtils.isNotBlank(group)) {
+                attributes.setGroup(group);
+            }
+        }
+    }
 }
diff --git 
a/nifi-extension-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/java/org/apache/nifi/processors/standard/TestPutSFTP.java
 
b/nifi-extension-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/java/org/apache/nifi/processors/standard/TestPutSFTP.java
index 797b645a543..b2671a213f6 100644
--- 
a/nifi-extension-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/java/org/apache/nifi/processors/standard/TestPutSFTP.java
+++ 
b/nifi-extension-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/java/org/apache/nifi/processors/standard/TestPutSFTP.java
@@ -31,9 +31,15 @@ import org.junit.jupiter.api.io.TempDir;
 import java.io.IOException;
 import java.nio.file.Files;
 import java.nio.file.Path;
+import java.nio.file.attribute.FileTime;
+import java.time.Instant;
+import java.time.OffsetDateTime;
+import java.time.ZoneId;
+import java.time.format.DateTimeFormatter;
 import java.util.Collections;
 import java.util.List;
 
+import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 import static org.junit.jupiter.api.Assertions.assertFalse;
 
@@ -50,14 +56,19 @@ class TestPutSFTP {
 
     private static final String TRANSIT_URI_FORMAT = "sftp://%s";;
 
+    private static final OffsetDateTime LAST_MODIFIED_TIME_CONFIGURED = 
OffsetDateTime.ofInstant(Instant.ofEpochSecond(30), ZoneId.systemDefault());
+
     private SSHTestServer sshTestServer;
 
     private TestRunner runner;
 
+    private Path serverRootPath;
+
     @BeforeEach
     void setRunner(@TempDir final Path rootPath) throws IOException {
         sshTestServer = new SSHTestServer(rootPath);
         sshTestServer.startServer();
+        serverRootPath = rootPath;
 
         runner = TestRunners.newTestRunner(PutSFTP.class);
         runner.setProperty(SFTPTransfer.HOSTNAME, sshTestServer.getHost());
@@ -192,8 +203,27 @@ class TestPutSFTP {
         final List<ProvenanceEventRecord> records = 
runner.getProvenanceEvents();
         assertFalse(records.isEmpty());
 
-        final ProvenanceEventRecord record = records.iterator().next();
+        final ProvenanceEventRecord record = records.getFirst();
         final String firstTransitUri = String.format(TRANSIT_URI_FORMAT, 
sshTestServer.getHost());
         assertTrue(record.getTransitUri().startsWith(firstTransitUri), 
"Transit URI not found");
     }
+
+    @Test
+    void testRunSetLastModifiedTime() throws IOException {
+        final DateTimeFormatter formatter = 
DateTimeFormatter.ofPattern(SFTPTransfer.FILE_MODIFY_DATE_ATTR_FORMAT);
+        final String lastModifiedTimeConfigured = 
formatter.format(LAST_MODIFIED_TIME_CONFIGURED);
+
+        runner.setProperty(SFTPTransfer.LAST_MODIFIED_TIME, 
lastModifiedTimeConfigured);
+        runner.enqueue(FLOW_FILE_CONTENTS, 
Collections.singletonMap(CoreAttributes.FILENAME.key(), FIRST_FILENAME));
+        runner.run();
+
+        runner.assertAllFlowFilesTransferred(PutSFTP.REL_SUCCESS);
+
+        final Path serverPath = 
serverRootPath.resolve(REMOTE_DIRECTORY).resolve(FIRST_FILENAME);
+        assertTrue(Files.exists(serverPath), "Server file not found 
[%s]".formatted(serverPath));
+
+        final FileTime lastModifiedTime = 
Files.getLastModifiedTime(serverPath);
+        final FileTime expectedLastModifiedTime = 
FileTime.from(LAST_MODIFIED_TIME_CONFIGURED.toInstant());
+        assertEquals(expectedLastModifiedTime, lastModifiedTime);
+    }
 }

Reply via email to