You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by cd...@apache.org on 2023/07/04 11:56:49 UTC
[camel] 02/03: CAMEL-18698 Enhance YAML DSL loader to support input/output data types
This is an automated email from the ASF dual-hosted git repository.
cdeppisch pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git
commit 2d8812eefe92451ddb91179e7abe14d283a6acc4
Author: Christoph Deppisch <cd...@redhat.com>
AuthorDate: Wed Jun 28 08:56:04 2023 +0200
CAMEL-18698 Enhance YAML DSL loader to support input/output data types
- Enable users to specify input/output data types on route and KameletBinding
- Automatically adds transformation steps and/or input/output data type specifications to the Camel route
---
.../deserializers/RouteDefinitionDeserializer.java | 12 +++
.../camel/dsl/yaml/YamlRoutesBuilderLoader.java | 26 ++++++
.../camel/dsl/yaml/KameletBindingLoaderTest.groovy | 97 ++++++++++++++++++++++
.../org/apache/camel/dsl/yaml/RoutesTest.groovy | 27 ++++++
.../org/apache/camel/dsl/yaml/TransformTest.groovy | 51 ++++++++++++
5 files changed, 213 insertions(+)
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 38ba442f082..3369c745d4d 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,6 +21,8 @@ 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.InputTypeDefinition;
+import org.apache.camel.model.OutputTypeDefinition;
import org.apache.camel.model.RouteDefinition;
import org.apache.camel.spi.annotations.YamlIn;
import org.apache.camel.spi.annotations.YamlProperty;
@@ -48,6 +50,8 @@ import org.snakeyaml.engine.v2.nodes.NodeTuple;
@YamlProperty(name = "message-history", type = "boolean"),
@YamlProperty(name = "log-mask", type = "boolean"),
@YamlProperty(name = "trace", type = "boolean"),
+ @YamlProperty(name = "input-type", type = "object:org.apache.camel.model.InputTypeDefinition"),
+ @YamlProperty(name = "output-type", type = "object:org.apache.camel.model.OutputTypeDefinition"),
@YamlProperty(name = "from", type = "object:org.apache.camel.model.FromDefinition", required = true)
})
public class RouteDefinitionDeserializer extends YamlDeserializerBase<RouteDefinition> {
@@ -119,6 +123,14 @@ public class RouteDefinitionDeserializer extends YamlDeserializerBase<RouteDefin
case "trace":
target.setTrace(asText(val));
break;
+ case "inputType":
+ case "input-type":
+ target.setInputType(asType(val, InputTypeDefinition.class));
+ break;
+ case "outputType":
+ case "output-type":
+ target.setOutputType(asType(val, OutputTypeDefinition.class));
+ 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/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 87eecb3f346..dd6a306aef7 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
@@ -57,6 +57,7 @@ import org.apache.camel.model.rest.RestConfigurationDefinition;
import org.apache.camel.model.rest.RestDefinition;
import org.apache.camel.model.rest.VerbDefinition;
import org.apache.camel.spi.CamelContextCustomizer;
+import org.apache.camel.spi.DataType;
import org.apache.camel.spi.DependencyStrategy;
import org.apache.camel.spi.Resource;
import org.apache.camel.spi.annotations.RoutesLoader;
@@ -648,6 +649,19 @@ public class YamlRoutesBuilderLoader extends YamlRoutesBuilderLoaderSupport {
}
}
+ MappingNode dataTypes = asMappingNode(nodeAt(source, "/dataTypes"));
+ if (dataTypes != null) {
+ MappingNode in = asMappingNode(nodeAt(dataTypes, "/in"));
+ if (in != null) {
+ route.inputType(extractTupleValue(in.getValue(), "format"));
+ }
+
+ MappingNode out = asMappingNode(nodeAt(dataTypes, "/out"));
+ if (out != null) {
+ route.transform(new DataType(extractTupleValue(out.getValue(), "format")));
+ }
+ }
+
// steps in the middle (optional)
Node steps = nodeAt(root, "/spec/steps");
if (steps != null) {
@@ -683,6 +697,18 @@ public class YamlRoutesBuilderLoader extends YamlRoutesBuilderLoaderSupport {
}
if (sink != null) {
+ dataTypes = asMappingNode(nodeAt(sink, "/dataTypes"));
+ if (dataTypes != null) {
+ MappingNode in = asMappingNode(nodeAt(dataTypes, "/in"));
+ if (in != null) {
+ route.transform(new DataType(extractTupleValue(in.getValue(), "format")));
+ }
+
+ MappingNode out = asMappingNode(nodeAt(dataTypes, "/out"));
+ if (out != null) {
+ route.outputType(extractTupleValue(out.getValue(), "format"));
+ }
+ }
// sink is at the end (mandatory)
line = -1;
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 2a15541d526..30454f5c188 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
@@ -22,6 +22,7 @@ import org.apache.camel.component.mock.MockEndpoint
import org.apache.camel.dsl.yaml.support.YamlTestSupport
import org.apache.camel.model.KameletDefinition
import org.apache.camel.model.ToDefinition
+import org.apache.camel.model.TransformDefinition
import org.apache.camel.model.errorhandler.DeadLetterChannelDefinition
import org.apache.camel.model.errorhandler.DefaultErrorHandlerDefinition
import org.apache.camel.model.errorhandler.NoErrorHandlerDefinition
@@ -657,4 +658,100 @@ class KameletBindingLoaderTest extends YamlTestSupport {
}
}
+ def "kamelet binding with input/output data types"() {
+ 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: timer-source
+ dataTypes:
+ in:
+ format: plain/text
+ properties:
+ message: "Hello world!"
+ sink:
+ ref:
+ kind: Kamelet
+ apiVersion: camel.apache.org/v1
+ name: log-sink
+ dataTypes:
+ out:
+ format: application/octet-stream
+ ''')
+ then:
+ context.routeDefinitions.size() == 3
+
+ with (context.routeDefinitions[0]) {
+ routeId == 'timer-event-source'
+ input.endpointUri == 'kamelet:timer-source?message=Hello+world%21'
+ input.lineNumber == 7
+ inputType.urn == 'plain/text'
+ outputType.urn == 'application/octet-stream'
+ outputs.size() == 1
+ with (outputs[0], ToDefinition) {
+ endpointUri == 'kamelet:log-sink'
+ lineNumber == 17
+ }
+ }
+ }
+
+ def "kamelet binding with data type transformation"() {
+ 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: timer-source
+ dataTypes:
+ out:
+ format: application/octet-stream
+ properties:
+ message: "Hello world!"
+ sink:
+ ref:
+ kind: Kamelet
+ apiVersion: camel.apache.org/v1
+ name: log-sink
+ dataTypes:
+ in:
+ format: plain/text
+ ''')
+ then:
+ context.routeDefinitions.size() == 3
+
+ with (context.routeDefinitions[0]) {
+ routeId == 'timer-event-source'
+ input.endpointUri == 'kamelet:timer-source?message=Hello+world%21'
+ input.lineNumber == 7
+ outputs.size() == 3
+ with (outputs[0], TransformDefinition) {
+ fromType == 'camel:any'
+ toType == 'application/octet-stream'
+ lineNumber == -1
+ }
+ with (outputs[1], TransformDefinition) {
+ fromType == 'camel:any'
+ toType == 'plain/text'
+ lineNumber == -1
+ }
+ with (outputs[2], ToDefinition) {
+ endpointUri == 'kamelet:log-sink'
+ lineNumber == 17
+ }
+ }
+ }
+
}
diff --git a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/RoutesTest.groovy b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/RoutesTest.groovy
index 983782d5577..3bfe4494be4 100644
--- a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/RoutesTest.groovy
+++ b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/RoutesTest.groovy
@@ -164,6 +164,33 @@ class RoutesTest extends YamlTestSupport {
}
}
+ def "load route with input/output types"() {
+ when:
+ loadRoutes '''
+ - route:
+ inputType:
+ urn: "plain/text"
+ outputType:
+ urn: "application/octet-stream"
+ from:
+ uri: "direct:info"
+ steps:
+ - log: "message"
+ '''
+ then:
+ context.routeDefinitions.size() == 1
+
+ with(context.routeDefinitions[0], RouteDefinition) {
+ inputType.urn == 'plain/text'
+ outputType.urn == 'application/octet-stream'
+
+ input.endpointUri == 'direct:info'
+ with (outputs[0], LogDefinition) {
+ message == 'message'
+ }
+ }
+ }
+
def "load route inlined"() {
when:
loadRoutes '''
diff --git a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/TransformTest.groovy b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/TransformTest.groovy
new file mode 100644
index 00000000000..32fd939de05
--- /dev/null
+++ b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/TransformTest.groovy
@@ -0,0 +1,51 @@
+/*
+ * 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.dsl.yaml.support.YamlTestSupport
+import org.apache.camel.model.StepDefinition
+import org.apache.camel.model.ToDefinition
+import org.apache.camel.model.TransformDefinition
+
+class TransformTest extends YamlTestSupport {
+
+ def "transform with data types"() {
+ when:
+ loadRoutes '''
+ - from:
+ uri: "direct:start"
+ steps:
+ - step:
+ steps:
+ - transform:
+ fromType: "plain-text"
+ toType: "application-octet-stream"
+ - to: "mock:result"
+
+ '''
+ then:
+ with(context.routeDefinitions[0].outputs[0], StepDefinition) {
+ with(outputs[0], TransformDefinition) {
+ fromType == 'plain-text'
+ toType == 'application-octet-stream'
+ }
+ }
+ with(context.routeDefinitions[0].outputs[1], ToDefinition) {
+ endpointUri == 'mock:result'
+ }
+ }
+}