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

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


The following commit(s) were added to refs/heads/main by this push:
     new 4f37187  CAMEL-17045: implements resume support for the camel-file 
component
4f37187 is described below

commit 4f371871496d13f9855f24887afbb28e9ef5c2f8
Author: Otavio Rodolfo Piske <[email protected]>
AuthorDate: Thu Oct 7 17:09:49 2021 +0200

    CAMEL-17045: implements resume support for the camel-file component
---
 .../org/apache/camel/catalog/components/file.json  |   1 +
 .../component/file/FileEndpointConfigurer.java     |   6 ++
 .../component/file/FileEndpointUriFactory.java     |   3 +-
 .../org/apache/camel/component/file/file.json      |   1 +
 .../apache/camel/component/file/FileConsumer.java  | 112 +++++++++++++--------
 .../apache/camel/component/file/FileEndpoint.java  |  20 ++++
 .../camel/component/file/GenericFileConsumer.java  |  33 +++---
 .../file/consumer/FileConsumerResumeStrategy.java  |  34 +++++++
 .../component/file/consumer/FileResumeInfo.java    |  43 ++++++++
 .../endpoint/dsl/FileEndpointBuilderFactory.java   |  38 +++++++
 10 files changed, 235 insertions(+), 56 deletions(-)

diff --git 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/file.json
 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/file.json
index 90a50d3..8f254fb 100644
--- 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/file.json
+++ 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/file.json
@@ -49,6 +49,7 @@
     "pollStrategy": { "kind": "parameter", "displayName": "Poll Strategy", 
"group": "consumer (advanced)", "label": "consumer,advanced", "required": 
false, "type": "object", "javaType": 
"org.apache.camel.spi.PollingConsumerPollStrategy", "deprecated": false, 
"autowired": false, "secret": false, "description": "A pluggable 
org.apache.camel.PollingConsumerPollingStrategy allowing you to provide your 
custom implementation to control error handling usually occurred during the 
poll operation  [...]
     "probeContentType": { "kind": "parameter", "displayName": "Probe Content 
Type", "group": "consumer (advanced)", "label": "consumer,advanced", 
"required": false, "type": "boolean", "javaType": "boolean", "deprecated": 
false, "autowired": false, "secret": false, "defaultValue": false, 
"description": "Whether to enable probing of the content type. If enable then 
the consumer uses Files#probeContentType(java.nio.file.Path) to determine the 
content-type of the file, and store that as a he [...]
     "processStrategy": { "kind": "parameter", "displayName": "Process 
Strategy", "group": "consumer (advanced)", "label": "consumer,advanced", 
"required": false, "type": "object", "javaType": 
"org.apache.camel.component.file.GenericFileProcessStrategy<java.io.File>", 
"deprecated": false, "autowired": false, "secret": false, "description": "A 
pluggable org.apache.camel.component.file.GenericFileProcessStrategy allowing 
you to implement your own readLock option or similar. Can also be used [...]
+    "resumeStrategy": { "kind": "parameter", "displayName": "Resume Strategy", 
"group": "consumer (advanced)", "label": "consumer,advanced", "required": 
false, "type": "object", "javaType": 
"org.apache.camel.component.file.consumer.FileConsumerResumeStrategy", 
"deprecated": false, "autowired": false, "secret": false, "description": "Set a 
resume strategy for files. This makes it possible to define a strategy for 
resuming reading files after the last point before stopping the application. 
[...]
     "startingDirectoryMustExist": { "kind": "parameter", "displayName": 
"Starting Directory Must Exist", "group": "consumer (advanced)", "label": 
"consumer,advanced", "required": false, "type": "boolean", "javaType": 
"boolean", "deprecated": false, "autowired": false, "secret": false, 
"defaultValue": false, "description": "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' [...]
     "startingDirectoryMustHaveAccess": { "kind": "parameter", "displayName": 
"Starting Directory Must Have Access", "group": "consumer (advanced)", "label": 
"consumer,advanced", "required": false, "type": "boolean", "javaType": 
"boolean", "deprecated": false, "autowired": false, "secret": false, 
"defaultValue": false, "description": "Whether the starting directory has 
access permissions. Mind that the startingDirectoryMustExist parameter must be 
set to true in order to verify that the di [...]
     "appendChars": { "kind": "parameter", "displayName": "Append Chars", 
"group": "producer", "label": "producer", "required": false, "type": "string", 
"javaType": "java.lang.String", "deprecated": false, "autowired": false, 
"secret": false, "description": "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 new files or existing files. To specify new-line (slash-n 
or slash-r) or tab (slash-t)  [...]
diff --git 
a/components/camel-file/src/generated/java/org/apache/camel/component/file/FileEndpointConfigurer.java
 
b/components/camel-file/src/generated/java/org/apache/camel/component/file/FileEndpointConfigurer.java
index 1e914ba..f291e0b 100644
--- 
a/components/camel-file/src/generated/java/org/apache/camel/component/file/FileEndpointConfigurer.java
+++ 
b/components/camel-file/src/generated/java/org/apache/camel/component/file/FileEndpointConfigurer.java
@@ -162,6 +162,8 @@ public class FileEndpointConfigurer extends 
PropertyConfigurerSupport implements
         case "renameUsingCopy": 
target.setRenameUsingCopy(property(camelContext, boolean.class, value)); return 
true;
         case "repeatcount":
         case "repeatCount": target.setRepeatCount(property(camelContext, 
long.class, value)); return true;
+        case "resumestrategy":
+        case "resumeStrategy": target.setResumeStrategy(property(camelContext, 
org.apache.camel.component.file.consumer.FileConsumerResumeStrategy.class, 
value)); return true;
         case "runlogginglevel":
         case "runLoggingLevel": 
target.setRunLoggingLevel(property(camelContext, 
org.apache.camel.LoggingLevel.class, value)); return true;
         case "scheduledexecutorservice":
@@ -338,6 +340,8 @@ public class FileEndpointConfigurer extends 
PropertyConfigurerSupport implements
         case "renameUsingCopy": return boolean.class;
         case "repeatcount":
         case "repeatCount": return long.class;
+        case "resumestrategy":
+        case "resumeStrategy": return 
org.apache.camel.component.file.consumer.FileConsumerResumeStrategy.class;
         case "runlogginglevel":
         case "runLoggingLevel": return org.apache.camel.LoggingLevel.class;
         case "scheduledexecutorservice":
@@ -515,6 +519,8 @@ public class FileEndpointConfigurer extends 
PropertyConfigurerSupport implements
         case "renameUsingCopy": return target.isRenameUsingCopy();
         case "repeatcount":
         case "repeatCount": return target.getRepeatCount();
+        case "resumestrategy":
+        case "resumeStrategy": return target.getResumeStrategy();
         case "runlogginglevel":
         case "runLoggingLevel": return target.getRunLoggingLevel();
         case "scheduledexecutorservice":
diff --git 
a/components/camel-file/src/generated/java/org/apache/camel/component/file/FileEndpointUriFactory.java
 
b/components/camel-file/src/generated/java/org/apache/camel/component/file/FileEndpointUriFactory.java
index 8387a9d..c77bc1c 100644
--- 
a/components/camel-file/src/generated/java/org/apache/camel/component/file/FileEndpointUriFactory.java
+++ 
b/components/camel-file/src/generated/java/org/apache/camel/component/file/FileEndpointUriFactory.java
@@ -20,7 +20,7 @@ public class FileEndpointUriFactory extends 
org.apache.camel.support.component.E
     private static final Set<String> PROPERTY_NAMES;
     private static final Set<String> SECRET_PROPERTY_NAMES;
     static {
-        Set<String> props = new HashSet<>(94);
+        Set<String> props = new HashSet<>(95);
         props.add("renameUsingCopy");
         props.add("moveExistingFileStrategy");
         props.add("fileName");
@@ -57,6 +57,7 @@ public class FileEndpointUriFactory extends 
org.apache.camel.support.component.E
         props.add("lazyStartProducer");
         props.add("delay");
         props.add("startScheduler");
+        props.add("resumeStrategy");
         props.add("readLockMarkerFile");
         props.add("readLockTimeout");
         props.add("exceptionHandler");
diff --git 
a/components/camel-file/src/generated/resources/org/apache/camel/component/file/file.json
 
b/components/camel-file/src/generated/resources/org/apache/camel/component/file/file.json
index 90a50d3..8f254fb 100644
--- 
a/components/camel-file/src/generated/resources/org/apache/camel/component/file/file.json
+++ 
b/components/camel-file/src/generated/resources/org/apache/camel/component/file/file.json
@@ -49,6 +49,7 @@
     "pollStrategy": { "kind": "parameter", "displayName": "Poll Strategy", 
"group": "consumer (advanced)", "label": "consumer,advanced", "required": 
false, "type": "object", "javaType": 
"org.apache.camel.spi.PollingConsumerPollStrategy", "deprecated": false, 
"autowired": false, "secret": false, "description": "A pluggable 
org.apache.camel.PollingConsumerPollingStrategy allowing you to provide your 
custom implementation to control error handling usually occurred during the 
poll operation  [...]
     "probeContentType": { "kind": "parameter", "displayName": "Probe Content 
Type", "group": "consumer (advanced)", "label": "consumer,advanced", 
"required": false, "type": "boolean", "javaType": "boolean", "deprecated": 
false, "autowired": false, "secret": false, "defaultValue": false, 
"description": "Whether to enable probing of the content type. If enable then 
the consumer uses Files#probeContentType(java.nio.file.Path) to determine the 
content-type of the file, and store that as a he [...]
     "processStrategy": { "kind": "parameter", "displayName": "Process 
Strategy", "group": "consumer (advanced)", "label": "consumer,advanced", 
"required": false, "type": "object", "javaType": 
"org.apache.camel.component.file.GenericFileProcessStrategy<java.io.File>", 
"deprecated": false, "autowired": false, "secret": false, "description": "A 
pluggable org.apache.camel.component.file.GenericFileProcessStrategy allowing 
you to implement your own readLock option or similar. Can also be used [...]
+    "resumeStrategy": { "kind": "parameter", "displayName": "Resume Strategy", 
"group": "consumer (advanced)", "label": "consumer,advanced", "required": 
false, "type": "object", "javaType": 
"org.apache.camel.component.file.consumer.FileConsumerResumeStrategy", 
"deprecated": false, "autowired": false, "secret": false, "description": "Set a 
resume strategy for files. This makes it possible to define a strategy for 
resuming reading files after the last point before stopping the application. 
[...]
     "startingDirectoryMustExist": { "kind": "parameter", "displayName": 
"Starting Directory Must Exist", "group": "consumer (advanced)", "label": 
"consumer,advanced", "required": false, "type": "boolean", "javaType": 
"boolean", "deprecated": false, "autowired": false, "secret": false, 
"defaultValue": false, "description": "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' [...]
     "startingDirectoryMustHaveAccess": { "kind": "parameter", "displayName": 
"Starting Directory Must Have Access", "group": "consumer (advanced)", "label": 
"consumer,advanced", "required": false, "type": "boolean", "javaType": 
"boolean", "deprecated": false, "autowired": false, "secret": false, 
"defaultValue": false, "description": "Whether the starting directory has 
access permissions. Mind that the startingDirectoryMustExist parameter must be 
set to true in order to verify that the di [...]
     "appendChars": { "kind": "parameter", "displayName": "Append Chars", 
"group": "producer", "label": "producer", "required": false, "type": "string", 
"javaType": "java.lang.String", "deprecated": false, "autowired": false, 
"secret": false, "description": "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 new files or existing files. To specify new-line (slash-n 
or slash-r) or tab (slash-t)  [...]
diff --git 
a/components/camel-file/src/main/java/org/apache/camel/component/file/FileConsumer.java
 
b/components/camel-file/src/main/java/org/apache/camel/component/file/FileConsumer.java
index 50087fb..fa3cb13 100644
--- 
a/components/camel-file/src/main/java/org/apache/camel/component/file/FileConsumer.java
+++ 
b/components/camel-file/src/main/java/org/apache/camel/component/file/FileConsumer.java
@@ -31,6 +31,8 @@ import java.util.Set;
 import org.apache.camel.Exchange;
 import org.apache.camel.Message;
 import org.apache.camel.Processor;
+import org.apache.camel.component.file.consumer.FileConsumerResumeStrategy;
+import org.apache.camel.component.file.consumer.FileResumeInfo;
 import org.apache.camel.util.FileUtil;
 import org.apache.camel.util.ObjectHelper;
 import org.slf4j.Logger;
@@ -42,6 +44,7 @@ import org.slf4j.LoggerFactory;
 public class FileConsumer extends GenericFileConsumer<File> {
 
     private static final Logger LOG = 
LoggerFactory.getLogger(FileConsumer.class);
+    private final FileConsumerResumeStrategy resumeStrategy;
     private String endpointPath;
     private Set<String> extendedAttributes;
 
@@ -54,6 +57,8 @@ public class FileConsumer extends GenericFileConsumer<File> {
             List<String> attributes = 
Arrays.asList(endpoint.getExtendedAttributes().split(","));
             this.extendedAttributes = new HashSet<>(attributes);
         }
+
+        resumeStrategy = endpoint.getResumeStrategy();
     }
 
     @Override
@@ -83,25 +88,18 @@ public class FileConsumer extends GenericFileConsumer<File> 
{
         if (LOG.isTraceEnabled()) {
             LOG.trace("Polling directory: {}, absolute path: {}", 
directory.getPath(), directory.getAbsolutePath());
         }
-        File[] dirFiles = directory.listFiles();
-        if (dirFiles == null || dirFiles.length == 0) {
-            // no files in this directory to poll
-            if (LOG.isTraceEnabled()) {
-                LOG.trace("No files found in directory: {}", 
directory.getPath());
-            }
+        File[] files = listFiles(directory);
+        if (files == null || files.length == 0) {
             return true;
-        } else {
-            // we found some files
-            if (LOG.isTraceEnabled()) {
-                LOG.trace("Found {} in directory: {}", dirFiles.length, 
directory.getPath());
-            }
         }
-        List<File> files = Arrays.asList(dirFiles);
+
         if (getEndpoint().isPreSort()) {
-            files.sort(Comparator.comparing(File::getAbsoluteFile));
+            Arrays.sort(files, Comparator.comparing(File::getAbsoluteFile));
         }
 
-        for (File file : dirFiles) {
+        List<File> filesArray = Arrays.asList(files);
+
+        for (File file : files) {
             // check if we can continue polling in files
             if (!canPollMoreFiles(fileList)) {
                 return false;
@@ -120,7 +118,7 @@ public class FileConsumer extends GenericFileConsumer<File> 
{
                     = asGenericFile(endpointPath, file, 
getEndpoint().getCharset(), getEndpoint().isProbeContentType());
 
             if (file.isDirectory()) {
-                if (endpoint.isRecursive() && depth < endpoint.getMaxDepth() 
&& isValidFile(gf, true, files)) {
+                if (endpoint.isRecursive() && depth < endpoint.getMaxDepth() 
&& isValidFile(gf, true, filesArray)) {
                     // recursive scan and add the sub files and folders
                     String subDirectory = fileName + File.separator + 
file.getName();
                     boolean canPollMore = pollDirectory(subDirectory, 
fileList, depth);
@@ -130,39 +128,15 @@ public class FileConsumer extends 
GenericFileConsumer<File> {
                 }
             } else {
                 // Windows can report false to a file on a share so regard it
-                // always as a file (if its not a directory)
-                if (depth >= endpoint.minDepth && isValidFile(gf, false, 
files)) {
+                // always as a file (if it is not a directory)
+                if (depth >= endpoint.minDepth && isValidFile(gf, false, 
filesArray)) {
                     LOG.trace("Adding valid file: {}", file);
                     // matched file so add
                     if (extendedAttributes != null) {
                         Path path = file.toPath();
                         Map<String, Object> allAttributes = new HashMap<>();
                         for (String attribute : extendedAttributes) {
-                            try {
-                                String prefix = null;
-                                if (attribute.endsWith(":*")) {
-                                    prefix = attribute.substring(0, 
attribute.length() - 1);
-                                } else if (attribute.equals("*")) {
-                                    prefix = "basic:";
-                                }
-
-                                if (ObjectHelper.isNotEmpty(prefix)) {
-                                    Map<String, Object> attributes = 
Files.readAttributes(path, attribute);
-                                    if (attributes != null) {
-                                        for (Map.Entry<String, Object> entry : 
attributes.entrySet()) {
-                                            allAttributes.put(prefix + 
entry.getKey(), entry.getValue());
-                                        }
-                                    }
-                                } else if (!attribute.contains(":")) {
-                                    allAttributes.put("basic:" + attribute, 
Files.getAttribute(path, attribute));
-                                } else {
-                                    allAttributes.put(attribute, 
Files.getAttribute(path, attribute));
-                                }
-                            } catch (IOException e) {
-                                if (LOG.isDebugEnabled()) {
-                                    LOG.debug("Unable to read attribute {} on 
file {}", attribute, file, e);
-                                }
-                            }
+                            readAttributes(file, path, allAttributes, 
attribute);
                         }
 
                         gf.setExtendedAttributes(allAttributes);
@@ -177,6 +151,60 @@ public class FileConsumer extends 
GenericFileConsumer<File> {
         return true;
     }
 
+    private File[] listFiles(File directory) {
+        final File[] dirFiles = directory.listFiles();
+
+        if (dirFiles == null || dirFiles.length == 0) {
+            // no files in this directory to poll
+            if (LOG.isTraceEnabled()) {
+                LOG.trace("No files found in directory: {}", 
directory.getPath());
+            }
+            return null;
+        } else {
+            // we found some files
+            if (LOG.isTraceEnabled()) {
+                LOG.trace("Found {} in directory: {}", dirFiles.length, 
directory.getPath());
+            }
+        }
+
+        if (resumeStrategy != null) {
+            FileResumeInfo resumeInfo = new FileResumeInfo(dirFiles);
+            resumeStrategy.resume(resumeInfo);
+
+            return resumeInfo.getOutputFiles();
+        }
+
+        return dirFiles;
+    }
+
+    private void readAttributes(File file, Path path, Map<String, Object> 
allAttributes, String attribute) {
+        try {
+            String prefix = null;
+            if (attribute.endsWith(":*")) {
+                prefix = attribute.substring(0, attribute.length() - 1);
+            } else if (attribute.equals("*")) {
+                prefix = "basic:";
+            }
+
+            if (ObjectHelper.isNotEmpty(prefix)) {
+                Map<String, Object> attributes = Files.readAttributes(path, 
attribute);
+                if (attributes != null) {
+                    for (Map.Entry<String, Object> entry : 
attributes.entrySet()) {
+                        allAttributes.put(prefix + entry.getKey(), 
entry.getValue());
+                    }
+                }
+            } else if (!attribute.contains(":")) {
+                allAttributes.put("basic:" + attribute, 
Files.getAttribute(path, attribute));
+            } else {
+                allAttributes.put(attribute, Files.getAttribute(path, 
attribute));
+            }
+        } catch (IOException e) {
+            if (LOG.isDebugEnabled()) {
+                LOG.debug("Unable to read attribute {} on file {}", attribute, 
file, e);
+            }
+        }
+    }
+
     @Override
     protected boolean isMatched(GenericFile<File> file, String doneFileName, 
List<File> files) {
         String onlyName = FileUtil.stripPath(doneFileName);
diff --git 
a/components/camel-file/src/main/java/org/apache/camel/component/file/FileEndpoint.java
 
b/components/camel-file/src/main/java/org/apache/camel/component/file/FileEndpoint.java
index dc51742..c57f0f3 100644
--- 
a/components/camel-file/src/main/java/org/apache/camel/component/file/FileEndpoint.java
+++ 
b/components/camel-file/src/main/java/org/apache/camel/component/file/FileEndpoint.java
@@ -31,6 +31,7 @@ import org.apache.camel.Exchange;
 import org.apache.camel.Message;
 import org.apache.camel.PollingConsumer;
 import org.apache.camel.Processor;
+import org.apache.camel.component.file.consumer.FileConsumerResumeStrategy;
 import org.apache.camel.component.file.strategy.FileMoveExistingStrategy;
 import org.apache.camel.component.file.strategy.FileProcessStrategyFactory;
 import org.apache.camel.spi.Metadata;
@@ -82,6 +83,9 @@ public class FileEndpoint extends GenericFileEndpoint<File> {
     @UriParam(label = "producer,advanced")
     private String chmodDirectory;
 
+    @UriParam(label = "consumer,advanced")
+    private FileConsumerResumeStrategy resumeStrategy;
+
     public FileEndpoint() {
     }
 
@@ -360,6 +364,22 @@ public class FileEndpoint extends 
GenericFileEndpoint<File> {
         this.extendedAttributes = extendedAttributes;
     }
 
+    public FileConsumerResumeStrategy getResumeStrategy() {
+        return resumeStrategy;
+    }
+
+    /**
+     * Set a resume strategy for files. This makes it possible to define a 
strategy for resuming reading files after the
+     * last point before stopping the application.
+     *
+     * See the {@link FileConsumerResumeStrategy} for implementation details
+     *
+     * @param resumeStrategy an instance of the resume strategy to be used
+     */
+    public void setResumeStrategy(FileConsumerResumeStrategy resumeStrategy) {
+        this.resumeStrategy = resumeStrategy;
+    }
+
     /**
      * Chmod value must be between 000 and 777; If there is a leading digit 
like in 0755 we will ignore it.
      */
diff --git 
a/components/camel-file/src/main/java/org/apache/camel/component/file/GenericFileConsumer.java
 
b/components/camel-file/src/main/java/org/apache/camel/component/file/GenericFileConsumer.java
index a3fa67c..17448e1 100644
--- 
a/components/camel-file/src/main/java/org/apache/camel/component/file/GenericFileConsumer.java
+++ 
b/components/camel-file/src/main/java/org/apache/camel/component/file/GenericFileConsumer.java
@@ -590,21 +590,10 @@ public abstract class GenericFileConsumer<T> extends 
ScheduledBatchPollingConsum
             return false;
         }
 
-        // if its a file then check we have the file in the idempotent registry
+        // if it is a file then check we have the file in the idempotent 
registry
         // already
         if (endpoint.isIdempotent()) {
-            // use absolute file path as default key, but evaluate if an
-            // expression key was configured
-            String key = file.getAbsoluteFilePath();
-            if (endpoint.getIdempotentKey() != null) {
-                Exchange dummy = endpoint.createExchange(file);
-                key = endpoint.getIdempotentKey().evaluate(dummy, 
String.class);
-                LOG.trace("Evaluated idempotentKey: {} for file: {}", key, 
file);
-            }
-            if (key != null && 
endpoint.getIdempotentRepository().contains(key)) {
-                LOG.trace(
-                        "This consumer is idempotent and the file has been 
consumed before matching idempotentKey: {}. Will skip this file: {}",
-                        key, file);
+            if (notUnique(file)) {
                 return false;
             }
         }
@@ -615,6 +604,24 @@ public abstract class GenericFileConsumer<T> extends 
ScheduledBatchPollingConsum
         return endpoint.getInProgressRepository().add(absoluteFilePath);
     }
 
+    private boolean notUnique(GenericFile<T> file) {
+        // use absolute file path as default key, but evaluate if an
+        // expression key was configured
+        String key = file.getAbsoluteFilePath();
+        if (endpoint.getIdempotentKey() != null) {
+            Exchange dummy = endpoint.createExchange(file);
+            key = endpoint.getIdempotentKey().evaluate(dummy, String.class);
+            LOG.trace("Evaluated idempotentKey: {} for file: {}", key, file);
+        }
+        if (key != null && endpoint.getIdempotentRepository().contains(key)) {
+            LOG.trace(
+                    "This consumer is idempotent and the file has been 
consumed before matching idempotentKey: {}. Will skip this file: {}",
+                    key, file);
+            return true;
+        }
+        return false;
+    }
+
     /**
      * Strategy to perform file matching based on endpoint configuration.
      * <p/>
diff --git 
a/components/camel-file/src/main/java/org/apache/camel/component/file/consumer/FileConsumerResumeStrategy.java
 
b/components/camel-file/src/main/java/org/apache/camel/component/file/consumer/FileConsumerResumeStrategy.java
new file mode 100644
index 0000000..fc4a991
--- /dev/null
+++ 
b/components/camel-file/src/main/java/org/apache/camel/component/file/consumer/FileConsumerResumeStrategy.java
@@ -0,0 +1,34 @@
+/*
+ * 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.consumer;
+
+import org.apache.camel.ResumeStrategy;
+
+/**
+ * Defines resume strategy for consumers of the file component.
+ */
+public interface FileConsumerResumeStrategy extends 
ResumeStrategy<FileResumeInfo> {
+
+    /**
+     * Perform the resume operation. This runs in the scope of the 
FileConsumer instance thread.
+     *
+     * @param resumeInfo resume information
+     */
+    @Override
+    void resume(FileResumeInfo resumeInfo);
+}
diff --git 
a/components/camel-file/src/main/java/org/apache/camel/component/file/consumer/FileResumeInfo.java
 
b/components/camel-file/src/main/java/org/apache/camel/component/file/consumer/FileResumeInfo.java
new file mode 100644
index 0000000..ae6e0eb
--- /dev/null
+++ 
b/components/camel-file/src/main/java/org/apache/camel/component/file/consumer/FileResumeInfo.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.consumer;
+
+import java.io.File;
+import java.util.Objects;
+
+public final class FileResumeInfo {
+    private final File[] inputFiles;
+    private File[] outputFiles;
+
+    public FileResumeInfo(File[] inputFiles) {
+        Objects.requireNonNull(inputFiles, "A list of input files must be 
provided for the resume info");
+        this.inputFiles = inputFiles;
+    }
+
+    public File[] getInputFiles() {
+        return inputFiles;
+    }
+
+    public File[] getOutputFiles() {
+        return outputFiles;
+    }
+
+    public void setOutputFiles(File[] outputFiles) {
+        this.outputFiles = outputFiles;
+    }
+}
diff --git 
a/core/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/FileEndpointBuilderFactory.java
 
b/core/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/FileEndpointBuilderFactory.java
index d88af29..d021942 100644
--- 
a/core/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/FileEndpointBuilderFactory.java
+++ 
b/core/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/FileEndpointBuilderFactory.java
@@ -2558,6 +2558,44 @@ public interface FileEndpointBuilderFactory {
             return this;
         }
         /**
+         * Set a resume strategy for files. This makes it possible to define a
+         * strategy for resuming reading files after the last point before
+         * stopping the application. See the FileConsumerResumeStrategy for
+         * implementation details.
+         * 
+         * The option is a:
+         * 
&lt;code&gt;org.apache.camel.component.file.consumer.FileConsumerResumeStrategy&lt;/code&gt;
 type.
+         * 
+         * Group: consumer (advanced)
+         * 
+         * @param resumeStrategy the value to set
+         * @return the dsl builder
+         */
+        default AdvancedFileEndpointConsumerBuilder resumeStrategy(
+                Object resumeStrategy) {
+            doSetProperty("resumeStrategy", resumeStrategy);
+            return this;
+        }
+        /**
+         * Set a resume strategy for files. This makes it possible to define a
+         * strategy for resuming reading files after the last point before
+         * stopping the application. See the FileConsumerResumeStrategy for
+         * implementation details.
+         * 
+         * The option will be converted to a
+         * 
&lt;code&gt;org.apache.camel.component.file.consumer.FileConsumerResumeStrategy&lt;/code&gt;
 type.
+         * 
+         * Group: consumer (advanced)
+         * 
+         * @param resumeStrategy the value to set
+         * @return the dsl builder
+         */
+        default AdvancedFileEndpointConsumerBuilder resumeStrategy(
+                String resumeStrategy) {
+            doSetProperty("resumeStrategy", resumeStrategy);
+            return this;
+        }
+        /**
          * 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

Reply via email to