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

davsclaus pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/camel.git

commit ea2166779b578ea8513ce9d178e24e36a19a76ad
Author: Claus Ibsen <claus.ib...@gmail.com>
AuthorDate: Tue Aug 6 09:56:21 2019 +0200

    CAMEL-9971: Added appendChars option to file component.
---
 .../camel-file/src/main/docs/file-component.adoc   |  4 +-
 .../camel/component/file/FileOperations.java       | 14 +++++
 .../camel/component/file/GenericFileEndpoint.java  | 41 ++++++++++++++
 .../component/file/FileProduceAppendCharsTest.java | 62 ++++++++++++++++++++++
 .../endpoint/dsl/FileEndpointBuilderFactory.java   | 14 +++++
 5 files changed, 134 insertions(+), 1 deletion(-)

diff --git a/components/camel-file/src/main/docs/file-component.adoc 
b/components/camel-file/src/main/docs/file-component.adoc
index daa2125..dae967f 100644
--- a/components/camel-file/src/main/docs/file-component.adoc
+++ b/components/camel-file/src/main/docs/file-component.adoc
@@ -85,7 +85,7 @@ with the following path and query parameters:
 |===
 
 
-=== Query Parameters (90 parameters):
+=== Query Parameters (91 parameters):
 
 
 [width="100%",cols="2,5,^1,2",options="header"]
@@ -114,6 +114,8 @@ with the following path and query parameters:
 | *processStrategy* (consumer) | A pluggable 
org.apache.camel.component.file.GenericFileProcessStrategy allowing you to 
implement your own readLock option or similar. Can also be used when special 
conditions must be met before a file can be consumed, such as a special ready 
file exists. If this option is set then the readLock option does not apply. |  
| GenericFileProcess Strategy
 | *startingDirectoryMustExist* (consumer) | Whether the starting directory 
must exist. Mind that the autoCreate option is default enabled, which means the 
starting directory is normally auto created if it doesn't exist. You can 
disable autoCreate and enable this to ensure the starting directory must exist. 
Will thrown an exception if the directory doesn't exist. | false | boolean
 | *startingDirectoryMustHave Access* (consumer) | Whether the starting 
directory has access permissions. Mind that the startingDirectoryMustExist 
parameter must be set to true in order to verify that the directory exists. 
Will thrown an exception if the directory doesn't have read and write 
permissions. | false | boolean
+| *appendChars* (producer) | Used to append characters (text) after writing 
files. This can for example be used to add new lines or other separators when 
writing and appending to existing files. To specify new-line (
+ or 
) or tab (      ) characters then escape with an extra slash, eg \n |  | String
 | *fileExist* (producer) | What to do if a file already exists with the same 
name. Override, which is the default, replaces the existing file. Append - adds 
content to the existing file. Fail - throws a GenericFileOperationException, 
indicating that there is already an existing file. Ignore - silently ignores 
the problem and does not override the existing file, but assumes everything is 
okay. Move - option requires to use the moveExisting option to be configured as 
well. The option eager [...]
 | *flatten* (producer) | Flatten is used to flatten the file name path to 
strip any leading paths, so it's just the file name. This allows you to consume 
recursively into sub-directories, but when you eg write the files to another 
directory they will be written in a single directory. Setting this to true on 
the producer enforces that any file name in CamelFileName header will be 
stripped for any leading paths. | false | boolean
 | *jailStartingDirectory* (producer) | Used for jailing (restricting) writing 
files to the starting directory (and sub) only. This is enabled by default to 
not allow Camel to write files to outside directories (to be more secured out 
of the box). You can turn this off to allow writing files to directories 
outside the starting directory, such as parent or root folders. | true | boolean
diff --git 
a/components/camel-file/src/main/java/org/apache/camel/component/file/FileOperations.java
 
b/components/camel-file/src/main/java/org/apache/camel/component/file/FileOperations.java
index 4578060..16aade7 100644
--- 
a/components/camel-file/src/main/java/org/apache/camel/component/file/FileOperations.java
+++ 
b/components/camel-file/src/main/java/org/apache/camel/component/file/FileOperations.java
@@ -412,6 +412,7 @@ public class FileOperations implements 
GenericFileOperations<File> {
     }
 
     private void writeFileByStream(InputStream in, File target) throws 
IOException {
+        boolean exists = target.exists();
         try (SeekableByteChannel out = prepareOutputFileChannel(target)) {
             
             LOG.debug("Using InputStream to write file: {}", target);
@@ -426,12 +427,21 @@ public class FileOperations implements 
GenericFileOperations<File> {
                 out.write(byteBuffer);
                 byteBuffer.clear();
             }
+
+            boolean append = endpoint.getFileExist() == 
GenericFileExist.Append;
+            if (append && exists && endpoint.getAppendChars() != null) {
+                byteBuffer = 
ByteBuffer.wrap(endpoint.getAppendChars().getBytes());
+                out.write(byteBuffer);
+                byteBuffer.clear();
+            }
+
         } finally {
             IOHelper.close(in, target.getName(), LOG);
         }
     }
 
     private void writeFileByReaderWithCharset(Reader in, File target, String 
charset) throws IOException {
+        boolean exists = target.exists();
         boolean append = endpoint.getFileExist() == GenericFileExist.Append;
         try (Writer out = Files.newBufferedWriter(target.toPath(), 
Charset.forName(charset), 
                                                   StandardOpenOption.WRITE,
@@ -440,6 +450,10 @@ public class FileOperations implements 
GenericFileOperations<File> {
             LOG.debug("Using Reader to write file: {} with charset: {}", 
target, charset);
             int size = endpoint.getBufferSize();
             IOHelper.copy(in, out, size);
+
+            if (append && exists && endpoint.getAppendChars() != null) {
+                out.write(endpoint.getAppendChars());
+            }
         } finally {
             IOHelper.close(in, target.getName(), LOG);
         }
diff --git 
a/components/camel-file/src/main/java/org/apache/camel/component/file/GenericFileEndpoint.java
 
b/components/camel-file/src/main/java/org/apache/camel/component/file/GenericFileEndpoint.java
index 473f0bc..3f6a020 100644
--- 
a/components/camel-file/src/main/java/org/apache/camel/component/file/GenericFileEndpoint.java
+++ 
b/components/camel-file/src/main/java/org/apache/camel/component/file/GenericFileEndpoint.java
@@ -97,6 +97,8 @@ public abstract class GenericFileEndpoint<T> extends 
ScheduledPollEndpoint imple
     protected boolean allowNullBody;
     @UriParam(label = "producer", defaultValue = "true")
     protected boolean jailStartingDirectory = true;
+    @UriParam(label = "producer")
+    protected String appendChars;
 
     // consumer options
 
@@ -1239,6 +1241,45 @@ public abstract class GenericFileEndpoint<T> extends 
ScheduledPollEndpoint imple
         this.jailStartingDirectory = jailStartingDirectory;
     }
 
+    public String getAppendChars() {
+        return appendChars;
+    }
+
+    /**
+     * Used to append characters (text) after writing files. This can for 
example be used to add new lines or other
+     * separators when writing and appending to existing files.
+     * <p/>
+     * To specify new-line (\n or \r) or tab (\t) characters then escape with 
an extra slash, eg \\n
+     */
+    public void setAppendChars(String appendChars) {
+        StringBuilder sb = new StringBuilder();
+        for (int i = 0; i < appendChars.length(); i++) {
+            char ch = appendChars.charAt(i);
+            boolean escaped = '\\' == ch;
+            if (escaped && i < appendChars.length() - 1) {
+                // grab next character to escape
+                char next = appendChars.charAt(i + 1);
+                // special for new line, tabs and carriage return
+                if ('n' == next) {
+                    sb.append("\n");
+                    i++;
+                    continue;
+                } else if ('t' == next) {
+                    sb.append("\t");
+                    i++;
+                    continue;
+                } else if ('r' == next) {
+                    sb.append("\r");
+                    i++;
+                    continue;
+                }
+            }
+            // not special just a regular character
+            sb.append(ch);
+        }
+        this.appendChars = sb.toString();
+    }
+
     public ExceptionHandler getOnCompletionExceptionHandler() {
         return onCompletionExceptionHandler;
     }
diff --git 
a/core/camel-core/src/test/java/org/apache/camel/component/file/FileProduceAppendCharsTest.java
 
b/core/camel-core/src/test/java/org/apache/camel/component/file/FileProduceAppendCharsTest.java
new file mode 100644
index 0000000..3f73322
--- /dev/null
+++ 
b/core/camel-core/src/test/java/org/apache/camel/component/file/FileProduceAppendCharsTest.java
@@ -0,0 +1,62 @@
+/*
+ * 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 org.apache.camel.ContextTestSupport;
+import org.apache.camel.Exchange;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * Unit test to verify the append chars option
+ */
+public class FileProduceAppendCharsTest extends ContextTestSupport {
+
+    @Test
+    public void testAppendChars() throws Exception {
+        MockEndpoint mock = getMockEndpoint("mock:result");
+        mock.expectedMessageCount(2);
+        mock.expectedFileExists("target/data/test-file-append/hello.txt", 
"Hello\nWorld\nHow are you?\n");
+
+        template.sendBody("direct:start", "World");
+        template.sendBody("direct:start", "How are you?");
+
+        assertMockEndpointsSatisfied();
+    }
+
+    @Override
+    @Before
+    public void setUp() throws Exception {
+        deleteDirectory("target/data/test-file-append");
+        super.setUp();
+        template.sendBodyAndHeader("file://target/data/test-file-append", 
"Hello\n", Exchange.FILE_NAME, "hello.txt");
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() {
+        return new RouteBuilder() {
+            public void configure() {
+                from("direct:start")
+                    .setHeader(Exchange.FILE_NAME, constant("hello.txt"))
+                    
.to("file://target/data/test-file-append?fileExist=Append&appendChars=\\n", 
"mock:result");
+            }
+        };
+    }
+
+}
\ No newline at end of file
diff --git 
a/core/camel-endpointdsl/src/main/java/org/apache/camel/builder/endpoint/dsl/FileEndpointBuilderFactory.java
 
b/core/camel-endpointdsl/src/main/java/org/apache/camel/builder/endpoint/dsl/FileEndpointBuilderFactory.java
index 8cd56fa..e2ccc7d 100644
--- 
a/core/camel-endpointdsl/src/main/java/org/apache/camel/builder/endpoint/dsl/FileEndpointBuilderFactory.java
+++ 
b/core/camel-endpointdsl/src/main/java/org/apache/camel/builder/endpoint/dsl/FileEndpointBuilderFactory.java
@@ -2346,6 +2346,20 @@ public interface FileEndpointBuilderFactory {
             return this;
         }
         /**
+         * Used to append characters (text) after writing files. This can for
+         * example be used to add new lines or other separators when writing 
and
+         * appending to existing files. To specify new-line (
+         * or 
) or tab (      ) characters then escape with an extra slash, eg \n.
+         * 
+         * The option is a: <code>java.lang.String</code> type.
+         * 
+         * Group: producer
+         */
+        default FileEndpointProducerBuilder appendChars(String appendChars) {
+            setProperty("appendChars", appendChars);
+            return this;
+        }
+        /**
          * What to do if a file already exists with the same name. Override,
          * which is the default, replaces the existing file. Append - adds
          * content to the existing file. Fail - throws a

Reply via email to