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

davsclaus pushed a commit to branch CAMEL-16607
in repository https://gitbox.apache.org/repos/asf/camel.git

commit e6740bc4e29e83f8c043a017a00751dd67e4a489
Author: Claus Ibsen <[email protected]>
AuthorDate: Thu May 13 09:46:56 2021 +0200

    CAMEL-16607: route template / kamelets. Allow to use #type and #class for 
local beans
---
 ...st.java => KameletLocalBeanClassThreeTest.java} |  27 +++---
 .../kamelet/KameletLocalBeanTypeTest.java          |   2 +-
 .../java/org/apache/camel/impl/DefaultModel.java   | 108 ++++++++++++++++++---
 .../services/org/apache/camel/model.properties     |   1 +
 .../resources/org/apache/camel/model/jaxb.index    |   1 +
 .../org/apache/camel/model/templateBean.json       |   3 +-
 .../org/apache/camel/model/templateScript.json     |  16 +++
 .../camel/model/RouteTemplateBeanDefinition.java   |  75 +++++++++++---
 .../camel/model/RouteTemplateScriptDefinition.java |  53 ++++++++++
 .../camel/builder/RouteTemplateLocalBeanTest.java  |  50 ++++++++++
 .../java/org/apache/camel/xml/in/ModelParser.java  |  13 ++-
 .../dsl/yaml/deserializers/ModelDeserializers.java |  46 ++++++++-
 .../deserializers/ModelDeserializersResolver.java  |   2 +
 .../src/generated/resources/camel-yaml-dsl.json    |  18 +++-
 14 files changed, 369 insertions(+), 46 deletions(-)

diff --git 
a/components/camel-kamelet/src/test/java/org/apache/camel/component/kamelet/KameletLocalBeanTypeTest.java
 
b/components/camel-kamelet/src/test/java/org/apache/camel/component/kamelet/KameletLocalBeanClassThreeTest.java
similarity index 78%
copy from 
components/camel-kamelet/src/test/java/org/apache/camel/component/kamelet/KameletLocalBeanTypeTest.java
copy to 
components/camel-kamelet/src/test/java/org/apache/camel/component/kamelet/KameletLocalBeanClassThreeTest.java
index 19d70dc..36b57a0 100644
--- 
a/components/camel-kamelet/src/test/java/org/apache/camel/component/kamelet/KameletLocalBeanTypeTest.java
+++ 
b/components/camel-kamelet/src/test/java/org/apache/camel/component/kamelet/KameletLocalBeanClassThreeTest.java
@@ -16,21 +16,17 @@
  */
 package org.apache.camel.component.kamelet;
 
-import org.apache.camel.BindToRegistry;
 import org.apache.camel.RoutesBuilder;
 import org.apache.camel.builder.RouteBuilder;
 import org.apache.camel.test.junit5.CamelTestSupport;
 import org.apache.http.annotation.Obsolete;
 import org.junit.jupiter.api.Test;
 
-public class KameletLocalBeanTypeTest extends CamelTestSupport {
-
-    @BindToRegistry("myBar")
-    private KameletLocalBeanClassTest.MyBar bar = new 
KameletLocalBeanClassTest.MyBar();
+public class KameletLocalBeanClassThreeTest extends CamelTestSupport {
 
     @Test
     public void testOne() throws Exception {
-        getMockEndpoint("mock:result").expectedBodiesReceived("Hi John we are 
going to Murphys");
+        getMockEndpoint("mock:result").expectedBodiesReceived("Hi John we are 
going to Moes");
 
         template.sendBody("direct:bar", "John");
 
@@ -49,25 +45,30 @@ public class KameletLocalBeanTypeTest extends 
CamelTestSupport {
             @Override
             public void configure() throws Exception {
                 routeTemplate("whereTo")
-                        .templateBean("myBar", 
"#type:org.apache.camel.component.kamelet.KameletLocalBeanTypeTest$Bar")
+                        .templateParameter("bar")
+                        .templateBean("myBar").property("bar", 
"{{bar}}").beanClass(MyBar.class)
                         .from("kamelet:source")
                         // must use {{myBar}} to refer to the local bean
                         .to("bean:{{myBar}}");
 
                 from("direct:bar")
-                        .kamelet("whereTo")
+                        .kamelet("whereTo?bar=Moes")
                         .to("mock:result");
             }
         };
     }
 
-    public interface Bar {
-        String where(String name);
-    }
+    public static class MyBar {
 
-    public static class MyBar implements Bar {
+        private String bar;
 
-        private final String bar = "Murphys";
+        public String getBar() {
+            return bar;
+        }
+
+        public void setBar(String bar) {
+            this.bar = bar;
+        }
 
         public String where(String name) {
             return "Hi " + name + " we are going to " + bar;
diff --git 
a/components/camel-kamelet/src/test/java/org/apache/camel/component/kamelet/KameletLocalBeanTypeTest.java
 
b/components/camel-kamelet/src/test/java/org/apache/camel/component/kamelet/KameletLocalBeanTypeTest.java
index 19d70dc..70d00d2 100644
--- 
a/components/camel-kamelet/src/test/java/org/apache/camel/component/kamelet/KameletLocalBeanTypeTest.java
+++ 
b/components/camel-kamelet/src/test/java/org/apache/camel/component/kamelet/KameletLocalBeanTypeTest.java
@@ -26,7 +26,7 @@ import org.junit.jupiter.api.Test;
 public class KameletLocalBeanTypeTest extends CamelTestSupport {
 
     @BindToRegistry("myBar")
-    private KameletLocalBeanClassTest.MyBar bar = new 
KameletLocalBeanClassTest.MyBar();
+    private MyBar bar = new MyBar();
 
     @Test
     public void testOne() throws Exception {
diff --git 
a/core/camel-core-engine/src/main/java/org/apache/camel/impl/DefaultModel.java 
b/core/camel-core-engine/src/main/java/org/apache/camel/impl/DefaultModel.java
index 1813a01..5ee5e8a 100644
--- 
a/core/camel-core-engine/src/main/java/org/apache/camel/impl/DefaultModel.java
+++ 
b/core/camel-core-engine/src/main/java/org/apache/camel/impl/DefaultModel.java
@@ -28,11 +28,13 @@ import java.util.concurrent.ConcurrentHashMap;
 import java.util.function.Function;
 
 import org.apache.camel.CamelContext;
+import org.apache.camel.Component;
 import org.apache.camel.Exchange;
 import org.apache.camel.Expression;
 import org.apache.camel.ExtendedCamelContext;
 import org.apache.camel.FailedToCreateRouteFromTemplateException;
 import org.apache.camel.NoSuchBeanException;
+import org.apache.camel.PropertyBindingException;
 import org.apache.camel.RouteTemplateContext;
 import org.apache.camel.model.DataFormatDefinition;
 import org.apache.camel.model.DefaultRouteTemplateContext;
@@ -57,9 +59,13 @@ import org.apache.camel.model.validator.ValidatorDefinition;
 import org.apache.camel.spi.ExchangeFactory;
 import org.apache.camel.spi.Language;
 import org.apache.camel.spi.ModelReifierFactory;
+import org.apache.camel.spi.PropertyConfigurer;
 import org.apache.camel.spi.ScriptingLanguage;
+import org.apache.camel.support.PropertyBindingSupport;
 import org.apache.camel.support.ScriptHelper;
+import org.apache.camel.support.service.ServiceHelper;
 import org.apache.camel.util.AntPathMatcher;
+import org.apache.camel.util.ObjectHelper;
 
 public class DefaultModel implements Model {
 
@@ -338,15 +344,21 @@ public class DefaultModel implements Model {
 
     private void addTemplateBeans(RouteTemplateContext routeTemplateContext, 
RouteTemplateDefinition target) throws Exception {
         for (RouteTemplateBeanDefinition b : target.getTemplateBeans()) {
+            final Map<String, Object> props = new HashMap<>();
+            if (b.getProperties() != null) {
+                b.getProperties().forEach((p) -> props.put(p.getKey(), 
p.getValue()));
+            }
             if (b.getBeanSupplier() != null) {
-                // bean class is optional for supplier
-                if (b.getBeanClass() != null) {
-                    routeTemplateContext.bind(b.getName(), b.getBeanClass(), 
b.getBeanSupplier());
-                } else {
-                    routeTemplateContext.bind(b.getName(), 
b.getBeanSupplier());
+                if (props.isEmpty()) {
+                    // bean class is optional for supplier
+                    if (b.getBeanClass() != null) {
+                        routeTemplateContext.bind(b.getName(), 
b.getBeanClass(), b.getBeanSupplier());
+                    } else {
+                        routeTemplateContext.bind(b.getName(), 
b.getBeanSupplier());
+                    }
                 }
             } else if (b.getScript() != null) {
-                final String script = b.getScript();
+                final String script = b.getScript().getScript();
                 final Language lan = camelContext.resolveLanguage(b.getType());
                 final Class<?> clazz = b.getBeanClass() != null ? 
b.getBeanClass() : Object.class;
                 final ScriptingLanguage slan = lan instanceof 
ScriptingLanguage ? (ScriptingLanguage) lan : null;
@@ -356,7 +368,11 @@ public class DefaultModel implements Model {
                         Map<String, Object> bindings = new HashMap<>();
                         // use rtx as the short-hand name, as context would 
imply its CamelContext
                         bindings.put("rtc", routeTemplateContext);
-                        return slan.evaluate(script, bindings, clazz);
+                        Object local = slan.evaluate(script, bindings, clazz);
+                        if (!props.isEmpty()) {
+                            setPropertiesOnTarget(camelContext, local, props);
+                        }
+                        return local;
                     });
                 } else {
                     // exchange based languages needs a dummy exchange to be 
evaluated
@@ -367,7 +383,11 @@ public class DefaultModel implements Model {
                             String text = 
ScriptHelper.resolveOptionalExternalScript(camelContext, dummy, script);
                             if (text != null) {
                                 Expression exp = lan.createExpression(text);
-                                return exp.evaluate(dummy, clazz);
+                                Object local = exp.evaluate(dummy, clazz);
+                                if (!props.isEmpty()) {
+                                    setPropertiesOnTarget(camelContext, local, 
props);
+                                }
+                                return local;
                             } else {
                                 return null;
                             }
@@ -376,14 +396,18 @@ public class DefaultModel implements Model {
                         }
                     });
                 }
-            } else if (b.getBeanClass() != null) {
+            } else if (b.getBeanClass() != null || b.getType() != null && 
b.getType().startsWith("#class:")) {
+                Class<?> clazz = b.getBeanClass() != null
+                        ? b.getBeanClass() : 
camelContext.getClassResolver().resolveMandatoryClass(b.getType().substring(7));
                 // we only have the bean class so we use that to create a new 
bean via the injector
-                routeTemplateContext.bind(b.getName(), b.getBeanClass(),
-                        () -> 
camelContext.getInjector().newInstance(b.getBeanClass()));
-            } else if (b.getType() != null && 
b.getType().startsWith("#class:")) {
-                Class<?> clazz = 
camelContext.getClassResolver().resolveMandatoryClass(b.getType().substring(7));
                 routeTemplateContext.bind(b.getName(), clazz,
-                        () -> camelContext.getInjector().newInstance(clazz));
+                        () -> {
+                            Object local = 
camelContext.getInjector().newInstance(clazz);
+                            if (!props.isEmpty()) {
+                                setPropertiesOnTarget(camelContext, local, 
props);
+                            }
+                            return local;
+                        });
             } else if (b.getType() != null && 
b.getType().startsWith("#type:")) {
                 Class<?> clazz = 
camelContext.getClassResolver().resolveMandatoryClass(b.getType().substring(6));
                 Set<?> found = 
getCamelContext().getRegistry().findByType(clazz);
@@ -393,6 +417,7 @@ public class DefaultModel implements Model {
                     throw new NoSuchBeanException(
                             "Found " + found.size() + " beans of type: " + 
clazz + ". Only one bean expected.");
                 } else {
+                    // do not set properties when using #type as it uses an 
existing shared bean
                     routeTemplateContext.bind(b.getName(), clazz, 
found.iterator().next());
                 }
             }
@@ -638,4 +663,59 @@ public class DefaultModel implements Model {
         }
     }
 
+    private static void setPropertiesOnTarget(CamelContext context, Object 
target, Map<String, Object> properties) {
+        ObjectHelper.notNull(context, "context");
+        ObjectHelper.notNull(target, "target");
+        ObjectHelper.notNull(properties, "properties");
+
+        if (target instanceof CamelContext) {
+            throw new UnsupportedOperationException("Configuring the Camel 
Context is not supported");
+        }
+
+        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) {
+            // see if there is a configurer for it
+            configurer = context.adapt(ExtendedCamelContext.class)
+                    .getConfigurerResolver()
+                    
.resolvePropertyConfigurer(target.getClass().getSimpleName(), 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/core/camel-core-model/src/generated/resources/META-INF/services/org/apache/camel/model.properties
 
b/core/camel-core-model/src/generated/resources/META-INF/services/org/apache/camel/model.properties
index 3e57411..b94ed3b 100644
--- 
a/core/camel-core-model/src/generated/resources/META-INF/services/org/apache/camel/model.properties
+++ 
b/core/camel-core-model/src/generated/resources/META-INF/services/org/apache/camel/model.properties
@@ -172,6 +172,7 @@ tarfile
 templateBean
 templateBeanFactory
 templateParameter
+templateScript
 threadPoolProfile
 threads
 thrift
diff --git 
a/core/camel-core-model/src/generated/resources/org/apache/camel/model/jaxb.index
 
b/core/camel-core-model/src/generated/resources/org/apache/camel/model/jaxb.index
index 88bee1b..c134380 100644
--- 
a/core/camel-core-model/src/generated/resources/org/apache/camel/model/jaxb.index
+++ 
b/core/camel-core-model/src/generated/resources/org/apache/camel/model/jaxb.index
@@ -69,6 +69,7 @@ RouteTemplateBeanDefinition
 RouteTemplateContextRefDefinition
 RouteTemplateDefinition
 RouteTemplateParameterDefinition
+RouteTemplateScriptDefinition
 RouteTemplatesDefinition
 RoutesDefinition
 RoutingSlipDefinition
diff --git 
a/core/camel-core-model/src/generated/resources/org/apache/camel/model/templateBean.json
 
b/core/camel-core-model/src/generated/resources/org/apache/camel/model/templateBean.json
index 0efe577..9f2c566 100644
--- 
a/core/camel-core-model/src/generated/resources/org/apache/camel/model/templateBean.json
+++ 
b/core/camel-core-model/src/generated/resources/org/apache/camel/model/templateBean.json
@@ -13,6 +13,7 @@
   "properties": {
     "name": { "kind": "attribute", "displayName": "Name", "required": true, 
"type": "string", "javaType": "java.lang.String", "deprecated": false, 
"autowired": false, "secret": false, "description": "Bean name" },
     "type": { "kind": "attribute", "displayName": "Type", "required": true, 
"type": "string", "javaType": "java.lang.String", "deprecated": false, 
"autowired": false, "secret": false, "description": "What type to use for 
creating the bean. Can be one of: 
#class,#type,bean,groovy,joor,language,mvel,ognl. #class or #type then the bean 
is created via the fully qualified classname, such as #class:com.foo.MyBean The 
others are scripting languages that gives more power to create the bean with  
[...]
-    "script": { "kind": "value", "displayName": "Script", "required": true, 
"type": "string", "javaType": "java.lang.String", "deprecated": false, 
"autowired": false, "secret": false, "description": "The script to execute that 
creates the bean when using scripting languages. If the script use the prefix 
resource: such as resource:classpath:com\/foo\/myscript.groovy, 
resource:file:\/var\/myscript.groovy, then its loaded from the external 
resource." }
+    "property": { "kind": "element", "displayName": "Property", "required": 
false, "type": "array", "javaType": 
"java.util.List<org.apache.camel.model.PropertyDefinition>", "deprecated": 
false, "autowired": false, "secret": false, "description": "Optional properties 
to set on the created local bean" },
+    "script": { "kind": "element", "displayName": "Script", "required": false, 
"type": "object", "javaType": 
"org.apache.camel.model.RouteTemplateScriptDefinition", "deprecated": false, 
"autowired": false, "secret": false, "description": "The script to execute that 
creates the bean when using scripting languages. If the script use the prefix 
resource: such as resource:classpath:com\/foo\/myscript.groovy, 
resource:file:\/var\/myscript.groovy, then its loaded from the external 
resource." }
   }
 }
diff --git 
a/core/camel-core-model/src/generated/resources/org/apache/camel/model/templateScript.json
 
b/core/camel-core-model/src/generated/resources/org/apache/camel/model/templateScript.json
new file mode 100644
index 0000000..2180976
--- /dev/null
+++ 
b/core/camel-core-model/src/generated/resources/org/apache/camel/model/templateScript.json
@@ -0,0 +1,16 @@
+{
+  "model": {
+    "kind": "model",
+    "name": "templateScript",
+    "title": "Template Script",
+    "description": "A route template script (local bean) when using scripting 
languages such as groovy",
+    "deprecated": false,
+    "label": "configuration",
+    "javaType": "org.apache.camel.model.RouteTemplateScriptDefinition",
+    "input": false,
+    "output": false
+  },
+  "properties": {
+    "script": { "kind": "value", "displayName": "Script", "required": true, 
"type": "string", "javaType": "java.lang.String", "deprecated": false, 
"autowired": false, "secret": false, "description": "The script to execute that 
creates the bean when using scripting languages. If the script use the prefix 
resource: such as resource:classpath:com\/foo\/myscript.groovy, 
resource:file:\/var\/myscript.groovy, then its loaded from the external 
resource." }
+  }
+}
diff --git 
a/core/camel-core-model/src/main/java/org/apache/camel/model/RouteTemplateBeanDefinition.java
 
b/core/camel-core-model/src/main/java/org/apache/camel/model/RouteTemplateBeanDefinition.java
index 2cb37c3..a07ba52 100644
--- 
a/core/camel-core-model/src/main/java/org/apache/camel/model/RouteTemplateBeanDefinition.java
+++ 
b/core/camel-core-model/src/main/java/org/apache/camel/model/RouteTemplateBeanDefinition.java
@@ -16,12 +16,16 @@
  */
 package org.apache.camel.model;
 
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
 import javax.xml.bind.annotation.XmlAccessType;
 import javax.xml.bind.annotation.XmlAccessorType;
 import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlRootElement;
 import javax.xml.bind.annotation.XmlTransient;
-import javax.xml.bind.annotation.XmlValue;
 
 import org.apache.camel.RouteTemplateContext;
 import org.apache.camel.spi.Metadata;
@@ -39,8 +43,10 @@ public class RouteTemplateBeanDefinition {
     private String name;
     @XmlAttribute(required = true)
     private String type;
-    @XmlValue
-    private String script;
+    @XmlElement(name = "property")
+    private List<PropertyDefinition> properties;
+    @XmlElement
+    private RouteTemplateScriptDefinition script;
     // special for java-dsl to allow using lambda style
     @XmlTransient
     private Class<?> beanClass;
@@ -93,18 +99,15 @@ public class RouteTemplateBeanDefinition {
         this.type = type;
     }
 
-    public String getScript() {
-        return script;
+    public List<PropertyDefinition> getProperties() {
+        return properties;
     }
 
     /**
-     * The script to execute that creates the bean when using scripting 
languages.
-     *
-     * If the script use the prefix <tt>resource:</tt> such as 
<tt>resource:classpath:com/foo/myscript.groovy</tt>,
-     * <tt>resource:file:/var/myscript.groovy</tt>, then its loaded from the 
external resource.
+     * Optional properties to set on the created local bean
      */
-    public void setScript(String script) {
-        this.script = script;
+    public void setProperties(List<PropertyDefinition> properties) {
+        this.properties = properties;
     }
 
     public RouteTemplateContext.BeanSupplier<Object> getBeanSupplier() {
@@ -118,6 +121,31 @@ public class RouteTemplateBeanDefinition {
         this.beanSupplier = beanSupplier;
     }
 
+    public RouteTemplateScriptDefinition getScript() {
+        return script;
+    }
+
+    /**
+     * The script to execute that creates the bean when using scripting 
languages.
+     *
+     * If the script use the prefix <tt>resource:</tt> such as 
<tt>resource:classpath:com/foo/myscript.groovy</tt>,
+     * <tt>resource:file:/var/myscript.groovy</tt>, then its loaded from the 
external resource.
+     */
+    public void setScript(RouteTemplateScriptDefinition script) {
+        this.script = script;
+    }
+
+    /**
+     * The script to execute that creates the bean when using scripting 
languages.
+     *
+     * If the script use the prefix <tt>resource:</tt> such as 
<tt>resource:classpath:com/foo/myscript.groovy</tt>,
+     * <tt>resource:file:/var/myscript.groovy</tt>, then its loaded from the 
external resource.
+     */
+    public void setScript(String script) {
+        this.script = new RouteTemplateScriptDefinition();
+        this.script.setScript(script);
+    }
+
     // fluent builders
     // ----------------------------------------------------
 
@@ -238,4 +266,29 @@ public class RouteTemplateBeanDefinition {
         return parent;
     }
 
+    /**
+     * Sets a property to set on the created local bean
+     *
+     * @param key   the property name
+     * @param value the property value
+     */
+    public RouteTemplateBeanDefinition property(String key, String value) {
+        if (properties == null) {
+            properties = new ArrayList<>();
+        }
+        properties.add(new PropertyDefinition(key, value));
+        return this;
+    }
+
+    /**
+     * Sets properties to set on the created local bean
+     */
+    public RouteTemplateBeanDefinition properties(Map<String, String> 
properties) {
+        if (this.properties == null) {
+            this.properties = new ArrayList<>();
+        }
+        properties.forEach((k, v) -> this.properties.add(new 
PropertyDefinition(k, v)));
+        return this;
+    }
+
 }
diff --git 
a/core/camel-core-model/src/main/java/org/apache/camel/model/RouteTemplateScriptDefinition.java
 
b/core/camel-core-model/src/main/java/org/apache/camel/model/RouteTemplateScriptDefinition.java
new file mode 100644
index 0000000..b4d583e
--- /dev/null
+++ 
b/core/camel-core-model/src/main/java/org/apache/camel/model/RouteTemplateScriptDefinition.java
@@ -0,0 +1,53 @@
+/*
+ * 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.model;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlValue;
+
+import org.apache.camel.spi.Metadata;
+
+/**
+ * A route template script (local bean) when using scripting languages such as 
groovy
+ */
+@Metadata(label = "configuration")
+@XmlRootElement(name = "templateScript")
+@XmlAccessorType(XmlAccessType.FIELD)
+public class RouteTemplateScriptDefinition {
+    @XmlValue
+    private String script;
+
+    public RouteTemplateScriptDefinition() {
+    }
+
+    public String getScript() {
+        return script;
+    }
+
+    /**
+     * The script to execute that creates the bean when using scripting 
languages.
+     *
+     * If the script use the prefix <tt>resource:</tt> such as 
<tt>resource:classpath:com/foo/myscript.groovy</tt>,
+     * <tt>resource:file:/var/myscript.groovy</tt>, then its loaded from the 
external resource.
+     */
+    public void setScript(String script) {
+        this.script = script;
+    }
+
+}
diff --git 
a/core/camel-core/src/test/java/org/apache/camel/builder/RouteTemplateLocalBeanTest.java
 
b/core/camel-core/src/test/java/org/apache/camel/builder/RouteTemplateLocalBeanTest.java
index 196470d..ef50ef3 100644
--- 
a/core/camel-core/src/test/java/org/apache/camel/builder/RouteTemplateLocalBeanTest.java
+++ 
b/core/camel-core/src/test/java/org/apache/camel/builder/RouteTemplateLocalBeanTest.java
@@ -587,6 +587,38 @@ public class RouteTemplateLocalBeanTest extends 
ContextTestSupport {
         }
     }
 
+    @Test
+    public void testLocalBeanClassPropertiesFluent() throws Exception {
+        context.addRoutes(new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                
routeTemplate("myTemplate").templateParameter("foo").templateParameter("bar").templateParameter("hi")
+                        .templateBean("myBar").property("prefix", 
"{{hi}}").beanClass(BuilderThreeProcessor.class)
+                        .from("direct:{{foo}}")
+                        .to("bean:{{bar}}");
+            }
+        });
+
+        context.start();
+
+        TemplatedRouteBuilder.builder(context, "myTemplate")
+                .parameter("foo", "one")
+                .parameter("bar", "myBar")
+                .parameter("hi", "Davs")
+                .routeId("myRoute")
+                .add();
+
+        assertEquals(1, context.getRoutes().size());
+
+        Object out = template.requestBody("direct:one", "World");
+        assertEquals("DavsBuilder3 World", out);
+
+        // should not be a global bean
+        assertNull(context.getRegistry().lookupByName("myBar"));
+
+        context.stop();
+    }
+
     public static class BuilderTwoProcessor implements Processor {
 
         private String prefix = "";
@@ -604,6 +636,24 @@ public class RouteTemplateLocalBeanTest extends 
ContextTestSupport {
         }
     }
 
+    public static class BuilderThreeProcessor implements Processor {
+
+        private String prefix = "";
+
+        public String getPrefix() {
+            return prefix;
+        }
+
+        public void setPrefix(String prefix) {
+            this.prefix = prefix;
+        }
+
+        @Override
+        public void process(Exchange exchange) throws Exception {
+            exchange.getMessage().setBody(prefix + "Builder3 " + 
exchange.getMessage().getBody());
+        }
+    }
+
     public Processor createBuilderProcessor() {
         return new BuilderProcessor();
     }
diff --git 
a/core/camel-xml-io/src/generated/java/org/apache/camel/xml/in/ModelParser.java 
b/core/camel-xml-io/src/generated/java/org/apache/camel/xml/in/ModelParser.java
index 5ac4a38..b8e7249 100644
--- 
a/core/camel-xml-io/src/generated/java/org/apache/camel/xml/in/ModelParser.java
+++ 
b/core/camel-xml-io/src/generated/java/org/apache/camel/xml/in/ModelParser.java
@@ -1028,7 +1028,18 @@ public class ModelParser extends BaseParser {
                 default: return false;
             }
             return true;
-        }, noElementHandler(), (def, val) -> def.setScript(val));
+        }, (def, key) -> {
+            switch (key) {
+                case "property": doAdd(doParsePropertyDefinition(), 
def.getProperties(), def::setProperties); break;
+                case "script": 
def.setScript(doParseRouteTemplateScriptDefinition()); break;
+                default: return false;
+            }
+            return true;
+        }, noValueHandler());
+    }
+    protected RouteTemplateScriptDefinition 
doParseRouteTemplateScriptDefinition() throws IOException, 
XmlPullParserException {
+        return doParse(new RouteTemplateScriptDefinition(),
+            noAttributeHandler(), noElementHandler(), (def, val) -> 
def.setScript(val));
     }
     protected RouteTemplateContextRefDefinition 
doParseRouteTemplateContextRefDefinition() throws IOException, 
XmlPullParserException {
         return doParse(new RouteTemplateContextRefDefinition(), (def, key, 
val) -> {
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 a8c0f4b..c1968d0 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
@@ -73,6 +73,7 @@ import org.apache.camel.model.RouteContextRefDefinition;
 import org.apache.camel.model.RouteDefinition;
 import org.apache.camel.model.RouteTemplateBeanDefinition;
 import org.apache.camel.model.RouteTemplateParameterDefinition;
+import org.apache.camel.model.RouteTemplateScriptDefinition;
 import org.apache.camel.model.RoutingSlipDefinition;
 import org.apache.camel.model.SagaActionUriDefinition;
 import org.apache.camel.model.SagaDefinition;
@@ -11740,7 +11741,8 @@ public final class ModelDeserializers extends 
YamlDeserializerSupport {
             nodes = "template-bean",
             properties = {
                     @YamlProperty(name = "name", type = "string", required = 
true),
-                    @YamlProperty(name = "script", type = "string"),
+                    @YamlProperty(name = "property", type = 
"array:org.apache.camel.model.PropertyDefinition"),
+                    @YamlProperty(name = "template-script", type = 
"object:org.apache.camel.model.RouteTemplateScriptDefinition"),
                     @YamlProperty(name = "type", type = "string", required = 
true)
             }
     )
@@ -11768,8 +11770,13 @@ public final class ModelDeserializers extends 
YamlDeserializerSupport {
                     target.setName(val);
                     break;
                 }
-                case "script": {
-                    String val = asText(node);
+                case "property": {
+                    java.util.List<org.apache.camel.model.PropertyDefinition> 
val = asFlatList(node, org.apache.camel.model.PropertyDefinition.class);
+                    target.setProperties(val);
+                    break;
+                }
+                case "template-script": {
+                    org.apache.camel.model.RouteTemplateScriptDefinition val = 
asType(node, org.apache.camel.model.RouteTemplateScriptDefinition.class);
                     target.setScript(val);
                     break;
                 }
@@ -11840,6 +11847,39 @@ public final class ModelDeserializers extends 
YamlDeserializerSupport {
     }
 
     @YamlType(
+            types = org.apache.camel.model.RouteTemplateScriptDefinition.class,
+            order = 
org.apache.camel.dsl.yaml.common.YamlDeserializerResolver.ORDER_LOWEST - 1,
+            nodes = "template-script",
+            properties = @YamlProperty(name = "script", type = "string")
+    )
+    public static class RouteTemplateScriptDefinitionDeserializer extends 
YamlDeserializerBase<RouteTemplateScriptDefinition> {
+        public RouteTemplateScriptDefinitionDeserializer() {
+            super(RouteTemplateScriptDefinition.class);
+        }
+
+        @Override
+        protected RouteTemplateScriptDefinition newInstance() {
+            return new RouteTemplateScriptDefinition();
+        }
+
+        @Override
+        protected boolean setProperty(RouteTemplateScriptDefinition target, 
String propertyKey,
+                String propertyName, Node node) {
+            switch(propertyKey) {
+                case "script": {
+                    String val = asText(node);
+                    target.setScript(val);
+                    break;
+                }
+                default: {
+                    return false;
+                }
+            }
+            return true;
+        }
+    }
+
+    @YamlType(
             inline = true,
             types = org.apache.camel.model.RoutingSlipDefinition.class,
             order = 
org.apache.camel.dsl.yaml.common.YamlDeserializerResolver.ORDER_LOWEST - 1,
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 10d3065..b27616c 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
@@ -296,6 +296,8 @@ public final class ModelDeserializersResolver implements 
YamlDeserializerResolve
             case "org.apache.camel.model.RouteTemplateBeanDefinition": return 
new ModelDeserializers.RouteTemplateBeanDefinitionDeserializer();
             case "template-parameter": return new 
ModelDeserializers.RouteTemplateParameterDefinitionDeserializer();
             case "org.apache.camel.model.RouteTemplateParameterDefinition": 
return new ModelDeserializers.RouteTemplateParameterDefinitionDeserializer();
+            case "template-script": return new 
ModelDeserializers.RouteTemplateScriptDefinitionDeserializer();
+            case "org.apache.camel.model.RouteTemplateScriptDefinition": 
return new ModelDeserializers.RouteTemplateScriptDefinitionDeserializer();
             case "routing-slip": return new 
ModelDeserializers.RoutingSlipDefinitionDeserializer();
             case "org.apache.camel.model.RoutingSlipDefinition": return new 
ModelDeserializers.RoutingSlipDefinitionDeserializer();
             case "rss": return new 
ModelDeserializers.RssDataFormatDeserializer();
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 1eeb7d6..d68e8d6 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
@@ -2068,8 +2068,14 @@
             "name" : {
               "type" : "string"
             },
-            "script" : {
-              "type" : "string"
+            "property" : {
+              "type" : "array",
+              "items" : {
+                "$ref" : 
"#/items/definitions/org.apache.camel.model.PropertyDefinition"
+              }
+            },
+            "template-script" : {
+              "$ref" : 
"#/items/definitions/org.apache.camel.model.RouteTemplateScriptDefinition"
             },
             "type" : {
               "type" : "string"
@@ -2120,6 +2126,14 @@
         },
         "required" : [ "name" ]
       },
+      "org.apache.camel.model.RouteTemplateScriptDefinition" : {
+        "type" : "object",
+        "properties" : {
+          "script" : {
+            "type" : "string"
+          }
+        }
+      },
       "org.apache.camel.model.RoutingSlipDefinition" : {
         "oneOf" : [ {
           "type" : "string"

Reply via email to