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&amp;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&amp;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": [

Reply via email to