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 f633c6fcbcd CAMEL-21728: Loop EIP to have onPrepare processor (#17081)
f633c6fcbcd is described below

commit f633c6fcbcdfe63ad4fc3f4d051c6a379fdd1c24
Author: Claus Ibsen <[email protected]>
AuthorDate: Thu Feb 6 10:22:40 2025 +0100

    CAMEL-21728: Loop EIP to have onPrepare processor (#17081)
    
    * CAMEL-21728: Loop EIP to have onPrepare processor
---
 .../org/apache/camel/catalog/models/loop.json      |  3 +-
 .../apache/camel/catalog/schemas/camel-spring.xsd  | 10 ++++
 .../META-INF/org/apache/camel/model/loop.json      |  3 +-
 .../org/apache/camel/model/LoopDefinition.java     | 46 ++++++++++++++++
 .../org/apache/camel/processor/LoopProcessor.java  | 18 +++++--
 .../java/org/apache/camel/reifier/LoopReifier.java |  6 ++-
 .../apache/camel/processor/LoopOnPrepareTest.java  | 62 ++++++++++++++++++++++
 .../api/management/mbean/ManagedLoopMBean.java     |  3 ++
 .../apache/camel/management/mbean/ManagedLoop.java |  5 ++
 .../java/org/apache/camel/xml/in/ModelParser.java  |  1 +
 .../java/org/apache/camel/xml/out/ModelWriter.java |  1 +
 .../org/apache/camel/yaml/out/ModelWriter.java     |  1 +
 .../dsl/yaml/deserializers/ModelDeserializers.java |  6 +++
 .../generated/resources/schema/camelYamlDsl.json   |  5 ++
 14 files changed, 163 insertions(+), 7 deletions(-)

diff --git 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/loop.json
 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/loop.json
index 78bf0db166d..f89a70df2de 100644
--- 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/loop.json
+++ 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/loop.json
@@ -19,7 +19,8 @@
     "copy": { "index": 4, "kind": "attribute", "displayName": "Copy", "group": 
"advanced", "label": "advanced", "required": false, "type": "boolean", 
"javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, 
"secret": false, "defaultValue": false, "description": "If the copy attribute 
is true, a copy of the input Exchange is used for each iteration. That means 
each iteration will start from a copy of the same message. By default loop will 
loop the same exchange all over,  [...]
     "doWhile": { "index": 5, "kind": "attribute", "displayName": "Do While", 
"group": "advanced", "label": "advanced", "required": false, "type": "boolean", 
"javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, 
"secret": false, "defaultValue": false, "description": "Enables the while loop 
that loops until the predicate evaluates to false or null." },
     "breakOnShutdown": { "index": 6, "kind": "attribute", "displayName": 
"Break On Shutdown", "group": "advanced", "label": "advanced", "required": 
false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, 
"autowired": false, "secret": false, "defaultValue": false, "description": "If 
the breakOnShutdown attribute is true, then the loop will not iterate until it 
reaches the end when Camel is shut down." },
-    "outputs": { "index": 7, "kind": "element", "displayName": "Outputs", 
"group": "common", "required": true, "type": "array", "javaType": 
"java.util.List<org.apache.camel.model.ProcessorDefinition<java.lang.Object>>", 
"oneOf": [ "aggregate", "bean", "choice", "circuitBreaker", "claimCheck", 
"convertBodyTo", "convertHeaderTo", "convertVariableTo", "delay", "doCatch", 
"doFinally", "doTry", "dynamicRouter", "enrich", "filter", 
"idempotentConsumer", "intercept", "interceptFrom", "intercept [...]
+    "onPrepare": { "index": 7, "kind": "attribute", "displayName": "On 
Prepare", "group": "advanced", "label": "advanced", "required": false, "type": 
"object", "javaType": "org.apache.camel.Processor", "deprecated": false, 
"autowired": false, "secret": false, "description": "Uses the Processor when 
preparing the org.apache.camel.Exchange for each loop iteration. This can be 
used to deep-clone messages, or any custom logic needed before the looping 
executes." },
+    "outputs": { "index": 8, "kind": "element", "displayName": "Outputs", 
"group": "common", "required": true, "type": "array", "javaType": 
"java.util.List<org.apache.camel.model.ProcessorDefinition<java.lang.Object>>", 
"oneOf": [ "aggregate", "bean", "choice", "circuitBreaker", "claimCheck", 
"convertBodyTo", "convertHeaderTo", "convertVariableTo", "delay", "doCatch", 
"doFinally", "doTry", "dynamicRouter", "enrich", "filter", 
"idempotentConsumer", "intercept", "interceptFrom", "intercept [...]
   },
   "exchangeProperties": {
     "CamelLoopIndex": { "index": 0, "kind": "exchangeProperty", "displayName": 
"Loop Index", "label": "producer", "required": false, "javaType": "int", 
"deprecated": false, "autowired": false, "secret": false, "description": "Index 
of the current iteration (0 based)." },
diff --git 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/schemas/camel-spring.xsd
 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/schemas/camel-spring.xsd
index 40197d0c90d..06008c197e7 100644
--- 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/schemas/camel-spring.xsd
+++ 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/schemas/camel-spring.xsd
@@ -7438,6 +7438,16 @@ Enables the while loop that loops until the predicate 
evaluates to false or null
 <![CDATA[
 If the breakOnShutdown attribute is true, then the loop will not iterate until 
it reaches the end when Camel is shut
 down. Default value: false
+]]>
+            </xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="onPrepare" type="xs:string">
+          <xs:annotation>
+            <xs:documentation xml:lang="en">
+<![CDATA[
+Uses the Processor when preparing the org.apache.camel.Exchange for each loop 
iteration. This can be used to deep-clone
+messages, or any custom logic needed before the looping executes.
 ]]>
             </xs:documentation>
           </xs:annotation>
diff --git 
a/core/camel-core-model/src/generated/resources/META-INF/org/apache/camel/model/loop.json
 
b/core/camel-core-model/src/generated/resources/META-INF/org/apache/camel/model/loop.json
index 78bf0db166d..f89a70df2de 100644
--- 
a/core/camel-core-model/src/generated/resources/META-INF/org/apache/camel/model/loop.json
+++ 
b/core/camel-core-model/src/generated/resources/META-INF/org/apache/camel/model/loop.json
@@ -19,7 +19,8 @@
     "copy": { "index": 4, "kind": "attribute", "displayName": "Copy", "group": 
"advanced", "label": "advanced", "required": false, "type": "boolean", 
"javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, 
"secret": false, "defaultValue": false, "description": "If the copy attribute 
is true, a copy of the input Exchange is used for each iteration. That means 
each iteration will start from a copy of the same message. By default loop will 
loop the same exchange all over,  [...]
     "doWhile": { "index": 5, "kind": "attribute", "displayName": "Do While", 
"group": "advanced", "label": "advanced", "required": false, "type": "boolean", 
"javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, 
"secret": false, "defaultValue": false, "description": "Enables the while loop 
that loops until the predicate evaluates to false or null." },
     "breakOnShutdown": { "index": 6, "kind": "attribute", "displayName": 
"Break On Shutdown", "group": "advanced", "label": "advanced", "required": 
false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, 
"autowired": false, "secret": false, "defaultValue": false, "description": "If 
the breakOnShutdown attribute is true, then the loop will not iterate until it 
reaches the end when Camel is shut down." },
-    "outputs": { "index": 7, "kind": "element", "displayName": "Outputs", 
"group": "common", "required": true, "type": "array", "javaType": 
"java.util.List<org.apache.camel.model.ProcessorDefinition<java.lang.Object>>", 
"oneOf": [ "aggregate", "bean", "choice", "circuitBreaker", "claimCheck", 
"convertBodyTo", "convertHeaderTo", "convertVariableTo", "delay", "doCatch", 
"doFinally", "doTry", "dynamicRouter", "enrich", "filter", 
"idempotentConsumer", "intercept", "interceptFrom", "intercept [...]
+    "onPrepare": { "index": 7, "kind": "attribute", "displayName": "On 
Prepare", "group": "advanced", "label": "advanced", "required": false, "type": 
"object", "javaType": "org.apache.camel.Processor", "deprecated": false, 
"autowired": false, "secret": false, "description": "Uses the Processor when 
preparing the org.apache.camel.Exchange for each loop iteration. This can be 
used to deep-clone messages, or any custom logic needed before the looping 
executes." },
+    "outputs": { "index": 8, "kind": "element", "displayName": "Outputs", 
"group": "common", "required": true, "type": "array", "javaType": 
"java.util.List<org.apache.camel.model.ProcessorDefinition<java.lang.Object>>", 
"oneOf": [ "aggregate", "bean", "choice", "circuitBreaker", "claimCheck", 
"convertBodyTo", "convertHeaderTo", "convertVariableTo", "delay", "doCatch", 
"doFinally", "doTry", "dynamicRouter", "enrich", "filter", 
"idempotentConsumer", "intercept", "interceptFrom", "intercept [...]
   },
   "exchangeProperties": {
     "CamelLoopIndex": { "index": 0, "kind": "exchangeProperty", "displayName": 
"Loop Index", "label": "producer", "required": false, "javaType": "int", 
"deprecated": false, "autowired": false, "secret": false, "description": "Index 
of the current iteration (0 based)." },
diff --git 
a/core/camel-core-model/src/main/java/org/apache/camel/model/LoopDefinition.java
 
b/core/camel-core-model/src/main/java/org/apache/camel/model/LoopDefinition.java
index 8877314e31b..30d0f3f5428 100644
--- 
a/core/camel-core-model/src/main/java/org/apache/camel/model/LoopDefinition.java
+++ 
b/core/camel-core-model/src/main/java/org/apache/camel/model/LoopDefinition.java
@@ -20,9 +20,11 @@ import jakarta.xml.bind.annotation.XmlAccessType;
 import jakarta.xml.bind.annotation.XmlAccessorType;
 import jakarta.xml.bind.annotation.XmlAttribute;
 import jakarta.xml.bind.annotation.XmlRootElement;
+import jakarta.xml.bind.annotation.XmlTransient;
 
 import org.apache.camel.Expression;
 import org.apache.camel.Predicate;
+import org.apache.camel.Processor;
 import org.apache.camel.model.language.ExpressionDefinition;
 import org.apache.camel.spi.Metadata;
 
@@ -34,6 +36,9 @@ import org.apache.camel.spi.Metadata;
 @XmlAccessorType(XmlAccessType.FIELD)
 public class LoopDefinition extends OutputExpressionNode {
 
+    @XmlTransient
+    private Processor onPrepareProcessor;
+
     @XmlAttribute
     @Metadata(label = "advanced", javaType = "java.lang.Boolean")
     private String copy;
@@ -43,6 +48,9 @@ public class LoopDefinition extends OutputExpressionNode {
     @XmlAttribute
     @Metadata(label = "advanced", javaType = "java.lang.Boolean")
     private String breakOnShutdown;
+    @XmlAttribute
+    @Metadata(label = "advanced", javaType = "org.apache.camel.Processor")
+    private String onPrepare;
 
     public LoopDefinition() {
     }
@@ -52,6 +60,8 @@ public class LoopDefinition extends OutputExpressionNode {
         this.copy = source.copy;
         this.doWhile = source.doWhile;
         this.breakOnShutdown = source.breakOnShutdown;
+        this.onPrepareProcessor = source.onPrepareProcessor;
+        this.onPrepare = source.onPrepare;
     }
 
     public LoopDefinition(Expression expression) {
@@ -72,6 +82,10 @@ public class LoopDefinition extends OutputExpressionNode {
         return new LoopDefinition(this);
     }
 
+    public Processor getOnPrepareProcessor() {
+        return onPrepareProcessor;
+    }
+
     /**
      * Enables copy mode so a copy of the input Exchange is used for each 
iteration.
      */
@@ -80,6 +94,30 @@ public class LoopDefinition extends OutputExpressionNode {
         return this;
     }
 
+    /**
+     * Uses the {@link Processor} when preparing the {@link 
org.apache.camel.Exchange} for each loop iteration. This can
+     * be used to deep-clone messages, or any custom logic needed before the 
looping executes.
+     *
+     * @param  onPrepare reference to the processor to lookup in the {@link 
org.apache.camel.spi.Registry}
+     * @return           the builder
+     */
+    public LoopDefinition onPrepare(Processor onPrepare) {
+        this.onPrepareProcessor = onPrepare;
+        return this;
+    }
+
+    /**
+     * Uses the {@link Processor} when preparing the {@link 
org.apache.camel.Exchange} for each loop iteration. This can
+     * be used to deep-clone messages, or any custom logic needed before the 
looping executes.
+     *
+     * @param  onPrepare reference to the processor to lookup in the {@link 
org.apache.camel.spi.Registry}
+     * @return           the builder
+     */
+    public LoopDefinition onPrepare(String onPrepare) {
+        setOnPrepare(onPrepare);
+        return this;
+    }
+
     public String getCopy() {
         return copy;
     }
@@ -122,6 +160,14 @@ public class LoopDefinition extends OutputExpressionNode {
         return breakOnShutdown;
     }
 
+    public String getOnPrepare() {
+        return onPrepare;
+    }
+
+    public void setOnPrepare(String onPrepare) {
+        this.onPrepare = onPrepare;
+    }
+
     @Override
     public String toString() {
         return "Loop[" + getExpression() + " -> " + getOutputs() + "]";
diff --git 
a/core/camel-core-processor/src/main/java/org/apache/camel/processor/LoopProcessor.java
 
b/core/camel-core-processor/src/main/java/org/apache/camel/processor/LoopProcessor.java
index e4e659a6026..bf203e940c2 100644
--- 
a/core/camel-core-processor/src/main/java/org/apache/camel/processor/LoopProcessor.java
+++ 
b/core/camel-core-processor/src/main/java/org/apache/camel/processor/LoopProcessor.java
@@ -52,16 +52,18 @@ public class LoopProcessor extends DelegateAsyncProcessor 
implements Traceable,
     private final ReactiveExecutor reactiveExecutor;
     private final Expression expression;
     private final Predicate predicate;
+    private final Processor onPrepare;
     private final boolean copy;
     private final boolean breakOnShutdown;
     private final LongAdder taskCount = new LongAdder();
 
     public LoopProcessor(CamelContext camelContext, Processor processor, 
Expression expression, Predicate predicate,
-                         boolean copy, boolean breakOnShutdown) {
+                         Processor onPrepare, boolean copy, boolean 
breakOnShutdown) {
         super(processor);
         this.reactiveExecutor = 
camelContext.getCamelContextExtension().getReactiveExecutor();
         this.expression = expression;
         this.predicate = predicate;
+        this.onPrepare = onPrepare;
         this.copy = copy;
         this.breakOnShutdown = breakOnShutdown;
     }
@@ -202,15 +204,19 @@ public class LoopProcessor extends DelegateAsyncProcessor 
implements Traceable,
      * @param  index    the index of the next iteration
      * @return          the exchange to use
      */
-    protected Exchange prepareExchange(Exchange exchange, int index) {
+    protected Exchange prepareExchange(Exchange exchange, int index) throws 
Exception {
+        Exchange answer = exchange;
         if (copy) {
             // use a copy but let it reuse the same exchange id so it appear 
as one exchange
             // use the original exchange rather than the looping exchange 
(esp. with the async routing engine)
-            return ExchangeHelper.createCopy(exchange, true);
+            answer = ExchangeHelper.createCopy(exchange, true);
         } else {
             ExchangeHelper.prepareOutToIn(exchange);
-            return exchange;
         }
+        if (onPrepare != null) {
+            onPrepare.process(answer);
+        }
+        return answer;
     }
 
     public Expression getExpression() {
@@ -225,6 +231,10 @@ public class LoopProcessor extends DelegateAsyncProcessor 
implements Traceable,
         return copy;
     }
 
+    public boolean isBreakOnShutdown() {
+        return breakOnShutdown;
+    }
+
     @Override
     public String getTraceLabel() {
         if (predicate != null) {
diff --git 
a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/LoopReifier.java
 
b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/LoopReifier.java
index bcdc7313a92..6483c495713 100644
--- 
a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/LoopReifier.java
+++ 
b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/LoopReifier.java
@@ -36,6 +36,10 @@ public class LoopReifier extends 
ExpressionReifier<LoopDefinition> {
         boolean isCopy = parseBoolean(definition.getCopy(), false);
         boolean isWhile = parseBoolean(definition.getDoWhile(), false);
         boolean isBreakOnShutdown = 
parseBoolean(definition.getBreakOnShutdown(), false);
+        Processor prepare = definition.getOnPrepareProcessor();
+        if (prepare == null && definition.getOnPrepare() != null) {
+            prepare = mandatoryLookup(definition.getOnPrepare(), 
Processor.class);
+        }
 
         Predicate predicate = null;
         Expression expression = null;
@@ -44,7 +48,7 @@ public class LoopReifier extends 
ExpressionReifier<LoopDefinition> {
         } else {
             expression = createExpression(definition.getExpression());
         }
-        return new LoopProcessor(camelContext, output, expression, predicate, 
isCopy, isBreakOnShutdown);
+        return new LoopProcessor(camelContext, output, expression, predicate, 
prepare, isCopy, isBreakOnShutdown);
     }
 
 }
diff --git 
a/core/camel-core/src/test/java/org/apache/camel/processor/LoopOnPrepareTest.java
 
b/core/camel-core/src/test/java/org/apache/camel/processor/LoopOnPrepareTest.java
new file mode 100644
index 00000000000..88e236e8093
--- /dev/null
+++ 
b/core/camel-core/src/test/java/org/apache/camel/processor/LoopOnPrepareTest.java
@@ -0,0 +1,62 @@
+/*
+ * 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;
+
+import org.apache.camel.ContextTestSupport;
+import org.apache.camel.Exchange;
+import org.apache.camel.Processor;
+import org.apache.camel.builder.RouteBuilder;
+import org.junit.jupiter.api.Test;
+
+public class LoopOnPrepareTest extends ContextTestSupport {
+
+    @Test
+    public void testLoopOnPrepare() throws Exception {
+        getMockEndpoint("mock:loop").expectedBodiesReceived("AB", "AB", "AB");
+        getMockEndpoint("mock:result").expectedBodiesReceived("AB");
+
+        template.sendBody("direct:start", "A");
+
+        assertMockEndpointsSatisfied();
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() {
+        return new RouteBuilder() {
+            @Override
+            public void configure() {
+                from("direct:start")
+                        .loop(3).onPrepare(new 
MyPrepare()).transform(body().append("B")).to("mock:loop").end().to("mock:result");
+            }
+        };
+    }
+
+    private class MyPrepare implements Processor {
+
+        private String original;
+
+        @Override
+        public void process(Exchange exchange) throws Exception {
+            if (original == null) {
+                original = exchange.getMessage().getBody(String.class);
+            } else {
+                // restore original input for each loop
+                exchange.getMessage().setBody(original);
+            }
+        }
+    }
+}
diff --git 
a/core/camel-management-api/src/main/java/org/apache/camel/api/management/mbean/ManagedLoopMBean.java
 
b/core/camel-management-api/src/main/java/org/apache/camel/api/management/mbean/ManagedLoopMBean.java
index a75551f4f3b..140cf4032ac 100644
--- 
a/core/camel-management-api/src/main/java/org/apache/camel/api/management/mbean/ManagedLoopMBean.java
+++ 
b/core/camel-management-api/src/main/java/org/apache/camel/api/management/mbean/ManagedLoopMBean.java
@@ -29,4 +29,7 @@ public interface ManagedLoopMBean extends 
ManagedProcessorMBean {
     @ManagedAttribute(description = "Whether a copy of the input Exchange is 
used for each iteration")
     Boolean isCopy();
 
+    @ManagedAttribute(description = "Whether to break looping if Camel is 
being shutdown")
+    Boolean isBreakOnShutdown();
+
 }
diff --git 
a/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedLoop.java
 
b/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedLoop.java
index 1bf0270e197..eb2dea9b7e7 100644
--- 
a/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedLoop.java
+++ 
b/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedLoop.java
@@ -50,4 +50,9 @@ public class ManagedLoop extends ManagedProcessor implements 
ManagedLoopMBean {
     public Boolean isCopy() {
         return processor.isCopy();
     }
+
+    @Override
+    public Boolean isBreakOnShutdown() {
+        return processor.isBreakOnShutdown();
+    }
 }
diff --git 
a/core/camel-xml-io/src/generated/java/org/apache/camel/xml/in/ModelParser.java 
b/core/camel-xml-io/src/generated/java/org/apache/camel/xml/in/ModelParser.java
index 46fa4335bdd..e0aa413639d 100644
--- 
a/core/camel-xml-io/src/generated/java/org/apache/camel/xml/in/ModelParser.java
+++ 
b/core/camel-xml-io/src/generated/java/org/apache/camel/xml/in/ModelParser.java
@@ -531,6 +531,7 @@ public class ModelParser extends BaseParser {
                 case "breakOnShutdown": def.setBreakOnShutdown(val); yield 
true;
                 case "copy": def.setCopy(val); yield true;
                 case "doWhile": def.setDoWhile(val); yield true;
+                case "onPrepare": def.setOnPrepare(val); yield true;
                 default: yield 
processorDefinitionAttributeHandler().accept(def, key, val);
             }, outputExpressionNodeElementHandler(), noValueHandler());
     }
diff --git 
a/core/camel-xml-io/src/generated/java/org/apache/camel/xml/out/ModelWriter.java
 
b/core/camel-xml-io/src/generated/java/org/apache/camel/xml/out/ModelWriter.java
index e185a32151c..08d86619ceb 100644
--- 
a/core/camel-xml-io/src/generated/java/org/apache/camel/xml/out/ModelWriter.java
+++ 
b/core/camel-xml-io/src/generated/java/org/apache/camel/xml/out/ModelWriter.java
@@ -1163,6 +1163,7 @@ public class ModelWriter extends BaseWriter {
     protected void doWriteLoopDefinition(String name, LoopDefinition def) 
throws IOException {
         startElement(name);
         doWriteProcessorDefinitionAttributes(def);
+        doWriteAttribute("onPrepare", def.getOnPrepare(), null);
         doWriteAttribute("doWhile", def.getDoWhile(), null);
         doWriteAttribute("breakOnShutdown", def.getBreakOnShutdown(), null);
         doWriteAttribute("copy", def.getCopy(), null);
diff --git 
a/core/camel-yaml-io/src/generated/java/org/apache/camel/yaml/out/ModelWriter.java
 
b/core/camel-yaml-io/src/generated/java/org/apache/camel/yaml/out/ModelWriter.java
index d9d911932fa..5175a869386 100644
--- 
a/core/camel-yaml-io/src/generated/java/org/apache/camel/yaml/out/ModelWriter.java
+++ 
b/core/camel-yaml-io/src/generated/java/org/apache/camel/yaml/out/ModelWriter.java
@@ -1163,6 +1163,7 @@ public class ModelWriter extends BaseWriter {
     protected void doWriteLoopDefinition(String name, LoopDefinition def) 
throws IOException {
         startElement(name);
         doWriteProcessorDefinitionAttributes(def);
+        doWriteAttribute("onPrepare", def.getOnPrepare(), null);
         doWriteAttribute("doWhile", def.getDoWhile(), null);
         doWriteAttribute("breakOnShutdown", def.getBreakOnShutdown(), null);
         doWriteAttribute("copy", def.getCopy(), null);
diff --git 
a/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/generated/java/org/apache/camel/dsl/yaml/deserializers/ModelDeserializers.java
 
b/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/generated/java/org/apache/camel/dsl/yaml/deserializers/ModelDeserializers.java
index aefab1977f5..5fbdc56df6f 100644
--- 
a/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/generated/java/org/apache/camel/dsl/yaml/deserializers/ModelDeserializers.java
+++ 
b/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/generated/java/org/apache/camel/dsl/yaml/deserializers/ModelDeserializers.java
@@ -9545,6 +9545,7 @@ public final class ModelDeserializers extends 
YamlDeserializerSupport {
                     @YamlProperty(name = "doWhile", type = "boolean", 
description = "Enables the while loop that loops until the predicate evaluates 
to false or null.", displayName = "Do While"),
                     @YamlProperty(name = "expression", type = 
"object:org.apache.camel.model.language.ExpressionDefinition", description = 
"Expression to define how many times we should loop. Notice the expression is 
only evaluated once, and should return a number as how many times to loop. A 
value of zero or negative means no looping. The loop is like a for-loop 
fashion, if you want a while loop, then the dynamic router may be a better 
choice.", displayName = "Expression", oneOf = "expr [...]
                     @YamlProperty(name = "id", type = "string", description = 
"Sets the id of this node", displayName = "Id"),
+                    @YamlProperty(name = "onPrepare", type = "string", 
description = "Uses the Processor when preparing the org.apache.camel.Exchange 
for each loop iteration. This can be used to deep-clone messages, or any custom 
logic needed before the looping executes.", displayName = "On Prepare"),
                     @YamlProperty(name = "steps", type = 
"array:org.apache.camel.model.ProcessorDefinition")
             }
     )
@@ -9588,6 +9589,11 @@ public final class ModelDeserializers extends 
YamlDeserializerSupport {
                     target.setExpression(val);
                     break;
                 }
+                case "onPrepare": {
+                    String val = asText(node);
+                    target.setOnPrepare(val);
+                    break;
+                }
                 case "id": {
                     String val = asText(node);
                     target.setId(val);
diff --git 
a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/schema/camelYamlDsl.json
 
b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/schema/camelYamlDsl.json
index 514a3be0ef1..7deecd56aaf 100644
--- 
a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/schema/camelYamlDsl.json
+++ 
b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/schema/camelYamlDsl.json
@@ -2775,6 +2775,11 @@
             "title" : "Id",
             "description" : "Sets the id of this node"
           },
+          "onPrepare" : {
+            "type" : "string",
+            "title" : "On Prepare",
+            "description" : "Uses the Processor when preparing the 
org.apache.camel.Exchange for each loop iteration. This can be used to 
deep-clone messages, or any custom logic needed before the looping executes."
+          },
           "steps" : {
             "type" : "array",
             "items" : {

Reply via email to