[camel-k-runtime] branch master updated: [yaml] support for configuring beans with the yaml dsl #376

classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

[camel-k-runtime] branch master updated: [yaml] support for configuring beans with the yaml dsl #376

lburgazzoli-2
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-k-runtime.git


The following commit(s) were added to refs/heads/master by this push:
     new b4399bb  [yaml] support for configuring beans with the yaml dsl #376
b4399bb is described below

commit b4399bbdd36652bd173b538814cf22bc29395350
Author: lburgazzoli <[hidden email]>
AuthorDate: Fri Jul 10 14:30:12 2020 +0200

    [yaml] support for configuring beans with the yaml dsl #376
---
 .../k/loader/yaml/parser/BeansStepParser.java      | 142 +++++++++++++++++++++
 .../src/generated/resources/camel-yaml-dsl.json    |  15 +++
 .../apache/camel/k/loader/yaml/RoutesTest.groovy   |  21 +++
 .../test/resources/routes/RoutesTest_beans.yaml    |  32 +++++
 4 files changed, 210 insertions(+)

diff --git a/camel-k-loader-yaml/camel-k-loader-yaml-common/src/main/java/org/apache/camel/k/loader/yaml/parser/BeansStepParser.java b/camel-k-loader-yaml/camel-k-loader-yaml-common/src/main/java/org/apache/camel/k/loader/yaml/parser/BeansStepParser.java
new file mode 100644
index 0000000..0de129c
--- /dev/null
+++ b/camel-k-loader-yaml/camel-k-loader-yaml-common/src/main/java/org/apache/camel/k/loader/yaml/parser/BeansStepParser.java
@@ -0,0 +1,142 @@
+/*
+ * 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.k.loader.yaml.parser;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.core.type.TypeReference;
+import org.apache.camel.CamelContext;
+import org.apache.camel.Component;
+import org.apache.camel.ExtendedCamelContext;
+import org.apache.camel.PropertyBindingException;
+import org.apache.camel.k.annotation.yaml.YAMLNodeDefinition;
+import org.apache.camel.k.annotation.yaml.YAMLStepParser;
+import org.apache.camel.k.loader.yaml.spi.StartStepParser;
+import org.apache.camel.spi.PropertyConfigurer;
+import org.apache.camel.support.PropertyBindingSupport;
+import org.apache.camel.support.service.ServiceHelper;
+import org.apache.camel.util.ObjectHelper;
+import org.apache.camel.util.StringHelper;
+
+
+@YAMLStepParser(id = "beans", definition = BeansStepParser.Definition.class, schema = false)
+public class BeansStepParser implements StartStepParser {
+    @Override
+    public Object process(Context context) {
+        final List<Definition> beans = context.node(new TypeReference<>() {});
+        final CamelContext camelContext = context.getCamelContext();
+
+        for (Definition bean: beans) {
+            ObjectHelper.notNull(bean.name, "bean name");
+            ObjectHelper.notNull(bean.type, "bean type");
+
+            final Map<String, Object> properties;
+
+            if (bean.properties != null) {
+                properties = new HashMap<>();
+                bean.properties.forEach((k, v) -> properties.put(StringHelper.dashToCamelCase(k), v));
+            } else {
+                properties = Collections.emptyMap();
+            }
+
+            try {
+                String type = bean.type;
+                if (!type.startsWith("#class:")) {
+                    type = "#class:" + type;
+                }
+
+                Object target = PropertyBindingSupport.resolveBean(camelContext, null, type);
+
+                setPropertiesOnTarget(camelContext, target, properties);
+                camelContext.getRegistry().bind(bean.name, target);
+            } catch (Exception e) {
+                throw new RuntimeException(e);
+            }
+        }
+
+        return null;
+    }
+
+    @YAMLNodeDefinition
+    public static final class Definition {
+        @JsonProperty(required = true)
+        public String name;
+        @JsonProperty(required = true)
+        public String type;
+        @JsonProperty
+        public Map<String, Object> properties;
+    }
+
+    protected static void setPropertiesOnTarget(
+            CamelContext context,
+            Object target,
+            Map<String, Object> properties) {
+
+        ObjectHelper.notNull(context, "context");
+        ObjectHelper.notNull(target, "target");
+        ObjectHelper.notNull(properties, "properties");
+
+        PropertyConfigurer configurer = null;
+        if (target instanceof Component) {
+            // the component needs to be initialized to have the configurer ready
+            ServiceHelper.initService(target);
+            configurer = ((Component) target).getComponentPropertyConfigurer();
+        }
+
+        if (configurer == null) {
+            String name = target.getClass().getSimpleName();
+            if (target instanceof ExtendedCamelContext) {
+                // special for camel context itself as we have an extended configurer
+                name = "ExtendedCamelContext";
+            }
+
+            // see if there is a configurer for it
+            configurer = context.adapt(ExtendedCamelContext.class)
+                .getConfigurerResolver()
+                .resolvePropertyConfigurer(name, context);
+        }
+
+        try {
+            PropertyBindingSupport.build()
+                .withMandatory(true)
+                .withRemoveParameters(false)
+                .withConfigurer(configurer)
+                .withIgnoreCase(true)
+                .withFlattenProperties(true)
+                .bind(context, target, properties);
+        } catch (PropertyBindingException e) {
+            String key = e.getOptionKey();
+            if (key == null) {
+                String prefix = e.getOptionPrefix();
+                if (prefix != null && !prefix.endsWith(".")) {
+                    prefix = "." + prefix;
+                }
+
+                key = prefix != null
+                    ? prefix + "." + e.getPropertyName()
+                    : e.getPropertyName();
+            }
+
+            // enrich the error with more precise details with option prefix and key
+            throw new PropertyBindingException(e.getTarget(), e.getPropertyName(), e.getValue(), null, key, e.getCause());
+        }
+    }
+}
diff --git a/camel-k-loader-yaml/camel-k-loader-yaml/src/generated/resources/camel-yaml-dsl.json b/camel-k-loader-yaml/camel-k-loader-yaml/src/generated/resources/camel-yaml-dsl.json
index 9bd6827..2bf79bf 100644
--- a/camel-k-loader-yaml/camel-k-loader-yaml/src/generated/resources/camel-yaml-dsl.json
+++ b/camel-k-loader-yaml/camel-k-loader-yaml/src/generated/resources/camel-yaml-dsl.json
@@ -2048,6 +2048,21 @@
           }
         } ]
       },
+      "org.apache.camel.k.loader.yaml.parser.BeansStepParser$Definition" : {
+        "type" : "object",
+        "properties" : {
+          "name" : {
+            "type" : "string"
+          },
+          "properties" : {
+            "type" : "object"
+          },
+          "type" : {
+            "type" : "string"
+          }
+        },
+        "required" : [ "name", "type" ]
+      },
       "org.apache.camel.k.loader.yaml.parser.ChoiceStepParser$Definition" : {
         "type" : "object",
         "properties" : {
diff --git a/camel-k-loader-yaml/camel-k-loader-yaml/src/test/groovy/org/apache/camel/k/loader/yaml/RoutesTest.groovy b/camel-k-loader-yaml/camel-k-loader-yaml/src/test/groovy/org/apache/camel/k/loader/yaml/RoutesTest.groovy
index f1cb5ae..df7b6e4 100644
--- a/camel-k-loader-yaml/camel-k-loader-yaml/src/test/groovy/org/apache/camel/k/loader/yaml/RoutesTest.groovy
+++ b/camel-k-loader-yaml/camel-k-loader-yaml/src/test/groovy/org/apache/camel/k/loader/yaml/RoutesTest.groovy
@@ -17,6 +17,7 @@
 package org.apache.camel.k.loader.yaml
 
 import org.apache.camel.component.mock.MockEndpoint
+import org.apache.camel.k.loader.yaml.support.MyBean
 import org.apache.camel.k.loader.yaml.support.MyFailingProcessor
 import org.apache.camel.k.loader.yaml.support.TestSupport
 import org.apache.camel.processor.aggregate.UseLatestAggregationStrategy
@@ -171,4 +172,24 @@ class RoutesTest extends TestSupport {
         cleanup:
             context?.stop()
     }
+
+    def 'beans'() {
+        when:
+            def context = startContextForSpec()
+        then:
+            with(context.registry.lookupByName('myNested'), MyBean) {
+                it.field1 == 'f1'
+                it.field2 == 'f2'
+                it.nested.field1 == 'nf1'
+                it.nested.field2 == 'nf2'
+            }
+            with(context.registry.lookupByName('myProps'), MyBean) {
+                it.field1 == 'f1_p'
+                it.field2 == 'f2_p'
+                it.nested.field1 == 'nf1_p'
+                it.nested.field2 == 'nf2_p'
+            }
+        cleanup:
+            context?.stop()
+    }
 }
diff --git a/camel-k-loader-yaml/camel-k-loader-yaml/src/test/resources/routes/RoutesTest_beans.yaml b/camel-k-loader-yaml/camel-k-loader-yaml/src/test/resources/routes/RoutesTest_beans.yaml
new file mode 100644
index 0000000..e2eef2b
--- /dev/null
+++ b/camel-k-loader-yaml/camel-k-loader-yaml/src/test/resources/routes/RoutesTest_beans.yaml
@@ -0,0 +1,32 @@
+#
+# 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.
+#
+- beans:
+    - name: myNested
+      type: org.apache.camel.k.loader.yaml.support.MyBean
+      properties:
+        field1: 'f1'
+        field2: 'f2'
+        nested:
+          field1: 'nf1'
+          field2: 'nf2'
+    - name: myProps
+      type: org.apache.camel.k.loader.yaml.support.MyBean
+      properties:
+        field1: 'f1_p'
+        field2: 'f2_p'
+        nested.field1: 'nf1_p'
+        nested.field2: 'nf2_p'
\ No newline at end of file