CAMEL-9610: Add chmodDirectory to allow setting file permissions on directories 
created by file producer.


Project: http://git-wip-us.apache.org/repos/asf/camel/repo
Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/9784d030
Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/9784d030
Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/9784d030

Branch: refs/heads/master
Commit: 9784d030100e74a909c2f5fa6d2801b3dfc2a57a
Parents: 5be46e4
Author: Claus Ibsen <davscl...@apache.org>
Authored: Thu Feb 18 18:42:43 2016 +0100
Committer: Claus Ibsen <davscl...@apache.org>
Committed: Thu Feb 18 19:57:39 2016 +0100

----------------------------------------------------------------------
 .../camel/component/file/FileOperations.java    |  54 +++++++--
 .../component/file/GenericFileEndpoint.java     |  63 ++++++++++
 .../FileProducerDirectoryChmodOptionTest.java   | 117 +++++++++++++++++++
 3 files changed, 226 insertions(+), 8 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/camel/blob/9784d030/camel-core/src/main/java/org/apache/camel/component/file/FileOperations.java
----------------------------------------------------------------------
diff --git 
a/camel-core/src/main/java/org/apache/camel/component/file/FileOperations.java 
b/camel-core/src/main/java/org/apache/camel/component/file/FileOperations.java
index 412d81a..c44c141 100644
--- 
a/camel-core/src/main/java/org/apache/camel/component/file/FileOperations.java
+++ 
b/camel-core/src/main/java/org/apache/camel/component/file/FileOperations.java
@@ -89,13 +89,47 @@ public class FileOperations implements 
GenericFileOperations<File> {
         return file.exists();
     }
 
+    protected boolean buildDirectory(File dir, Set<PosixFilePermission> 
permissions) {
+        if (dir.exists()) {
+            return true;
+        }
+
+        if (permissions == null || permissions.isEmpty()) {
+            return dir.mkdirs();
+        }
+
+        // create directory one part of a time and set permissions
+        try {
+            String[] parts = dir.getPath().split("\\" + File.separatorChar);
+            File base = new File(".");
+            for (String part : parts) {
+                File subDir = new File(base, part);
+                if (!subDir.exists()) {
+                    if (subDir.mkdir()) {
+                        if (LOG.isTraceEnabled()) {
+                            LOG.trace("Setting chmod: {} on directory: {} ", 
PosixFilePermissions.toString(permissions), subDir);
+                        }
+                        Files.setPosixFilePermissions(subDir.toPath(), 
permissions);
+                    } else {
+                        return false;
+                    }
+                }
+                base = new File(base, subDir.getName());
+            }
+        } catch (IOException e) {
+            throw new GenericFileOperationFailedException("Error setting chmod 
on directory: " + dir, e);
+        }
+
+        return true;
+    }
+
     public boolean buildDirectory(String directory, boolean absolute) throws 
GenericFileOperationFailedException {
         ObjectHelper.notNull(endpoint, "endpoint");
 
         // always create endpoint defined directory
         if (endpoint.isAutoCreate() && !endpoint.getFile().exists()) {
             LOG.trace("Building starting directory: {}", endpoint.getFile());
-            endpoint.getFile().mkdirs();
+            buildDirectory(endpoint.getFile(), 
endpoint.getDirectoryPermissions());
         }
 
         if (ObjectHelper.isEmpty(directory)) {
@@ -131,10 +165,8 @@ public class FileOperations implements 
GenericFileOperations<File> {
                 // the directory already exists
                 return true;
             } else {
-                if (LOG.isTraceEnabled()) {
-                    LOG.trace("Building directory: {}", path);
-                }
-                return path.mkdirs();
+                LOG.trace("Building directory: {}", path);
+                return buildDirectory(path, 
endpoint.getDirectoryPermissions());
             }
         }
     }
@@ -246,8 +278,10 @@ public class FileOperations implements 
GenericFileOperations<File> {
                         if (ObjectHelper.isNotEmpty(endpoint.getChmod())) {
                             Set<PosixFilePermission> permissions = 
endpoint.getPermissions();
                             if (!permissions.isEmpty()) {
+                                if (LOG.isTraceEnabled()) {
+                                    LOG.trace("Setting chmod: {} on file: {} 
", PosixFilePermissions.toString(permissions), file);
+                                }
                                 Files.setPosixFilePermissions(file.toPath(), 
permissions);
-                                LOG.trace("Setting chmod: {} on file: {} ", 
PosixFilePermissions.toString(permissions), file);
                             }
                         }
                         // clear header as we have renamed the file
@@ -265,8 +299,10 @@ public class FileOperations implements 
GenericFileOperations<File> {
                     if (ObjectHelper.isNotEmpty(endpoint.getChmod())) {
                         Set<PosixFilePermission> permissions = 
endpoint.getPermissions();
                         if (!permissions.isEmpty()) {
+                            if (LOG.isTraceEnabled()) {
+                                LOG.trace("Setting chmod: {} on file: {} ", 
PosixFilePermissions.toString(permissions), file);
+                            }
                             Files.setPosixFilePermissions(file.toPath(), 
permissions);
-                            LOG.trace("Setting chmod: {} on file: {} ", 
PosixFilePermissions.toString(permissions), file);
                         }
                     }
                     return true;
@@ -296,8 +332,10 @@ public class FileOperations implements 
GenericFileOperations<File> {
             if (ObjectHelper.isNotEmpty(endpoint.getChmod())) {
                 Set<PosixFilePermission> permissions = 
endpoint.getPermissions();
                 if (!permissions.isEmpty()) {
+                    if (LOG.isTraceEnabled()) {
+                        LOG.trace("Setting chmod: {} on file: {} ", 
PosixFilePermissions.toString(permissions), file);
+                    }
                     Files.setPosixFilePermissions(file.toPath(), permissions);
-                    LOG.trace("Setting chmod: {} on file: {} ", 
PosixFilePermissions.toString(permissions), file);
                 }
             }
 

http://git-wip-us.apache.org/repos/asf/camel/blob/9784d030/camel-core/src/main/java/org/apache/camel/component/file/GenericFileEndpoint.java
----------------------------------------------------------------------
diff --git 
a/camel-core/src/main/java/org/apache/camel/component/file/GenericFileEndpoint.java
 
b/camel-core/src/main/java/org/apache/camel/component/file/GenericFileEndpoint.java
index 0e20247..da6f235 100644
--- 
a/camel-core/src/main/java/org/apache/camel/component/file/GenericFileEndpoint.java
+++ 
b/camel-core/src/main/java/org/apache/camel/component/file/GenericFileEndpoint.java
@@ -96,6 +96,8 @@ public abstract class GenericFileEndpoint<T> extends 
ScheduledPollEndpoint imple
     protected boolean allowNullBody;
     @UriParam(label = "producer,advanced")
     protected String chmod;
+    @UriParam(label = "producer,advanced")
+    protected String chmodDirectory;
 
     // consumer options
 
@@ -391,6 +393,67 @@ public abstract class GenericFileEndpoint<T> extends 
ScheduledPollEndpoint imple
         }
     }
 
+    public Set<PosixFilePermission> getDirectoryPermissions() {
+        Set<PosixFilePermission> permissions = new 
HashSet<PosixFilePermission>();
+        if (ObjectHelper.isEmpty(chmodDirectory)) {
+            return permissions;
+        }
+
+        String chmodString = chmodDirectory.substring(chmodDirectory.length() 
- 3);  // if 4 digits chop off leading one
+
+        Integer ownerValue = Integer.parseInt(chmodString.substring(0, 1));
+        Integer groupValue = Integer.parseInt(chmodString.substring(1, 2));
+        Integer othersValue = Integer.parseInt(chmodString.substring(2, 3));
+
+        if ((ownerValue & CHMOD_WRITE_MASK) > 0) {
+            permissions.add(PosixFilePermission.OWNER_WRITE);
+        }
+        if ((ownerValue & CHMOD_READ_MASK) > 0) {
+            permissions.add(PosixFilePermission.OWNER_READ);
+        }
+        if ((ownerValue & CHMOD_EXECUTE_MASK) > 0) {
+            permissions.add(PosixFilePermission.OWNER_EXECUTE);
+        }
+
+        if ((groupValue & CHMOD_WRITE_MASK) > 0) {
+            permissions.add(PosixFilePermission.GROUP_WRITE);
+        }
+        if ((groupValue & CHMOD_READ_MASK) > 0) {
+            permissions.add(PosixFilePermission.GROUP_READ);
+        }
+        if ((groupValue & CHMOD_EXECUTE_MASK) > 0) {
+            permissions.add(PosixFilePermission.GROUP_EXECUTE);
+        }
+
+        if ((othersValue & CHMOD_WRITE_MASK) > 0) {
+            permissions.add(PosixFilePermission.OTHERS_WRITE);
+        }
+        if ((othersValue & CHMOD_READ_MASK) > 0) {
+            permissions.add(PosixFilePermission.OTHERS_READ);
+        }
+        if ((othersValue & CHMOD_EXECUTE_MASK) > 0) {
+            permissions.add(PosixFilePermission.OTHERS_EXECUTE);
+        }
+
+        return permissions;
+    }
+
+    public String getChmodDirectory() {
+        return chmodDirectory;
+    }
+
+    /**
+     * Specify the directory permissions used when the producer creates 
missing directories, the chmod value must be between 000 and 777;
+     * If there is a leading digit like in 0755 we will ignore it.
+     */
+    public void setChmodDirectory(String chmodDirectory) throws Exception {
+        if (ObjectHelper.isNotEmpty(chmodDirectory) && 
chmodPermissionsAreValid(chmodDirectory)) {
+            this.chmodDirectory = chmodDirectory.trim();
+        } else {
+            throw new IllegalArgumentException("chmodDirectory option [" + 
chmodDirectory + "] is not valid");
+        }
+    }
+
     public boolean isNoop() {
         return noop;
     }

http://git-wip-us.apache.org/repos/asf/camel/blob/9784d030/camel-core/src/test/java/org/apache/camel/component/file/FileProducerDirectoryChmodOptionTest.java
----------------------------------------------------------------------
diff --git 
a/camel-core/src/test/java/org/apache/camel/component/file/FileProducerDirectoryChmodOptionTest.java
 
b/camel-core/src/test/java/org/apache/camel/component/file/FileProducerDirectoryChmodOptionTest.java
new file mode 100644
index 0000000..932b767
--- /dev/null
+++ 
b/camel-core/src/test/java/org/apache/camel/component/file/FileProducerDirectoryChmodOptionTest.java
@@ -0,0 +1,117 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.camel.component.file;
+
+import java.io.File;
+import java.nio.file.Files;
+import java.nio.file.LinkOption;
+import java.nio.file.attribute.PosixFilePermission;
+import java.nio.file.attribute.PosixFilePermissions;
+import java.util.Date;
+import java.util.Set;
+
+import org.apache.camel.ContextTestSupport;
+import org.apache.camel.Exchange;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+
+public class FileProducerDirectoryChmodOptionTest extends ContextTestSupport {
+    public static final String TEST_DIRECTORY = "target/chmoddir/foo/";
+
+    @Override
+    protected void setUp() throws Exception {
+        deleteDirectory(TEST_DIRECTORY);
+        super.setUp();
+    }
+
+    private boolean canTest() {
+        // can not run on windows
+        return !isPlatform("windows");
+    }
+
+    public void testWriteValidNoDir() throws Exception {
+        if (!canTest()) {
+            return;
+        }
+
+        runChmodCheck("NoDir", null, "rwxr-xr-x");
+    }
+
+    public void testWriteValidChmod0755() throws Exception {
+        if (!canTest()) {
+            return;
+        }
+
+        runChmodCheck("0755", "rwxrwxrwx", "rwxr-xr-x");
+    }
+
+    public void testWriteValidChmod666() throws Exception {
+        if (!canTest()) {
+            return;
+        }
+
+        runChmodCheck("666", "rwxrwxrwx", "rw-rw-rw-");
+    }
+
+    private void runChmodCheck(String routeSuffix, String 
expectedDirectoryPermissions, String expectedPermissions) throws Exception {
+        MockEndpoint mock = getMockEndpoint("mock:chmod" + routeSuffix);
+        mock.expectedMessageCount(1);
+        String testFileName = "chmod" + routeSuffix + ".txt";
+        String fullTestFileName = TEST_DIRECTORY + testFileName;
+        String testFileContent = "Writing file with chmod " + routeSuffix + " 
option at " + new Date();
+        mock.expectedFileExists(fullTestFileName, testFileContent);
+
+        template.sendBodyAndHeader("direct:write" + routeSuffix, 
testFileContent, Exchange.FILE_NAME, testFileName);
+
+        if (expectedDirectoryPermissions != null) {
+            File d = new File(TEST_DIRECTORY);
+            Set<PosixFilePermission> permissions = 
Files.getPosixFilePermissions(d.toPath(), LinkOption.NOFOLLOW_LINKS);
+            assertEquals(expectedDirectoryPermissions, 
PosixFilePermissions.toString(permissions));
+            assertEquals(expectedDirectoryPermissions.replace("-", 
"").length(), permissions.size());
+        }
+
+        if (expectedPermissions != null) {
+            File f = new File(fullTestFileName);
+            Set<PosixFilePermission> permissions = 
Files.getPosixFilePermissions(f.toPath(), LinkOption.NOFOLLOW_LINKS);
+            assertEquals(expectedPermissions, 
PosixFilePermissions.toString(permissions));
+            assertEquals(expectedPermissions.replace("-", "").length(), 
permissions.size());
+        }
+
+        assertMockEndpointsSatisfied();
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() {
+        return new RouteBuilder() {
+            public void configure() {
+                // Valid chmod values
+                from("direct:write666")
+                        .to("file://" + TEST_DIRECTORY + 
"?chmodDirectory=777&chmod=666")
+                        .to("mock:chmod666");
+
+                from("direct:write0755")
+                        .to("file://" + TEST_DIRECTORY + 
"?chmodDirectory=777&chmod=0755")
+                        .to("mock:chmod0755");
+
+                from("direct:writeNoDir")
+                        .to("file://" + TEST_DIRECTORY + "?chmod=0755")
+                        .to("mock:chmodNoDir");
+
+            }
+        };
+    }
+}

Reply via email to