This is an automated email from the ASF dual-hosted git repository.
davsclaus 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 38042d59704 optimize camel-file when filtering files by name (#16663)
38042d59704 is described below
commit 38042d5970471752e116eb82602bd9eae8d152c1
Author: Claus Ibsen <[email protected]>
AuthorDate: Mon Dec 30 08:42:32 2024 +0100
optimize camel-file when filtering files by name (#16663)
* CAMEL-17648: camel-file - Optimize file consumer when filtering file
names.
---
.../camel/component/file/azure/FilesConsumer.java | 27 +++++--
...atcherGenericFileFilter.java => AntFilter.java} | 19 ++---
.../file/AntPathMatcherGenericFileFilter.java | 4 +-
.../apache/camel/component/file/FileConsumer.java | 84 +++++++++++++-------
.../camel/component/file/GenericFileConsumer.java | 90 ++++++++++++++--------
.../camel/component/file/GenericFileEndpoint.java | 8 +-
.../camel/component/file/GenericFileFilter.java | 2 +
...ricFileFilter.java => OptimizedFileFilter.java} | 20 +++--
.../MarkerFileExclusiveReadLockStrategy.java | 7 +-
.../camel/component/file/remote/FtpConsumer.java | 71 ++++++++++-------
.../camel/component/file/remote/FtpUtils.java | 35 ++++++++-
.../camel/component/file/remote/RemoteFile.java | 3 +-
.../camel/component/file/remote/SftpConsumer.java | 67 +++++++++-------
.../remote/RemoteFileIgnoreDoPollErrorTest.java | 8 +-
.../integration/SftpMoveWithOutMessageTest.java | 2 +
.../file/FileConsumerFileFilterOptimizedTest.java | 85 ++++++++++++++++++++
.../ROOT/pages/camel-4x-upgrade-guide-4_10.adoc | 11 +++
17 files changed, 389 insertions(+), 154 deletions(-)
diff --git
a/components/camel-azure/camel-azure-files/src/main/java/org/apache/camel/component/file/azure/FilesConsumer.java
b/components/camel-azure/camel-azure-files/src/main/java/org/apache/camel/component/file/azure/FilesConsumer.java
index d329a0452dd..e11f4635906 100644
---
a/components/camel-azure/camel-azure-files/src/main/java/org/apache/camel/component/file/azure/FilesConsumer.java
+++
b/components/camel-azure/camel-azure-files/src/main/java/org/apache/camel/component/file/azure/FilesConsumer.java
@@ -19,6 +19,7 @@ package org.apache.camel.component.file.azure;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
+import java.util.function.Supplier;
import com.azure.storage.file.share.models.ShareFileItem;
import org.apache.camel.Message;
@@ -33,6 +34,7 @@ import
org.apache.camel.component.file.remote.RemoteFileConsumer;
import org.apache.camel.util.FileUtil;
import org.apache.camel.util.StringHelper;
import org.apache.camel.util.URISupport;
+import org.apache.camel.util.function.Suppliers;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -152,8 +154,10 @@ public class FilesConsumer extends
RemoteFileConsumer<ShareFileItem> {
int depth, ShareFileItem[] listedFileItems, ShareFileItem dir) {
if (endpoint.isRecursive() && depth < endpoint.getMaxDepth()) {
- var remote = asRemoteFile(path, dir);
- if (isValidFile(remote, true, listedFileItems)) {
+ Supplier<GenericFile<ShareFileItem>> remote =
Suppliers.memorize(() -> asRemoteFile(path, dir));
+ String absoluteFilePath = FilesPath.concat(path, dir.getName());
+ Supplier<String> relative = getRelativeFilePath(endpointPath,
path, absoluteFilePath, dir);
+ if (isValidFile(remote, dir.getName(), absoluteFilePath, relative,
true, listedFileItems)) {
String dirName = dir.getName();
String dirPath = FilesPath.concat(path, dirName);
boolean canPollMore = doSafePollSubDirectory(dirPath, dirName,
polledFiles, depth);
@@ -169,9 +173,12 @@ public class FilesConsumer extends
RemoteFileConsumer<ShareFileItem> {
String path, List<GenericFile<ShareFileItem>> polledFiles, int
depth,
ShareFileItem[] listedFileItems, ShareFileItem file) {
if (depth >= endpoint.getMinDepth()) {
- var remote = asRemoteFile(path, file);
- if (isValidFile(remote, false, listedFileItems)) {
- polledFiles.add(remote);
+ Supplier<GenericFile<ShareFileItem>> remote =
Suppliers.memorize(() -> asRemoteFile(path, file));
+ String absoluteFilePath = FilesPath.concat(path, file.getName());
+ Supplier<String> relative = getRelativeFilePath(endpointPath,
path, absoluteFilePath, file);
+ if (isValidFile(remote, file.getName(), absoluteFilePath,
relative, false,
+ listedFileItems)) {
+ polledFiles.add(remote.get());
}
}
}
@@ -193,7 +200,7 @@ public class FilesConsumer extends
RemoteFileConsumer<ShareFileItem> {
@Override
protected boolean isMatched(
- GenericFile<ShareFileItem> file, String doneFileName,
+ Supplier<GenericFile<ShareFileItem>> file, String doneFileName,
ShareFileItem[] files) {
String onlyName = FileUtil.stripPath(doneFileName);
@@ -232,6 +239,14 @@ public class FilesConsumer extends
RemoteFileConsumer<ShareFileItem> {
return answer;
}
+ @Override
+ protected Supplier<String> getRelativeFilePath(String endpointPath, String
path, String absolutePath, ShareFileItem file) {
+ return () -> {
+ String relativePath = StringHelper.after(absolutePath,
endpointPath);
+ return FilesPath.ensureRelative(relativePath);
+ };
+ }
+
@Override
protected void updateFileHeaders(GenericFile<ShareFileItem> file, Message
message) {
message.setHeader(FilesHeaders.FILE_LENGTH, file.getFileLength());
diff --git
a/components/camel-file/src/main/java/org/apache/camel/component/file/AntPathMatcherGenericFileFilter.java
b/components/camel-file/src/main/java/org/apache/camel/component/file/AntFilter.java
similarity index 82%
copy from
components/camel-file/src/main/java/org/apache/camel/component/file/AntPathMatcherGenericFileFilter.java
copy to
components/camel-file/src/main/java/org/apache/camel/component/file/AntFilter.java
index 02f72c8c117..7e2b7711729 100644
---
a/components/camel-file/src/main/java/org/apache/camel/component/file/AntPathMatcherGenericFileFilter.java
+++
b/components/camel-file/src/main/java/org/apache/camel/component/file/AntFilter.java
@@ -20,31 +20,26 @@ package org.apache.camel.component.file;
* File filter using AntPathMatcher.
* <p/>
* Exclude take precedence over includes. If a file match both exclude and
include it will be regarded as excluded.
- *
- * @param <T>
*/
-public class AntPathMatcherGenericFileFilter<T> implements
GenericFileFilter<T> {
+public class AntFilter {
private final AntPathMatcherFileFilter filter;
- public AntPathMatcherGenericFileFilter() {
+ public AntFilter() {
filter = new AntPathMatcherFileFilter();
}
- public AntPathMatcherGenericFileFilter(String... includes) {
+ public AntFilter(String... includes) {
filter = new AntPathMatcherFileFilter();
filter.setIncludes(includes);
}
- @Override
- public boolean accept(GenericFile<T> file) {
+ public boolean accept(boolean directory, String relativeFilePath) {
// directories should always be accepted by ANT path matcher
- if (file.isDirectory()) {
+ if (directory) {
return true;
}
-
- String path = file.getRelativeFilePath();
- return filter.acceptPathName(path);
+ return filter.acceptPathName(relativeFilePath);
}
public String[] getExcludes() {
@@ -78,7 +73,7 @@ public class AntPathMatcherGenericFileFilter<T> implements
GenericFileFilter<T>
}
/**
- * Sets case sensitive flag on {@link
org.apache.camel.component.file.AntPathMatcherFileFilter}
+ * Sets case sensitive flag on {@link AntPathMatcherFileFilter}
* <p/>
* Is by default turned on <tt>true</tt>.
*/
diff --git
a/components/camel-file/src/main/java/org/apache/camel/component/file/AntPathMatcherGenericFileFilter.java
b/components/camel-file/src/main/java/org/apache/camel/component/file/AntPathMatcherGenericFileFilter.java
index 02f72c8c117..ae7902a03a9 100644
---
a/components/camel-file/src/main/java/org/apache/camel/component/file/AntPathMatcherGenericFileFilter.java
+++
b/components/camel-file/src/main/java/org/apache/camel/component/file/AntPathMatcherGenericFileFilter.java
@@ -21,8 +21,10 @@ package org.apache.camel.component.file;
* <p/>
* Exclude take precedence over includes. If a file match both exclude and
include it will be regarded as excluded.
*
- * @param <T>
+ * @param <T>
+ * @deprecated use {@link AntFilter}
*/
+@Deprecated
public class AntPathMatcherGenericFileFilter<T> implements
GenericFileFilter<T> {
private final AntPathMatcherFileFilter filter;
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 1cc3327ef1c..d2b6dfbd57b 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
@@ -27,6 +27,7 @@ import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.function.Supplier;
import org.apache.camel.Exchange;
import org.apache.camel.Message;
@@ -39,6 +40,7 @@ import org.apache.camel.resume.ResumeStrategy;
import org.apache.camel.support.resume.Resumables;
import org.apache.camel.util.FileUtil;
import org.apache.camel.util.ObjectHelper;
+import org.apache.camel.util.function.Suppliers;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -109,12 +111,11 @@ public class FileConsumer extends
GenericFileConsumer<File> implements ResumeAwa
}
// creates a generic file
- GenericFile<File> gf
- = asGenericFile(endpointPath, file,
getEndpoint().getCharset(), getEndpoint().isProbeContentType());
+ Supplier<GenericFile<File>> gf = Suppliers.memorize(
+ () -> asGenericFile(endpointPath, file,
getEndpoint().getCharset(), getEndpoint().isProbeContentType()));
if (resumeStrategy != null) {
- final ResumeAdapter adapter = setupResumeStrategy(gf);
-
+ final ResumeAdapter adapter = setupResumeStrategy(gf.get());
if (adapter instanceof DirectoryEntriesResumeAdapter
directoryEntriesResumeAdapter) {
LOG.trace("Running the resume process for file {}", file);
if (directoryEntriesResumeAdapter.resume(file)) {
@@ -131,7 +132,8 @@ public class FileConsumer extends GenericFileConsumer<File>
implements ResumeAwa
return false;
}
- private boolean processEntry(List<GenericFile<File>> fileList, int depth,
File file, GenericFile<File> gf, File[] files) {
+ private boolean processEntry(
+ List<GenericFile<File>> fileList, int depth, File file,
Supplier<GenericFile<File>> gf, File[] files) {
if (file.isDirectory()) {
return processDirectoryEntry(fileList, depth, file, gf, files);
} else {
@@ -141,32 +143,40 @@ public class FileConsumer extends
GenericFileConsumer<File> implements ResumeAwa
return false;
}
- private void processFileEntry(List<GenericFile<File>> fileList, int depth,
File file, GenericFile<File> gf, File[] files) {
+ private void processFileEntry(
+ List<GenericFile<File>> fileList, int depth, File file,
Supplier<GenericFile<File>> gf, File[] files) {
// Windows can report false to a file on a share so regard it
// always as a file (if it is not a directory)
- if (depth >= endpoint.minDepth && isValidFile(gf, false, files)) {
- 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) {
- readAttributes(file, path, allAttributes, attribute);
+ if (depth >= endpoint.minDepth) {
+ boolean valid
+ = isValidFile(gf, file.getName(), file.getAbsolutePath(),
+ getRelativeFilePath(endpointPath, null, null,
file),
+ false, files);
+ if (valid) {
+ LOG.trace("Adding valid file: {}", file);
+ if (extendedAttributes != null) {
+ Path path = file.toPath();
+ Map<String, Object> allAttributes = new HashMap<>();
+ for (String attribute : extendedAttributes) {
+ readAttributes(file, path, allAttributes, attribute);
+ }
+ gf.get().setExtendedAttributes(allAttributes);
}
-
- gf.setExtendedAttributes(allAttributes);
+ fileList.add(gf.get());
}
-
- fileList.add(gf);
}
}
private boolean processDirectoryEntry(
- List<GenericFile<File>> fileList, int depth, File file,
GenericFile<File> gf, File[] files) {
- if (endpoint.isRecursive() && depth < endpoint.getMaxDepth() &&
isValidFile(gf, true, files)) {
- boolean canPollMore = pollDirectory(file, fileList, depth);
- if (!canPollMore) {
- return true;
+ List<GenericFile<File>> fileList, int depth, File file,
Supplier<GenericFile<File>> gf, File[] files) {
+ if (endpoint.isRecursive() && depth < endpoint.getMaxDepth()) {
+ boolean valid
+ = isValidFile(gf, file.getName(), file.getAbsolutePath(),
+ getRelativeFilePath(endpointPath, null, null,
file),
+ true, files);
+ if (valid) {
+ boolean canPollMore = pollDirectory(file, fileList, depth);
+ return !canPollMore;
}
}
return false;
@@ -250,7 +260,7 @@ public class FileConsumer extends GenericFileConsumer<File>
implements ResumeAwa
}
@Override
- protected boolean isMatched(GenericFile<File> file, String doneFileName,
File[] files) {
+ protected boolean isMatched(Supplier<GenericFile<File>> file, String
doneFileName, File[] files) {
String onlyName = FileUtil.stripPath(doneFileName);
// the done file name must be among the files
for (File f : files) {
@@ -319,6 +329,27 @@ public class FileConsumer extends
GenericFileConsumer<File> implements ResumeAwa
return answer;
}
+ @Override
+ protected Supplier<String> getRelativeFilePath(String endpointPath, String
path, String absolutePath, File file) {
+ return () -> {
+ File f;
+ String endpointNormalizedSep =
FileUtil.normalizePath(endpointPath) + File.separator;
+ String p = file.getPath();
+ if (p.startsWith(endpointNormalizedSep)) {
+ p = p.substring(endpointNormalizedSep.length());
+ }
+ f = new File(p);
+
+ String answer;
+ if (f.getParent() != null) {
+ answer = f.getParent() + File.separator + file.getName();
+ } else {
+ answer = f.getName();
+ }
+ return answer;
+ };
+ }
+
@Override
protected void updateFileHeaders(GenericFile<File> file, Message message) {
File upToDateFile = file.getFile();
@@ -345,9 +376,8 @@ public class FileConsumer extends GenericFileConsumer<File>
implements ResumeAwa
}
@Override
- protected boolean isMatchedHiddenFile(GenericFile<File> file, boolean
isDirectory) {
+ protected boolean isMatchedHiddenFile(Supplier<GenericFile<File>> file,
String name, boolean isDirectory) {
if (isDirectory) {
- String name = file.getFileNameOnly();
if (!name.startsWith(".")) {
return true;
}
@@ -357,7 +387,7 @@ public class FileConsumer extends GenericFileConsumer<File>
implements ResumeAwa
if (getEndpoint().isIncludeHiddenFiles()) {
return true;
} else {
- return super.isMatchedHiddenFile(file, isDirectory);
+ return super.isMatchedHiddenFile(file, name, isDirectory);
}
}
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 87d51223983..7f87cb2af1d 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
@@ -22,6 +22,7 @@ import java.util.Deque;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
+import java.util.function.Supplier;
import java.util.regex.Pattern;
import org.apache.camel.CamelContextAware;
@@ -580,15 +581,16 @@ public abstract class GenericFileConsumer<T> extends
ScheduledBatchPollingConsum
* Strategy for validating if the given remote file should be included or
not
*
* @param file the file
+ * @param name the file name
* @param isDirectory whether the file is a directory or a file
* @param files files in the directory
* @return <tt>true</tt> to include the file, <tt>false</tt>
to skip it
*/
- protected boolean isValidFile(GenericFile<T> file, boolean isDirectory,
T[] files) {
- String absoluteFilePath = file.getAbsoluteFilePath();
-
- if (!isMatched(file, isDirectory, files)) {
- LOG.trace("File did not match. Will skip this file: {}", file);
+ protected boolean isValidFile(
+ Supplier<GenericFile<T>> file, String name, String
absoluteFilePath,
+ Supplier<String> relativeFilePath, boolean isDirectory, T[] files)
{
+ if (!isMatched(file, name, absoluteFilePath, relativeFilePath,
isDirectory, files)) {
+ LOG.trace("File did not match. Will skip this file: {}", name);
return false;
}
@@ -600,7 +602,7 @@ public abstract class GenericFileConsumer<T> extends
ScheduledBatchPollingConsum
// check if file is already in progress
if (endpoint.getInProgressRepository().contains(absoluteFilePath)) {
if (LOG.isTraceEnabled()) {
- LOG.trace("Skipping as file is already in progress: {}",
file.getFileName());
+ LOG.trace("Skipping as file is already in progress: {}", name);
}
return false;
}
@@ -608,7 +610,7 @@ public abstract class GenericFileConsumer<T> extends
ScheduledBatchPollingConsum
// if it is a file then check we have the file in the idempotent
registry
// already
if (Boolean.TRUE.equals(endpoint.isIdempotent())) {
- if (notUnique(file)) {
+ if (notUnique(file, absoluteFilePath)) {
return false;
}
}
@@ -619,13 +621,13 @@ public abstract class GenericFileConsumer<T> extends
ScheduledBatchPollingConsum
return endpoint.getInProgressRepository().add(absoluteFilePath);
}
- private boolean notUnique(GenericFile<T> file) {
+ private boolean notUnique(Supplier<GenericFile<T>> file, String
absoluteFilePath) {
boolean answer = false;
// use absolute file path as default key, but evaluate if an
// expression key was configured
- String key = file.getAbsoluteFilePath();
+ String key = absoluteFilePath;
if (endpoint.getIdempotentKey() != null) {
- Exchange dummy = endpoint.createExchange(file);
+ Exchange dummy = endpoint.createExchange(file.get());
key = endpoint.getIdempotentKey().evaluate(dummy, String.class);
LOG.trace("Evaluated idempotentKey: {} for file: {}", key, file);
}
@@ -649,9 +651,7 @@ public abstract class GenericFileConsumer<T> extends
ScheduledBatchPollingConsum
* <li>Starting with a dot (hidden)</li>
* </ul>
*/
- protected boolean isMatchedHiddenFile(GenericFile<T> file, boolean
isDirectory) {
- String name = file.getFileNameOnly();
-
+ protected boolean isMatchedHiddenFile(Supplier<GenericFile<T>> file,
String name, boolean isDirectory) {
// folders/names starting with dot is always skipped (eg. ".",
".camel",
// ".camelLock")
if (name.startsWith(".")) {
@@ -661,6 +661,12 @@ public abstract class GenericFileConsumer<T> extends
ScheduledBatchPollingConsum
return true;
}
+ /**
+ * Geta the relative path from the given file, calculated from the
starting path, current path, and current absolute
+ * path
+ */
+ protected abstract Supplier<String> getRelativeFilePath(String
endpointPath, String path, String absolutePath, T file);
+
/**
* Strategy to perform file matching based on endpoint configuration.
* <p/>
@@ -671,15 +677,19 @@ public abstract class GenericFileConsumer<T> extends
ScheduledBatchPollingConsum
* </ul>
* And then <tt>true</tt> for directories.
*
- * @param file the file
- * @param isDirectory whether the file is a directory or a file
- * @param files files in the directory
- * @return <tt>true</tt> if the file is matched,
<tt>false</tt> if not
+ * @param file the file
+ * @param name the file name
+ * @param absoluteFilePath the absolute file name
+ * @param relativeFilePath the relative file name
+ * @param isDirectory whether the file is a directory or a file
+ * @param files files in the directory
+ * @return <tt>true</tt> if the file is matched,
<tt>false</tt> if not
*/
- protected boolean isMatched(GenericFile<T> file, boolean isDirectory, T[]
files) {
- String name = file.getFileNameOnly();
+ protected boolean isMatched(
+ Supplier<GenericFile<T>> file, String name, String
absoluteFilePath,
+ Supplier<String> relativeFilePath, boolean isDirectory, T[] files)
{
- if (!isMatchedHiddenFile(file, isDirectory)) {
+ if (!isMatchedHiddenFile(file, name, isDirectory)) {
// folders/names starting with dot is always skipped (eg. ".",
".camel",
// ".camelLock")
return false;
@@ -691,13 +701,22 @@ public abstract class GenericFileConsumer<T> extends
ScheduledBatchPollingConsum
}
if (endpoint.getFilter() != null) {
- if (!endpoint.getFilter().accept(file)) {
+ Boolean accepted = null;
+ if (endpoint.getFilter() instanceof OptimizedFileFilter off) {
+ // use optimized test using file name only
+ accepted = off.accept(name);
+ }
+ if (accepted == null) {
+ // use default test using generic file
+ accepted = endpoint.getFilter().accept(file.get());
+ }
+ if (!accepted) {
return false;
}
}
if (endpoint.getAntFilter() != null) {
- if (!endpoint.getAntFilter().accept(file)) {
+ if (!endpoint.getAntFilter().accept(isDirectory,
relativeFilePath.get())) {
return false;
}
}
@@ -705,7 +724,7 @@ public abstract class GenericFileConsumer<T> extends
ScheduledBatchPollingConsum
if (isDirectory && endpoint.getFilterDirectory() != null) {
// create a dummy exchange as Exchange is needed for expression
// evaluation
- Exchange dummy = endpoint.createExchange(file);
+ Exchange dummy = endpoint.createExchange(file.get());
boolean matches = endpoint.getFilterDirectory().matches(dummy);
if (!matches) {
return false;
@@ -717,13 +736,13 @@ public abstract class GenericFileConsumer<T> extends
ScheduledBatchPollingConsum
return true;
}
- if (hasInclusionsOrExclusions(file, name)) {
+ if (hasInclusionsOrExclusions(name)) {
return false;
}
if (endpoint.getFileName() != null) {
// create a dummy exchange as Exchange is needed for expression
evaluation
- Exchange dummy = endpoint.createExchange(file);
+ Exchange dummy = endpoint.createExchange(file.get());
String result = evaluateFileExpression(dummy);
if (result != null) {
if (!name.equals(result)) {
@@ -734,7 +753,7 @@ public abstract class GenericFileConsumer<T> extends
ScheduledBatchPollingConsum
if (endpoint.getFilterFile() != null) {
// create a dummy exchange as Exchange is needed for expression
evaluation
- Exchange dummy = endpoint.createExchange(file);
+ Exchange dummy = endpoint.createExchange(file.get());
boolean matches = endpoint.getFilterFile().matches(dummy);
if (!matches) {
return false;
@@ -745,11 +764,11 @@ public abstract class GenericFileConsumer<T> extends
ScheduledBatchPollingConsum
// file exists
if (endpoint.getDoneFileName() != null) {
// done file must be in same path as the file
- String doneFileName =
endpoint.createDoneFileName(file.getAbsoluteFilePath());
+ String doneFileName =
endpoint.createDoneFileName(absoluteFilePath);
StringHelper.notEmpty(doneFileName, "doneFileName", endpoint);
// is it a done file name?
- if (endpoint.isDoneFile(file.getFileNameOnly())) {
+ if (endpoint.isDoneFile(name)) {
LOG.trace("Skipping done file: {}", file);
return false;
}
@@ -762,15 +781,16 @@ public abstract class GenericFileConsumer<T> extends
ScheduledBatchPollingConsum
return true;
}
- private boolean hasInclusionsOrExclusions(GenericFile<T> file, String
name) {
+ private boolean hasInclusionsOrExclusions(String name) {
// exclude take precedence over include
if (excludePattern != null) {
if (excludePattern.matcher(name).matches()) {
return true;
}
}
+ String fname = null;
if (excludeExt != null) {
- String fname = file.getFileName().toLowerCase();
+ fname = name.toLowerCase();
if (hasExtExlusions(fname)) {
return true;
}
@@ -781,7 +801,9 @@ public abstract class GenericFileConsumer<T> extends
ScheduledBatchPollingConsum
}
}
if (includeExt != null) {
- String fname = file.getFileName().toLowerCase();
+ if (fname == null) {
+ fname = name.toLowerCase();
+ }
if (hasExtInclusions(fname)) {
return true;
}
@@ -789,7 +811,7 @@ public abstract class GenericFileConsumer<T> extends
ScheduledBatchPollingConsum
return false;
}
- private boolean hasExtInclusions(String fname) {
+ protected boolean hasExtInclusions(String fname) {
boolean any = false;
for (String include : includeExt) {
any |= fname.endsWith("." + include);
@@ -800,7 +822,7 @@ public abstract class GenericFileConsumer<T> extends
ScheduledBatchPollingConsum
return false;
}
- private boolean hasExtExlusions(String fname) {
+ protected boolean hasExtExlusions(String fname) {
for (String exclude : excludeExt) {
if (fname.endsWith("." + exclude)) {
return true;
@@ -817,7 +839,7 @@ public abstract class GenericFileConsumer<T> extends
ScheduledBatchPollingConsum
* @param files files in the directory
* @return <tt>true</tt> if the file is matched,
<tt>false</tt> if not
*/
- protected abstract boolean isMatched(GenericFile<T> file, String
doneFileName, T[] files);
+ protected abstract boolean isMatched(Supplier<GenericFile<T>> file, String
doneFileName, T[] files);
protected String evaluateFileExpression(Exchange exchange) {
String result = endpoint.getFileName().evaluate(exchange,
String.class);
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 392f44d9a82..b32bfad5f1f 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
@@ -308,7 +308,7 @@ public abstract class GenericFileEndpoint<T> extends
ScheduledPollEndpoint imple
protected Predicate filterFile;
@UriParam(label = "consumer,filter", defaultValue = "true", description =
"Sets case sensitive flag on ant filter.")
protected boolean antFilterCaseSensitive = true;
- protected volatile AntPathMatcherGenericFileFilter<T> antFilter;
+ protected volatile AntFilter antFilter;
@UriParam(label = "consumer,filter",
description = "Ant style filter inclusion. Multiple inclusions
may be " + "specified in comma-delimited format.")
protected String antInclude;
@@ -685,7 +685,7 @@ public abstract class GenericFileEndpoint<T> extends
ScheduledPollEndpoint imple
this.antFilterCaseSensitive = antFilterCaseSensitive;
}
- public GenericFileFilter<T> getAntFilter() {
+ public AntFilter getAntFilter() {
return antFilter;
}
@@ -1878,13 +1878,13 @@ public abstract class GenericFileEndpoint<T> extends
ScheduledPollEndpoint imple
if (antInclude != null) {
if (antFilter == null) {
- antFilter = new AntPathMatcherGenericFileFilter<>();
+ antFilter = new AntFilter();
}
antFilter.setIncludes(antInclude);
}
if (antExclude != null) {
if (antFilter == null) {
- antFilter = new AntPathMatcherGenericFileFilter<>();
+ antFilter = new AntFilter();
}
antFilter.setExcludes(antExclude);
}
diff --git
a/components/camel-file/src/main/java/org/apache/camel/component/file/GenericFileFilter.java
b/components/camel-file/src/main/java/org/apache/camel/component/file/GenericFileFilter.java
index 5178dc96d62..6e1f5acf9fb 100644
---
a/components/camel-file/src/main/java/org/apache/camel/component/file/GenericFileFilter.java
+++
b/components/camel-file/src/main/java/org/apache/camel/component/file/GenericFileFilter.java
@@ -18,6 +18,8 @@ package org.apache.camel.component.file;
/**
* A filter for {@link GenericFile}.
+ *
+ * @see OptimizedFileFilter
*/
public interface GenericFileFilter<T> {
diff --git
a/components/camel-file/src/main/java/org/apache/camel/component/file/GenericFileFilter.java
b/components/camel-file/src/main/java/org/apache/camel/component/file/OptimizedFileFilter.java
similarity index 64%
copy from
components/camel-file/src/main/java/org/apache/camel/component/file/GenericFileFilter.java
copy to
components/camel-file/src/main/java/org/apache/camel/component/file/OptimizedFileFilter.java
index 5178dc96d62..3f57c4f3b75 100644
---
a/components/camel-file/src/main/java/org/apache/camel/component/file/GenericFileFilter.java
+++
b/components/camel-file/src/main/java/org/apache/camel/component/file/OptimizedFileFilter.java
@@ -17,16 +17,24 @@
package org.apache.camel.component.file;
/**
- * A filter for {@link GenericFile}.
+ * A filter for filtering file that is optimized for matching by name only.
+ *
+ * @see GenericFileFilter
*/
-public interface GenericFileFilter<T> {
+public interface OptimizedFileFilter extends GenericFileFilter {
+
+ @Override
+ default boolean accept(GenericFile file) {
+ return false;
+ }
/**
- * Tests whether the specified generic file should be included
+ * Tests whether the specified file should be included (quick test using
only file name)
*
- * @param file the generic file to be tested
- * @return <code>true</code> if and only if <code>file</code> should
be included
+ * @param name the file name
+ * @return <code>true</code> if and only if <code>file</code> should
be included, <tt>null</tt> to use the
+ * {@link #accept(GenericFile)} method.
*/
- boolean accept(GenericFile<T> file);
+ Boolean accept(String name);
}
diff --git
a/components/camel-file/src/main/java/org/apache/camel/component/file/strategy/MarkerFileExclusiveReadLockStrategy.java
b/components/camel-file/src/main/java/org/apache/camel/component/file/strategy/MarkerFileExclusiveReadLockStrategy.java
index da924dc71ce..123871090d0 100644
---
a/components/camel-file/src/main/java/org/apache/camel/component/file/strategy/MarkerFileExclusiveReadLockStrategy.java
+++
b/components/camel-file/src/main/java/org/apache/camel/component/file/strategy/MarkerFileExclusiveReadLockStrategy.java
@@ -21,6 +21,7 @@ import java.util.regex.Pattern;
import org.apache.camel.Exchange;
import org.apache.camel.LoggingLevel;
+import org.apache.camel.component.file.AntFilter;
import org.apache.camel.component.file.FileComponent;
import org.apache.camel.component.file.GenericFile;
import org.apache.camel.component.file.GenericFileEndpoint;
@@ -174,7 +175,7 @@ public class MarkerFileExclusiveReadLockStrategy implements
GenericFileExclusive
private static <T> void deleteLockFiles(
File dir, boolean recursive, int minDepth, int maxDepth, int
depth, boolean hiddenFilesEnabled, String endpointPath,
GenericFileFilter<T> filter,
- GenericFileFilter<T> antFilter,
+ AntFilter antFilter,
Pattern excludePattern,
Pattern includePattern) {
@@ -232,7 +233,7 @@ public class MarkerFileExclusiveReadLockStrategy implements
GenericFileExclusive
@SuppressWarnings("unchecked")
private static <T> boolean acceptFile(
- File file, String endpointPath, GenericFileFilter<T> filter,
GenericFileFilter<T> antFilter, Pattern excludePattern,
+ File file, String endpointPath, GenericFileFilter<T> filter,
AntFilter antFilter, Pattern excludePattern,
Pattern includePattern) {
GenericFile gf = new GenericFile<>();
gf.setEndpointPath(endpointPath);
@@ -286,7 +287,7 @@ public class MarkerFileExclusiveReadLockStrategy implements
GenericFileExclusive
}
if (antFilter != null) {
- if (!antFilter.accept(gf)) {
+ if (!antFilter.accept(gf.isDirectory(), gf.getRelativeFilePath()))
{
return false;
}
}
diff --git
a/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/FtpConsumer.java
b/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/FtpConsumer.java
index 127aa045759..d7f931c019d 100644
---
a/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/FtpConsumer.java
+++
b/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/FtpConsumer.java
@@ -19,6 +19,7 @@ package org.apache.camel.component.file.remote;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
+import java.util.function.Supplier;
import org.apache.camel.Exchange;
import org.apache.camel.Message;
@@ -34,6 +35,7 @@ import org.apache.camel.util.ObjectHelper;
import org.apache.camel.util.StringHelper;
import org.apache.camel.util.TimeUtils;
import org.apache.camel.util.URISupport;
+import org.apache.camel.util.function.Suppliers;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.slf4j.Logger;
@@ -181,14 +183,21 @@ public class FtpConsumer extends
RemoteFileConsumer<FTPFile> {
private boolean handleDirectory(
String absolutePath, List<GenericFile<FTPFile>> fileList, int
depth, FTPFile[] files, FTPFile file) {
- RemoteFile<FTPFile> remote = asRemoteFile(absolutePath, file,
getEndpoint().getCharset());
- if (endpoint.isRecursive() && depth < endpoint.getMaxDepth() &&
isValidFile(remote, true, files)) {
- // recursive scan and add the sub files and folders
- String subDirectory = file.getName();
- String path = ObjectHelper.isNotEmpty(absolutePath) ? absolutePath
+ "/" + subDirectory : subDirectory;
- boolean canPollMore = pollSubDirectory(path, subDirectory,
fileList, depth);
- if (!canPollMore) {
- return true;
+ if (endpoint.isRecursive() && depth < endpoint.getMaxDepth()) {
+ // calculate the absolute file path using util class
+ String absoluteFilePath
+ = FtpUtils.absoluteFilePath((FtpConfiguration)
endpoint.getConfiguration(), absolutePath, file.getName());
+ Supplier<GenericFile<FTPFile>> remote
+ = Suppliers.memorize(() -> asRemoteFile(absolutePath,
absoluteFilePath, file, getEndpoint().getCharset()));
+ Supplier<String> relativePath = getRelativeFilePath(endpointPath,
null, absolutePath, file);
+ if (isValidFile(remote, file.getName(), absoluteFilePath,
relativePath, true, files)) {
+ // recursive scan and add the sub files and folders
+ String subDirectory = file.getName();
+ String path = ObjectHelper.isNotEmpty(absolutePath) ?
absolutePath + "/" + subDirectory : subDirectory;
+ boolean canPollMore = pollSubDirectory(path, subDirectory,
fileList, depth);
+ if (!canPollMore) {
+ return true;
+ }
}
}
return false;
@@ -196,10 +205,17 @@ public class FtpConsumer extends
RemoteFileConsumer<FTPFile> {
private void handleFile(
String absolutePath, List<GenericFile<FTPFile>> fileList, int
depth, FTPFile[] files, FTPFile file) {
- RemoteFile<FTPFile> remote = asRemoteFile(absolutePath, file,
getEndpoint().getCharset());
- if (depth >= endpoint.getMinDepth() && isValidFile(remote, false,
files)) {
- // matched file so add
- fileList.add(remote);
+ if (depth >= endpoint.getMinDepth()) {
+ // calculate the absolute file path using util class
+ String absoluteFilePath
+ = FtpUtils.absoluteFilePath((FtpConfiguration)
endpoint.getConfiguration(), absolutePath, file.getName());
+ Supplier<GenericFile<FTPFile>> remote
+ = Suppliers.memorize(() -> asRemoteFile(absolutePath,
absoluteFilePath, file, getEndpoint().getCharset()));
+ Supplier<String> relativePath = getRelativeFilePath(endpointPath,
null, absolutePath, file);
+ if (isValidFile(remote, file.getName(), absoluteFilePath,
relativePath, false, files)) {
+ // matched file so add
+ fileList.add(remote.get());
+ }
}
}
@@ -258,7 +274,7 @@ public class FtpConsumer extends
RemoteFileConsumer<FTPFile> {
}
@Override
- protected boolean isMatched(GenericFile<FTPFile> file, String
doneFileName, FTPFile[] files) {
+ protected boolean isMatched(Supplier<GenericFile<FTPFile>> file, String
doneFileName, FTPFile[] files) {
String onlyName = FileUtil.stripPath(doneFileName);
for (FTPFile f : files) {
@@ -294,7 +310,17 @@ public class FtpConsumer extends
RemoteFileConsumer<FTPFile> {
return super.ignoreCannotRetrieveFile(name, exchange, cause);
}
- private RemoteFile<FTPFile> asRemoteFile(String absolutePath, FTPFile
file, String charset) {
+ @Override
+ protected Supplier<String> getRelativeFilePath(String endpointPath, String
path, String absolutePath, FTPFile file) {
+ return () -> {
+ // the relative filename, skip the leading endpoint configured path
+ String relativePath = StringHelper.after(absolutePath,
endpointPath);
+ // skip leading /
+ return FileUtil.stripLeadingSeparator(relativePath);
+ };
+ }
+
+ private RemoteFile<FTPFile> asRemoteFile(String absolutePath, String
absoluteFilePath, FTPFile file, String charset) {
RemoteFile<FTPFile> answer = new RemoteFile<>();
answer.setCharset(charset);
@@ -311,23 +337,10 @@ public class FtpConsumer extends
RemoteFileConsumer<FTPFile> {
// absolute or relative path
boolean absolute = FileUtil.hasLeadingSeparator(absolutePath);
answer.setAbsolute(absolute);
-
- // create a pseudo absolute name
- String dir = FileUtil.stripTrailingSeparator(absolutePath);
- String fileName = file.getName();
- if (((FtpConfiguration)
endpoint.getConfiguration()).isHandleDirectoryParserAbsoluteResult()) {
- fileName = FtpUtils.extractDirNameFromAbsolutePath(file.getName());
- }
- String absoluteFileName = FileUtil.stripLeadingSeparator(dir + "/" +
fileName);
- // if absolute start with a leading separator otherwise let it be
- // relative
- if (absolute) {
- absoluteFileName = "/" + absoluteFileName;
- }
- answer.setAbsoluteFilePath(absoluteFileName);
+ answer.setAbsoluteFilePath(absoluteFilePath);
// the relative filename, skip the leading endpoint configured path
- String relativePath = StringHelper.after(absoluteFileName,
endpointPath);
+ String relativePath = StringHelper.after(absoluteFilePath,
endpointPath);
// skip leading /
relativePath = FileUtil.stripLeadingSeparator(relativePath);
answer.setRelativeFilePath(relativePath);
diff --git
a/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/FtpUtils.java
b/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/FtpUtils.java
index ec84ed12952..f39f1d36b16 100644
---
a/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/FtpUtils.java
+++
b/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/FtpUtils.java
@@ -126,9 +126,7 @@ public final class FtpUtils {
* Checks whether directory used in ftp/ftps/sftp endpoint URI is
relative. Absolute path will be converted to
* relative path and a WARN will be printed.
*
- * @see <a
href="http://camel.apache.org/ftp2.html">FTP/SFTP/FTPS Component</a>
- * @param ftpComponent
- * @param configuration
+ * @see <a href="http://camel.apache.org/ftp2.html">FTP/SFTP/FTPS
Component</a>
*/
public static void ensureRelativeFtpDirectory(Component ftpComponent,
RemoteFileConfiguration configuration) {
if (FileUtil.hasLeadingSeparator(configuration.getDirectoryName())) {
@@ -141,4 +139,35 @@ public final class FtpUtils {
}
}
+ public static String absoluteFilePath(FtpConfiguration configuration,
String absolutePath, String name) {
+ boolean absolute = FileUtil.hasLeadingSeparator(absolutePath);
+ // create a pseudo absolute name
+ String dir = FileUtil.stripTrailingSeparator(absolutePath);
+ String fileName = name;
+ if (configuration.isHandleDirectoryParserAbsoluteResult()) {
+ fileName = FtpUtils.extractDirNameFromAbsolutePath(name);
+ }
+ String absoluteFileName = FileUtil.stripLeadingSeparator(dir + "/" +
fileName);
+ // if absolute start with a leading separator otherwise let it be
+ // relative
+ if (absolute) {
+ absoluteFileName = "/" + absoluteFileName;
+ }
+ return absoluteFileName;
+ }
+
+ public static String absoluteFilePath(String absolutePath, String name) {
+ boolean absolute = FileUtil.hasLeadingSeparator(absolutePath);
+
+ // create a pseudo absolute name
+ String dir = FileUtil.stripTrailingSeparator(absolutePath);
+ String absoluteFileName = FileUtil.stripLeadingSeparator(dir + "/" +
name);
+ // if absolute start with a leading separator otherwise let it be
+ // relative
+ if (absolute) {
+ absoluteFileName = "/" + absoluteFileName;
+ }
+ return absoluteFileName;
+ }
+
}
diff --git
a/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/RemoteFile.java
b/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/RemoteFile.java
index e2c539128ba..c7787bb4f4f 100644
---
a/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/RemoteFile.java
+++
b/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/RemoteFile.java
@@ -64,7 +64,7 @@ public class RemoteFile<T> extends GenericFile<T> implements
Cloneable {
@Override
protected boolean isAbsolute(String name) {
- if (name.length() > 0) {
+ if (!name.isEmpty()) {
return name.charAt(0) == '/' || name.charAt(0) == '\\';
}
return false;
@@ -79,7 +79,6 @@ public class RemoteFile<T> extends GenericFile<T> implements
Cloneable {
public void copyFromPopulateAdditional(GenericFile<T> source,
GenericFile<T> result) {
RemoteFile<?> remoteSource = (RemoteFile<?>) source;
RemoteFile<?> remoteResult = (RemoteFile<?>) result;
-
remoteResult.setHostname(remoteSource.getHostname());
}
diff --git
a/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/SftpConsumer.java
b/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/SftpConsumer.java
index 56c10fec3c8..d231d6a3fd8 100644
---
a/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/SftpConsumer.java
+++
b/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/SftpConsumer.java
@@ -19,6 +19,7 @@ package org.apache.camel.component.file.remote;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
+import java.util.function.Supplier;
import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.SftpException;
@@ -33,6 +34,7 @@ import org.apache.camel.util.FileUtil;
import org.apache.camel.util.ObjectHelper;
import org.apache.camel.util.StringHelper;
import org.apache.camel.util.URISupport;
+import org.apache.camel.util.function.Suppliers;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -124,7 +126,7 @@ public class SftpConsumer extends
RemoteFileConsumer<SftpRemoteFile> {
dirName = FileUtil.stripTrailingSeparator(dirName);
// compute dir depending on stepwise is enabled or not
- String dir = null;
+ String dir;
if (isStepwise()) {
dir = ObjectHelper.isNotEmpty(dirName) ? dirName : absolutePath;
operations.changeCurrentDirectory(dir);
@@ -160,24 +162,36 @@ public class SftpConsumer extends
RemoteFileConsumer<SftpRemoteFile> {
}
if (file.isDirectory()) {
- RemoteFile<SftpRemoteFile> remote = asRemoteFile(absolutePath,
file, getEndpoint().getCharset());
- if (endpoint.isRecursive() && depth < endpoint.getMaxDepth()
&& isValidFile(remote, true, files)) {
- // recursive scan and add the sub files and folders
- String subDirectory = file.getFilename();
- String path = ObjectHelper.isNotEmpty(absolutePath) ?
absolutePath + "/" + subDirectory : subDirectory;
- boolean canPollMore = pollSubDirectory(path, subDirectory,
fileList, depth);
- if (!canPollMore) {
- return false;
+ if (endpoint.isRecursive() && depth < endpoint.getMaxDepth()) {
+ String absoluteFilePath =
FtpUtils.absoluteFilePath(absolutePath, file.getFilename());
+ Supplier<GenericFile<SftpRemoteFile>> remote
+ = Suppliers.memorize(
+ () -> asRemoteFile(absolutePath,
absoluteFilePath, file, getEndpoint().getCharset()));
+ Supplier<String> relativePath =
getRelativeFilePath(endpointPath, null, absolutePath, file);
+ if (isValidFile(remote, file.getFilename(),
absoluteFilePath, relativePath, true, files)) {
+ // recursive scan and add the sub files and folders
+ String subDirectory = file.getFilename();
+ String path = ObjectHelper.isNotEmpty(absolutePath) ?
absolutePath + "/" + subDirectory : subDirectory;
+ boolean canPollMore = pollSubDirectory(path,
subDirectory, fileList, depth);
+ if (!canPollMore) {
+ return false;
+ }
}
}
// we cannot use file.getAttrs().isLink on Windows, so we dont
// invoke the method
// just assuming its a file we should poll
} else {
- RemoteFile<SftpRemoteFile> remote = asRemoteFile(absolutePath,
file, getEndpoint().getCharset());
- if (depth >= endpoint.getMinDepth() && isValidFile(remote,
false, files)) {
- // matched file so add
- fileList.add(remote);
+ if (depth >= endpoint.getMinDepth()) {
+ String absoluteFilePath =
FtpUtils.absoluteFilePath(absolutePath, file.getFilename());
+ Supplier<GenericFile<SftpRemoteFile>> remote
+ = Suppliers.memorize(
+ () -> asRemoteFile(absolutePath,
absoluteFilePath, file, getEndpoint().getCharset()));
+ Supplier<String> relativePath =
getRelativeFilePath(endpointPath, null, absolutePath, file);
+ if (isValidFile(remote, file.getFilename(),
absoluteFilePath, relativePath, false, files)) {
+ // matched file so add
+ fileList.add(remote.get());
+ }
}
}
}
@@ -229,7 +243,7 @@ public class SftpConsumer extends
RemoteFileConsumer<SftpRemoteFile> {
}
@Override
- protected boolean isMatched(GenericFile<SftpRemoteFile> file, String
doneFileName, SftpRemoteFile[] files) {
+ protected boolean isMatched(Supplier<GenericFile<SftpRemoteFile>> file,
String doneFileName, SftpRemoteFile[] files) {
String onlyName = FileUtil.stripPath(doneFileName);
for (SftpRemoteFile f : files) {
@@ -253,7 +267,17 @@ public class SftpConsumer extends
RemoteFileConsumer<SftpRemoteFile> {
return super.ignoreCannotRetrieveFile(name, exchange, cause);
}
- private RemoteFile<SftpRemoteFile> asRemoteFile(String absolutePath,
SftpRemoteFile file, String charset) {
+ @Override
+ protected Supplier<String> getRelativeFilePath(String endpointPath, String
path, String absolutePath, SftpRemoteFile file) {
+ return () -> {
+ String relativePath = StringHelper.after(absolutePath,
endpointPath);
+ // skip trailing /
+ return FileUtil.stripLeadingSeparator(relativePath);
+ };
+ }
+
+ private RemoteFile<SftpRemoteFile> asRemoteFile(
+ String absolutePath, String absoluteFilePath, SftpRemoteFile file,
String charset) {
RemoteFile<SftpRemoteFile> answer = new RemoteFile<>();
answer.setCharset(charset);
@@ -268,19 +292,10 @@ public class SftpConsumer extends
RemoteFileConsumer<SftpRemoteFile> {
// absolute or relative path
boolean absolute = FileUtil.hasLeadingSeparator(absolutePath);
answer.setAbsolute(absolute);
-
- // create a pseudo absolute name
- String dir = FileUtil.stripTrailingSeparator(absolutePath);
- String absoluteFileName = FileUtil.stripLeadingSeparator(dir + "/" +
file.getFilename());
- // if absolute start with a leading separator otherwise let it be
- // relative
- if (absolute) {
- absoluteFileName = "/" + absoluteFileName;
- }
- answer.setAbsoluteFilePath(absoluteFileName);
+ answer.setAbsoluteFilePath(absoluteFilePath);
// the relative filename, skip the leading endpoint configured path
- String relativePath = StringHelper.after(absoluteFileName,
endpointPath);
+ String relativePath = StringHelper.after(absoluteFilePath,
endpointPath);
// skip trailing /
relativePath = FileUtil.stripLeadingSeparator(relativePath);
answer.setRelativeFilePath(relativePath);
diff --git
a/components/camel-ftp/src/test/java/org/apache/camel/component/file/remote/RemoteFileIgnoreDoPollErrorTest.java
b/components/camel-ftp/src/test/java/org/apache/camel/component/file/remote/RemoteFileIgnoreDoPollErrorTest.java
index 13afb717835..780d3d5f1a6 100644
---
a/components/camel-ftp/src/test/java/org/apache/camel/component/file/remote/RemoteFileIgnoreDoPollErrorTest.java
+++
b/components/camel-ftp/src/test/java/org/apache/camel/component/file/remote/RemoteFileIgnoreDoPollErrorTest.java
@@ -19,6 +19,7 @@ package org.apache.camel.component.file.remote;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
+import java.util.function.Supplier;
import org.apache.camel.CamelContext;
import org.apache.camel.Exchange;
@@ -128,7 +129,7 @@ public class RemoteFileIgnoreDoPollErrorTest {
}
@Override
- protected boolean isMatched(GenericFile<Object> file, String
doneFileName, Object[] files) {
+ protected boolean isMatched(Supplier<GenericFile<Object>> file,
String doneFileName, Object[] files) {
return false;
}
@@ -141,6 +142,11 @@ public class RemoteFileIgnoreDoPollErrorTest {
protected void updateFileHeaders(GenericFile<Object> genericFile,
Message message) {
// noop
}
+
+ @Override
+ protected Supplier<String> getRelativeFilePath(String
endpointPath, String path, String absolutePath, Object file) {
+ return null;
+ }
};
}
}
diff --git
a/components/camel-ftp/src/test/java/org/apache/camel/component/file/remote/sftp/integration/SftpMoveWithOutMessageTest.java
b/components/camel-ftp/src/test/java/org/apache/camel/component/file/remote/sftp/integration/SftpMoveWithOutMessageTest.java
index 1f01c1d386a..a529cc97cd8 100644
---
a/components/camel-ftp/src/test/java/org/apache/camel/component/file/remote/sftp/integration/SftpMoveWithOutMessageTest.java
+++
b/components/camel-ftp/src/test/java/org/apache/camel/component/file/remote/sftp/integration/SftpMoveWithOutMessageTest.java
@@ -24,6 +24,7 @@ import org.apache.camel.Processor;
import org.apache.camel.ProducerTemplate;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.support.DefaultMessage;
+import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.Timeout;
import org.junit.jupiter.api.condition.EnabledIf;
@@ -36,6 +37,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
* Test that the existence of a outMessage in an exchange will not break the
move-file post-processing
*/
@EnabledIf(value =
"org.apache.camel.test.infra.ftp.services.embedded.SftpUtil#hasRequiredAlgorithms('src/test/resources/hostkey.pem')")
+@Disabled
public class SftpMoveWithOutMessageTest extends SftpServerTestSupport {
@Timeout(value = 30)
diff --git
a/core/camel-core/src/test/java/org/apache/camel/component/file/FileConsumerFileFilterOptimizedTest.java
b/core/camel-core/src/test/java/org/apache/camel/component/file/FileConsumerFileFilterOptimizedTest.java
new file mode 100644
index 00000000000..5a879799e05
--- /dev/null
+++
b/core/camel-core/src/test/java/org/apache/camel/component/file/FileConsumerFileFilterOptimizedTest.java
@@ -0,0 +1,85 @@
+/*
+ * 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.apache.camel.spi.Registry;
+import org.junit.jupiter.api.Test;
+
+/**
+ * Unit test for the file filter option
+ */
+public class FileConsumerFileFilterOptimizedTest extends ContextTestSupport {
+
+ @Override
+ protected Registry createCamelRegistry() throws Exception {
+ Registry jndi = super.createCamelRegistry();
+ jndi.bind("myFilter", new MyFileFilter());
+ return jndi;
+ }
+
+ @Test
+ public void testFilterFiles() throws Exception {
+ MockEndpoint mock = getMockEndpoint("mock:result");
+ mock.expectedMessageCount(0);
+
+ template.sendBodyAndHeader(fileUri(), "This is a file to be filtered",
+ Exchange.FILE_NAME,
+ "skipme.txt");
+
+ mock.setResultWaitTime(100);
+ mock.assertIsSatisfied();
+ }
+
+ @Test
+ public void testFilterFilesWithARegularFile() throws Exception {
+ MockEndpoint mock = getMockEndpoint("mock:result");
+ mock.expectedBodiesReceived("Hello World");
+
+ template.sendBodyAndHeader(fileUri(), "This is a file to be filtered",
+ Exchange.FILE_NAME,
+ "skipme.txt");
+
+ template.sendBodyAndHeader(fileUri(), "Hello World",
Exchange.FILE_NAME,
+ "hello.txt");
+
+ mock.assertIsSatisfied();
+ }
+
+ @Override
+ protected RouteBuilder createRouteBuilder() {
+ return new RouteBuilder() {
+ public void configure() {
+ from(fileUri("?initialDelay=0&delay=10&filter=#myFilter"))
+ .convertBodyTo(String.class).to("mock:result");
+ }
+ };
+ }
+
+ public static class MyFileFilter implements OptimizedFileFilter {
+
+ @Override
+ public Boolean accept(String name) {
+ // we dont accept any files starting with skip in the name
+ return !name.startsWith("skip");
+ }
+ }
+
+}
diff --git
a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_10.adoc
b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_10.adoc
index c69e7440a40..58d4454ee7b 100644
--- a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_10.adoc
+++ b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_10.adoc
@@ -6,6 +6,17 @@ from both 4.0 to 4.1 and 4.1 to 4.2.
== Upgrading Camel 4.9 to 4.10
+=== camel-file
+
+The `camel-file` consumer has been optimized when filtering file names using
name matching only,
+to avoid creating an `GenericFile` object that represent the file. This is
unnessasary if the file
+is to be excluded due the filtering.
+
+This optimization has changed APIs in the `camel-file` component to let
methods that accept
+`GenericFile` as parameter, has been changed to use a `Supplier<GenericFile>`
to lazy create the wrapper.
+
+Camel users who have created 3rd party component extending `camel-file` may
need to migrate your components.
+
=== camel-jgroups
The cluster lock has been removed as it has been removed in JGroups 5.4
onwards, and it was