[
https://issues.apache.org/jira/browse/CAMEL-5558?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=16635068#comment-16635068
]
ASF GitHub Bot commented on CAMEL-5558:
---------------------------------------
oscerd closed pull request #2541: CAMEL-5558 - add file existing move strategy
interface to let custom
URL: https://github.com/apache/camel/pull/2541
This is a PR merged from a forked repository.
As GitHub hides the original diff on merge, it is displayed below for
the sake of provenance:
As this is a foreign pull request (from a fork), the diff is supplied
below (as it won't show otherwise due to GitHub magic):
diff --git a/camel-core/src/main/docs/file-component.adoc
b/camel-core/src/main/docs/file-component.adoc
index 19eea919656..4efaac5f47d 100644
--- a/camel-core/src/main/docs/file-component.adoc
+++ b/camel-core/src/main/docs/file-component.adoc
@@ -72,7 +72,7 @@ with the following path and query parameters:
|===
-==== Query Parameters (85 parameters):
+==== Query Parameters (86 parameters):
[width="100%",cols="2,5,^1,2",options="header"]
@@ -111,6 +111,7 @@ with the following path and query parameters:
| *eagerDeleteTargetFile* (producer) | Whether or not to eagerly delete any
existing target file. This option only applies when you use fileExists=Override
and the tempFileName option as well. You can use this to disable (set it to
false) deleting the target file before the temp file is written. For example
you may write big files and want the target file to exists during the temp file
is being written. This ensure the target file is only deleted until the very
last moment, just before the temp file is being renamed to the target filename.
This option is also used to control whether to delete any existing files when
fileExist=Move is enabled, and an existing file exists. If this option
copyAndDeleteOnRenameFails false, then an exception will be thrown if an
existing file existed, if its true, then the existing file is deleted before
the move operation. | true | boolean
| *forceWrites* (producer) | Whether to force syncing writes to the file
system. You can turn this off if you do not want this level of guarantee, for
example if writing to logs / audit logs etc; this would yield better
performance. | true | boolean
| *keepLastModified* (producer) | Will keep the last modified timestamp from
the source file (if any). Will use the Exchange.FILE_LAST_MODIFIED header to
located the timestamp. This header can contain either a java.util.Date or long
with the timestamp. If the timestamp exists and the option is enabled it will
set this timestamp on the written file. Note: This option only applies to the
file producer. You cannot use this option with any of the ftp producers. |
false | boolean
+| *moveExistingFileStrategy* (producer) | Strategy (Custom Strategy) used to
move file with special naming token to use when fileExist=Move is configured.
By default, there is an implementation used if no custom strategy is provided |
| FileMoveExisting Strategy
| *autoCreate* (advanced) | Automatically create missing directories in the
file's pathname. For the file consumer, that means creating the starting
directory. For the file producer, it means the directory the files should be
written to. | true | boolean
| *bufferSize* (advanced) | Write buffer sized in bytes. | 131072 | int
| *copyAndDeleteOnRenameFail* (advanced) | Whether to fallback and do a copy
and delete file, in case the file could not be renamed directly. This option is
not available for the FTP component. | true | boolean
diff --git
a/camel-core/src/main/java/org/apache/camel/component/file/FileEndpoint.java
b/camel-core/src/main/java/org/apache/camel/component/file/FileEndpoint.java
index 2481b88c905..b866cba8ad3 100644
--- a/camel-core/src/main/java/org/apache/camel/component/file/FileEndpoint.java
+++ b/camel-core/src/main/java/org/apache/camel/component/file/FileEndpoint.java
@@ -29,6 +29,7 @@
import org.apache.camel.Message;
import org.apache.camel.PollingConsumer;
import org.apache.camel.Processor;
+import org.apache.camel.component.file.strategy.FileMoveExistingStrategy;
import org.apache.camel.processor.idempotent.MemoryIdempotentRepository;
import org.apache.camel.spi.Metadata;
import org.apache.camel.spi.UriEndpoint;
@@ -158,7 +159,9 @@ public PollingConsumer createPollingConsumer() throws
Exception {
} else if (getMoveExisting() != null && getFileExist() !=
GenericFileExist.Move) {
throw new IllegalArgumentException("You must configure
fileExist=Move when moveExisting has been set");
}
-
+ if (this.getMoveExistingFileStrategy() == null) {
+
this.setMoveExistingFileStrategy(createDefaultMoveExistingFileStrategy());
+ }
return new GenericFileProducer<>(this, operations);
}
@@ -181,6 +184,14 @@ protected FileConsumer newFileConsumer(Processor
processor, GenericFileOperation
return new FileConsumer(this, processor, operations, processStrategy
!= null ? processStrategy : createGenericFileStrategy());
}
+ /**
+ * Default Existing File Move Strategy
+ * @return the default implementation for file component
+ */
+ private FileMoveExistingStrategy createDefaultMoveExistingFileStrategy() {
+ return new GenericFileDefaultMoveExistingFileStrategy();
+ }
+
public File getFile() {
return file;
}
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 7a89227042f..9224b872ae6 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
@@ -227,7 +227,7 @@ public boolean storeFile(String fileName, Exchange
exchange, long size) throws G
throw new GenericFileOperationFailedException("File already
exist: " + file + ". Cannot write new file.");
} else if (endpoint.getFileExist() == GenericFileExist.Move) {
// move any existing file first
- doMoveExistingFile(fileName);
+
this.endpoint.getMoveExistingFileStrategy().moveExistingFile(endpoint, this,
fileName);
}
}
@@ -354,57 +354,7 @@ public boolean storeFile(String fileName, Exchange
exchange, long size) throws G
throw new GenericFileOperationFailedException("Cannot store file:
" + file, e);
}
}
-
- /**
- * Moves any existing file due fileExists=Move is in use.
- */
- private void doMoveExistingFile(String fileName) throws
GenericFileOperationFailedException {
- // need to evaluate using a dummy and simulate the file first, to have
access to all the file attributes
- // create a dummy exchange as Exchange is needed for expression
evaluation
- // we support only the following 3 tokens.
- Exchange dummy = endpoint.createExchange();
- String parent = FileUtil.onlyPath(fileName);
- String onlyName = FileUtil.stripPath(fileName);
- dummy.getIn().setHeader(Exchange.FILE_NAME, fileName);
- dummy.getIn().setHeader(Exchange.FILE_NAME_ONLY, onlyName);
- dummy.getIn().setHeader(Exchange.FILE_PARENT, parent);
-
- String to = endpoint.getMoveExisting().evaluate(dummy, String.class);
- // we must normalize it (to avoid having both \ and / in the name
which confuses java.io.File)
- to = FileUtil.normalizePath(to);
- if (ObjectHelper.isEmpty(to)) {
- throw new GenericFileOperationFailedException("moveExisting
evaluated as empty String, cannot move existing file: " + fileName);
- }
-
- // ensure any paths is created before we rename as the renamed file
may be in a different path (which may be non exiting)
- // use java.io.File to compute the file path
- File toFile = new File(to);
- String directory = toFile.getParent();
- boolean absolute = FileUtil.isAbsolute(toFile);
- if (directory != null) {
- if (!buildDirectory(directory, absolute)) {
- LOG.debug("Cannot build directory [{}] (could be because of
denied permissions)", directory);
- }
- }
-
- // deal if there already exists a file
- if (existsFile(to)) {
- if (endpoint.isEagerDeleteTargetFile()) {
- LOG.trace("Deleting existing file: {}", to);
- if (!deleteFile(to)) {
- throw new GenericFileOperationFailedException("Cannot
delete file: " + to);
- }
- } else {
- throw new GenericFileOperationFailedException("Cannot move
existing file from: " + fileName + " to: " + to + " as there already exists a
file: " + to);
- }
- }
-
- LOG.trace("Moving existing file: {} to: {}", fileName, to);
- if (!renameFile(fileName, to)) {
- throw new GenericFileOperationFailedException("Cannot rename file
from: " + fileName + " to: " + to);
- }
- }
-
+
private void keepLastModified(Exchange exchange, File file) {
if (endpoint.isKeepLastModified()) {
Long last;
diff --git
a/camel-core/src/main/java/org/apache/camel/component/file/GenericFileDefaultMoveExistingFileStrategy.java
b/camel-core/src/main/java/org/apache/camel/component/file/GenericFileDefaultMoveExistingFileStrategy.java
new file mode 100644
index 00000000000..a8ddac8d92c
--- /dev/null
+++
b/camel-core/src/main/java/org/apache/camel/component/file/GenericFileDefaultMoveExistingFileStrategy.java
@@ -0,0 +1,87 @@
+/**
+ * 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 org.apache.camel.Exchange;
+import org.apache.camel.component.file.strategy.FileMoveExistingStrategy;
+import org.apache.camel.util.FileUtil;
+import org.apache.camel.util.ObjectHelper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class GenericFileDefaultMoveExistingFileStrategy implements
FileMoveExistingStrategy {
+
+ private static final Logger LOG =
LoggerFactory.getLogger(GenericFileDefaultMoveExistingFileStrategy.class);
+
+ /**
+ * Moves any existing file due fileExists=Move is in use.
+ */
+ @Override
+ public boolean moveExistingFile(GenericFileEndpoint endpoint,
GenericFileOperations operations, String fileName)
+ throws GenericFileOperationFailedException {
+
+ // need to evaluate using a dummy and simulate the file first, to have
access to all the file attributes
+ // create a dummy exchange as Exchange is needed for expression
evaluation
+ // we support only the following 3 tokens.
+ Exchange dummy = endpoint.createExchange();
+ String parent = FileUtil.onlyPath(fileName);
+ String onlyName = FileUtil.stripPath(fileName);
+ dummy.getIn().setHeader(Exchange.FILE_NAME, fileName);
+ dummy.getIn().setHeader(Exchange.FILE_NAME_ONLY, onlyName);
+ dummy.getIn().setHeader(Exchange.FILE_PARENT, parent);
+
+ String to = endpoint.getMoveExisting().evaluate(dummy, String.class);
+ // we must normalize it (to avoid having both \ and / in the name
which confuses java.io.File)
+ to = FileUtil.normalizePath(to);
+ if (ObjectHelper.isEmpty(to)) {
+ throw new GenericFileOperationFailedException("moveExisting
evaluated as empty String, cannot move existing file: " + fileName);
+ }
+
+ // ensure any paths is created before we rename as the renamed file
may be in a different path (which may be non exiting)
+ // use java.io.File to compute the file path
+ File toFile = new File(to);
+ String directory = toFile.getParent();
+ boolean absolute = FileUtil.isAbsolute(toFile);
+ if (directory != null) {
+ if (!operations.buildDirectory(directory, absolute)) {
+ LOG.debug("Cannot build directory [{}] (could be because of
denied permissions)", directory);
+ }
+ }
+
+ // deal if there already exists a file
+ if (operations.existsFile(to)) {
+ if (endpoint.isEagerDeleteTargetFile()) {
+ LOG.trace("Deleting existing file: {}", to);
+ if (!operations.deleteFile(to)) {
+ throw new GenericFileOperationFailedException("Cannot
delete file: " + to);
+ }
+ } else {
+ throw new GenericFileOperationFailedException("Cannot move
existing file from: " + fileName + " to: " + to + " as there already exists a
file: " + to);
+ }
+ }
+
+ LOG.trace("Moving existing file: {} to: {}", fileName, to);
+ if (!operations.renameFile(fileName, to)) {
+ throw new GenericFileOperationFailedException("Cannot rename file
from: " + fileName + " to: " + to);
+ }
+
+ return true;
+ }
+
+}
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 954859303ff..fac9e7e8fbe 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
@@ -36,6 +36,7 @@
import org.apache.camel.Message;
import org.apache.camel.Predicate;
import org.apache.camel.Processor;
+import org.apache.camel.component.file.strategy.FileMoveExistingStrategy;
import org.apache.camel.impl.ScheduledPollEndpoint;
import org.apache.camel.processor.idempotent.MemoryIdempotentRepository;
import org.apache.camel.spi.BrowsableEndpoint;
@@ -135,6 +136,8 @@
protected Expression preMove;
@UriParam(label = "producer", javaType = "java.lang.String")
protected Expression moveExisting;
+ @UriParam(label = "producer,advanced")
+ protected FileMoveExistingStrategy moveExistingFileStrategy;
@UriParam(label = "consumer,filter", defaultValue = "false")
protected Boolean idempotent;
@UriParam(label = "consumer,filter", javaType = "java.lang.String")
@@ -570,6 +573,18 @@ public Expression getMoveExisting() {
public void setMoveExisting(Expression moveExisting) {
this.moveExisting = moveExisting;
}
+
+ public FileMoveExistingStrategy getMoveExistingFileStrategy() {
+ return moveExistingFileStrategy;
+ }
+
+ /**
+ * Strategy (Custom Strategy) used to move file with special naming token
to use when fileExist=Move is configured.
+ * By default, there is an implementation used if no custom strategy is
provided
+ */
+ public void setMoveExistingFileStrategy(FileMoveExistingStrategy
moveExistingFileStrategy) {
+ this.moveExistingFileStrategy = moveExistingFileStrategy;
+ }
public void setMoveExisting(String fileLanguageExpression) {
String expression =
configureMoveOrPreMoveExpression(fileLanguageExpression);
diff --git
a/camel-core/src/main/java/org/apache/camel/component/file/strategy/FileMoveExistingStrategy.java
b/camel-core/src/main/java/org/apache/camel/component/file/strategy/FileMoveExistingStrategy.java
new file mode 100644
index 00000000000..48123e4cd3f
--- /dev/null
+++
b/camel-core/src/main/java/org/apache/camel/component/file/strategy/FileMoveExistingStrategy.java
@@ -0,0 +1,43 @@
+/**
+ * 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.strategy;
+
+import org.apache.camel.component.file.GenericFileEndpoint;
+import org.apache.camel.component.file.GenericFileOperationFailedException;
+import org.apache.camel.component.file.GenericFileOperations;
+
+/**
+ * This is the interface to be implemented when a custom implementation needs
to be
+ * provided in case of fileExists=Move is in use while moving any existing
file in producer
+ * endpoints.
+ */
+public interface FileMoveExistingStrategy {
+
+ /**
+ * Moves any existing file due fileExists=Move is in use.
+ *
+ * @param endpoint the given endpoint of the component
+ * @param operations file operations API of the relevant component's API
+ * @return result of the file opeartion can be returned
+ * note that for now, implemetion classes for file component
+ * and ftp components, always returned true. However,if such
+ * a need of direct usage of File API returning true|false,
+ * you can use that return value for implementation's return value.
+ */
+ boolean moveExistingFile(GenericFileEndpoint endpoint,
GenericFileOperations operations, String fileName) throws
GenericFileOperationFailedException;
+
+}
diff --git
a/camel-core/src/test/java/org/apache/camel/component/file/FileProducerMoveExistingStrategyTest.java
b/camel-core/src/test/java/org/apache/camel/component/file/FileProducerMoveExistingStrategyTest.java
new file mode 100644
index 00000000000..f8b2a6f8205
--- /dev/null
+++
b/camel-core/src/test/java/org/apache/camel/component/file/FileProducerMoveExistingStrategyTest.java
@@ -0,0 +1,137 @@
+/**
+ * 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 org.apache.camel.ContextTestSupport;
+import org.apache.camel.Exchange;
+import org.apache.camel.component.file.strategy.FileMoveExistingStrategy;
+import org.apache.camel.impl.JndiRegistry;
+import org.apache.camel.util.FileUtil;
+import org.apache.camel.util.ObjectHelper;
+import org.junit.Before;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ *
+ */
+public class FileProducerMoveExistingStrategyTest extends ContextTestSupport {
+
+ private MyStrategy myStrategy = new MyStrategy();
+
+ @Override
+ @Before
+ public void setUp() throws Exception {
+ deleteDirectory("target/file");
+ super.setUp();
+ }
+
+ @Override
+ protected JndiRegistry createRegistry() throws Exception {
+ JndiRegistry jndi = super.createRegistry();
+ jndi.bind("myStrategy", myStrategy);
+ return jndi;
+ }
+
+ @Test
+ public void testExistingFileExists() throws Exception {
+
template.sendBodyAndHeader("file://target/file?fileExist=Move&moveExisting=${file:parent}/renamed-${file:onlyname}&moveExistingFileStrategy=#myStrategy",
+ "Hello World", Exchange.FILE_NAME, "hello.txt");
+
template.sendBodyAndHeader("file://target/file?fileExist=Move&moveExisting=${file:parent}/renamed-${file:onlyname}&moveExistingFileStrategy=#myStrategy",
+ "Bye Existing World 1", Exchange.FILE_NAME, "hello.txt");
+
template.sendBodyAndHeader("file://target/file?fileExist=Move&moveExisting=${file:parent}/renamed-${file:onlyname}&moveExistingFileStrategy=#myStrategy",
+ "Bye Existing World 2", Exchange.FILE_NAME, "hello.txt");
+
+ assertFileExists("target/file/hello.txt");
+ assertEquals("Bye Existing World 2",
context.getTypeConverter().convertTo(String.class, new
File("target/file/hello.txt")));
+
+ assertFileExists("target/file/renamed-hello2.txt");
+ assertEquals("Bye Existing World 1",
context.getTypeConverter().convertTo(String.class, new
File("target/file/renamed-hello2.txt")));
+
+ assertFileExists("target/file/renamed-hello1.txt");
+ assertEquals("Hello World",
context.getTypeConverter().convertTo(String.class, new
File("target/file/renamed-hello1.txt")));
+ }
+
+ private static class MyStrategy implements FileMoveExistingStrategy {
+
+ private static final Logger LOG =
LoggerFactory.getLogger(FileMoveExistingStrategy.class);
+ private int counter;
+
+ @Override
+ public boolean moveExistingFile(GenericFileEndpoint endpoint,
GenericFileOperations operations, String fileName)
+ throws GenericFileOperationFailedException {
+
+ // need to evaluate using a dummy and simulate the file first, to
have access to all the file attributes
+ // create a dummy exchange as Exchange is needed for expression
evaluation
+ // we support only the following 3 tokens.
+ Exchange dummy = endpoint.createExchange();
+ String parent = FileUtil.onlyPath(fileName);
+ String onlyName = FileUtil.stripPath(fileName);
+
+ dummy.getIn().setHeader(Exchange.FILE_NAME, fileName);
+ dummy.getIn().setHeader(Exchange.FILE_NAME_ONLY, onlyName);
+ dummy.getIn().setHeader(Exchange.FILE_PARENT, parent);
+
+ String to = endpoint.getMoveExisting().evaluate(dummy,
String.class);
+ counter++;
+ String fileNameWithoutExtension = to.substring(0,
to.lastIndexOf('.')) + "" + counter;
+ to = fileNameWithoutExtension + to.substring(to.lastIndexOf('.'),
to.length());
+ // we must normalize it (to avoid having both \ and / in the name
which confuses java.io.File)
+ to = FileUtil.normalizePath(to);
+ if (ObjectHelper.isEmpty(to)) {
+ throw new GenericFileOperationFailedException("moveExisting
evaluated as empty String, cannot move existing file: " + fileName);
+ }
+
+ // ensure any paths is created before we rename as the renamed
file may be in a different path (which may be non exiting)
+ // use java.io.File to compute the file path
+ File toFile = new File(to);
+ String directory = toFile.getParent();
+ boolean absolute = FileUtil.isAbsolute(toFile);
+ if (directory != null) {
+ if (!operations.buildDirectory(directory, absolute)) {
+ LOG.debug("Cannot build directory [{}] (could be because
of denied permissions)", directory);
+ }
+ }
+
+ // deal if there already exists a file
+ if (operations.existsFile(to)) {
+ if (endpoint.isEagerDeleteTargetFile()) {
+ LOG.trace("Deleting existing file: {}", to);
+ if (!operations.deleteFile(to)) {
+ throw new GenericFileOperationFailedException("Cannot
delete file: " + to);
+ }
+ } else {
+ throw new GenericFileOperationFailedException("Cannot
moved existing file from: " + fileName + " to: " + to + " as there already
exists a file: " + to);
+ }
+ }
+
+ LOG.trace("Moving existing file: {} to: {}", fileName, to);
+ if (!operations.renameFile(fileName, to)) {
+ throw new GenericFileOperationFailedException("Cannot rename
file from: " + fileName + " to: " + to);
+ }
+ return true;
+ }
+
+ }
+
+ @Override
+ public boolean isUseRouteBuilder() {
+ return false;
+ }
+}
diff --git a/components/camel-ftp/src/main/docs/ftp-component.adoc
b/components/camel-ftp/src/main/docs/ftp-component.adoc
index a4046c0d07d..590eb5b6803 100644
--- a/components/camel-ftp/src/main/docs/ftp-component.adoc
+++ b/components/camel-ftp/src/main/docs/ftp-component.adoc
@@ -100,7 +100,7 @@ with the following path and query parameters:
|===
-==== Query Parameters (108 parameters):
+==== Query Parameters (109 parameters):
[width="100%",cols="2,5,^1,2",options="header"]
@@ -151,6 +151,7 @@ with the following path and query parameters:
| *disconnectOnBatchComplete* (producer) | Whether or not to disconnect from
remote FTP server right after a Batch upload is complete.
disconnectOnBatchComplete will only disconnect the current connection to the
FTP server. | false | boolean
| *eagerDeleteTargetFile* (producer) | Whether or not to eagerly delete any
existing target file. This option only applies when you use fileExists=Override
and the tempFileName option as well. You can use this to disable (set it to
false) deleting the target file before the temp file is written. For example
you may write big files and want the target file to exists during the temp file
is being written. This ensure the target file is only deleted until the very
last moment, just before the temp file is being renamed to the target filename.
This option is also used to control whether to delete any existing files when
fileExist=Move is enabled, and an existing file exists. If this option
copyAndDeleteOnRenameFails false, then an exception will be thrown if an
existing file existed, if its true, then the existing file is deleted before
the move operation. | true | boolean
| *keepLastModified* (producer) | Will keep the last modified timestamp from
the source file (if any). Will use the Exchange.FILE_LAST_MODIFIED header to
located the timestamp. This header can contain either a java.util.Date or long
with the timestamp. If the timestamp exists and the option is enabled it will
set this timestamp on the written file. Note: This option only applies to the
file producer. You cannot use this option with any of the ftp producers. |
false | boolean
+| *moveExistingFileStrategy* (producer) | Strategy (Custom Strategy) used to
move file with special naming token to use when fileExist=Move is configured.
By default, there is an implementation used if no custom strategy is provided |
| FileMoveExisting Strategy
| *sendNoop* (producer) | Whether to send a noop command as a pre-write check
before uploading files to the FTP server. This is enabled by default as a
validation of the connection is still valid, which allows to silently
re-connect to be able to upload the file. However if this causes problems, you
can turn this option off. | true | boolean
| *activePortRange* (advanced) | Set the client side port range in active
mode. The syntax is: minPort-maxPort Both port numbers are inclusive, eg
10000-19999 to include all 1xxxx ports. | | String
| *autoCreate* (advanced) | Automatically create missing directories in the
file's pathname. For the file consumer, that means creating the starting
directory. For the file producer, it means the directory the files should be
written to. | true | boolean
diff --git a/components/camel-ftp/src/main/docs/ftps-component.adoc
b/components/camel-ftp/src/main/docs/ftps-component.adoc
index 3ccaf392519..797a1c8bc3d 100644
--- a/components/camel-ftp/src/main/docs/ftps-component.adoc
+++ b/components/camel-ftp/src/main/docs/ftps-component.adoc
@@ -60,7 +60,7 @@ with the following path and query parameters:
|===
-==== Query Parameters (120 parameters):
+==== Query Parameters (121 parameters):
[width="100%",cols="2,5,^1,2",options="header"]
@@ -111,6 +111,7 @@ with the following path and query parameters:
| *disconnectOnBatchComplete* (producer) | Whether or not to disconnect from
remote FTP server right after a Batch upload is complete.
disconnectOnBatchComplete will only disconnect the current connection to the
FTP server. | false | boolean
| *eagerDeleteTargetFile* (producer) | Whether or not to eagerly delete any
existing target file. This option only applies when you use fileExists=Override
and the tempFileName option as well. You can use this to disable (set it to
false) deleting the target file before the temp file is written. For example
you may write big files and want the target file to exists during the temp file
is being written. This ensure the target file is only deleted until the very
last moment, just before the temp file is being renamed to the target filename.
This option is also used to control whether to delete any existing files when
fileExist=Move is enabled, and an existing file exists. If this option
copyAndDeleteOnRenameFails false, then an exception will be thrown if an
existing file existed, if its true, then the existing file is deleted before
the move operation. | true | boolean
| *keepLastModified* (producer) | Will keep the last modified timestamp from
the source file (if any). Will use the Exchange.FILE_LAST_MODIFIED header to
located the timestamp. This header can contain either a java.util.Date or long
with the timestamp. If the timestamp exists and the option is enabled it will
set this timestamp on the written file. Note: This option only applies to the
file producer. You cannot use this option with any of the ftp producers. |
false | boolean
+| *moveExistingFileStrategy* (producer) | Strategy (Custom Strategy) used to
move file with special naming token to use when fileExist=Move is configured.
By default, there is an implementation used if no custom strategy is provided |
| FileMoveExisting Strategy
| *sendNoop* (producer) | Whether to send a noop command as a pre-write check
before uploading files to the FTP server. This is enabled by default as a
validation of the connection is still valid, which allows to silently
re-connect to be able to upload the file. However if this causes problems, you
can turn this option off. | true | boolean
| *activePortRange* (advanced) | Set the client side port range in active
mode. The syntax is: minPort-maxPort Both port numbers are inclusive, eg
10000-19999 to include all 1xxxx ports. | | String
| *autoCreate* (advanced) | Automatically create missing directories in the
file's pathname. For the file consumer, that means creating the starting
directory. For the file producer, it means the directory the files should be
written to. | true | boolean
diff --git a/components/camel-ftp/src/main/docs/sftp-component.adoc
b/components/camel-ftp/src/main/docs/sftp-component.adoc
index b3c8d344ba5..2fc626ae211 100644
--- a/components/camel-ftp/src/main/docs/sftp-component.adoc
+++ b/components/camel-ftp/src/main/docs/sftp-component.adoc
@@ -51,7 +51,7 @@ with the following path and query parameters:
|===
-==== Query Parameters (116 parameters):
+==== Query Parameters (117 parameters):
[width="100%",cols="2,5,^1,2",options="header"]
@@ -95,6 +95,7 @@ with the following path and query parameters:
| *disconnectOnBatchComplete* (producer) | Whether or not to disconnect from
remote FTP server right after a Batch upload is complete.
disconnectOnBatchComplete will only disconnect the current connection to the
FTP server. | false | boolean
| *eagerDeleteTargetFile* (producer) | Whether or not to eagerly delete any
existing target file. This option only applies when you use fileExists=Override
and the tempFileName option as well. You can use this to disable (set it to
false) deleting the target file before the temp file is written. For example
you may write big files and want the target file to exists during the temp file
is being written. This ensure the target file is only deleted until the very
last moment, just before the temp file is being renamed to the target filename.
This option is also used to control whether to delete any existing files when
fileExist=Move is enabled, and an existing file exists. If this option
copyAndDeleteOnRenameFails false, then an exception will be thrown if an
existing file existed, if its true, then the existing file is deleted before
the move operation. | true | boolean
| *keepLastModified* (producer) | Will keep the last modified timestamp from
the source file (if any). Will use the Exchange.FILE_LAST_MODIFIED header to
located the timestamp. This header can contain either a java.util.Date or long
with the timestamp. If the timestamp exists and the option is enabled it will
set this timestamp on the written file. Note: This option only applies to the
file producer. You cannot use this option with any of the ftp producers. |
false | boolean
+| *moveExistingFileStrategy* (producer) | Strategy (Custom Strategy) used to
move file with special naming token to use when fileExist=Move is configured.
By default, there is an implementation used if no custom strategy is provided |
| FileMoveExisting Strategy
| *sendNoop* (producer) | Whether to send a noop command as a pre-write check
before uploading files to the FTP server. This is enabled by default as a
validation of the connection is still valid, which allows to silently
re-connect to be able to upload the file. However if this causes problems, you
can turn this option off. | true | boolean
| *autoCreate* (advanced) | Automatically create missing directories in the
file's pathname. For the file consumer, that means creating the starting
directory. For the file producer, it means the directory the files should be
written to. | true | boolean
| *bindAddress* (advanced) | Specifies the address of the local interface
against which the connection should bind. | | String
diff --git
a/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/FtpDefaultMoveExistingFileStrategy.java
b/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/FtpDefaultMoveExistingFileStrategy.java
new file mode 100644
index 00000000000..9d3757a5ed5
--- /dev/null
+++
b/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/FtpDefaultMoveExistingFileStrategy.java
@@ -0,0 +1,96 @@
+/**
+ * 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.remote;
+
+import java.io.IOException;
+
+import org.apache.camel.Exchange;
+import org.apache.camel.component.file.GenericFileEndpoint;
+import org.apache.camel.component.file.GenericFileOperationFailedException;
+import org.apache.camel.component.file.GenericFileOperations;
+import org.apache.camel.component.file.strategy.FileMoveExistingStrategy;
+import org.apache.camel.util.FileUtil;
+import org.apache.camel.util.ObjectHelper;
+import org.apache.commons.net.ftp.FTPFile;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class FtpDefaultMoveExistingFileStrategy implements
FileMoveExistingStrategy {
+
+ private static final Logger LOG =
LoggerFactory.getLogger(FtpDefaultMoveExistingFileStrategy.class);
+
+ /**
+ * Moves any existing file due fileExists=Move is in use.
+ */
+ @Override
+ public boolean moveExistingFile(GenericFileEndpoint endpoint,
GenericFileOperations operations, String fileName)
+ throws GenericFileOperationFailedException {
+ // need to evaluate using a dummy and simulate the file first, to have
access to all the file attributes
+ // create a dummy exchange as Exchange is needed for expression
evaluation
+ // we support only the following 3 tokens.
+ Exchange dummy = endpoint.createExchange();
+ // we only support relative paths for the ftp component, so dont
provide any parent
+ String parent = null;
+ String onlyName = FileUtil.stripPath(fileName);
+ dummy.getIn().setHeader(Exchange.FILE_NAME, fileName);
+ dummy.getIn().setHeader(Exchange.FILE_NAME_ONLY, onlyName);
+ dummy.getIn().setHeader(Exchange.FILE_PARENT, parent);
+
+ String to = endpoint.getMoveExisting().evaluate(dummy, String.class);
+ // we only support relative paths for the ftp component, so strip any
leading paths
+ to = FileUtil.stripLeadingSeparator(to);
+ // normalize accordingly to configuration
+ to =
((FtpEndpoint<FTPFile>)endpoint).getConfiguration().normalizePath(to);
+ if (ObjectHelper.isEmpty(to)) {
+ throw new GenericFileOperationFailedException("moveExisting
evaluated as empty String, cannot move existing file: " + fileName);
+ }
+
+ // do we have a sub directory
+ String dir = FileUtil.onlyPath(to);
+ if (dir != null) {
+ // ensure directory exists
+ operations.buildDirectory(dir, false);
+ }
+
+ // deal if there already exists a file
+ if (operations.existsFile(to)) {
+ if (endpoint.isEagerDeleteTargetFile()) {
+ LOG.trace("Deleting existing file: {}", to);
+ boolean result;
+ try {
+ result =
((FtpOperations)operations).getClient().deleteFile(to);
+ if (!result) {
+ throw new GenericFileOperationFailedException("Cannot
delete file: " + to);
+ }
+ } catch (IOException e) {
+ throw new
GenericFileOperationFailedException(((FtpOperations)operations).getClient().getReplyCode(),
+
((FtpOperations)operations).getClient().getReplyString(),
+ "Cannot
delete file: " + to, e);
+ }
+ } else {
+ throw new GenericFileOperationFailedException("Cannot move
existing file from: " + fileName + " to: " + to + " as there already exists a
file: " + to);
+ }
+ }
+
+ LOG.trace("Moving existing file: {} to: {}", fileName, to);
+ if (!operations.renameFile(fileName, to)) {
+ throw new GenericFileOperationFailedException("Cannot rename file
from: " + fileName + " to: " + to);
+ }
+ return true;
+ }
+
+}
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 8334e69861b..22a72ca61dc 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
@@ -28,6 +28,7 @@
import org.apache.camel.component.file.GenericFileConfiguration;
import org.apache.camel.component.file.GenericFileProducer;
import
org.apache.camel.component.file.remote.RemoteFileConfiguration.PathSeparator;
+import org.apache.camel.component.file.strategy.FileMoveExistingStrategy;
import org.apache.camel.spi.ClassResolver;
import org.apache.camel.spi.UriEndpoint;
import org.apache.camel.spi.UriParam;
@@ -103,12 +104,23 @@ public String getScheme() {
protected GenericFileProducer<FTPFile> buildProducer() {
try {
+ if (this.getMoveExistingFileStrategy() == null) {
+
this.setMoveExistingFileStrategy(createDefaultFtpMoveExistingFileStrategy());
+ }
return new RemoteFileProducer<>(this,
createRemoteFileOperations());
} catch (Exception e) {
throw new FailedToCreateProducerException(this, e);
}
}
+ /**
+ * Default Existing File Move Strategy
+ * @return the default implementation for ftp components
+ */
+ private FileMoveExistingStrategy
createDefaultFtpMoveExistingFileStrategy() {
+ return new FtpDefaultMoveExistingFileStrategy();
+ }
+
public RemoteFileOperations<FTPFile> createRemoteFileOperations() throws
Exception {
// configure ftp client
FTPClient client = ftpClient;
diff --git
a/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/FtpOperations.java
b/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/FtpOperations.java
index 196dfc258fe..25ea4fc8196 100644
---
a/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/FtpOperations.java
+++
b/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/FtpOperations.java
@@ -646,7 +646,7 @@ private boolean doStoreFile(String name, String targetName,
Exchange exchange) t
throw new GenericFileOperationFailedException("File already
exist: " + name + ". Cannot write new file.");
} else if (existFile && endpoint.getFileExist() ==
GenericFileExist.Move) {
// move any existing file first
- doMoveExistingFile(name, targetName);
+
this.endpoint.getMoveExistingFileStrategy().moveExistingFile(endpoint, this,
targetName);
}
}
@@ -715,61 +715,6 @@ private boolean doStoreFile(String name, String
targetName, Exchange exchange) t
}
}
- /**
- * Moves any existing file due fileExists=Move is in use.
- */
- private void doMoveExistingFile(String name, String targetName) throws
GenericFileOperationFailedException {
- // need to evaluate using a dummy and simulate the file first, to have
access to all the file attributes
- // create a dummy exchange as Exchange is needed for expression
evaluation
- // we support only the following 3 tokens.
- Exchange dummy = endpoint.createExchange();
- // we only support relative paths for the ftp component, so dont
provide any parent
- String parent = null;
- String onlyName = FileUtil.stripPath(targetName);
- dummy.getIn().setHeader(Exchange.FILE_NAME, targetName);
- dummy.getIn().setHeader(Exchange.FILE_NAME_ONLY, onlyName);
- dummy.getIn().setHeader(Exchange.FILE_PARENT, parent);
-
- String to = endpoint.getMoveExisting().evaluate(dummy, String.class);
- // we only support relative paths for the ftp component, so strip any
leading paths
- to = FileUtil.stripLeadingSeparator(to);
- // normalize accordingly to configuration
- to = endpoint.getConfiguration().normalizePath(to);
- if (ObjectHelper.isEmpty(to)) {
- throw new GenericFileOperationFailedException("moveExisting
evaluated as empty String, cannot move existing file: " + name);
- }
-
- // do we have a sub directory
- String dir = FileUtil.onlyPath(to);
- if (dir != null) {
- // ensure directory exists
- buildDirectory(dir, false);
- }
-
- // deal if there already exists a file
- if (existsFile(to)) {
- if (endpoint.isEagerDeleteTargetFile()) {
- log.trace("Deleting existing file: {}", to);
- boolean result;
- try {
- result = client.deleteFile(to);
- if (!result) {
- throw new GenericFileOperationFailedException("Cannot
delete file: " + to);
- }
- } catch (IOException e) {
- throw new
GenericFileOperationFailedException(client.getReplyCode(),
client.getReplyString(), "Cannot delete file: " + to, e);
- }
- } else {
- throw new GenericFileOperationFailedException("Cannot move
existing file from: " + name + " to: " + to + " as there already exists a file:
" + to);
- }
- }
-
- log.trace("Moving existing file: {} to: {}", name, to);
- if (!renameFile(targetName, to)) {
- throw new GenericFileOperationFailedException("Cannot rename file
from: " + name + " to: " + to);
- }
- }
-
public boolean existsFile(String name) throws
GenericFileOperationFailedException {
log.trace("existsFile({})", name);
if (endpoint.isFastExistsCheck()) {
@@ -980,5 +925,9 @@ private boolean buildDirectoryChunks(String dirName) throws
IOException {
return success;
}
+
+ public FTPClient getClient() {
+ return client;
+ }
}
diff --git
a/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/SftpDefaultMoveExistingFileStrategy.java
b/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/SftpDefaultMoveExistingFileStrategy.java
new file mode 100644
index 00000000000..48a8fb4cba0
--- /dev/null
+++
b/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/SftpDefaultMoveExistingFileStrategy.java
@@ -0,0 +1,83 @@
+/**
+ * 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.remote;
+
+import org.apache.camel.Exchange;
+import org.apache.camel.component.file.GenericFileEndpoint;
+import org.apache.camel.component.file.GenericFileOperationFailedException;
+import org.apache.camel.component.file.GenericFileOperations;
+import org.apache.camel.component.file.strategy.FileMoveExistingStrategy;
+import org.apache.camel.util.FileUtil;
+import org.apache.camel.util.ObjectHelper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class SftpDefaultMoveExistingFileStrategy implements
FileMoveExistingStrategy {
+
+ private static final Logger LOG =
LoggerFactory.getLogger(SftpDefaultMoveExistingFileStrategy.class);
+ /**
+ * Moves any existing file due fileExists=Move is in use.
+ */
+ @Override
+ public boolean moveExistingFile(GenericFileEndpoint endpoint,
GenericFileOperations operations, String fileName)
+ throws GenericFileOperationFailedException {
+ // need to evaluate using a dummy and simulate the file first, to have
access to all the file attributes
+ // create a dummy exchange as Exchange is needed for expression
evaluation
+ // we support only the following 3 tokens.
+ Exchange dummy = endpoint.createExchange();
+ // we only support relative paths for the ftp component, so dont
provide any parent
+ String parent = null;
+ String onlyName = FileUtil.stripPath(fileName);
+ dummy.getIn().setHeader(Exchange.FILE_NAME, fileName);
+ dummy.getIn().setHeader(Exchange.FILE_NAME_ONLY, onlyName);
+ dummy.getIn().setHeader(Exchange.FILE_PARENT, parent);
+
+ String to = endpoint.getMoveExisting().evaluate(dummy, String.class);
+ // we only support relative paths for the ftp component, so strip any
leading paths
+ to = FileUtil.stripLeadingSeparator(to);
+ // normalize accordingly to configuration
+ to = ((SftpEndpoint)endpoint).getConfiguration().normalizePath(to);
+ if (ObjectHelper.isEmpty(to)) {
+ throw new GenericFileOperationFailedException("moveExisting
evaluated as empty String, cannot move existing file: " + fileName);
+ }
+
+ // do we have a sub directory
+ String dir = FileUtil.onlyPath(to);
+ if (dir != null) {
+ // ensure directory exists
+ operations.buildDirectory(dir, false);
+ }
+
+ // deal if there already exists a file
+ if (operations.existsFile(to)) {
+ if (endpoint.isEagerDeleteTargetFile()) {
+ LOG.trace("Deleting existing file: {}", to);
+ operations.deleteFile(to);
+ } else {
+ throw new GenericFileOperationFailedException("Cannot move
existing file from: " + fileName + " to: " + to + " as there already exists a
file: " + to);
+ }
+ }
+
+ LOG.trace("Moving existing file: {} to: {}", fileName, to);
+ if (!operations.renameFile(fileName, to)) {
+ throw new GenericFileOperationFailedException("Cannot rename file
from: " + fileName + " to: " + to);
+ }
+
+ return true;
+ }
+
+}
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 5f82b3a1bee..069dfa7411d 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
@@ -20,6 +20,7 @@
import org.apache.camel.Processor;
import org.apache.camel.component.file.GenericFileConfiguration;
import org.apache.camel.component.file.GenericFileProducer;
+import org.apache.camel.component.file.strategy.FileMoveExistingStrategy;
import org.apache.camel.spi.UriEndpoint;
import org.apache.camel.spi.UriParam;
@@ -65,9 +66,20 @@ public void setConfiguration(GenericFileConfiguration
configuration) {
}
protected GenericFileProducer<SftpRemoteFile> buildProducer() {
+ if (this.getMoveExistingFileStrategy() == null) {
+
this.setMoveExistingFileStrategy(createDefaultSftpMoveExistingFileStrategy());
+ }
return new RemoteFileProducer<>(this, createRemoteFileOperations());
}
+ /**
+ * Default Existing File Move Strategy
+ * @return the default implementation for sftp component
+ */
+ private FileMoveExistingStrategy
createDefaultSftpMoveExistingFileStrategy() {
+ return new SftpDefaultMoveExistingFileStrategy();
+ }
+
public RemoteFileOperations<SftpRemoteFile> createRemoteFileOperations() {
SftpOperations operations = new SftpOperations(proxy);
operations.setEndpoint(this);
diff --git
a/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/SftpOperations.java
b/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/SftpOperations.java
index 8c3a1e7cc53..1db1c84e210 100644
---
a/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/SftpOperations.java
+++
b/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/SftpOperations.java
@@ -900,7 +900,7 @@ private boolean doStoreFile(String name, String targetName,
Exchange exchange) t
throw new GenericFileOperationFailedException("File already
exist: " + name + ". Cannot write new file.");
} else if (existFile && endpoint.getFileExist() ==
GenericFileExist.Move) {
// move any existing file first
- doMoveExistingFile(name, targetName);
+
this.endpoint.getMoveExistingFileStrategy().moveExistingFile(endpoint, this,
targetName);
}
}
@@ -965,54 +965,7 @@ private boolean doStoreFile(String name, String
targetName, Exchange exchange) t
IOHelper.close(is, "store: " + name, LOG);
}
}
-
- /**
- * Moves any existing file due fileExists=Move is in use.
- */
- private void doMoveExistingFile(String name, String targetName) throws
GenericFileOperationFailedException {
- // need to evaluate using a dummy and simulate the file first, to have
access to all the file attributes
- // create a dummy exchange as Exchange is needed for expression
evaluation
- // we support only the following 3 tokens.
- Exchange dummy = endpoint.createExchange();
- // we only support relative paths for the ftp component, so dont
provide any parent
- String parent = null;
- String onlyName = FileUtil.stripPath(targetName);
- dummy.getIn().setHeader(Exchange.FILE_NAME, targetName);
- dummy.getIn().setHeader(Exchange.FILE_NAME_ONLY, onlyName);
- dummy.getIn().setHeader(Exchange.FILE_PARENT, parent);
-
- String to = endpoint.getMoveExisting().evaluate(dummy, String.class);
- // we only support relative paths for the ftp component, so strip any
leading paths
- to = FileUtil.stripLeadingSeparator(to);
- // normalize accordingly to configuration
- to = endpoint.getConfiguration().normalizePath(to);
- if (ObjectHelper.isEmpty(to)) {
- throw new GenericFileOperationFailedException("moveExisting
evaluated as empty String, cannot move existing file: " + name);
- }
-
- // do we have a sub directory
- String dir = FileUtil.onlyPath(to);
- if (dir != null) {
- // ensure directory exists
- buildDirectory(dir, false);
- }
-
- // deal if there already exists a file
- if (existsFile(to)) {
- if (endpoint.isEagerDeleteTargetFile()) {
- LOG.trace("Deleting existing file: {}", to);
- deleteFile(to);
- } else {
- throw new GenericFileOperationFailedException("Cannot move
existing file from: " + name + " to: " + to + " as there already exists a file:
" + to);
- }
- }
-
- LOG.trace("Moving existing file: {} to: {}", name, to);
- if (!renameFile(targetName, to)) {
- throw new GenericFileOperationFailedException("Cannot rename file
from: " + name + " to: " + to);
- }
- }
-
+
public synchronized boolean existsFile(String name) throws
GenericFileOperationFailedException {
LOG.trace("existsFile({})", name);
if (endpoint.isFastExistsCheck()) {
diff --git a/components/camel-jsch/src/main/docs/scp-component.adoc
b/components/camel-jsch/src/main/docs/scp-component.adoc
index 836162ab3dd..7303285b145 100644
--- a/components/camel-jsch/src/main/docs/scp-component.adoc
+++ b/components/camel-jsch/src/main/docs/scp-component.adoc
@@ -83,7 +83,7 @@ with the following path and query parameters:
|===
-==== Query Parameters (20 parameters):
+==== Query Parameters (21 parameters):
[width="100%",cols="2,5,^1,2",options="header"]
@@ -96,6 +96,7 @@ with the following path and query parameters:
| *strictHostKeyChecking* (producer) | Sets whether to use strict host key
checking. Possible values are: no, yes | no | String
| *allowNullBody* (producer) | Used to specify if a null body is allowed
during file writing. If set to true then an empty file will be created, when
set to false, and attempting to send a null body to the file component, a
GenericFileWriteException of 'Cannot write null body to file.' will be thrown.
If the fileExist option is set to 'Override', then the file will be truncated,
and if set to append the file will remain unchanged. | false | boolean
| *disconnectOnBatchComplete* (producer) | Whether or not to disconnect from
remote FTP server right after a Batch upload is complete.
disconnectOnBatchComplete will only disconnect the current connection to the
FTP server. | false | boolean
+| *moveExistingFileStrategy* (producer) | Strategy (Custom Strategy) used to
move file with special naming token to use when fileExist=Move is configured.
By default, there is an implementation used if no custom strategy is provided |
| FileMoveExisting Strategy
| *connectTimeout* (advanced) | Sets the connect timeout for waiting for a
connection to be established Used by both FTPClient and JSCH | 10000 | int
| *soTimeout* (advanced) | Sets the so timeout Used only by FTPClient | 300000
| int
| *synchronous* (advanced) | Sets whether synchronous processing should be
strictly used, or Camel is allowed to use asynchronous processing (if
supported). | false | boolean
----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on GitHub and use the
URL above to go to the specific comment.
For queries about this service, please contact Infrastructure at:
[email protected]
> Add fileExist option to write file with a new name in case file already exists
> ------------------------------------------------------------------------------
>
> Key: CAMEL-5558
> URL: https://issues.apache.org/jira/browse/CAMEL-5558
> Project: Camel
> Issue Type: New Feature
> Components: camel-core, camel-ftp
> Affects Versions: 2.10.0
> Reporter: Claus Ibsen
> Assignee: Önder Sezgin
> Priority: Major
> Fix For: 2.23.0
>
>
> See nabble
> http://camel.465427.n5.nabble.com/Camel-FTP-component-Append-a-sequence-number-if-the-filename-already-exists-tp5718469.html
> We should allow to configure fileExists=RenameAndRetry option, which allows
> you to rename the file and retry writing the file again, in case there
> already exists a file.
> The trick is to find a optimal solution if you append a sequence number to a
> file. And when there is a lot of files. You kinda want to know what is the
> highest filename, (some way of listing and sorting).
> Maybe a way to get a list of existing files based on a file name pattern, and
> a sort configuration. Then people can check in the list, to find a free
> sequence number to use etc.
--
This message was sent by Atlassian JIRA
(v7.6.3#76005)