You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by lb...@apache.org on 2021/04/15 08:53:43 UTC

[camel] branch master updated (8897432 -> 536d508)

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

lburgazzoli pushed a change to branch master
in repository https://gitbox.apache.org/repos/asf/camel.git.


    from 8897432  Upgrade Jetty to 9.4.39
     new 910f142  [CAMEL-16504] YAML Dsl : support for "flow" like route definition
     new 536d508  [CAMEL-16510] YAML Dsl : support for Kamelet EIP

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../org/apache/camel/model/KameletDefinition.java  |   4 +
 .../yaml/common/YamlDeserializationContext.java    |  10 +
 .../dsl/yaml/common/YamlDeserializationMode.java   |  73 +++++++
 .../dsl/yaml/common/YamlDeserializerBase.java      |   2 +-
 .../dsl/yaml/common/YamlDeserializerSupport.java   |  21 ++
 .../camel-yaml-dsl-deserializers/pom.xml           |   1 +
 .../dsl/yaml/deserializers/ModelDeserializers.java | 194 ++++---------------
 .../deserializers/ModelDeserializersResolver.java  |   2 -
 .../dsl/yaml/deserializers/CustomResolver.java     |   5 +-
 ...nDeserializer.java => KameletDeserializer.java} |  67 ++++---
 .../deserializers/RouteDefinitionDeserializer.java |   5 +-
 .../RouteFromDefinitionDeserializer.java           |   5 +-
 .../dsl/yaml/GenerateYamlDeserializersMojo.java    |   4 +-
 dsl/camel-yaml-dsl/camel-yaml-dsl/pom.xml          |   5 +
 .../src/generated/resources/camel-yaml-dsl.json    |  33 ++--
 .../camel/dsl/yaml/YamlRoutesBuilderLoader.java    |  33 ++--
 .../org/apache/camel/dsl/yaml/AggregateTest.groovy |  64 +++++-
 .../org/apache/camel/dsl/yaml/KameletTest.groovy   | 215 +++++++++++++++++++++
 .../org/apache/camel/dsl/yaml/LoopTest.groovy      |  29 +++
 .../org/apache/camel/dsl/yaml/SplitTest.groovy     |  44 +++++
 .../camel/dsl/yaml/support/YamlTestSupport.groovy  |  45 ++++-
 21 files changed, 632 insertions(+), 229 deletions(-)
 create mode 100644 dsl/camel-yaml-dsl/camel-yaml-dsl-common/src/main/java/org/apache/camel/dsl/yaml/common/YamlDeserializationMode.java
 copy dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/main/java/org/apache/camel/dsl/yaml/deserializers/{RouteDefinitionDeserializer.java => KameletDeserializer.java} (57%)
 create mode 100644 dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/KameletTest.groovy

[camel] 02/02: [CAMEL-16510] YAML Dsl : support for Kamelet EIP

Posted by lb...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 536d50806833e6f2c22f9b3dc18173a34a4cfc91
Author: Luca Burgazzoli <lb...@gmail.com>
AuthorDate: Wed Apr 14 20:04:26 2021 +0200

    [CAMEL-16510] YAML Dsl : support for Kamelet EIP
---
 .../org/apache/camel/model/KameletDefinition.java  |   4 +
 .../camel-yaml-dsl-deserializers/pom.xml           |   1 +
 .../dsl/yaml/deserializers/ModelDeserializers.java |  47 -----
 .../deserializers/ModelDeserializersResolver.java  |   2 -
 .../dsl/yaml/deserializers/CustomResolver.java     |   5 +-
 .../yaml/deserializers/KameletDeserializer.java    | 102 ++++++++++
 dsl/camel-yaml-dsl/camel-yaml-dsl/pom.xml          |   5 +
 .../src/generated/resources/camel-yaml-dsl.json    |  33 ++--
 .../org/apache/camel/dsl/yaml/KameletTest.groovy   | 215 +++++++++++++++++++++
 .../camel/dsl/yaml/support/YamlTestSupport.groovy  |  40 +++-
 10 files changed, 386 insertions(+), 68 deletions(-)

diff --git a/core/camel-core-model/src/main/java/org/apache/camel/model/KameletDefinition.java b/core/camel-core-model/src/main/java/org/apache/camel/model/KameletDefinition.java
index f4c1625..1f1364a 100644
--- a/core/camel-core-model/src/main/java/org/apache/camel/model/KameletDefinition.java
+++ b/core/camel-core-model/src/main/java/org/apache/camel/model/KameletDefinition.java
@@ -37,6 +37,10 @@ public class KameletDefinition extends OutputDefinition<KameletDefinition> {
     public KameletDefinition() {
     }
 
+    public KameletDefinition(String name) {
+        this.name = name;
+    }
+
     @Override
     public String toString() {
         return "Kamelet[" + getOutputs() + "]";
diff --git a/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/pom.xml b/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/pom.xml
index a3b85bf..8a7dd45 100644
--- a/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/pom.xml
+++ b/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/pom.xml
@@ -128,6 +128,7 @@
                                 <bannedDefinition>org.apache.camel.model.language.ExpressionDefinition</bannedDefinition>
                                 <bannedDefinition>org.apache.camel.model.ExpressionSubElementDefinition</bannedDefinition>
                                 <bannedDefinition>org.apache.camel.model.PropertyDefinitions</bannedDefinition>
+                                <bannedDefinition>org.apache.camel.model.KameletDefinition</bannedDefinition>
                             </bannedDefinitions>
                             <additionalDefinitions>
                                 <additionalDefinition>org.apache.camel.model.SagaOptionDefinition</additionalDefinition>
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 f12f10d..df21838 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
@@ -35,7 +35,6 @@ import org.apache.camel.model.InputTypeDefinition;
 import org.apache.camel.model.InterceptDefinition;
 import org.apache.camel.model.InterceptFromDefinition;
 import org.apache.camel.model.InterceptSendToEndpointDefinition;
-import org.apache.camel.model.KameletDefinition;
 import org.apache.camel.model.LoadBalanceDefinition;
 import org.apache.camel.model.LoadBalancerDefinition;
 import org.apache.camel.model.LogDefinition;
@@ -6830,52 +6829,6 @@ public final class ModelDeserializers extends YamlDeserializerSupport {
     }
 
     @YamlType(
-            types = org.apache.camel.model.KameletDefinition.class,
-            order = org.apache.camel.dsl.yaml.common.YamlDeserializerResolver.ORDER_LOWEST - 1,
-            nodes = "kamelet",
-            properties = {
-                    @YamlProperty(name = "inherit-error-handler", type = "boolean"),
-                    @YamlProperty(name = "name", type = "string", required = true),
-                    @YamlProperty(name = "steps", type = "array:org.apache.camel.model.ProcessorDefinition")
-            }
-    )
-    public static class KameletDefinitionDeserializer extends YamlDeserializerBase<KameletDefinition> {
-        public KameletDefinitionDeserializer() {
-            super(KameletDefinition.class);
-        }
-
-        @Override
-        protected KameletDefinition newInstance() {
-            return new KameletDefinition();
-        }
-
-        @Override
-        protected boolean setProperty(KameletDefinition target, String propertyKey,
-                String propertyName, Node node) {
-            switch(propertyKey) {
-                case "inherit-error-handler": {
-                    String val = asText(node);
-                    target.setInheritErrorHandler(java.lang.Boolean.valueOf(val));
-                    break;
-                }
-                case "name": {
-                    String val = asText(node);
-                    target.setName(val);
-                    break;
-                }
-                case "steps": {
-                    setSteps(target, node);;
-                    break;
-                }
-                default: {
-                    return false;
-                }
-            }
-            return true;
-        }
-    }
-
-    @YamlType(
             types = org.apache.camel.model.cloud.KubernetesServiceCallServiceDiscoveryConfiguration.class,
             order = org.apache.camel.dsl.yaml.common.YamlDeserializerResolver.ORDER_LOWEST - 1,
             nodes = "kubernetes-service-discovery",
diff --git a/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/generated/java/org/apache/camel/dsl/yaml/deserializers/ModelDeserializersResolver.java b/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/generated/java/org/apache/camel/dsl/yaml/deserializers/ModelDeserializersResolver.java
index 513a1a9..0a1741b 100644
--- a/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/generated/java/org/apache/camel/dsl/yaml/deserializers/ModelDeserializersResolver.java
+++ b/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/generated/java/org/apache/camel/dsl/yaml/deserializers/ModelDeserializersResolver.java
@@ -167,8 +167,6 @@ public final class ModelDeserializersResolver implements YamlDeserializerResolve
             case "org.apache.camel.model.dataformat.JsonDataFormat": return new ModelDeserializers.JsonDataFormatDeserializer();
             case "jsonpath": return new ModelDeserializers.JsonPathExpressionDeserializer();
             case "org.apache.camel.model.language.JsonPathExpression": return new ModelDeserializers.JsonPathExpressionDeserializer();
-            case "kamelet": return new ModelDeserializers.KameletDefinitionDeserializer();
-            case "org.apache.camel.model.KameletDefinition": return new ModelDeserializers.KameletDefinitionDeserializer();
             case "kubernetes-service-discovery": return new ModelDeserializers.KubernetesServiceCallServiceDiscoveryConfigurationDeserializer();
             case "org.apache.camel.model.cloud.KubernetesServiceCallServiceDiscoveryConfiguration": return new ModelDeserializers.KubernetesServiceCallServiceDiscoveryConfigurationDeserializer();
             case "lzf": return new ModelDeserializers.LZFDataFormatDeserializer();
diff --git a/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/main/java/org/apache/camel/dsl/yaml/deserializers/CustomResolver.java b/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/main/java/org/apache/camel/dsl/yaml/deserializers/CustomResolver.java
index 16b29bb..448cf74 100644
--- a/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/main/java/org/apache/camel/dsl/yaml/deserializers/CustomResolver.java
+++ b/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/main/java/org/apache/camel/dsl/yaml/deserializers/CustomResolver.java
@@ -54,10 +54,11 @@ public class CustomResolver implements YamlDeserializerResolver {
                 return new BeansDeserializer();
             case "error-handler":
                 return new ErrorHandlerBuilderDeserializer();
-            //case "do-try":
-            //    return new TryDefinitionDeserializer();
             case "org.apache.camel.model.ProcessorDefinition":
                 return new ProcessorDefinitionDeserializer();
+            case "kamelet":
+            case "org.apache.camel.model.KameletDefinition":
+                return new KameletDeserializer();
             default:
                 return null;
         }
diff --git a/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/main/java/org/apache/camel/dsl/yaml/deserializers/KameletDeserializer.java b/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/main/java/org/apache/camel/dsl/yaml/deserializers/KameletDeserializer.java
new file mode 100644
index 0000000..6f1c1dd
--- /dev/null
+++ b/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/main/java/org/apache/camel/dsl/yaml/deserializers/KameletDeserializer.java
@@ -0,0 +1,102 @@
+/*
+ * 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.dsl.yaml.deserializers;
+
+import java.net.URISyntaxException;
+import java.util.Map;
+
+import org.apache.camel.dsl.yaml.common.YamlDeserializationContext;
+import org.apache.camel.dsl.yaml.common.YamlDeserializerBase;
+import org.apache.camel.dsl.yaml.common.YamlDeserializerResolver;
+import org.apache.camel.dsl.yaml.common.exception.UnsupportedFieldException;
+import org.apache.camel.dsl.yaml.common.exception.YamlDeserializationException;
+import org.apache.camel.model.KameletDefinition;
+import org.apache.camel.spi.annotations.YamlProperty;
+import org.apache.camel.spi.annotations.YamlType;
+import org.apache.camel.util.URISupport;
+import org.snakeyaml.engine.v2.nodes.MappingNode;
+import org.snakeyaml.engine.v2.nodes.Node;
+import org.snakeyaml.engine.v2.nodes.NodeTuple;
+
+@YamlType(
+          inline = true,
+          types = org.apache.camel.model.KameletDefinition.class,
+          order = YamlDeserializerResolver.ORDER_DEFAULT,
+          nodes = "kamelet",
+          properties = {
+                  @YamlProperty(name = "inherit-error-handler", type = "boolean"),
+                  @YamlProperty(name = "name", type = "string", required = true),
+                  @YamlProperty(name = "parameters", type = "object"),
+                  @YamlProperty(name = "steps", type = "array:org.apache.camel.model.ProcessorDefinition")
+          })
+public class KameletDeserializer extends YamlDeserializerBase<KameletDefinition> {
+    public KameletDeserializer() {
+        super(KameletDefinition.class);
+    }
+
+    @Override
+    protected KameletDefinition newInstance() {
+        return new KameletDefinition();
+    }
+
+    @Override
+    protected KameletDefinition newInstance(String value) {
+        return new KameletDefinition(value);
+    }
+
+    @Override
+    protected void setProperties(KameletDefinition target, MappingNode node) {
+        final YamlDeserializationContext dc = getDeserializationContext(node);
+
+        String name = null;
+        Map<String, Object> parameters = null;
+
+        for (NodeTuple tuple : node.getValue()) {
+            final String key = asText(tuple.getKeyNode());
+            final Node val = tuple.getValueNode();
+
+            setDeserializationContext(val, dc);
+
+            switch (key) {
+                case "steps":
+                    setSteps(target, val);
+                    break;
+                case "id":
+                    target.setId(asText(val));
+                    break;
+                case "name":
+                    name = asText(val);
+                    break;
+                case "parameters":
+                    parameters = asScalarMap(tuple.getValueNode());
+                    break;
+                default:
+                    throw new UnsupportedFieldException(node, key);
+            }
+        }
+
+        if (parameters != null) {
+            try {
+                name += "?" + URISupport.createQueryString(parameters, false);
+            } catch (URISyntaxException e) {
+                throw new YamlDeserializationException(e);
+            }
+        }
+
+        target.setName(name);
+    }
+}
diff --git a/dsl/camel-yaml-dsl/camel-yaml-dsl/pom.xml b/dsl/camel-yaml-dsl/camel-yaml-dsl/pom.xml
index 54169ce..9d850e9 100644
--- a/dsl/camel-yaml-dsl/camel-yaml-dsl/pom.xml
+++ b/dsl/camel-yaml-dsl/camel-yaml-dsl/pom.xml
@@ -129,6 +129,11 @@
             <artifactId>camel-seda</artifactId>
             <scope>test</scope>
         </dependency>
+        <dependency>
+            <groupId>org.apache.camel</groupId>
+            <artifactId>camel-kamelet</artifactId>
+            <scope>test</scope>
+        </dependency>
 
         <dependency>
             <groupId>org.codehaus.groovy</groupId>
diff --git a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/camel-yaml-dsl.json b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/camel-yaml-dsl.json
index 5aa0842..1d2caf5 100644
--- a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/camel-yaml-dsl.json
+++ b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/camel-yaml-dsl.json
@@ -1036,21 +1036,28 @@
         "required" : [ "uri" ]
       },
       "org.apache.camel.model.KameletDefinition" : {
-        "type" : "object",
-        "properties" : {
-          "inherit-error-handler" : {
-            "type" : "boolean"
-          },
-          "name" : {
-            "type" : "string"
-          },
-          "steps" : {
-            "type" : "array",
-            "items" : {
-              "$ref" : "#/items/definitions/org.apache.camel.model.ProcessorDefinition"
+        "oneOf" : [ {
+          "type" : "string"
+        }, {
+          "type" : "object",
+          "properties" : {
+            "inherit-error-handler" : {
+              "type" : "boolean"
+            },
+            "name" : {
+              "type" : "string"
+            },
+            "parameters" : {
+              "type" : "object"
+            },
+            "steps" : {
+              "type" : "array",
+              "items" : {
+                "$ref" : "#/items/definitions/org.apache.camel.model.ProcessorDefinition"
+              }
             }
           }
-        },
+        } ],
         "required" : [ "name" ]
       },
       "org.apache.camel.model.LoadBalanceDefinition" : {
diff --git a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/KameletTest.groovy b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/KameletTest.groovy
new file mode 100644
index 0000000..b1ff173
--- /dev/null
+++ b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/KameletTest.groovy
@@ -0,0 +1,215 @@
+/*
+ * 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.dsl.yaml
+
+import org.apache.camel.component.mock.MockEndpoint
+import org.apache.camel.dsl.yaml.common.YamlDeserializationMode
+import org.apache.camel.dsl.yaml.support.YamlTestSupport
+import org.apache.camel.processor.aggregate.UseLatestAggregationStrategy
+import org.apache.camel.spi.Resource
+
+class KameletTest extends YamlTestSupport {
+    @Override
+    def doSetup() {
+        context.start()
+    }
+
+    def "kamelet (#resource)"(Tuple2<YamlDeserializationMode, Resource> resource) {
+        setup:
+            addTemplate('setPayload') {
+                from('kamelet:source')
+                    .setBody().simple('${body}: {{payload}}')
+            }
+
+            setFlowMode(resource[0] as YamlDeserializationMode)
+            loadRoutes(resource[1] as Resource)
+
+            withMock('mock:kamelet') {
+                expectedMessageCount 1
+                expectedBodiesReceived 'a: 1'
+            }
+        when:
+            withTemplate {
+                to('direct:start').withBody('a').send()
+            }
+
+        then:
+            MockEndpoint.assertIsSatisfied(context)
+
+        where:
+            resource << [
+                new Tuple2<YamlDeserializationMode, Resource>(
+                    YamlDeserializationMode.CLASSIC,
+                    asResource('inline', '''
+                        - from:
+                            uri: "direct:start"
+                            steps:
+                              - kamelet: "setPayload?payload=1"
+                              - to: "mock:kamelet"
+                        ''')),
+                new Tuple2<YamlDeserializationMode, Resource>(
+                    YamlDeserializationMode.CLASSIC,
+                    asResource('name', '''
+                        - from:
+                            uri: "direct:start"
+                            steps:
+                              - kamelet: 
+                                  name: "setPayload?payload=1"
+                              - to: "mock:kamelet"
+                        ''')),
+                new Tuple2<YamlDeserializationMode, Resource>(
+                        YamlDeserializationMode.CLASSIC,
+                        asResource('name_with_steps', '''
+                        - from:
+                            uri: "direct:start"
+                            steps:
+                              - kamelet: 
+                                  name: "setPayload?payload=1"
+                                  steps:
+                                    - to: "mock:kamelet"
+                        ''')),
+                new Tuple2<YamlDeserializationMode, Resource>(
+                        YamlDeserializationMode.CLASSIC,
+                        asResource('properties', '''
+                            - from:
+                                uri: "direct:start"
+                                steps:
+                                  - kamelet: 
+                                      name: "setPayload"
+                                      parameters:
+                                        payload: 1
+                                  - to: "mock:kamelet"
+                            ''')),
+                new Tuple2<YamlDeserializationMode, Resource>(
+                        YamlDeserializationMode.CLASSIC,
+                        asResource('properties_with_steps', '''
+                            - from:
+                                uri: "direct:start"
+                                steps:
+                                  - kamelet: 
+                                      name: "setPayload"
+                                      parameters:
+                                        payload: 1
+                                      steps:
+                                        - to: "mock:kamelet"
+                            ''')),
+                new Tuple2<YamlDeserializationMode, Resource>(
+                        YamlDeserializationMode.FLOW,
+                        asResource('inline', '''
+                        - from:
+                            uri: "direct:start"
+                            steps:
+                              - kamelet: "setPayload?payload=1"
+                              - to: "mock:kamelet"
+                        ''')),
+                new Tuple2<YamlDeserializationMode, Resource>(
+                        YamlDeserializationMode.FLOW,
+                        asResource('name', '''
+                        - from:
+                            uri: "direct:start"
+                            steps:
+                              - kamelet: 
+                                  name: "setPayload?payload=1"
+                              - to: "mock:kamelet"
+                        ''')),
+                new Tuple2<YamlDeserializationMode, Resource>(
+                        YamlDeserializationMode.FLOW,
+                        asResource('properties', '''
+                            - from:
+                                uri: "direct:start"
+                                steps:
+                                  - kamelet: 
+                                      name: "setPayload"
+                                      parameters:
+                                        payload: 1
+                                  - to: "mock:kamelet"
+                            '''))
+            ]
+    }
+
+    def "kamelet (aggregation)"() {
+        setup:
+            addTemplate('aggregate') {
+                from('kamelet:source')
+                        .aggregate()
+                            .simple('${header.StockSymbol}')
+                            .aggregationStrategy(new UseLatestAggregationStrategy())
+                            .completionSize("{{size}}")
+                            .to("kamelet:sink")
+            }
+
+            loadRoutes '''
+                - from:
+                    uri: "direct:route"
+                    steps:
+                      - kamelet: 
+                          name: aggregate?size=2
+                          steps:
+                            - to: "mock:result"
+            '''
+
+            withMock('mock:result') {
+                expectedBodiesReceived '2', '4'
+            }
+
+        when:
+            withTemplate {
+                to('direct:route').withBody('1').withHeader('StockSymbol', 1).send()
+                to('direct:route').withBody('2').withHeader('StockSymbol', 1).send()
+                to('direct:route').withBody('3').withHeader('StockSymbol', 2).send()
+                to('direct:route').withBody('4').withHeader('StockSymbol', 2).send()
+            }
+        then:
+            MockEndpoint.assertIsSatisfied(context)
+    }
+
+    def "kamelet (aggregation with flow)"() {
+        setup:
+            setFlowMode(YamlDeserializationMode.FLOW)
+
+            addTemplate('aggregate') {
+                from('kamelet:source')
+                        .aggregate()
+                        .simple('${header.StockSymbol}')
+                        .aggregationStrategy(new UseLatestAggregationStrategy())
+                        .completionSize("{{size}}")
+                        .to("kamelet:sink")
+            }
+
+            loadRoutes '''
+                - from:
+                    uri: "direct:route"
+                    steps:
+                      - kamelet: aggregate?size=2
+                      - to: "mock:result"
+            '''
+
+            withMock('mock:result') {
+                expectedBodiesReceived '2', '4'
+            }
+
+        when:
+            withTemplate {
+                to('direct:route').withBody('1').withHeader('StockSymbol', 1).send()
+                to('direct:route').withBody('2').withHeader('StockSymbol', 1).send()
+                to('direct:route').withBody('3').withHeader('StockSymbol', 2).send()
+                to('direct:route').withBody('4').withHeader('StockSymbol', 2).send()
+            }
+        then:
+            MockEndpoint.assertIsSatisfied(context)
+    }
+}
diff --git a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/support/YamlTestSupport.groovy b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/support/YamlTestSupport.groovy
index 1aedc0d..bbffe8d 100644
--- a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/support/YamlTestSupport.groovy
+++ b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/support/YamlTestSupport.groovy
@@ -23,16 +23,20 @@ import com.github.fge.jsonschema.main.JsonSchemaFactory
 import groovy.util.logging.Slf4j
 import org.apache.camel.CamelContext
 import org.apache.camel.FluentProducerTemplate
+import org.apache.camel.builder.RouteBuilder
 import org.apache.camel.component.mock.MockEndpoint
 import org.apache.camel.dsl.yaml.YamlRoutesBuilderLoader
 import org.apache.camel.dsl.yaml.common.YamlDeserializationMode
 import org.apache.camel.impl.DefaultCamelContext
+import org.apache.camel.model.RouteTemplateDefinition
 import org.apache.camel.spi.HasCamelContext
 import org.apache.camel.spi.Resource
 import org.apache.camel.support.ResourceHelper
 import spock.lang.AutoCleanup
 import spock.lang.Specification
 
+import java.nio.charset.StandardCharsets
+
 @Slf4j
 class YamlTestSupport extends Specification implements HasCamelContext {
     static def MAPPER = new ObjectMapper(new YAMLFactory())
@@ -56,6 +60,17 @@ class YamlTestSupport extends Specification implements HasCamelContext {
         context.routesLoader.loadRoutes(resources)
     }
 
+    def addTemplate(String name, @DelegatesTo(RouteTemplateDefinition) Closure<?> closure) {
+        context.addRoutes(new RouteBuilder() {
+            @Override
+            void configure() throws Exception {
+                closure.resolveStrategy = Closure.DELEGATE_FIRST
+                closure.delegate = routeTemplate(name)
+                closure.call()
+            }
+        });
+    }
+
     def loadRoutes(Resource... resources) {
         loadRoutes(resources.toList())
     }
@@ -92,10 +107,27 @@ class YamlTestSupport extends Specification implements HasCamelContext {
     }
 
     static Resource asResource(String location, String content) {
-        return ResourceHelper.fromString(
-                location.endsWith('.yaml') ? location : location + '.yaml',
-                content.stripIndent()
-        )
+        return new Resource() {
+            @Override
+            String getLocation() {
+                return location.endsWith('.yaml') ? location : location + '.yaml'
+            }
+
+            @Override
+            boolean exists() {
+                return false
+            }
+
+            @Override
+            InputStream getInputStream() throws IOException {
+                return new ByteArrayInputStream(content.stripIndent().getBytes(StandardCharsets.UTF_8))
+            }
+
+            @Override
+            String toString() {
+                return location
+            }
+        }
     }
 
     def setFlowMode(YamlDeserializationMode mode) {

[camel] 01/02: [CAMEL-16504] YAML Dsl : support for "flow" like route definition

Posted by lb...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 910f142ce013234868fc6da5eda7cffb80b45b2b
Author: Luca Burgazzoli <lb...@gmail.com>
AuthorDate: Wed Apr 14 19:06:29 2021 +0200

    [CAMEL-16504] YAML Dsl : support for "flow" like route definition
---
 .../yaml/common/YamlDeserializationContext.java    |  10 ++
 .../dsl/yaml/common/YamlDeserializationMode.java   |  73 ++++++++++
 .../dsl/yaml/common/YamlDeserializerBase.java      |   2 +-
 .../dsl/yaml/common/YamlDeserializerSupport.java   |  21 +++
 .../dsl/yaml/deserializers/ModelDeserializers.java | 149 +++++----------------
 .../deserializers/RouteDefinitionDeserializer.java |   5 +-
 .../RouteFromDefinitionDeserializer.java           |   5 +-
 .../dsl/yaml/GenerateYamlDeserializersMojo.java    |   4 +-
 .../camel/dsl/yaml/YamlRoutesBuilderLoader.java    |  33 +++--
 .../org/apache/camel/dsl/yaml/AggregateTest.groovy |  64 ++++++++-
 .../org/apache/camel/dsl/yaml/LoopTest.groovy      |  29 ++++
 .../org/apache/camel/dsl/yaml/SplitTest.groovy     |  44 ++++++
 .../camel/dsl/yaml/support/YamlTestSupport.groovy  |   5 +
 13 files changed, 307 insertions(+), 137 deletions(-)

diff --git a/dsl/camel-yaml-dsl/camel-yaml-dsl-common/src/main/java/org/apache/camel/dsl/yaml/common/YamlDeserializationContext.java b/dsl/camel-yaml-dsl/camel-yaml-dsl-common/src/main/java/org/apache/camel/dsl/yaml/common/YamlDeserializationContext.java
index 769d779..cb20da3 100644
--- a/dsl/camel-yaml-dsl/camel-yaml-dsl-common/src/main/java/org/apache/camel/dsl/yaml/common/YamlDeserializationContext.java
+++ b/dsl/camel-yaml-dsl/camel-yaml-dsl-common/src/main/java/org/apache/camel/dsl/yaml/common/YamlDeserializationContext.java
@@ -46,6 +46,7 @@ public class YamlDeserializationContext extends StandardConstructor implements C
     private final Set<YamlDeserializerResolver> resolvers;
     private final Map<String, ConstructNode> constructors;
 
+    private YamlDeserializationMode deserializationMode;
     private ExtendedCamelContext camelContext;
 
     public YamlDeserializationContext(LoadSettings settings) {
@@ -53,6 +54,7 @@ public class YamlDeserializationContext extends StandardConstructor implements C
 
         this.resolvers = new TreeSet<>(Comparator.comparing(Ordered::getOrder));
         this.constructors = new HashMap<>();
+        this.deserializationMode = YamlDeserializationMode.CLASSIC;
     }
 
     public void addResolver(YamlDeserializerResolver resolver) {
@@ -67,6 +69,14 @@ public class YamlDeserializationContext extends StandardConstructor implements C
         this.resolvers.addAll(resolvers);
     }
 
+    public void setDeserializationMode(YamlDeserializationMode deserializationMode) {
+        this.deserializationMode = deserializationMode;
+    }
+
+    public YamlDeserializationMode getDeserializationMode() {
+        return deserializationMode;
+    }
+
     @Override
     public CamelContext getCamelContext() {
         return camelContext;
diff --git a/dsl/camel-yaml-dsl/camel-yaml-dsl-common/src/main/java/org/apache/camel/dsl/yaml/common/YamlDeserializationMode.java b/dsl/camel-yaml-dsl/camel-yaml-dsl-common/src/main/java/org/apache/camel/dsl/yaml/common/YamlDeserializationMode.java
new file mode 100644
index 0000000..1fdfa41
--- /dev/null
+++ b/dsl/camel-yaml-dsl/camel-yaml-dsl-common/src/main/java/org/apache/camel/dsl/yaml/common/YamlDeserializationMode.java
@@ -0,0 +1,73 @@
+/*
+ * 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.dsl.yaml.common;
+
+public enum YamlDeserializationMode {
+    /**
+     * This option configure the deserialization engine to strictly respect the model definition.
+     *
+     * </p>
+     * As example, a Split step is expected to have it's own steps to process the result of the split.
+     *
+     * <pre>
+     * {@code
+     * - from:
+     *     uri: "direct:a"
+     *     steps:
+     *       - split:
+     *            tokenize: \n"
+     *          steps:
+     *            - log: "${body}"
+     * }
+     * </pre>
+     */
+    CLASSIC,
+
+    /**
+     * Mimics the Java Dsl.
+     * </p>
+     * When the deserializer is configured to use this mode, a route can be defined using a syntax that is closed to the
+     * Java DSL, as example, the following Java route:
+     *
+     * <pre>
+     * {@code
+     * from("direct:a")
+     *     .split().tokenize("\n"))
+     *     .log("${body}");
+     * }
+     * </pre>
+     *
+     * Can be represented by the following YAML:
+     *
+     * <pre>
+     * {@code
+     * - from:
+     *     uri: "direct:a"
+     *     steps:
+     *       - split:
+     *            tokenize: \n"
+     *       - log: "${body}"
+     * }
+     * </pre>
+     *
+     * As you may have noticed, there's no need to define the split's specific steps as the subsequent log processor is
+     * automatically added to the step's outputs.
+     * </p>
+     * See https://issues.apache.org/jira/browse/CAMEL-16504
+     */
+    FLOW;
+}
diff --git a/dsl/camel-yaml-dsl/camel-yaml-dsl-common/src/main/java/org/apache/camel/dsl/yaml/common/YamlDeserializerBase.java b/dsl/camel-yaml-dsl/camel-yaml-dsl-common/src/main/java/org/apache/camel/dsl/yaml/common/YamlDeserializerBase.java
index 128ed36..02ec14a 100644
--- a/dsl/camel-yaml-dsl/camel-yaml-dsl-common/src/main/java/org/apache/camel/dsl/yaml/common/YamlDeserializerBase.java
+++ b/dsl/camel-yaml-dsl/camel-yaml-dsl-common/src/main/java/org/apache/camel/dsl/yaml/common/YamlDeserializerBase.java
@@ -91,7 +91,7 @@ public abstract class YamlDeserializerBase<T> extends YamlDeserializerSupport im
      * @param target the target object
      */
     protected void setProperties(T target, MappingNode node) {
-        org.apache.camel.dsl.yaml.common.YamlDeserializationContext dc = getDeserializationContext(node);
+        YamlDeserializationContext dc = getDeserializationContext(node);
 
         for (NodeTuple tuple : node.getValue()) {
             final ScalarNode key = (ScalarNode) tuple.getKeyNode();
diff --git a/dsl/camel-yaml-dsl/camel-yaml-dsl-common/src/main/java/org/apache/camel/dsl/yaml/common/YamlDeserializerSupport.java b/dsl/camel-yaml-dsl/camel-yaml-dsl-common/src/main/java/org/apache/camel/dsl/yaml/common/YamlDeserializerSupport.java
index 56430ba..48cade8 100644
--- a/dsl/camel-yaml-dsl/camel-yaml-dsl-common/src/main/java/org/apache/camel/dsl/yaml/common/YamlDeserializerSupport.java
+++ b/dsl/camel-yaml-dsl/camel-yaml-dsl-common/src/main/java/org/apache/camel/dsl/yaml/common/YamlDeserializerSupport.java
@@ -30,7 +30,11 @@ import org.apache.camel.CamelContext;
 import org.apache.camel.dsl.yaml.common.exception.UnsupportedFieldException;
 import org.apache.camel.dsl.yaml.common.exception.UnsupportedNodeTypeException;
 import org.apache.camel.dsl.yaml.common.exception.YamlDeserializationException;
+import org.apache.camel.model.Block;
+import org.apache.camel.model.OutputNode;
+import org.apache.camel.model.ProcessorDefinition;
 import org.apache.camel.util.CollectionHelper;
+import org.apache.camel.util.ObjectHelper;
 import org.apache.camel.util.StringHelper;
 import org.snakeyaml.engine.v2.api.ConstructNode;
 import org.snakeyaml.engine.v2.nodes.MappingNode;
@@ -331,4 +335,21 @@ public class YamlDeserializerSupport {
         node.setProperty(YamlDeserializationContext.class.getName(), context);
         return node;
     }
+
+    public static void setSteps(Block target, Node node) {
+        final YamlDeserializationContext dc = getDeserializationContext(node);
+
+        Block block = target;
+        for (ProcessorDefinition<?> definition : asFlatList(node, ProcessorDefinition.class)) {
+            block.addOutput(definition);
+
+            if (dc.getDeserializationMode() == YamlDeserializationMode.FLOW) {
+                if (definition instanceof OutputNode) {
+                    if (ObjectHelper.isEmpty(definition.getOutputs())) {
+                        block = definition;
+                    }
+                }
+            }
+        }
+    }
 }
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 643afa5..f12f10d 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
@@ -54,7 +54,6 @@ import org.apache.camel.model.PipelineDefinition;
 import org.apache.camel.model.PolicyDefinition;
 import org.apache.camel.model.PollEnrichDefinition;
 import org.apache.camel.model.ProcessDefinition;
-import org.apache.camel.model.ProcessorDefinition;
 import org.apache.camel.model.PropertyDefinition;
 import org.apache.camel.model.RecipientListDefinition;
 import org.apache.camel.model.RedeliveryPolicyDefinition;
@@ -480,9 +479,7 @@ public final class ModelDeserializers extends YamlDeserializerSupport {
                     break;
                 }
                 case "steps": {
-                    for (ProcessorDefinition<?> definition: asFlatList(node, ProcessorDefinition.class)) {
-                        target.addOutput(definition);
-                    }
+                    setSteps(target, node);;
                     break;
                 }
                 default: {
@@ -1340,9 +1337,7 @@ public final class ModelDeserializers extends YamlDeserializerSupport {
                     break;
                 }
                 case "steps": {
-                    for (ProcessorDefinition<?> definition: asFlatList(node, ProcessorDefinition.class)) {
-                        target.addOutput(definition);
-                    }
+                    setSteps(target, node);;
                     break;
                 }
                 default: {
@@ -1394,9 +1389,7 @@ public final class ModelDeserializers extends YamlDeserializerSupport {
                     break;
                 }
                 case "steps": {
-                    for (ProcessorDefinition<?> definition: asFlatList(node, ProcessorDefinition.class)) {
-                        target.addOutput(definition);
-                    }
+                    setSteps(target, node);;
                     break;
                 }
                 default: {
@@ -1466,9 +1459,7 @@ public final class ModelDeserializers extends YamlDeserializerSupport {
                     break;
                 }
                 case "steps": {
-                    for (ProcessorDefinition<?> definition: asFlatList(node, ProcessorDefinition.class)) {
-                        target.addOutput(definition);
-                    }
+                    setSteps(target, node);;
                     break;
                 }
                 default: {
@@ -3692,9 +3683,7 @@ public final class ModelDeserializers extends YamlDeserializerSupport {
                     break;
                 }
                 case "steps": {
-                    for (ProcessorDefinition<?> definition: asFlatList(node, ProcessorDefinition.class)) {
-                        target.addOutput(definition);
-                    }
+                    setSteps(target, node);;
                     break;
                 }
                 default: {
@@ -4644,9 +4633,7 @@ public final class ModelDeserializers extends YamlDeserializerSupport {
                     break;
                 }
                 case "steps": {
-                    for (ProcessorDefinition<?> definition: asFlatList(node, ProcessorDefinition.class)) {
-                        target.addOutput(definition);
-                    }
+                    setSteps(target, node);;
                     break;
                 }
                 default: {
@@ -4695,9 +4682,7 @@ public final class ModelDeserializers extends YamlDeserializerSupport {
                     break;
                 }
                 case "steps": {
-                    for (ProcessorDefinition<?> definition: asFlatList(node, ProcessorDefinition.class)) {
-                        target.addOutput(definition);
-                    }
+                    setSteps(target, node);;
                     break;
                 }
                 default: {
@@ -4927,9 +4912,7 @@ public final class ModelDeserializers extends YamlDeserializerSupport {
                     break;
                 }
                 case "steps": {
-                    for (ProcessorDefinition<?> definition: asFlatList(node, ProcessorDefinition.class)) {
-                        target.addOutput(definition);
-                    }
+                    setSteps(target, node);;
                     break;
                 }
                 default: {
@@ -5345,9 +5328,7 @@ public final class ModelDeserializers extends YamlDeserializerSupport {
                     break;
                 }
                 case "steps": {
-                    for (ProcessorDefinition<?> definition: asFlatList(node, ProcessorDefinition.class)) {
-                        target.addOutput(definition);
-                    }
+                    setSteps(target, node);;
                     break;
                 }
                 default: {
@@ -5851,9 +5832,7 @@ public final class ModelDeserializers extends YamlDeserializerSupport {
                     break;
                 }
                 case "steps": {
-                    for (ProcessorDefinition<?> definition: asFlatList(node, ProcessorDefinition.class)) {
-                        target.addOutput(definition);
-                    }
+                    setSteps(target, node);;
                     break;
                 }
                 default: {
@@ -6065,9 +6044,7 @@ public final class ModelDeserializers extends YamlDeserializerSupport {
                     break;
                 }
                 case "steps": {
-                    for (ProcessorDefinition<?> definition: asFlatList(node, ProcessorDefinition.class)) {
-                        target.addOutput(definition);
-                    }
+                    setSteps(target, node);;
                     break;
                 }
                 default: {
@@ -6119,9 +6096,7 @@ public final class ModelDeserializers extends YamlDeserializerSupport {
                     break;
                 }
                 case "steps": {
-                    for (ProcessorDefinition<?> definition: asFlatList(node, ProcessorDefinition.class)) {
-                        target.addOutput(definition);
-                    }
+                    setSteps(target, node);;
                     break;
                 }
                 default: {
@@ -6185,9 +6160,7 @@ public final class ModelDeserializers extends YamlDeserializerSupport {
                     break;
                 }
                 case "steps": {
-                    for (ProcessorDefinition<?> definition: asFlatList(node, ProcessorDefinition.class)) {
-                        target.addOutput(definition);
-                    }
+                    setSteps(target, node);;
                     break;
                 }
                 default: {
@@ -6891,9 +6864,7 @@ public final class ModelDeserializers extends YamlDeserializerSupport {
                     break;
                 }
                 case "steps": {
-                    for (ProcessorDefinition<?> definition: asFlatList(node, ProcessorDefinition.class)) {
-                        target.addOutput(definition);
-                    }
+                    setSteps(target, node);;
                     break;
                 }
                 default: {
@@ -7238,9 +7209,7 @@ public final class ModelDeserializers extends YamlDeserializerSupport {
                     break;
                 }
                 case "steps": {
-                    for (ProcessorDefinition<?> definition: asFlatList(node, ProcessorDefinition.class)) {
-                        target.addOutput(definition);
-                    }
+                    setSteps(target, node);;
                     break;
                 }
                 default: {
@@ -7408,9 +7377,7 @@ public final class ModelDeserializers extends YamlDeserializerSupport {
                     break;
                 }
                 case "steps": {
-                    for (ProcessorDefinition<?> definition: asFlatList(node, ProcessorDefinition.class)) {
-                        target.addOutput(definition);
-                    }
+                    setSteps(target, node);;
                     break;
                 }
                 default: {
@@ -7968,9 +7935,7 @@ public final class ModelDeserializers extends YamlDeserializerSupport {
                     break;
                 }
                 case "steps": {
-                    for (ProcessorDefinition<?> definition: asFlatList(node, ProcessorDefinition.class)) {
-                        target.addOutput(definition);
-                    }
+                    setSteps(target, node);;
                     break;
                 }
                 default: {
@@ -8176,9 +8141,7 @@ public final class ModelDeserializers extends YamlDeserializerSupport {
                     break;
                 }
                 case "steps": {
-                    for (ProcessorDefinition<?> definition: asFlatList(node, ProcessorDefinition.class)) {
-                        target.addOutput(definition);
-                    }
+                    setSteps(target, node);;
                     break;
                 }
                 default: {
@@ -8285,9 +8248,7 @@ public final class ModelDeserializers extends YamlDeserializerSupport {
                     break;
                 }
                 case "steps": {
-                    for (ProcessorDefinition<?> definition: asFlatList(node, ProcessorDefinition.class)) {
-                        target.addOutput(definition);
-                    }
+                    setSteps(target, node);;
                     break;
                 }
                 default: {
@@ -8333,9 +8294,7 @@ public final class ModelDeserializers extends YamlDeserializerSupport {
                     break;
                 }
                 case "steps": {
-                    for (ProcessorDefinition<?> definition: asFlatList(node, ProcessorDefinition.class)) {
-                        target.addOutput(definition);
-                    }
+                    setSteps(target, node);;
                     break;
                 }
                 default: {
@@ -8434,9 +8393,7 @@ public final class ModelDeserializers extends YamlDeserializerSupport {
                     break;
                 }
                 case "steps": {
-                    for (ProcessorDefinition<?> definition: asFlatList(node, ProcessorDefinition.class)) {
-                        target.addOutput(definition);
-                    }
+                    setSteps(target, node);;
                     break;
                 }
                 default: {
@@ -8475,9 +8432,7 @@ public final class ModelDeserializers extends YamlDeserializerSupport {
                     break;
                 }
                 case "steps": {
-                    for (ProcessorDefinition<?> definition: asFlatList(node, ProcessorDefinition.class)) {
-                        target.addOutput(definition);
-                    }
+                    setSteps(target, node);;
                     break;
                 }
                 default: {
@@ -8872,9 +8827,7 @@ public final class ModelDeserializers extends YamlDeserializerSupport {
                     break;
                 }
                 case "steps": {
-                    for (ProcessorDefinition<?> definition: asFlatList(node, ProcessorDefinition.class)) {
-                        target.addOutput(definition);
-                    }
+                    setSteps(target, node);;
                     break;
                 }
                 default: {
@@ -8914,9 +8867,7 @@ public final class ModelDeserializers extends YamlDeserializerSupport {
                     break;
                 }
                 case "steps": {
-                    for (ProcessorDefinition<?> definition: asFlatList(node, ProcessorDefinition.class)) {
-                        target.addOutput(definition);
-                    }
+                    setSteps(target, node);;
                     break;
                 }
                 default: {
@@ -8962,9 +8913,7 @@ public final class ModelDeserializers extends YamlDeserializerSupport {
                     break;
                 }
                 case "steps": {
-                    for (ProcessorDefinition<?> definition: asFlatList(node, ProcessorDefinition.class)) {
-                        target.addOutput(definition);
-                    }
+                    setSteps(target, node);;
                     break;
                 }
                 default: {
@@ -9204,9 +9153,7 @@ public final class ModelDeserializers extends YamlDeserializerSupport {
                     break;
                 }
                 case "steps": {
-                    for (ProcessorDefinition<?> definition: asFlatList(node, ProcessorDefinition.class)) {
-                        target.addOutput(definition);
-                    }
+                    setSteps(target, node);;
                     break;
                 }
                 default: {
@@ -9534,9 +9481,7 @@ public final class ModelDeserializers extends YamlDeserializerSupport {
                     break;
                 }
                 case "steps": {
-                    for (ProcessorDefinition<?> definition: asFlatList(node, ProcessorDefinition.class)) {
-                        target.addOutput(definition);
-                    }
+                    setSteps(target, node);;
                     break;
                 }
                 default: {
@@ -10209,9 +10154,7 @@ public final class ModelDeserializers extends YamlDeserializerSupport {
                     break;
                 }
                 case "steps": {
-                    for (ProcessorDefinition<?> definition: asFlatList(node, ProcessorDefinition.class)) {
-                        target.addOutput(definition);
-                    }
+                    setSteps(target, node);;
                     break;
                 }
                 default: {
@@ -11551,9 +11494,7 @@ public final class ModelDeserializers extends YamlDeserializerSupport {
                     break;
                 }
                 case "steps": {
-                    for (ProcessorDefinition<?> definition: asFlatList(node, ProcessorDefinition.class)) {
-                        target.addOutput(definition);
-                    }
+                    setSteps(target, node);;
                     break;
                 }
                 default: {
@@ -11996,9 +11937,7 @@ public final class ModelDeserializers extends YamlDeserializerSupport {
                     break;
                 }
                 case "steps": {
-                    for (ProcessorDefinition<?> definition: asFlatList(node, ProcessorDefinition.class)) {
-                        target.addOutput(definition);
-                    }
+                    setSteps(target, node);;
                     break;
                 }
                 default: {
@@ -13423,9 +13362,7 @@ public final class ModelDeserializers extends YamlDeserializerSupport {
                     break;
                 }
                 case "steps": {
-                    for (ProcessorDefinition<?> definition: asFlatList(node, ProcessorDefinition.class)) {
-                        target.addOutput(definition);
-                    }
+                    setSteps(target, node);;
                     break;
                 }
                 default: {
@@ -13521,9 +13458,7 @@ public final class ModelDeserializers extends YamlDeserializerSupport {
                     break;
                 }
                 case "steps": {
-                    for (ProcessorDefinition<?> definition: asFlatList(node, ProcessorDefinition.class)) {
-                        target.addOutput(definition);
-                    }
+                    setSteps(target, node);;
                     break;
                 }
                 default: {
@@ -14534,9 +14469,7 @@ public final class ModelDeserializers extends YamlDeserializerSupport {
                     break;
                 }
                 case "steps": {
-                    for (ProcessorDefinition<?> definition: asFlatList(node, ProcessorDefinition.class)) {
-                        target.addOutput(definition);
-                    }
+                    setSteps(target, node);;
                     break;
                 }
                 default: {
@@ -14706,9 +14639,7 @@ public final class ModelDeserializers extends YamlDeserializerSupport {
                     break;
                 }
                 case "steps": {
-                    for (ProcessorDefinition<?> definition: asFlatList(node, ProcessorDefinition.class)) {
-                        target.addOutput(definition);
-                    }
+                    setSteps(target, node);;
                     break;
                 }
                 default: {
@@ -15705,9 +15636,7 @@ public final class ModelDeserializers extends YamlDeserializerSupport {
                     break;
                 }
                 case "steps": {
-                    for (ProcessorDefinition<?> definition: asFlatList(node, ProcessorDefinition.class)) {
-                        target.addOutput(definition);
-                    }
+                    setSteps(target, node);;
                     break;
                 }
                 default: {
@@ -15807,9 +15736,7 @@ public final class ModelDeserializers extends YamlDeserializerSupport {
                     break;
                 }
                 case "steps": {
-                    for (ProcessorDefinition<?> definition: asFlatList(node, ProcessorDefinition.class)) {
-                        target.addOutput(definition);
-                    }
+                    setSteps(target, node);;
                     break;
                 }
                 default: {
@@ -15865,9 +15792,7 @@ public final class ModelDeserializers extends YamlDeserializerSupport {
                     break;
                 }
                 case "steps": {
-                    for (ProcessorDefinition<?> definition: asFlatList(node, ProcessorDefinition.class)) {
-                        target.addOutput(definition);
-                    }
+                    setSteps(target, node);;
                     break;
                 }
                 default: {
diff --git a/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/main/java/org/apache/camel/dsl/yaml/deserializers/RouteDefinitionDeserializer.java b/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/main/java/org/apache/camel/dsl/yaml/deserializers/RouteDefinitionDeserializer.java
index 1379569..9170fcb 100644
--- a/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/main/java/org/apache/camel/dsl/yaml/deserializers/RouteDefinitionDeserializer.java
+++ b/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/main/java/org/apache/camel/dsl/yaml/deserializers/RouteDefinitionDeserializer.java
@@ -21,7 +21,6 @@ import org.apache.camel.dsl.yaml.common.YamlDeserializerBase;
 import org.apache.camel.dsl.yaml.common.YamlDeserializerResolver;
 import org.apache.camel.dsl.yaml.common.exception.UnsupportedFieldException;
 import org.apache.camel.model.FromDefinition;
-import org.apache.camel.model.ProcessorDefinition;
 import org.apache.camel.model.RouteDefinition;
 import org.apache.camel.spi.annotations.YamlIn;
 import org.apache.camel.spi.annotations.YamlProperty;
@@ -63,9 +62,7 @@ public class RouteDefinitionDeserializer extends YamlDeserializerBase<RouteDefin
 
             switch (key) {
                 case "steps":
-                    for (ProcessorDefinition<?> definition : asFlatList(val, ProcessorDefinition.class)) {
-                        target.addOutput(definition);
-                    }
+                    setSteps(target, val);
                     break;
                 case "id":
                     target.setId(asText(val));
diff --git a/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/main/java/org/apache/camel/dsl/yaml/deserializers/RouteFromDefinitionDeserializer.java b/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/main/java/org/apache/camel/dsl/yaml/deserializers/RouteFromDefinitionDeserializer.java
index 16aee6d..0ae312c 100644
--- a/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/main/java/org/apache/camel/dsl/yaml/deserializers/RouteFromDefinitionDeserializer.java
+++ b/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/main/java/org/apache/camel/dsl/yaml/deserializers/RouteFromDefinitionDeserializer.java
@@ -24,7 +24,6 @@ import org.apache.camel.dsl.yaml.common.YamlDeserializerResolver;
 import org.apache.camel.dsl.yaml.common.YamlSupport;
 import org.apache.camel.dsl.yaml.deserializers.model.OutputAwareFromDefinition;
 import org.apache.camel.model.FromDefinition;
-import org.apache.camel.model.ProcessorDefinition;
 import org.apache.camel.spi.annotations.YamlIn;
 import org.apache.camel.spi.annotations.YamlProperty;
 import org.apache.camel.spi.annotations.YamlType;
@@ -73,9 +72,7 @@ public class RouteFromDefinitionDeserializer extends YamlDeserializerBase<Output
 
             switch (key) {
                 case "steps":
-                    for (ProcessorDefinition<?> definition : asFlatList(val, ProcessorDefinition.class)) {
-                        target.addOutput(definition);
-                    }
+                    setSteps(target, val);
                     break;
                 case "uri":
                     uri = asText(val);
diff --git a/dsl/camel-yaml-dsl/camel-yaml-dsl-maven-plugin/src/main/java/org/apache/camel/maven/dsl/yaml/GenerateYamlDeserializersMojo.java b/dsl/camel-yaml-dsl/camel-yaml-dsl-maven-plugin/src/main/java/org/apache/camel/maven/dsl/yaml/GenerateYamlDeserializersMojo.java
index a88d4dd..a454a0e 100644
--- a/dsl/camel-yaml-dsl/camel-yaml-dsl-maven-plugin/src/main/java/org/apache/camel/maven/dsl/yaml/GenerateYamlDeserializersMojo.java
+++ b/dsl/camel-yaml-dsl/camel-yaml-dsl-maven-plugin/src/main/java/org/apache/camel/maven/dsl/yaml/GenerateYamlDeserializersMojo.java
@@ -497,9 +497,7 @@ public class GenerateYamlDeserializersMojo extends GenerateYamlSupportMojo {
 
         if (implementType(info, OUTPUT_NODE_CLASS)) {
             setProperty.beginControlFlow("case \"steps\":");
-            setProperty.beginControlFlow("for ($T<?> definition: asFlatList(node, $T.class))", CN_PROCESSOR_DEFINITION, CN_PROCESSOR_DEFINITION);
-            setProperty.addStatement("target.addOutput(definition)");
-            setProperty.endControlFlow();
+            setProperty.addStatement("setSteps(target, node);");
             setProperty.addStatement("break");
             setProperty.endControlFlow();
 
diff --git a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/main/java/org/apache/camel/dsl/yaml/YamlRoutesBuilderLoader.java b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/main/java/org/apache/camel/dsl/yaml/YamlRoutesBuilderLoader.java
index 73c1d8c..82ac857 100644
--- a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/main/java/org/apache/camel/dsl/yaml/YamlRoutesBuilderLoader.java
+++ b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/main/java/org/apache/camel/dsl/yaml/YamlRoutesBuilderLoader.java
@@ -18,12 +18,15 @@ package org.apache.camel.dsl.yaml;
 
 import java.io.InputStream;
 import java.util.List;
+import java.util.Locale;
+import java.util.Map;
 
 import org.apache.camel.api.management.ManagedResource;
 import org.apache.camel.builder.ErrorHandlerBuilder;
 import org.apache.camel.builder.RouteBuilder;
 import org.apache.camel.dsl.support.RouteBuilderLoaderSupport;
 import org.apache.camel.dsl.yaml.common.YamlDeserializationContext;
+import org.apache.camel.dsl.yaml.common.YamlDeserializationMode;
 import org.apache.camel.dsl.yaml.deserializers.CustomResolver;
 import org.apache.camel.dsl.yaml.deserializers.EndpointProducerDeserializersResolver;
 import org.apache.camel.dsl.yaml.deserializers.ModelDeserializersResolver;
@@ -43,10 +46,11 @@ import org.snakeyaml.engine.v2.api.LoadSettings;
 @ManagedResource(description = "Managed YAML RoutesBuilderLoader")
 @RoutesLoader(YamlRoutesBuilderLoader.EXTENSION)
 public class YamlRoutesBuilderLoader extends RouteBuilderLoaderSupport {
+    public static final String DESERIALIZATION_MODE = "CamelYamlDslDeserializationMode";
     public static final String EXTENSION = "yaml";
 
     private LoadSettings settings;
-    private YamlDeserializationContext constructor;
+    private YamlDeserializationContext deserializationContext;
 
     public YamlRoutesBuilderLoader() {
         super(EXTENSION);
@@ -57,39 +61,46 @@ public class YamlRoutesBuilderLoader extends RouteBuilderLoaderSupport {
         super.doBuild();
 
         this.settings = LoadSettings.builder().build();
-        this.constructor = new YamlDeserializationContext(settings);
-        this.constructor.setCamelContext(getCamelContext());
-        this.constructor.addResolvers(new CustomResolver());
-        this.constructor.addResolvers(new ModelDeserializersResolver());
-        this.constructor.addResolvers(new EndpointProducerDeserializersResolver());
+        this.deserializationContext = new YamlDeserializationContext(settings);
+        this.deserializationContext.setCamelContext(getCamelContext());
+        this.deserializationContext.addResolvers(new CustomResolver());
+        this.deserializationContext.addResolvers(new ModelDeserializersResolver());
+        this.deserializationContext.addResolvers(new EndpointProducerDeserializersResolver());
     }
 
     @Override
     protected void doStart() throws Exception {
         super.doStart();
 
-        ServiceHelper.startService(this.constructor);
+        final Map<String, String> options = getCamelContext().getGlobalOptions();
+        final String mode = options.getOrDefault(DESERIALIZATION_MODE, YamlDeserializationMode.CLASSIC.name());
+        if (mode != null) {
+            this.deserializationContext.setDeserializationMode(
+                    YamlDeserializationMode.valueOf(mode.toUpperCase(Locale.US)));
+        }
+
+        ServiceHelper.startService(this.deserializationContext);
     }
 
     @Override
     protected void doStop() throws Exception {
         super.doStop();
 
-        ServiceHelper.stopService(this.constructor);
+        ServiceHelper.stopService(this.deserializationContext);
 
-        this.constructor = null;
+        this.deserializationContext = null;
         this.settings = null;
     }
 
     @Override
     public RouteBuilder doLoadRouteBuilder(Resource resource) throws Exception {
-        ObjectHelper.notNull(constructor, "constructor");
+        ObjectHelper.notNull(deserializationContext, "constructor");
         ObjectHelper.notNull(settings, "settings");
 
         return new RouteBuilder() {
             @Override
             public void configure() throws Exception {
-                final Load load = new Load(settings, constructor);
+                final Load load = new Load(settings, deserializationContext);
 
                 try (InputStream is = resource.getInputStream()) {
                     for (Object item : (List<?>) load.loadFromInputStream(is)) {
diff --git a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/AggregateTest.groovy b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/AggregateTest.groovy
index 232eba6..1305c2a 100644
--- a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/AggregateTest.groovy
+++ b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/AggregateTest.groovy
@@ -16,10 +16,17 @@
  */
 package org.apache.camel.dsl.yaml
 
-import org.apache.camel.dsl.yaml.support.YamlTestSupport
+import org.apache.camel.FailedToCreateRouteException
 import org.apache.camel.component.mock.MockEndpoint
+import org.apache.camel.dsl.yaml.common.YamlDeserializationMode
+import org.apache.camel.dsl.yaml.support.YamlTestSupport
 
 class AggregateTest extends YamlTestSupport {
+    @Override
+    def doSetup() {
+        context.start()
+    }
+
     def 'aggregate'() {
         setup:
             loadRoutes '''
@@ -43,8 +50,40 @@ class AggregateTest extends YamlTestSupport {
             }
 
         when:
-            context.start()
+            withTemplate {
+                to('direct:route').withBody('1').withHeader('StockSymbol', 1).send()
+                to('direct:route').withBody('2').withHeader('StockSymbol', 1).send()
+                to('direct:route').withBody('3').withHeader('StockSymbol', 2).send()
+                to('direct:route').withBody('4').withHeader('StockSymbol', 2).send()
+            }
+        then:
+            MockEndpoint.assertIsSatisfied(context)
+    }
 
+    def 'aggregate (flow)'() {
+        setup:
+            setFlowMode(YamlDeserializationMode.FLOW)
+
+            loadRoutes '''
+                - beans:
+                  - name: myAggregatorStrategy
+                    type: org.apache.camel.processor.aggregate.UseLatestAggregationStrategy
+                - from:
+                    uri: "direct:route"
+                    steps:
+                      - aggregate:
+                          strategy-ref: "myAggregatorStrategy"
+                          completion-size: 2
+                          correlation-expression:
+                            simple: "${header.StockSymbol}"
+                      - to: "mock:route"
+            '''
+
+            withMock('mock:route') {
+                expectedBodiesReceived '2', '4'
+            }
+
+        when:
             withTemplate {
                 to('direct:route').withBody('1').withHeader('StockSymbol', 1).send()
                 to('direct:route').withBody('2').withHeader('StockSymbol', 1).send()
@@ -54,4 +93,25 @@ class AggregateTest extends YamlTestSupport {
         then:
             MockEndpoint.assertIsSatisfied(context)
     }
+
+    def 'aggregate (disabled)'() {
+        when:
+            loadRoutes '''
+                - beans:
+                  - name: myAggregatorStrategy
+                    type: org.apache.camel.processor.aggregate.UseLatestAggregationStrategy
+                - from:
+                    uri: "direct:route"
+                    steps:
+                      - aggregate:
+                          strategy-ref: "myAggregatorStrategy"
+                          completion-size: 2
+                          correlation-expression:
+                            simple: "${header.StockSymbol}"
+                      - to: "mock:route"
+            '''
+        then:
+            def ex = thrown(FailedToCreateRouteException)
+            ex.message.contains('Failed to create route')
+    }
 }
diff --git a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/LoopTest.groovy b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/LoopTest.groovy
index 44f17aa..beda4b0 100644
--- a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/LoopTest.groovy
+++ b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/LoopTest.groovy
@@ -16,6 +16,8 @@
  */
 package org.apache.camel.dsl.yaml
 
+import org.apache.camel.component.mock.MockEndpoint
+import org.apache.camel.dsl.yaml.common.YamlDeserializationMode
 import org.apache.camel.dsl.yaml.support.YamlTestSupport
 import org.apache.camel.model.LoopDefinition
 import org.apache.camel.model.language.ExpressionDefinition
@@ -56,4 +58,31 @@ class LoopTest extends YamlTestSupport {
                     ''')
             ]
     }
+
+    def "loop (flow)"() {
+        setup:
+            setFlowMode(YamlDeserializationMode.FLOW)
+
+            loadRoutes '''
+                - from:
+                    uri: "direct:route"
+                    steps:    
+                      - loop:
+                         copy: true 
+                         constant: "3"
+                      - to: "mock:result"
+            '''
+
+            withMock('mock:result') {
+                expectedMessageCount 3
+            }
+        when:
+            context.start()
+
+            withTemplate {
+                to('direct:route').withBody('a').send()
+            }
+        then:
+            MockEndpoint.assertIsSatisfied(context)
+    }
 }
diff --git a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/SplitTest.groovy b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/SplitTest.groovy
index 31ae2c1..fe1b701 100644
--- a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/SplitTest.groovy
+++ b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/SplitTest.groovy
@@ -16,7 +16,9 @@
  */
 package org.apache.camel.dsl.yaml
 
+import org.apache.camel.FailedToCreateRouteException
 import org.apache.camel.component.mock.MockEndpoint
+import org.apache.camel.dsl.yaml.common.YamlDeserializationMode
 import org.apache.camel.dsl.yaml.support.YamlTestSupport
 
 class SplitTest extends YamlTestSupport {
@@ -56,4 +58,46 @@ class SplitTest extends YamlTestSupport {
         then:
             MockEndpoint.assertIsSatisfied(context)
     }
+
+    def "split (flow)"() {
+        setup:
+            setFlowMode(YamlDeserializationMode.FLOW)
+
+            loadRoutes '''
+                - from:
+                    uri: "direct:route"
+                    steps:
+                      - split:
+                          tokenize: ","
+                      - to: "mock:split"
+            '''
+
+            withMock('mock:split') {
+                expectedMessageCount 3
+                expectedBodiesReceived 'a', 'b', 'c'
+            }
+
+        when:
+            withTemplate {
+                to('direct:route').withBody('a,b,c').send()
+            }
+
+        then:
+            MockEndpoint.assertIsSatisfied(context)
+    }
+
+    def "split (flow disabled)"() {
+        when:
+            loadRoutes '''
+                - from:
+                    uri: "direct:route"
+                    steps:
+                      - split:
+                          tokenize: ","
+                      - to: "mock:split"
+            '''
+        then:
+            def ex = thrown(FailedToCreateRouteException)
+            ex.message.contains('Failed to create route')
+    }
 }
diff --git a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/support/YamlTestSupport.groovy b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/support/YamlTestSupport.groovy
index 5427bc7..1aedc0d 100644
--- a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/support/YamlTestSupport.groovy
+++ b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/support/YamlTestSupport.groovy
@@ -24,6 +24,8 @@ import groovy.util.logging.Slf4j
 import org.apache.camel.CamelContext
 import org.apache.camel.FluentProducerTemplate
 import org.apache.camel.component.mock.MockEndpoint
+import org.apache.camel.dsl.yaml.YamlRoutesBuilderLoader
+import org.apache.camel.dsl.yaml.common.YamlDeserializationMode
 import org.apache.camel.impl.DefaultCamelContext
 import org.apache.camel.spi.HasCamelContext
 import org.apache.camel.spi.Resource
@@ -96,6 +98,9 @@ class YamlTestSupport extends Specification implements HasCamelContext {
         )
     }
 
+    def setFlowMode(YamlDeserializationMode mode) {
+        context.globalOptions[YamlRoutesBuilderLoader.DESERIALIZATION_MODE] = mode.name()
+    }
 
     // ***********************************
     //