You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by da...@apache.org on 2022/08/10 11:56:16 UTC

[camel] 02/02: CAMEL-18366: camel-yaml-dsl - Allow to configure route options in route-templates/kamelets.

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

commit a760d0e1ab30c4284515ceee83eaa6df5070289a
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Wed Aug 10 13:55:26 2022 +0200

    CAMEL-18366: camel-yaml-dsl - Allow to configure route options in route-templates/kamelets.
---
 .../dsl/yaml/common/YamlDeserializerBase.java      |  8 +++
 .../common/exception/InvalidRouteException.java    | 30 +++++++++
 .../deserializers/RouteDefinitionDeserializer.java | 12 ++++
 .../RouteTemplateDefinitionDeserializer.java       | 22 ++++++-
 .../generated/resources/schema/camel-yaml-dsl.json | 14 ++++-
 .../generated/resources/schema/camelYamlDsl.json   | 14 ++++-
 .../camel/dsl/yaml/KameletBindingLoaderTest.groovy | 35 +++++++++++
 .../apache/camel/dsl/yaml/RouteTemplateTest.groovy | 30 +++++++++
 .../kamelets/route-timer-source.kamelet.yaml       | 72 ++++++++++++++++++++++
 9 files changed, 233 insertions(+), 4 deletions(-)

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 118b30d041e..9ad857c5f8a 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
@@ -63,6 +63,7 @@ public abstract class YamlDeserializerBase<T> extends YamlDeserializerSupport im
             target = newInstance();
             onNewTarget(node, target, line);
             setProperties(target, mn);
+            afterPropertiesSet(target, mn);
         } else {
             throw new UnsupportedNodeTypeException(node);
         }
@@ -77,6 +78,13 @@ public abstract class YamlDeserializerBase<T> extends YamlDeserializerSupport im
      */
     protected abstract T newInstance();
 
+    /**
+     * Allows custom validation after the properties has been set on the target
+     */
+    protected void afterPropertiesSet(T target, Node node) {
+        // noop
+    }
+
     /**
      * Creates a Java instance of the expected type from a string.
      *
diff --git a/dsl/camel-yaml-dsl/camel-yaml-dsl-common/src/main/java/org/apache/camel/dsl/yaml/common/exception/InvalidRouteException.java b/dsl/camel-yaml-dsl/camel-yaml-dsl-common/src/main/java/org/apache/camel/dsl/yaml/common/exception/InvalidRouteException.java
new file mode 100644
index 00000000000..fc0a9fa53b4
--- /dev/null
+++ b/dsl/camel-yaml-dsl/camel-yaml-dsl-common/src/main/java/org/apache/camel/dsl/yaml/common/exception/InvalidRouteException.java
@@ -0,0 +1,30 @@
+/*
+ * 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.exception;
+
+import java.util.Optional;
+
+import org.snakeyaml.engine.v2.exceptions.MarkedYamlEngineException;
+import org.snakeyaml.engine.v2.nodes.Node;
+
+public class InvalidRouteException extends MarkedYamlEngineException {
+
+    public InvalidRouteException(Node node, String message) {
+        super(null, Optional.empty(), message, node.getStartMark());
+    }
+
+}
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 719829d4272..f1d3c615a24 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
@@ -45,6 +45,9 @@ import org.snakeyaml.engine.v2.nodes.NodeTuple;
                   @YamlProperty(name = "route-policy", type = "string"),
                   @YamlProperty(name = "startup-order", type = "number"),
                   @YamlProperty(name = "stream-caching", type = "boolean"),
+                  @YamlProperty(name = "message-history", type = "boolean"),
+                  @YamlProperty(name = "log-mask", type = "boolean"),
+                  @YamlProperty(name = "trace", type = "boolean"),
                   @YamlProperty(name = "from", type = "object:org.apache.camel.model.FromDefinition", required = true)
           })
 public class RouteDefinitionDeserializer extends YamlDeserializerBase<RouteDefinition> {
@@ -96,6 +99,15 @@ public class RouteDefinitionDeserializer extends YamlDeserializerBase<RouteDefin
                 case "stream-caching":
                     target.setStreamCache(asText(val));
                     break;
+                case "log-mask":
+                    target.setLogMask(asText(val));
+                    break;
+                case "message-history":
+                    target.setMessageHistory(asText(val));
+                    break;
+                case "trace":
+                    target.setTrace(asText(val));
+                    break;
                 case "from":
                     val.setProperty(RouteDefinition.class.getName(), target);
                     target.setInput(asType(val, FromDefinition.class));
diff --git a/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/main/java/org/apache/camel/dsl/yaml/deserializers/RouteTemplateDefinitionDeserializer.java b/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/main/java/org/apache/camel/dsl/yaml/deserializers/RouteTemplateDefinitionDeserializer.java
index aaf0417b51f..f68aaae710c 100644
--- a/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/main/java/org/apache/camel/dsl/yaml/deserializers/RouteTemplateDefinitionDeserializer.java
+++ b/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/main/java/org/apache/camel/dsl/yaml/deserializers/RouteTemplateDefinitionDeserializer.java
@@ -19,6 +19,7 @@ package org.apache.camel.dsl.yaml.deserializers;
 import java.util.List;
 
 import org.apache.camel.dsl.yaml.common.YamlDeserializerBase;
+import org.apache.camel.dsl.yaml.common.exception.InvalidRouteException;
 import org.apache.camel.model.RouteDefinition;
 import org.apache.camel.model.RouteTemplateBeanDefinition;
 import org.apache.camel.model.RouteTemplateDefinition;
@@ -37,9 +38,10 @@ import org.snakeyaml.engine.v2.nodes.Node;
                   @YamlProperty(name = "id",
                                 type = "string",
                                 required = true),
+                  @YamlProperty(name = "route",
+                                type = "object:org.apache.camel.model.RouteDefinition"),
                   @YamlProperty(name = "from",
-                                type = "object:org.apache.camel.model.FromDefinition",
-                                required = true),
+                                type = "object:org.apache.camel.model.FromDefinition"),
                   @YamlProperty(name = "parameters",
                                 type = "array:org.apache.camel.model.RouteTemplateParameterDefinition"),
                   @YamlProperty(name = "beans",
@@ -64,6 +66,11 @@ public class RouteTemplateDefinitionDeserializer extends YamlDeserializerBase<Ro
                 target.setId(asText(node));
                 break;
             }
+            case "route": {
+                RouteDefinition route = asType(node, RouteDefinition.class);
+                target.setRoute(route);
+                break;
+            }
             case "from": {
                 OutputAwareFromDefinition val = asType(node, OutputAwareFromDefinition.class);
                 RouteDefinition route = new RouteDefinition();
@@ -88,4 +95,15 @@ public class RouteTemplateDefinitionDeserializer extends YamlDeserializerBase<Ro
         }
         return true;
     }
+
+    @Override
+    protected void afterPropertiesSet(RouteTemplateDefinition target, Node node) {
+        // either from or route must be set
+        if (target.getRoute() == null) {
+            throw new InvalidRouteException(node, "RouteTemplate must have route or from set");
+        }
+        if (target.getRoute().getInput() == null) {
+            throw new InvalidRouteException(node, "RouteTemplate must have from set");
+        }
+    }
 }
diff --git a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/schema/camel-yaml-dsl.json b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/schema/camel-yaml-dsl.json
index 7630c7f567d..abb996ff519 100644
--- a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/schema/camel-yaml-dsl.json
+++ b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/schema/camel-yaml-dsl.json
@@ -2421,6 +2421,12 @@
           "id" : {
             "type" : "string"
           },
+          "log-mask" : {
+            "type" : "boolean"
+          },
+          "message-history" : {
+            "type" : "boolean"
+          },
           "precondition" : {
             "type" : "string"
           },
@@ -2435,6 +2441,9 @@
           },
           "stream-caching" : {
             "type" : "boolean"
+          },
+          "trace" : {
+            "type" : "boolean"
           }
         },
         "required" : [ "from" ]
@@ -2486,9 +2495,12 @@
             "items" : {
               "$ref" : "#/items/definitions/org.apache.camel.model.RouteTemplateParameterDefinition"
             }
+          },
+          "route" : {
+            "$ref" : "#/items/definitions/org.apache.camel.model.RouteDefinition"
           }
         },
-        "required" : [ "from", "id" ]
+        "required" : [ "id" ]
       },
       "org.apache.camel.model.RouteTemplateParameterDefinition" : {
         "type" : "object",
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 800351a0e61..9a159975e99 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
@@ -2325,6 +2325,12 @@
           "id" : {
             "type" : "string"
           },
+          "logMask" : {
+            "type" : "boolean"
+          },
+          "messageHistory" : {
+            "type" : "boolean"
+          },
           "precondition" : {
             "type" : "string"
           },
@@ -2339,6 +2345,9 @@
           },
           "streamCaching" : {
             "type" : "boolean"
+          },
+          "trace" : {
+            "type" : "boolean"
           }
         },
         "required" : [ "from" ]
@@ -2390,9 +2399,12 @@
             "items" : {
               "$ref" : "#/items/definitions/org.apache.camel.model.RouteTemplateParameterDefinition"
             }
+          },
+          "route" : {
+            "$ref" : "#/items/definitions/org.apache.camel.model.RouteDefinition"
           }
         },
-        "required" : [ "from", "id" ]
+        "required" : [ "id" ]
       },
       "org.apache.camel.model.RouteTemplateParameterDefinition" : {
         "type" : "object",
diff --git a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/KameletBindingLoaderTest.groovy b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/KameletBindingLoaderTest.groovy
index a4c4a97ae64..096aedf01d1 100644
--- a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/KameletBindingLoaderTest.groovy
+++ b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/KameletBindingLoaderTest.groovy
@@ -552,4 +552,39 @@ class KameletBindingLoaderTest extends YamlTestSupport {
         }
     }
 
+    def "kamelet start route"() {
+        when:
+        loadBindings('''
+                apiVersion: camel.apache.org/v1alpha1
+                kind: KameletBinding
+                metadata:
+                  name: timer-event-source                  
+                spec:
+                  source:
+                    ref:
+                      kind: Kamelet
+                      apiVersion: camel.apache.org/v1
+                      name: route-timer-source
+                    properties:
+                      message: "Hello world!"
+                  sink:
+                    ref:
+                      kind: Kamelet
+                      apiVersion: camel.apache.org/v1
+                      name: log-sink
+            ''')
+        then:
+        context.routeDefinitions.size() == 3
+
+        // global stream caching enabled
+        context.streamCaching == true
+
+        with (context.routeDefinitions[1]) {
+            template == true
+            // stream-caching is disabled in the kamelet
+            streamCache == "false"
+            messageHistory == "true"
+        }
+    }
+
 }
diff --git a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/RouteTemplateTest.groovy b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/RouteTemplateTest.groovy
index 7fba412d4fa..362eb48a614 100644
--- a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/RouteTemplateTest.groovy
+++ b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/RouteTemplateTest.groovy
@@ -20,6 +20,7 @@ import org.apache.camel.component.mock.MockEndpoint
 import org.apache.camel.dsl.yaml.support.YamlTestSupport
 import org.apache.camel.dsl.yaml.support.model.MySetBody
 import org.apache.camel.dsl.yaml.support.model.MyUppercaseProcessor
+import org.apache.camel.impl.engine.DefaultRoute
 import org.apache.camel.model.LogDefinition
 import org.apache.camel.model.RouteTemplateDefinition
 import org.apache.camel.model.ToDefinition
@@ -454,4 +455,33 @@ class RouteTemplateTest extends YamlTestSupport {
         }
     }
 
+    def "create route-template with route"() {
+        setup:
+        loadRoutes """
+                - route-template:
+                    id: "myTemplate"
+                    parameters:
+                      - name: "foo"
+                      - name: "bar"
+                    route:
+                      stream-caching: false
+                      message-history: true
+                      log-mask: true
+                      from:
+                        uri: "direct:{{foo}}"
+                        steps:
+                          - to: "mock:{{bar}}"
+            """
+        when:
+            context.addRouteFromTemplate('myId', 'myTemplate', [foo: "start", bar: "result"])
+            context.start()
+
+        then:
+            with(context.routes[0], DefaultRoute) {
+                it.isStreamCaching() == false
+                it.isMessageHistory() == true
+                it.isLogMask() == true
+            }
+    }
+
 }
diff --git a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/resources/kamelets/route-timer-source.kamelet.yaml b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/resources/kamelets/route-timer-source.kamelet.yaml
new file mode 100644
index 00000000000..08dd0217d75
--- /dev/null
+++ b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/resources/kamelets/route-timer-source.kamelet.yaml
@@ -0,0 +1,72 @@
+# ---------------------------------------------------------------------------
+# 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.
+# ---------------------------------------------------------------------------
+
+apiVersion: camel.apache.org/v1alpha1
+kind: Kamelet
+metadata:
+  name: route-timer-source
+  annotations:
+    camel.apache.org/kamelet.support.level: "Preview"
+    camel.apache.org/catalog.version: "main-SNAPSHOT"
+    camel.apache.org/kamelet.icon: data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4NCjwhLS0gU3ZnIFZlY3RvciBJY29ucyA6IGh0dHA6Ly93d3cub25saW5ld2ViZm9udHMuY29tL2ljb24gLS0+DQo8IURPQ1RZUEUgc3ZnIFBVQkxJQyAiLS8vVzNDLy9EVEQgU1ZHIDEuMS8vRU4iICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPg0KPHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IiB2aWV3Qm9 [...]
+    camel.apache.org/provider: "Apache Software Foundation"
+    camel.apache.org/kamelet.group: "Route Timer"
+  labels:
+    camel.apache.org/kamelet.type: source
+    camel.apache.org/kamelet.verified: "true"
+spec:
+  definition:
+    title: Timer Source
+    description: Produces periodic events with a custom payload.
+    required:
+      - message
+    type: object
+    properties:
+      period:
+        title: Period
+        description: The interval between two events in milliseconds
+        type: integer
+        default: 1000
+      message:
+        title: Message
+        description: The message to generate
+        type: string
+        example: hello world
+      contentType:
+        title: Content Type
+        description: The content type of the message being generated
+        type: string
+        default: text/plain
+  dependencies:
+    - "camel:core"
+    - "camel:timer"
+    - "camel:kamelet"
+  template:
+    route:
+      stream-caching: false
+      message-history: true
+      from:
+        uri: timer:tick
+        parameters:
+          period: "{{period}}"
+        steps:
+          - set-body:
+              constant: "{{message}}"
+          - set-header:
+              name: "Content-Type"
+              constant: "{{contentType}}"
+          - to: kamelet:sink
\ No newline at end of file