You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by da...@apache.org on 2019/08/06 08:04:10 UTC

[camel] branch master updated (d83aa63 -> 3fa8160)

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

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


    from d83aa63  Camel-Salesforce: Fix - Integration tests ignore salesforce endpoint setting.
     new ea21667  CAMEL-9971: Added appendChars option to file component.
     new 3fa8160  CAMEL-9971: Added appendChars option to file component.

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../camel-file/src/main/docs/file-component.adoc   |   4 +-
 .../camel/component/file/FileOperations.java       |  14 +++
 .../camel/component/file/GenericFileEndpoint.java  |  41 +++++++
 .../camel-ftp/src/main/docs/ftps-component.adoc    |   6 +-
 .../camel/component/file/remote/FtpEndpoint.java   |   2 +-
 .../camel/component/file/remote/FtpsEndpoint.java  |   3 +-
 .../camel/component/file/remote/SftpEndpoint.java  |   2 +-
 .../apache/camel/component/scp/ScpEndpoint.java    |   2 +-
 ...ndTest.java => FileProduceAppendCharsTest.java} |  19 +--
 .../endpoint/dsl/FileEndpointBuilderFactory.java   |  14 +++
 .../endpoint/dsl/FtpsEndpointBuilderFactory.java   | 132 ---------------------
 11 files changed, 88 insertions(+), 151 deletions(-)
 copy core/camel-core/src/test/java/org/apache/camel/component/file/{FileProduceAppendTest.java => FileProduceAppendCharsTest.java} (79%)


[camel] 02/02: CAMEL-9971: Added appendChars option to file component.

Posted by da...@apache.org.
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 3fa816071a182f52f053ca35b0b43262f09d30ef
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Tue Aug 6 10:02:44 2019 +0200

    CAMEL-9971: Added appendChars option to file component.
---
 .../camel-ftp/src/main/docs/ftps-component.adoc    |   6 +-
 .../camel/component/file/remote/FtpEndpoint.java   |   2 +-
 .../camel/component/file/remote/FtpsEndpoint.java  |   3 +-
 .../camel/component/file/remote/SftpEndpoint.java  |   2 +-
 .../apache/camel/component/scp/ScpEndpoint.java    |   2 +-
 .../endpoint/dsl/FtpsEndpointBuilderFactory.java   | 132 ---------------------
 6 files changed, 6 insertions(+), 141 deletions(-)

diff --git a/components/camel-ftp/src/main/docs/ftps-component.adoc b/components/camel-ftp/src/main/docs/ftps-component.adoc
index 4722341..726cb2a 100644
--- a/components/camel-ftp/src/main/docs/ftps-component.adoc
+++ b/components/camel-ftp/src/main/docs/ftps-component.adoc
@@ -61,7 +61,7 @@ with the following path and query parameters:
 |===
 
 
-=== Query Parameters (122 parameters):
+=== Query Parameters (118 parameters):
 
 
 [width="100%",cols="2,5,^1,2",options="header"]
@@ -151,10 +151,6 @@ with the following path and query parameters:
 | *readLock* (lock) | Used by consumer, to only poll the files if it has exclusive read-lock on the file (i.e. the file is not in-progress or being written). Camel will wait until the file lock is granted. This option provides the build in strategies: none - No read lock is in use markerFile - Camel creates a marker file (fileName.camelLock) and then holds a lock on it. This option is not available for the FTP component changed - Changed is using file length/modification timestamp to det [...]
 | *readLockCheckInterval* (lock) | Interval in millis for the read-lock, if supported by the read lock. This interval is used for sleeping between attempts to acquire the read lock. For example when using the changed read lock, you can set a higher interval period to cater for slow writes. The default of 1 sec. may be too fast if the producer is very slow writing the file. Notice: For FTP the default readLockCheckInterval is 5000. The readLockTimeout value must be higher than readLockChe [...]
 | *readLockDeleteOrphanLock Files* (lock) | Whether or not read lock with marker files should upon startup delete any orphan read lock files, which may have been left on the file system, if Camel was not properly shutdown (such as a JVM crash). If turning this option to false then any orphaned lock file will cause Camel to not attempt to pickup that file, this could also be due another node is concurrently reading files from the same shared directory. | true | boolean
-| *readLockIdempotentRelease Async* (lock) | Whether the delayed release task should be synchronous or asynchronous. See more details at the readLockIdempotentReleaseDelay option. | false | boolean
-| *readLockIdempotentRelease AsyncPoolSize* (lock) | The number of threads in the scheduled thread pool when using asynchronous release tasks. Using a default of 1 core threads should be sufficient in almost all use-cases, only set this to a higher value if either updating the idempotent repository is slow, or there are a lot of files to process. This option is not in-use if you use a shared thread pool by configuring the readLockIdempotentReleaseExecutorService option. See more details  [...]
-| *readLockIdempotentRelease Delay* (lock) | Whether to delay the release task for a period of millis. This can be used to delay the release tasks to expand the window when a file is regarded as read-locked, in an active/active cluster scenario with a shared idempotent repository, to ensure other nodes cannot potentially scan and acquire the same file, due to race-conditions. By expanding the time-window of the release tasks helps prevents these situations. Note delaying is only needed i [...]
-| *readLockIdempotentRelease ExecutorService* (lock) | To use a custom and shared thread pool for asynchronous release tasks. See more details at the readLockIdempotentReleaseDelay option. |  | ScheduledExecutor Service
 | *readLockLoggingLevel* (lock) | Logging level used when a read lock could not be acquired. By default a DEBUG is logged. You can change this level, for example to OFF to not have any logging. This option is only applicable for readLock of types: changed, fileLock, idempotent, idempotent-changed, idempotent-rename, rename. | DEBUG | LoggingLevel
 | *readLockMarkerFile* (lock) | Whether to use marker file with the changed, rename, or exclusive read lock types. By default a marker file is used as well to guard against other processes picking up the same files. This behavior can be turned off by setting this option to false. For example if you do not want to write marker files to the file systems by the Camel application. | true | boolean
 | *readLockMinAge* (lock) | This option is applied only for readLock=changed. It allows to specify a minimum age the file must be before attempting to acquire the read lock. For example use readLockMinAge=300s to require the file is at last 5 minutes old. This can speedup the changed read lock as it will only attempt to acquire files which are at least that given age. | 0 | long
diff --git a/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/FtpEndpoint.java b/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/FtpEndpoint.java
index 87fbdd3..649688a 100644
--- a/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/FtpEndpoint.java
+++ b/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/FtpEndpoint.java
@@ -44,7 +44,7 @@ import org.apache.commons.net.ftp.FTPFile;
 @UriEndpoint(firstVersion = "1.1.0", scheme = "ftp", extendsScheme = "file", title = "FTP",
         syntax = "ftp:host:port/directoryName", alternativeSyntax = "ftp:username:password@host:port/directoryName",
         label = "file",
-        excludeProperties = "readLockIdempotentReleaseAsync,readLockIdempotentReleaseAsyncPoolSize,readLockIdempotentReleaseDelay,readLockIdempotentReleaseExecutorService")
+        excludeProperties = "appendChars,readLockIdempotentReleaseAsync,readLockIdempotentReleaseAsyncPoolSize,readLockIdempotentReleaseDelay,readLockIdempotentReleaseExecutorService")
 @ManagedResource(description = "Managed FtpEndpoint")
 public class FtpEndpoint<T extends FTPFile> extends RemoteFileEndpoint<FTPFile> {
     protected int soTimeout;
diff --git a/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/FtpsEndpoint.java b/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/FtpsEndpoint.java
index 7862cd6..a89ae92 100644
--- a/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/FtpsEndpoint.java
+++ b/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/FtpsEndpoint.java
@@ -42,7 +42,8 @@ import org.apache.commons.net.ftp.FTPSClient;
  */
 @UriEndpoint(firstVersion = "2.2.0", scheme = "ftps", extendsScheme = "file", title = "FTPS",
         syntax = "ftps:host:port/directoryName", alternativeSyntax = "ftps:username:password@host:port/directoryName",
-        label = "file")
+        label = "file",
+        excludeProperties = "appendChars,readLockIdempotentReleaseAsync,readLockIdempotentReleaseAsyncPoolSize,readLockIdempotentReleaseDelay,readLockIdempotentReleaseExecutorService")
 @ManagedResource(description = "Managed FtpsEndpoint")
 public class FtpsEndpoint extends FtpEndpoint<FTPFile> {
     @UriParam
diff --git a/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/SftpEndpoint.java b/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/SftpEndpoint.java
index 31b0c9e9..4f20cfc 100644
--- a/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/SftpEndpoint.java
+++ b/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/SftpEndpoint.java
@@ -29,7 +29,7 @@ import org.apache.camel.spi.UriParam;
  */
 @UriEndpoint(firstVersion = "1.1.0", scheme = "sftp", extendsScheme = "file", title = "SFTP",
         syntax = "sftp:host:port/directoryName", label = "file",
-        excludeProperties = "binary,passiveMode,receiveBufferSize,siteCommand")
+        excludeProperties = "appendChars,binary,passiveMode,receiveBufferSize,siteCommand")
 public class SftpEndpoint extends RemoteFileEndpoint<SftpRemoteFile> {
 
     @UriParam
diff --git a/components/camel-jsch/src/main/java/org/apache/camel/component/scp/ScpEndpoint.java b/components/camel-jsch/src/main/java/org/apache/camel/component/scp/ScpEndpoint.java
index e1b9954..d136059 100644
--- a/components/camel-jsch/src/main/java/org/apache/camel/component/scp/ScpEndpoint.java
+++ b/components/camel-jsch/src/main/java/org/apache/camel/component/scp/ScpEndpoint.java
@@ -30,7 +30,7 @@ import org.apache.camel.spi.UriParam;
  */
 @UriEndpoint(firstVersion = "2.10.0", scheme = "scp", extendsScheme = "ftp", title = "SCP",
         syntax = "scp:host:port/directoryName", producerOnly = true, label = "file",
-        excludeProperties = "binary,charset,doneFileName,download,fastExistsCheck,fileExist,moveExisting,passiveMode"
+        excludeProperties = "appendChars,binary,charset,doneFileName,download,fastExistsCheck,fileExist,moveExisting,passiveMode"
                 + ",separator,tempFileName,tempPrefix,eagerDeleteTargetFile,keepLastModified,sendNoop"
                 + ",maximumReconnectAttempts,reconnectDelay,autoCreate,bufferSize,siteCommand,stepwise,throwExceptionOnConnectFailed")
 public class ScpEndpoint extends RemoteFileEndpoint<ScpFile> {
diff --git a/core/camel-endpointdsl/src/main/java/org/apache/camel/builder/endpoint/dsl/FtpsEndpointBuilderFactory.java b/core/camel-endpointdsl/src/main/java/org/apache/camel/builder/endpoint/dsl/FtpsEndpointBuilderFactory.java
index de80991..c27dbc0 100644
--- a/core/camel-endpointdsl/src/main/java/org/apache/camel/builder/endpoint/dsl/FtpsEndpointBuilderFactory.java
+++ b/core/camel-endpointdsl/src/main/java/org/apache/camel/builder/endpoint/dsl/FtpsEndpointBuilderFactory.java
@@ -1173,138 +1173,6 @@ public interface FtpsEndpointBuilderFactory {
             return this;
         }
         /**
-         * Whether the delayed release task should be synchronous or
-         * asynchronous. See more details at the readLockIdempotentReleaseDelay
-         * option.
-         * 
-         * The option is a: <code>boolean</code> type.
-         * 
-         * Group: lock
-         */
-        default FtpsEndpointConsumerBuilder readLockIdempotentReleaseAsync(
-                boolean readLockIdempotentReleaseAsync) {
-            setProperty("readLockIdempotentReleaseAsync", readLockIdempotentReleaseAsync);
-            return this;
-        }
-        /**
-         * Whether the delayed release task should be synchronous or
-         * asynchronous. See more details at the readLockIdempotentReleaseDelay
-         * option.
-         * 
-         * The option will be converted to a <code>boolean</code> type.
-         * 
-         * Group: lock
-         */
-        default FtpsEndpointConsumerBuilder readLockIdempotentReleaseAsync(
-                String readLockIdempotentReleaseAsync) {
-            setProperty("readLockIdempotentReleaseAsync", readLockIdempotentReleaseAsync);
-            return this;
-        }
-        /**
-         * The number of threads in the scheduled thread pool when using
-         * asynchronous release tasks. Using a default of 1 core threads should
-         * be sufficient in almost all use-cases, only set this to a higher
-         * value if either updating the idempotent repository is slow, or there
-         * are a lot of files to process. This option is not in-use if you use a
-         * shared thread pool by configuring the
-         * readLockIdempotentReleaseExecutorService option. See more details at
-         * the readLockIdempotentReleaseDelay option.
-         * 
-         * The option is a: <code>int</code> type.
-         * 
-         * Group: lock
-         */
-        default FtpsEndpointConsumerBuilder readLockIdempotentReleaseAsyncPoolSize(
-                int readLockIdempotentReleaseAsyncPoolSize) {
-            setProperty("readLockIdempotentReleaseAsyncPoolSize", readLockIdempotentReleaseAsyncPoolSize);
-            return this;
-        }
-        /**
-         * The number of threads in the scheduled thread pool when using
-         * asynchronous release tasks. Using a default of 1 core threads should
-         * be sufficient in almost all use-cases, only set this to a higher
-         * value if either updating the idempotent repository is slow, or there
-         * are a lot of files to process. This option is not in-use if you use a
-         * shared thread pool by configuring the
-         * readLockIdempotentReleaseExecutorService option. See more details at
-         * the readLockIdempotentReleaseDelay option.
-         * 
-         * The option will be converted to a <code>int</code> type.
-         * 
-         * Group: lock
-         */
-        default FtpsEndpointConsumerBuilder readLockIdempotentReleaseAsyncPoolSize(
-                String readLockIdempotentReleaseAsyncPoolSize) {
-            setProperty("readLockIdempotentReleaseAsyncPoolSize", readLockIdempotentReleaseAsyncPoolSize);
-            return this;
-        }
-        /**
-         * Whether to delay the release task for a period of millis. This can be
-         * used to delay the release tasks to expand the window when a file is
-         * regarded as read-locked, in an active/active cluster scenario with a
-         * shared idempotent repository, to ensure other nodes cannot
-         * potentially scan and acquire the same file, due to race-conditions.
-         * By expanding the time-window of the release tasks helps prevents
-         * these situations. Note delaying is only needed if you have configured
-         * readLockRemoveOnCommit to true.
-         * 
-         * The option is a: <code>int</code> type.
-         * 
-         * Group: lock
-         */
-        default FtpsEndpointConsumerBuilder readLockIdempotentReleaseDelay(
-                int readLockIdempotentReleaseDelay) {
-            setProperty("readLockIdempotentReleaseDelay", readLockIdempotentReleaseDelay);
-            return this;
-        }
-        /**
-         * Whether to delay the release task for a period of millis. This can be
-         * used to delay the release tasks to expand the window when a file is
-         * regarded as read-locked, in an active/active cluster scenario with a
-         * shared idempotent repository, to ensure other nodes cannot
-         * potentially scan and acquire the same file, due to race-conditions.
-         * By expanding the time-window of the release tasks helps prevents
-         * these situations. Note delaying is only needed if you have configured
-         * readLockRemoveOnCommit to true.
-         * 
-         * The option will be converted to a <code>int</code> type.
-         * 
-         * Group: lock
-         */
-        default FtpsEndpointConsumerBuilder readLockIdempotentReleaseDelay(
-                String readLockIdempotentReleaseDelay) {
-            setProperty("readLockIdempotentReleaseDelay", readLockIdempotentReleaseDelay);
-            return this;
-        }
-        /**
-         * To use a custom and shared thread pool for asynchronous release
-         * tasks. See more details at the readLockIdempotentReleaseDelay option.
-         * 
-         * The option is a:
-         * <code>java.util.concurrent.ScheduledExecutorService</code> type.
-         * 
-         * Group: lock
-         */
-        default FtpsEndpointConsumerBuilder readLockIdempotentReleaseExecutorService(
-                ScheduledExecutorService readLockIdempotentReleaseExecutorService) {
-            setProperty("readLockIdempotentReleaseExecutorService", readLockIdempotentReleaseExecutorService);
-            return this;
-        }
-        /**
-         * To use a custom and shared thread pool for asynchronous release
-         * tasks. See more details at the readLockIdempotentReleaseDelay option.
-         * 
-         * The option will be converted to a
-         * <code>java.util.concurrent.ScheduledExecutorService</code> type.
-         * 
-         * Group: lock
-         */
-        default FtpsEndpointConsumerBuilder readLockIdempotentReleaseExecutorService(
-                String readLockIdempotentReleaseExecutorService) {
-            setProperty("readLockIdempotentReleaseExecutorService", readLockIdempotentReleaseExecutorService);
-            return this;
-        }
-        /**
          * Logging level used when a read lock could not be acquired. By default
          * a DEBUG is logged. You can change this level, for example to OFF to
          * not have any logging. This option is only applicable for readLock of


[camel] 01/02: CAMEL-9971: Added appendChars option to file component.

Posted by da...@apache.org.
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 <cl...@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