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 <cdeppi...@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' + } + } +}