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 31004ce515b5 CAMEL-25792: camel-file - poll and pollEnrich evaluate a
fileName without the file functions on the current message (#28087)
31004ce515b5 is described below
commit 31004ce515b5bd0ba24241b0889a4126b76a9692
Author: Claus Ibsen <[email protected]>
AuthorDate: Mon Oct 19 21:24:19 2026 +0200
CAMEL-25792: camel-file - poll and pollEnrich evaluate a fileName without
the file functions on the current message (#28087)
Co-authored-by: Claude Opus 5.5 (1M context) <[email protected]>
---
.../org/apache/camel/catalog/docs/poll-eip.adoc | 53 ++++++++++
.../apache/camel/catalog/docs/pollEnrich-eip.adoc | 64 ++++++++++++
.../camel/component/file/GenericFileConsumer.java | 49 ++++++++-
.../camel/component/file/GenericFileEndpoint.java | 21 ++++
.../integration/PollDynamicFileNameTest.java | 14 +++
.../src/main/docs/modules/eips/pages/poll-eip.adoc | 53 ++++++++++
.../docs/modules/eips/pages/pollEnrich-eip.adoc | 64 ++++++++++++
.../enricher/PollDynamicFileNameBodyTest.java | 113 +++++++++++++++++++++
.../ROOT/pages/camel-4x-upgrade-guide-4_24.adoc | 10 ++
.../dsl/jbang/core/commands/ai/eip-samples.json | 8 ++
10 files changed, 446 insertions(+), 3 deletions(-)
diff --git
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/poll-eip.adoc
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/poll-eip.adoc
index f29e63ad8d7c..641f37cdece3 100644
---
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/poll-eip.adoc
+++
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/poll-eip.adoc
@@ -205,6 +205,59 @@ and then `poll` or `pollEnrich` will then pick the top
file after the sorting.
This improves performance for use-cases without need for sorting first.
+==== The file name of a dynamic uri
+
+With the file based components (file, ftp, ftps, sftp, smb and azure-files),
Camel reuses one endpoint for every
+message, and the consumer evaluates the `fileName` option when it looks for
the file:
+
+* A `fileName` that uses the file functions, such as `${file:onlyname.noext}`
or `${date:file:yyyyMMdd}`, is evaluated
+ for each file found, as these functions read that file.
+* Any other `fileName` is evaluated on the current message: its body, headers,
variables and exchange properties.
+
+For example, the body is the name of the report to download:
+
+[tabs]
+====
+Java::
++
+[source,java]
+----
+from("direct:report")
+ .poll("ftp:myserver.com/myfolder?fileName=${body}");
+----
+
+XML::
++
+[source,xml]
+----
+<route>
+ <from uri="direct:report"/>
+ <poll uri="ftp:myserver.com/myfolder?fileName=${body}"/>
+</route>
+----
+
+YAML::
++
+[source,yaml]
+----
+- route:
+ from:
+ uri: direct:report
+ steps:
+ - poll:
+ uri: ftp:myserver.com/myfolder
+ parameters:
+ fileName: "${body}"
+----
+====
+
+NOTE: Before Camel 4.24, `+${body}+` in the `fileName` was the file found, not
the current message, and only the
+headers, variables and exchange properties of the message could be used. With
an older version, put the value in a
+header or a variable first.
+
+To evaluate the whole uri on the message instead, with an endpoint for each
file name, set `allowOptimisedComponents` to
+`false`.
+
== See More
- xref:poll-eip.adoc[Poll EIP]
diff --git
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/pollEnrich-eip.adoc
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/pollEnrich-eip.adoc
index 2ad4c0890e0a..ebb8726bc2cb 100644
---
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/pollEnrich-eip.adoc
+++
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/pollEnrich-eip.adoc
@@ -321,6 +321,70 @@ and then `poll` or `pollEnrich` will then pick the top
file after the sorting.
This improves performance for use-cases without need for sorting first.
+==== The file name of a dynamic uri
+
+With the file based components (file, ftp, ftps, sftp, smb and azure-files),
Camel reuses one endpoint for every
+message, and the consumer evaluates the `fileName` option when it looks for
the file:
+
+* A `fileName` that uses the file functions, such as `${file:onlyname.noext}`
or `${date:file:yyyyMMdd}`, is evaluated
+ for each file found, as these functions read that file.
+* Any other `fileName` is evaluated on the message being enriched: its body,
headers, variables and exchange
+ properties.
+
+For example, the body is an order as a Map, and the route reads the file of
its customer into the variable `customer`,
+so the order stays the body:
+
+[tabs]
+====
+Java::
++
+[source,java]
+----
+from("direct:order")
+
.pollEnrich().simple("file:customers?fileName=${body[customer]}.json&noop=true")
+ .timeout(5000).variableReceive("customer")
+ .log("Order ${body[orderId]} for customer ${variable.customer}");
+----
+
+XML::
++
+[source,xml]
+----
+<route>
+ <from uri="direct:order"/>
+ <pollEnrich timeout="5000" variableReceive="customer">
+
<simple>file:customers?fileName=${body[customer]}.json&noop=true</simple>
+ </pollEnrich>
+ <log message="Order ${body[orderId]} for customer ${variable.customer}"/>
+</route>
+----
+
+YAML::
++
+[source,yaml]
+----
+- route:
+ from:
+ uri: direct:order
+ steps:
+ - pollEnrich:
+ expression:
+ simple:
+ expression:
"file:customers?fileName=${body[customer]}.json&noop=true"
+ timeout: 5000
+ variableReceive: customer
+ - log:
+ message: "Order ${body[orderId]} for customer ${variable.customer}"
+----
+====
+
+NOTE: Before Camel 4.24, `+${body}+` in the `fileName` was the file found, not
the message being enriched, and only the
+headers, variables and exchange properties of the message could be used. With
an older version, put the value in a
+header or a variable first.
+
+To evaluate the whole uri on the message instead, with an endpoint for each
file name, set `allowOptimisedComponents` to
+`false`.
+
== See More
- xref:poll-eip.adoc[Poll EIP]
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 f26f005fcffa..8f93f07a20a6 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
@@ -58,6 +58,10 @@ public abstract class GenericFileConsumer<T> extends
ScheduledBatchPollingConsum
protected GenericFileOperations<T> operations;
protected GenericFileProcessStrategy<T> processStrategy;
protected volatile ShutdownRunningTask shutdownRunningTask;
+ // the fileName of the message that poll or pollEnrich polls for, during
that poll (CAMEL-25792). Parallel pollEnrich
+ // calls can share this consumer, so the value may belong to another
exchange: isMatched() then evaluates the
+ // fileName itself, and the cache only saves work
+ private volatile DynamicFileName dynamicFileName;
protected volatile int pendingExchanges;
protected Processor customProcessor;
protected boolean eagerLimitMaxMessagesPerPoll = true;
@@ -130,6 +134,23 @@ public abstract class GenericFileConsumer<T> extends
ScheduledBatchPollingConsum
*/
@Override
protected int poll(Exchange dynamic) throws Exception {
+ if (dynamic == null || endpoint.getFileName() == null ||
endpoint.isFileNameUsingFileFunctions()) {
+ return doPoll(dynamic);
+ }
+ // poll and pollEnrich: a fileName without the file functions is about
the message being enriched, not the
+ // file found, so it is evaluated once for this poll on a copy of that
message (CAMEL-25792)
+ DynamicFileName current = new DynamicFileName(dynamic,
evaluateDynamicFileName(dynamic));
+ dynamicFileName = current;
+ try {
+ return doPoll(dynamic);
+ } finally {
+ if (dynamicFileName == current) {
+ dynamicFileName = null;
+ }
+ }
+ }
+
+ private int doPoll(Exchange dynamic) throws Exception {
// must prepare on startup the very first time
if (!prepareOnStartup) {
// prepare on startup
@@ -966,9 +987,17 @@ public abstract class GenericFileConsumer<T> extends
ScheduledBatchPollingConsum
}
if (endpoint.getFileName() != null) {
- // create a dummy exchange as Exchange is needed for expression
evaluation
- Exchange dummy = GenericFileHelper.createDummy(endpoint, dynamic,
file);
- String result = evaluateFileExpression(dummy);
+ String result;
+ if (dynamic != null && !endpoint.isFileNameUsingFileFunctions()) {
+ // poll and pollEnrich: the fileName of the message being
enriched (CAMEL-25792)
+ DynamicFileName current = dynamicFileName;
+ result = current != null && current.exchange() == dynamic
+ ? current.name() : evaluateDynamicFileName(dynamic);
+ } else {
+ // create a dummy exchange as Exchange is needed for
expression evaluation
+ Exchange dummy = GenericFileHelper.createDummy(endpoint,
dynamic, file);
+ result = evaluateFileExpression(dummy);
+ }
if (result != null) {
if (!name.equals(result)) {
return false;
@@ -1066,6 +1095,20 @@ public abstract class GenericFileConsumer<T> extends
ScheduledBatchPollingConsum
*/
protected abstract boolean isMatched(Supplier<GenericFile<T>> file, String
doneFileName, T[] files);
+ /**
+ * The fileName evaluated on a copy of the message being enriched by poll
or pollEnrich: its body, headers,
+ * variables and exchange properties, without the file found (CAMEL-25792).
+ */
+ private String evaluateDynamicFileName(Exchange dynamic) {
+ Exchange copy = GenericFileHelper.createDummy(endpoint, dynamic);
+ copy.getMessage().setBody(dynamic.getMessage().getBody());
+ return evaluateFileExpression(copy);
+ }
+
+ /** The fileName of the message being enriched, for the poll of that
message. */
+ private record DynamicFileName(Exchange exchange, String name) {
+ }
+
protected String evaluateFileExpression(Exchange exchange) {
String result = endpoint.getFileName().evaluate(exchange,
String.class);
if (exchange.getException() != null) {
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 e8a50e83bf49..c78fd9cf5516 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
@@ -61,6 +61,11 @@ public abstract class GenericFileEndpoint<T> extends
ScheduledPollEndpoint imple
protected static final int DEFAULT_IN_PROGRESS_CACHE_SIZE = 50000;
private static final Logger LOG =
LoggerFactory.getLogger(GenericFileEndpoint.class);
+ /**
+ * The file functions of the File Language, which read the file found:
${file:name}, ${date:file:yyyyMMdd},
+ * ${date-with-timezone:file:yyyyMMdd z}, and the same as
$simple{file:name}.
+ */
+ private static final Pattern FILE_FUNCTION =
Pattern.compile("\\$(simple)?\\{(date(-with-timezone)?:)?file:");
// common options
@@ -90,6 +95,9 @@ public abstract class GenericFileEndpoint<T> extends
ScheduledPollEndpoint imple
+ "CamelFileName
header; the CamelOverruleFileName is a header that is used only once, and makes
it easier "
+ "as this avoids
to temporary store CamelFileName and have to restore it afterwards.")
protected Expression fileName;
+ // whether the fileName uses the file functions: poll and pollEnrich then
evaluate it for each file found, else on the
+ // message they enrich (CAMEL-25792)
+ private boolean fileNameUsesFileFunctions = true;
@UriParam(description = "Producer: If provided, then Camel will write a
2nd done file when the original file has "
+ "been written. The done file will be empty. This
option configures what file name to use. Either you can "
+ "specify a fixed name. Or you can use dynamic
placeholders. The done file will always be written in the "
@@ -914,10 +922,23 @@ public abstract class GenericFileEndpoint<T> extends
ScheduledPollEndpoint imple
*/
public void setFileName(Expression fileName) {
this.fileName = fileName;
+ // what an expression object reads is unknown, so poll and pollEnrich
evaluate it for each file found as before
+ this.fileNameUsesFileFunctions = true;
}
public void setFileName(String fileLanguageExpression) {
this.fileName = createFileLanguageExpression(fileLanguageExpression);
+ this.fileNameUsesFileFunctions
+ = fileLanguageExpression != null &&
FILE_FUNCTION.matcher(fileLanguageExpression).find();
+ }
+
+ /**
+ * Whether the fileName uses the file functions of the File Language, such
as ${file:name}, which read the file
+ * found. Poll and pollEnrich evaluate such a fileName for each file
found, and any other on the message they enrich
+ * (CAMEL-25792).
+ */
+ boolean isFileNameUsingFileFunctions() {
+ return fileNameUsesFileFunctions;
}
public String getDoneFileName() {
diff --git
a/components/camel-ftp/src/test/java/org/apache/camel/component/file/remote/integration/PollDynamicFileNameTest.java
b/components/camel-ftp/src/test/java/org/apache/camel/component/file/remote/integration/PollDynamicFileNameTest.java
index ff8e5abf473b..9ae528b0b813 100644
---
a/components/camel-ftp/src/test/java/org/apache/camel/component/file/remote/integration/PollDynamicFileNameTest.java
+++
b/components/camel-ftp/src/test/java/org/apache/camel/component/file/remote/integration/PollDynamicFileNameTest.java
@@ -73,6 +73,16 @@ public class PollDynamicFileNameTest extends
FtpServerTestSupport {
Assertions.assertEquals(1, c, "There should only be 1 ftp endpoint");
}
+ @Test
+ public void testPollFileNameFromBody() throws Exception {
+ // CAMEL-25792: a fileName without the file functions is evaluated on
the message, so ${body} is its body
+ getMockEndpoint("mock:body").expectedBodiesReceived("Hello World");
+
+ template.sendBody("direct:body", "myfile.txt");
+
+ MockEndpoint.assertIsSatisfied(context);
+ }
+
private void prepareFtpServer() throws Exception {
// prepares the FTP Server by creating a file on the server that we
want
// to unit test that we can pool and store as a local file
@@ -99,6 +109,10 @@ public class PollDynamicFileNameTest extends
FtpServerTestSupport {
from("direct:start")
.poll(getFtpUrl() + "&fileName=${header.target}", 2000)
.to("mock:result");
+
+ from("direct:body")
+ .poll(getFtpUrl() + "&fileName=${body}", 2000)
+ .to("mock:body");
}
};
}
diff --git
a/core/camel-core-engine/src/main/docs/modules/eips/pages/poll-eip.adoc
b/core/camel-core-engine/src/main/docs/modules/eips/pages/poll-eip.adoc
index f29e63ad8d7c..641f37cdece3 100644
--- a/core/camel-core-engine/src/main/docs/modules/eips/pages/poll-eip.adoc
+++ b/core/camel-core-engine/src/main/docs/modules/eips/pages/poll-eip.adoc
@@ -205,6 +205,59 @@ and then `poll` or `pollEnrich` will then pick the top
file after the sorting.
This improves performance for use-cases without need for sorting first.
+==== The file name of a dynamic uri
+
+With the file based components (file, ftp, ftps, sftp, smb and azure-files),
Camel reuses one endpoint for every
+message, and the consumer evaluates the `fileName` option when it looks for
the file:
+
+* A `fileName` that uses the file functions, such as `${file:onlyname.noext}`
or `${date:file:yyyyMMdd}`, is evaluated
+ for each file found, as these functions read that file.
+* Any other `fileName` is evaluated on the current message: its body, headers,
variables and exchange properties.
+
+For example, the body is the name of the report to download:
+
+[tabs]
+====
+Java::
++
+[source,java]
+----
+from("direct:report")
+ .poll("ftp:myserver.com/myfolder?fileName=${body}");
+----
+
+XML::
++
+[source,xml]
+----
+<route>
+ <from uri="direct:report"/>
+ <poll uri="ftp:myserver.com/myfolder?fileName=${body}"/>
+</route>
+----
+
+YAML::
++
+[source,yaml]
+----
+- route:
+ from:
+ uri: direct:report
+ steps:
+ - poll:
+ uri: ftp:myserver.com/myfolder
+ parameters:
+ fileName: "${body}"
+----
+====
+
+NOTE: Before Camel 4.24, `+${body}+` in the `fileName` was the file found, not
the current message, and only the
+headers, variables and exchange properties of the message could be used. With
an older version, put the value in a
+header or a variable first.
+
+To evaluate the whole uri on the message instead, with an endpoint for each
file name, set `allowOptimisedComponents` to
+`false`.
+
== See More
- xref:poll-eip.adoc[Poll EIP]
diff --git
a/core/camel-core-engine/src/main/docs/modules/eips/pages/pollEnrich-eip.adoc
b/core/camel-core-engine/src/main/docs/modules/eips/pages/pollEnrich-eip.adoc
index 2ad4c0890e0a..ebb8726bc2cb 100644
---
a/core/camel-core-engine/src/main/docs/modules/eips/pages/pollEnrich-eip.adoc
+++
b/core/camel-core-engine/src/main/docs/modules/eips/pages/pollEnrich-eip.adoc
@@ -321,6 +321,70 @@ and then `poll` or `pollEnrich` will then pick the top
file after the sorting.
This improves performance for use-cases without need for sorting first.
+==== The file name of a dynamic uri
+
+With the file based components (file, ftp, ftps, sftp, smb and azure-files),
Camel reuses one endpoint for every
+message, and the consumer evaluates the `fileName` option when it looks for
the file:
+
+* A `fileName` that uses the file functions, such as `${file:onlyname.noext}`
or `${date:file:yyyyMMdd}`, is evaluated
+ for each file found, as these functions read that file.
+* Any other `fileName` is evaluated on the message being enriched: its body,
headers, variables and exchange
+ properties.
+
+For example, the body is an order as a Map, and the route reads the file of
its customer into the variable `customer`,
+so the order stays the body:
+
+[tabs]
+====
+Java::
++
+[source,java]
+----
+from("direct:order")
+
.pollEnrich().simple("file:customers?fileName=${body[customer]}.json&noop=true")
+ .timeout(5000).variableReceive("customer")
+ .log("Order ${body[orderId]} for customer ${variable.customer}");
+----
+
+XML::
++
+[source,xml]
+----
+<route>
+ <from uri="direct:order"/>
+ <pollEnrich timeout="5000" variableReceive="customer">
+
<simple>file:customers?fileName=${body[customer]}.json&noop=true</simple>
+ </pollEnrich>
+ <log message="Order ${body[orderId]} for customer ${variable.customer}"/>
+</route>
+----
+
+YAML::
++
+[source,yaml]
+----
+- route:
+ from:
+ uri: direct:order
+ steps:
+ - pollEnrich:
+ expression:
+ simple:
+ expression:
"file:customers?fileName=${body[customer]}.json&noop=true"
+ timeout: 5000
+ variableReceive: customer
+ - log:
+ message: "Order ${body[orderId]} for customer ${variable.customer}"
+----
+====
+
+NOTE: Before Camel 4.24, `+${body}+` in the `fileName` was the file found, not
the message being enriched, and only the
+headers, variables and exchange properties of the message could be used. With
an older version, put the value in a
+header or a variable first.
+
+To evaluate the whole uri on the message instead, with an endpoint for each
file name, set `allowOptimisedComponents` to
+`false`.
+
== See More
- xref:poll-eip.adoc[Poll EIP]
diff --git
a/core/camel-core/src/test/java/org/apache/camel/processor/enricher/PollDynamicFileNameBodyTest.java
b/core/camel-core/src/test/java/org/apache/camel/processor/enricher/PollDynamicFileNameBodyTest.java
new file mode 100644
index 000000000000..77e6638d8557
--- /dev/null
+++
b/core/camel-core/src/test/java/org/apache/camel/processor/enricher/PollDynamicFileNameBodyTest.java
@@ -0,0 +1,113 @@
+/*
+ * 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.processor.enricher;
+
+import java.util.Map;
+
+import org.apache.camel.ContextTestSupport;
+import org.apache.camel.Exchange;
+import org.apache.camel.builder.RouteBuilder;
+import org.junit.jupiter.api.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * CAMEL-25792: poll and pollEnrich evaluate a fileName without the file
functions on the message being enriched, so
+ * ${body} is its body and not the file found. A fileName with the file
functions is still evaluated for each file
+ * found.
+ */
+class PollDynamicFileNameBodyTest extends ContextTestSupport {
+
+ @Test
+ void testFileNameFromBody() throws Exception {
+ getMockEndpoint("mock:body").expectedMessageCount(2);
+ getMockEndpoint("mock:body").message(0).body().isEqualTo("Hello
World");
+ getMockEndpoint("mock:body").message(1).body().isNull();
+
+ template.sendBodyAndHeader(fileUri(), "Hello World",
Exchange.FILE_NAME, "myfile.txt");
+ template.sendBody("direct:body", "myfile.txt");
+ template.sendBody("direct:body", "unknown.txt");
+
+ assertMockEndpointsSatisfied();
+ long c = context.getEndpoints().stream()
+ .filter(e -> e.getEndpointKey().startsWith("file") &&
e.getEndpointUri().contains("?fileName=")).count();
+ assertThat(c).as("Optimized: should reuse a single file
endpoint").isEqualTo(1);
+ }
+
+ @Test
+ void testFileNameFromAKeyOfTheBody() throws Exception {
+ getMockEndpoint("mock:map").expectedBodiesReceived("Hello World");
+
+ template.sendBodyAndHeader(fileUri(), "Hello World",
Exchange.FILE_NAME, "C-482.json");
+ template.sendBody("direct:map", Map.of("orderId", "ORD-1001",
"customer", "C-482"));
+
+ assertMockEndpointsSatisfied();
+ }
+
+ @Test
+ void testFileNameFromVariable() throws Exception {
+ getMockEndpoint("mock:variable").expectedBodiesReceived("Hello World");
+
+ template.sendBodyAndHeader(fileUri(), "Hello World",
Exchange.FILE_NAME, "myfile.txt");
+ template.send("direct:variable", e -> {
+ e.getMessage().setBody("Foo");
+ e.setVariable("target", "myfile.txt");
+ });
+
+ assertMockEndpointsSatisfied();
+ }
+
+ @Test
+ void testFileFunctionsReadTheFileFound() throws Exception {
+ getMockEndpoint("mock:file").expectedBodiesReceived("Hello World");
+
+ template.sendBodyAndHeader(fileUri(), "Bye World", Exchange.FILE_NAME,
"data.csv");
+ template.sendBodyAndHeader(fileUri(), "Hello World",
Exchange.FILE_NAME, "myfile.txt");
+ template.sendBody("direct:file", "Foo");
+
+ assertMockEndpointsSatisfied();
+ }
+
+ @Override
+ protected RouteBuilder createRouteBuilder() {
+ return new RouteBuilder() {
+ @Override
+ public void configure() {
+ from("direct:body")
+ .pollEnrich().simple(fileUri() +
"?noop=true&fileName=${body}")
+ .timeout(500)
+ .to("mock:body");
+
+ from("direct:map")
+ .pollEnrich().simple(fileUri() +
"?noop=true&fileName=${body[customer]}.json")
+ .timeout(500)
+ .to("mock:map");
+
+ from("direct:variable")
+ .pollEnrich().simple(fileUri() +
"?noop=true&fileName=${variable.target}")
+ .timeout(500)
+ .to("mock:variable");
+
+ // the name of each file found with the .txt extension: only
myfile.txt matches
+ from("direct:file")
+ .pollEnrich().simple(fileUri() +
"?noop=true&fileName=${file:onlyname.noext}.txt")
+ .timeout(500)
+ .to("mock:file");
+ }
+ };
+ }
+}
diff --git
a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_24.adoc
b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_24.adoc
index f73972ebe986..6045480f4d23 100644
--- a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_24.adoc
+++ b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_24.adoc
@@ -217,6 +217,16 @@ also applies to `pollEnrich` and
`ConsumerTemplate.receive`, which take one file
until the last file of the directory is received, where before the first
received file deleted it. This applies to
camel-ftp, camel-sftp, camel-smb and camel-azure-files as well.
+=== camel-file - poll and pollEnrich evaluate the fileName on the current
message
+
+`poll` and `pollEnrich` with a file based component (file, ftp, ftps, sftp,
smb and azure-files) evaluate a dynamic
+`fileName` that does not use the file functions on the current message, so
`+fileName=${body}+` and
+`fileName=${body[customer]}.json` read its body. Before, the consumer
evaluated it for each file found, with that file
+as the body, so `+${body}+` was the file found. A `fileName` that uses the
file functions (`${file:...}`,
+`${date:file:...}`) is still evaluated for each file found, and headers,
variables and exchange properties work as
+before. A `fileName` that read the file found through its headers, such as
`${header.CamelFileName}`, must use the file
+functions instead (`${file:name}`).
+
=== camel-pqc - an unknown hybridKdfAlgorithm is rejected
The hybrid KEM operations now fail with an `IllegalArgumentException` when
`hybridKdfAlgorithm` is not one of
diff --git
a/dsl/camel-jbang/camel-jbang-core/src/generated/resources/org/apache/camel/dsl/jbang/core/commands/ai/eip-samples.json
b/dsl/camel-jbang/camel-jbang-core/src/generated/resources/org/apache/camel/dsl/jbang/core/commands/ai/eip-samples.json
index c8a033a3242a..e3e762268884 100644
---
a/dsl/camel-jbang/camel-jbang-core/src/generated/resources/org/apache/camel/dsl/jbang/core/commands/ai/eip-samples.json
+++
b/dsl/camel-jbang/camel-jbang-core/src/generated/resources/org/apache/camel/dsl/jbang/core/commands/ai/eip-samples.json
@@ -857,6 +857,10 @@
{
"source": "poll-eip.adoc",
"yaml": "- rest:\n path: \/report\n get:\n - path:
\/{id}\/payload\n to:\n uri: direct:payload\n- route:\n
from:\n uri: direct:payload\n steps:\n - poll:\n
uri: aws-s3:xavier-dev\n parameters:\n amazonS3Client:
\"#s3client\"\n deleteAfterRead: false\n fileName:
report-file.pdf\n"
+ },
+ {
+ "source": "poll-eip.adoc",
+ "yaml": "- route:\n from:\n uri: direct:report\n steps:\n
- poll:\n uri: ftp:myserver.com\/myfolder\n
parameters:\n fileName: \"${body}\"\n"
}
],
"pollEnrich": [
@@ -875,6 +879,10 @@
{
"source": "pollEnrich-eip.adoc",
"yaml": "- rest:\n path: \/report\n get:\n - path:
\/{id}\/report\n to:\n uri: direct:report\n\n- route:\n
from:\n uri: direct:report\n steps:\n - pollEnrich:\n
expression:\n constant:\n expression:
\"aws-s3:xavier-dev?amazonS3Client=#s3client&deleteAfterRead=false&fileName=report-file.pdf\"\n"
+ },
+ {
+ "source": "pollEnrich-eip.adoc",
+ "yaml": "- route:\n from:\n uri: direct:order\n steps:\n
- pollEnrich:\n expression:\n simple:\n
expression: \"file:customers?fileName=${body[customer]}.json&noop=true\"\n
timeout: 5000\n variableReceive: customer\n - log:\n
message: \"Order ${body[orderId]} for customer
${variable.customer}\"\n"
}
],
"process": [