diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/templateBean.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/templateBean.json
index d2b0b7ce9bf72..0efe57794d4c0 100644
--- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/templateBean.json
+++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/templateBean.json
@@ -12,7 +12,7 @@
},
"properties": {
"name": { "kind": "attribute", "displayName": "Name", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Bean name" },
- "language": { "kind": "attribute", "displayName": "Language", "required": false, "type": "enum", "javaType": "java.lang.String", "enum": [ "bean", "groovy", "joor", "language", "mvel", "ognl" ], "deprecated": false, "autowired": false, "secret": false, "description": "The language to use for creating the bean (such as groovy, joor)" },
- "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. 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." }
+ "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 an inlined code in the script section, such as using groovy." },
+ "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/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/schemas/camel-spring.xsd b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/schemas/camel-spring.xsd
index 1147f5db98857..57c504da6441f 100644
--- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/schemas/camel-spring.xsd
+++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/schemas/camel-spring.xsd
@@ -10337,31 +10337,21 @@ Reference to the route templates in the xml dsl.
-
-
-
-
-
diff --git a/components/camel-kamelet/src/test/java/org/apache/camel/component/kamelet/KameletLocalBeanClassFourTest.java b/components/camel-kamelet/src/test/java/org/apache/camel/component/kamelet/KameletLocalBeanClassFourTest.java
new file mode 100644
index 0000000000000..3b254b37e1c4d
--- /dev/null
+++ b/components/camel-kamelet/src/test/java/org/apache/camel/component/kamelet/KameletLocalBeanClassFourTest.java
@@ -0,0 +1,81 @@
+/*
+ * 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.component.kamelet;
+
+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 KameletLocalBeanClassFourTest extends CamelTestSupport {
+
+ @Test
+ public void testOne() throws Exception {
+ getMockEndpoint("mock:result").expectedBodiesReceived("Hi John we are going to Moes");
+
+ template.sendBody("direct:bar", "John");
+
+ assertMockEndpointsSatisfied();
+ }
+
+ // **********************************************
+ //
+ // test set-up
+ //
+ // **********************************************
+
+ @Obsolete
+ protected RoutesBuilder createRouteBuilder() throws Exception {
+ return new RouteBuilder() {
+ @Override
+ public void configure() throws Exception {
+ routeTemplate("whereTo")
+ .templateParameter("bar")
+ .templateBean("myBar")
+ .type("org.apache.camel.component.kamelet.KameletLocalBeanClassFourTest$MyBar")
+ .property("bar", "{{bar}}")
+ .end()
+ .from("kamelet:source")
+ // must use {{myBar}} to refer to the local bean
+ .to("bean:{{myBar}}");
+
+ from("direct:bar")
+ .kamelet("whereTo?bar=Moes")
+ .to("mock:result");
+ }
+ };
+ }
+
+ public static class MyBar {
+
+ private String bar;
+
+ 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/KameletLocalBeanClassTest.java b/components/camel-kamelet/src/test/java/org/apache/camel/component/kamelet/KameletLocalBeanClassTest.java
new file mode 100644
index 0000000000000..b69240113e3a4
--- /dev/null
+++ b/components/camel-kamelet/src/test/java/org/apache/camel/component/kamelet/KameletLocalBeanClassTest.java
@@ -0,0 +1,69 @@
+/*
+ * 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.component.kamelet;
+
+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 KameletLocalBeanClassTest extends CamelTestSupport {
+
+ @Test
+ public void testOne() throws Exception {
+ getMockEndpoint("mock:result").expectedBodiesReceived("Hi John we are going to Murphys");
+
+ template.sendBody("direct:bar", "John");
+
+ assertMockEndpointsSatisfied();
+ }
+
+ // **********************************************
+ //
+ // test set-up
+ //
+ // **********************************************
+
+ @Obsolete
+ protected RoutesBuilder createRouteBuilder() throws Exception {
+ return new RouteBuilder() {
+ @Override
+ public void configure() throws Exception {
+ routeTemplate("whereTo")
+ .templateBean("myBar", MyBar.class)
+ .from("kamelet:source")
+ // must use {{myBar}} to refer to the local bean
+ .to("bean:{{myBar}}");
+
+ from("direct:bar")
+ .kamelet("whereTo")
+ .to("mock:result");
+ }
+ };
+ }
+
+ public static class MyBar {
+
+ private final String bar = "Murphys";
+
+ 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/KameletLocalBeanClassThreeTest.java b/components/camel-kamelet/src/test/java/org/apache/camel/component/kamelet/KameletLocalBeanClassThreeTest.java
new file mode 100644
index 0000000000000..5d4b3f8e51d85
--- /dev/null
+++ b/components/camel-kamelet/src/test/java/org/apache/camel/component/kamelet/KameletLocalBeanClassThreeTest.java
@@ -0,0 +1,81 @@
+/*
+ * 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.component.kamelet;
+
+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 KameletLocalBeanClassThreeTest extends CamelTestSupport {
+
+ @Test
+ public void testOne() throws Exception {
+ getMockEndpoint("mock:result").expectedBodiesReceived("Hi John we are going to Moes");
+
+ template.sendBody("direct:bar", "John");
+
+ assertMockEndpointsSatisfied();
+ }
+
+ // **********************************************
+ //
+ // test set-up
+ //
+ // **********************************************
+
+ @Obsolete
+ protected RoutesBuilder createRouteBuilder() throws Exception {
+ return new RouteBuilder() {
+ @Override
+ public void configure() throws Exception {
+ routeTemplate("whereTo")
+ .templateParameter("bar")
+ .templateBean("myBar")
+ .type(MyBar.class)
+ .property("bar", "{{bar}}")
+ .end()
+ .from("kamelet:source")
+ // must use {{myBar}} to refer to the local bean
+ .to("bean:{{myBar}}");
+
+ from("direct:bar")
+ .kamelet("whereTo?bar=Moes")
+ .to("mock:result");
+ }
+ };
+ }
+
+ public static class MyBar {
+
+ private String bar;
+
+ 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/KameletLocalBeanClassTwoTest.java b/components/camel-kamelet/src/test/java/org/apache/camel/component/kamelet/KameletLocalBeanClassTwoTest.java
new file mode 100644
index 0000000000000..e57760b2ae187
--- /dev/null
+++ b/components/camel-kamelet/src/test/java/org/apache/camel/component/kamelet/KameletLocalBeanClassTwoTest.java
@@ -0,0 +1,69 @@
+/*
+ * 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.component.kamelet;
+
+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 KameletLocalBeanClassTwoTest extends CamelTestSupport {
+
+ @Test
+ public void testOne() throws Exception {
+ getMockEndpoint("mock:result").expectedBodiesReceived("Hi John we are going to Murphys");
+
+ template.sendBody("direct:bar", "John");
+
+ assertMockEndpointsSatisfied();
+ }
+
+ // **********************************************
+ //
+ // test set-up
+ //
+ // **********************************************
+
+ @Obsolete
+ protected RoutesBuilder createRouteBuilder() throws Exception {
+ return new RouteBuilder() {
+ @Override
+ public void configure() throws Exception {
+ routeTemplate("whereTo")
+ .templateBean("myBar", "#class:org.apache.camel.component.kamelet.KameletLocalBeanClassTwoTest$MyBar")
+ .from("kamelet:source")
+ // must use {{myBar}} to refer to the local bean
+ .to("bean:{{myBar}}");
+
+ from("direct:bar")
+ .kamelet("whereTo")
+ .to("mock:result");
+ }
+ };
+ }
+
+ public static class MyBar {
+
+ private final String bar = "Murphys";
+
+ 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
new file mode 100644
index 0000000000000..70d00d2f74189
--- /dev/null
+++ b/components/camel-kamelet/src/test/java/org/apache/camel/component/kamelet/KameletLocalBeanTypeTest.java
@@ -0,0 +1,77 @@
+/*
+ * 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.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 MyBar bar = new MyBar();
+
+ @Test
+ public void testOne() throws Exception {
+ getMockEndpoint("mock:result").expectedBodiesReceived("Hi John we are going to Murphys");
+
+ template.sendBody("direct:bar", "John");
+
+ assertMockEndpointsSatisfied();
+ }
+
+ // **********************************************
+ //
+ // test set-up
+ //
+ // **********************************************
+
+ @Obsolete
+ protected RoutesBuilder createRouteBuilder() throws Exception {
+ return new RouteBuilder() {
+ @Override
+ public void configure() throws Exception {
+ routeTemplate("whereTo")
+ .templateBean("myBar", "#type:org.apache.camel.component.kamelet.KameletLocalBeanTypeTest$Bar")
+ .from("kamelet:source")
+ // must use {{myBar}} to refer to the local bean
+ .to("bean:{{myBar}}");
+
+ from("direct:bar")
+ .kamelet("whereTo")
+ .to("mock:result");
+ }
+ };
+ }
+
+ public interface Bar {
+ String where(String name);
+ }
+
+ public static class MyBar implements Bar {
+
+ private final String bar = "Murphys";
+
+ public String where(String name) {
+ return "Hi " + name + " we are going to " + bar;
+ }
+ }
+
+}
diff --git a/components/camel-spring-xml/src/test/java/org/apache/camel/spring/routebuilder/MyLocalBean.java b/components/camel-spring-xml/src/test/java/org/apache/camel/spring/routebuilder/MyLocalBean.java
new file mode 100644
index 0000000000000..47fed854d9f6f
--- /dev/null
+++ b/components/camel-spring-xml/src/test/java/org/apache/camel/spring/routebuilder/MyLocalBean.java
@@ -0,0 +1,34 @@
+/*
+ * 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.spring.routebuilder;
+
+public class MyLocalBean {
+
+ private String prefix;
+
+ public String getPrefix() {
+ return prefix;
+ }
+
+ public void setPrefix(String prefix) {
+ this.prefix = prefix;
+ }
+
+ public String hello(String body) {
+ return prefix + " " + body;
+ }
+}
diff --git a/components/camel-spring-xml/src/test/java/org/apache/camel/spring/routebuilder/SpringRouteTemplateLocalBeanTest.java b/components/camel-spring-xml/src/test/java/org/apache/camel/spring/routebuilder/SpringRouteTemplateLocalBeanTest.java
new file mode 100644
index 0000000000000..7f0eba54d4428
--- /dev/null
+++ b/components/camel-spring-xml/src/test/java/org/apache/camel/spring/routebuilder/SpringRouteTemplateLocalBeanTest.java
@@ -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.spring.routebuilder;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.spring.SpringTestSupport;
+import org.junit.jupiter.api.Test;
+import org.springframework.context.support.AbstractXmlApplicationContext;
+import org.springframework.context.support.ClassPathXmlApplicationContext;
+
+public class SpringRouteTemplateLocalBeanTest extends SpringTestSupport {
+
+ @Override
+ protected AbstractXmlApplicationContext createApplicationContext() {
+ return new ClassPathXmlApplicationContext("org/apache/camel/spring/routebuilder/SpringRouteTemplateLocalBeanTest.xml");
+ }
+
+ @Test
+ public void testLocalBean() throws Exception {
+ Map parameters = new HashMap<>();
+ parameters.put("foo", "one");
+ parameters.put("bar", "cheese");
+ parameters.put("greeting", "Davs");
+ context.addRouteFromTemplate("first", "myTemplate", parameters);
+
+ MockEndpoint mock = getMockEndpoint("mock:cheese");
+ mock.expectedBodiesReceived("Davs World");
+
+ template.sendBody("direct:one", "World");
+
+ assertMockEndpointsSatisfied();
+ }
+
+}
diff --git a/components/camel-spring-xml/src/test/resources/org/apache/camel/spring/routebuilder/SpringRouteTemplateLocalBeanTest.xml b/components/camel-spring-xml/src/test/resources/org/apache/camel/spring/routebuilder/SpringRouteTemplateLocalBeanTest.xml
new file mode 100644
index 0000000000000..73b77084698e8
--- /dev/null
+++ b/components/camel-spring-xml/src/test/resources/org/apache/camel/spring/routebuilder/SpringRouteTemplateLocalBeanTest.xml
@@ -0,0 +1,46 @@
+
+
+
+
+
+
+ blah blah
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/core/camel-api/src/main/java/org/apache/camel/spi/Registry.java b/core/camel-api/src/main/java/org/apache/camel/spi/Registry.java
index a15a4652865e9..683d8aae845bb 100644
--- a/core/camel-api/src/main/java/org/apache/camel/spi/Registry.java
+++ b/core/camel-api/src/main/java/org/apache/camel/spi/Registry.java
@@ -36,7 +36,9 @@ public interface Registry extends BeanRepository {
* @throws RuntimeCamelException is thrown if binding is not possible
*/
default void bind(String id, Object bean) throws RuntimeCamelException {
- bind(id, bean.getClass(), bean);
+ if (bean != null) {
+ bind(id, bean.getClass(), bean);
+ }
}
/**
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 53b02cc9f1ae4..43114166daca1 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
@@ -22,15 +22,19 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.Set;
import java.util.StringJoiner;
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;
@@ -55,9 +59,13 @@
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 {
@@ -336,16 +344,22 @@ public String addRouteFromTemplate(String routeId, String routeTemplateId, Route
private void addTemplateBeans(RouteTemplateContext routeTemplateContext, RouteTemplateDefinition target) throws Exception {
for (RouteTemplateBeanDefinition b : target.getTemplateBeans()) {
+ final Map 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 Language lan = camelContext.resolveLanguage(b.getLanguage());
+ 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;
if (slan != null) {
@@ -354,7 +368,11 @@ private void addTemplateBeans(RouteTemplateContext routeTemplateContext, RouteTe
Map 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
@@ -365,7 +383,11 @@ private void addTemplateBeans(RouteTemplateContext routeTemplateContext, RouteTe
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;
}
@@ -374,10 +396,30 @@ private void addTemplateBeans(RouteTemplateContext routeTemplateContext, RouteTe
}
});
}
- } 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()));
+ routeTemplateContext.bind(b.getName(), 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);
+ if (found == null || found.isEmpty()) {
+ throw new NoSuchBeanException(null, clazz.getName());
+ } else if (found.size() > 1) {
+ 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());
+ }
}
}
}
@@ -621,4 +663,59 @@ private static T lookup(CamelContext context, String ref, Class type) {
}
}
+ private static void setPropertiesOnTarget(CamelContext context, Object target, Map 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 3e5741135aed0..b94ed3bb0d10c 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 88bee1bbf8b05..c13438052112a 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 d2b0b7ce9bf72..9f2c566570688 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
@@ -12,7 +12,8 @@
},
"properties": {
"name": { "kind": "attribute", "displayName": "Name", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Bean name" },
- "language": { "kind": "attribute", "displayName": "Language", "required": false, "type": "enum", "javaType": "java.lang.String", "enum": [ "bean", "groovy", "joor", "language", "mvel", "ognl" ], "deprecated": false, "autowired": false, "secret": false, "description": "The language to use for creating the bean (such as groovy, joor)" },
- "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. 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." }
+ "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 an inlined code in the script section, such as using groovy." },
+ "property": { "kind": "element", "displayName": "Property", "required": false, "type": "array", "javaType": "java.util.List", "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 0000000000000..2180976239763
--- /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 84bd5a798f9e4..79876d3f9e17c 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;
@@ -37,17 +41,16 @@ public class RouteTemplateBeanDefinition {
private RouteTemplateDefinition parent;
@XmlAttribute(required = true)
private String name;
- @XmlTransient
- private Class> beanClass;
- // it only makes sense to use the languages that are general purpose scripting languages
@XmlAttribute(required = true)
- @Metadata(enums = "bean,groovy,joor,language,mvel,ognl")
- private String language;
- @XmlValue
- @Metadata(required = true)
- private String script;
+ private String type;
+ @XmlElement(name = "property")
+ private List properties;
+ @XmlElement
+ private RouteTemplateScriptDefinition script;
// special for java-dsl to allow using lambda style
@XmlTransient
+ private Class> beanClass;
+ @XmlTransient
private RouteTemplateContext.BeanSupplier