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 7b78495cbc90090b05e1c5ef6bf375185b952201 Author: Claus Ibsen <[email protected]> AuthorDate: Thu May 13 07:53:22 2021 +0200 CAMEL-16607: route template / kamelets. Allow to use #type and #class for local beans --- .../apache/camel/catalog/models/templateBean.json | 4 +- .../apache/camel/catalog/schemas/camel-spring.xsd | 16 ++---- .../main/java/org/apache/camel/spi/Registry.java | 4 +- .../java/org/apache/camel/impl/DefaultModel.java | 18 ++++++- .../org/apache/camel/model/templateBean.json | 4 +- .../camel/model/RouteTemplateBeanDefinition.java | 59 +++++++++++++++------- .../camel/model/RouteTemplateDefinition.java | 2 +- .../camel/builder/RouteTemplateLocalBeanTest.java | 35 ++++++++++++- .../org/apache/camel/support/DefaultRegistry.java | 20 +++++--- .../org/apache/camel/support/SimpleRegistry.java | 4 +- .../org/apache/camel/support/SupplierRegistry.java | 4 +- .../java/org/apache/camel/xml/in/ModelParser.java | 2 +- .../dsl/yaml/deserializers/ModelDeserializers.java | 14 ++--- .../src/generated/resources/camel-yaml-dsl.json | 8 +-- 14 files changed, 133 insertions(+), 61 deletions(-) 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 d2b0b7c..0efe577 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 [...] + "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 1147f5d..57c504d 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. <xs:attribute name="name" type="xs:string" use="required"> <xs:annotation> <xs:documentation xml:lang="en"><![CDATA[ -The name of the parameter. - ]]></xs:documentation> - </xs:annotation> - </xs:attribute> - <xs:attribute name="required" type="xs:boolean"> - <xs:annotation> - <xs:documentation xml:lang="en"><![CDATA[ -Whether the parameter is required or not. A parameter is required unless this -option is set to false or a default value has been configured. Default value: -false +Parameter name. ]]></xs:documentation> </xs:annotation> </xs:attribute> <xs:attribute name="defaultValue" type="xs:string"> <xs:annotation> <xs:documentation xml:lang="en"><![CDATA[ -Default value of the parameter. If a default value is provided then the -parameter is implied not to be required. +Parameter default value. ]]></xs:documentation> </xs:annotation> </xs:attribute> <xs:attribute name="description" type="xs:string"> <xs:annotation> <xs:documentation xml:lang="en"><![CDATA[ -Description of the parameter. +Parameter description. ]]></xs:documentation> </xs:annotation> </xs:attribute> 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 a15a465..683d8aa 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 53b02cc..d462721 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,6 +22,7 @@ import java.util.Collections; 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; @@ -345,7 +346,7 @@ public class DefaultModel implements Model { } } else if (b.getScript() != null) { final String script = b.getScript(); - final Language lan = camelContext.resolveLanguage(b.getLanguage()); + 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) { @@ -378,6 +379,21 @@ public class DefaultModel implements Model { // 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)); + } else if (b.getType() != null && b.getType().startsWith("#type:")) { + Class<?> clazz = camelContext.getClassResolver().resolveMandatoryClass(b.getType().substring(6)); + routeTemplateContext.bind(b.getName(), clazz, + () -> { + Set<?> set = camelContext.getRegistry().findByType(clazz); + if (set.size() == 1) { + return set.iterator().next(); + } else { + return null; + } + }); } } } 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 d2b0b7c..0efe577 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,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 [...] + "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 84bd5a7..2cb37c3 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 @@ -37,17 +37,14 @@ 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; + private String type; @XmlValue - @Metadata(required = true) private String script; // special for java-dsl to allow using lambda style @XmlTransient + private Class<?> beanClass; + @XmlTransient private RouteTemplateContext.BeanSupplier<Object> beanSupplier; public RouteTemplateBeanDefinition() { @@ -80,15 +77,20 @@ public class RouteTemplateBeanDefinition { this.beanClass = beanType; } - public String getLanguage() { - return language; + public String getType() { + return type; } /** - * The language to use for creating the bean (such as groovy, joor) + * 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. */ - public void setLanguage(String language) { - this.language = language; + public void setType(String type) { + this.type = type; } public String getScript() { @@ -96,7 +98,7 @@ public class RouteTemplateBeanDefinition { } /** - * The script to execute that creates the bean. + * 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. @@ -120,6 +122,27 @@ public class RouteTemplateBeanDefinition { // ---------------------------------------------------- /** + * Creates the bean from the given class type + * + * @param type the type of the class to create as bean + */ + public RouteTemplateDefinition beanClass(Class<?> type) { + setType("#class:" + type.getName()); + return parent; + } + + /** + * Lookup in the registry for bean instances of the given type, and if there is a single instance of the given type, + * then that bean will be used as the local bean (danger this bean is shared) + * + * @param type the type of the class to lookup in the registry + */ + public RouteTemplateDefinition beanType(Class<?> type) { + setType("#type:" + type.getName()); + return parent; + } + + /** * Calls a method on a bean for creating the local template bean * * @param type the bean class to call @@ -135,7 +158,7 @@ public class RouteTemplateBeanDefinition { * @param method the name of the method to call */ public RouteTemplateDefinition bean(Class<?> type, String method) { - setLanguage("bean"); + setType("bean"); if (method != null) { setScript(type.getName() + "?method=" + method); } else { @@ -153,7 +176,7 @@ public class RouteTemplateBeanDefinition { * @param script the script */ public RouteTemplateDefinition groovy(String script) { - setLanguage("groovy"); + setType("groovy"); setScript(script); return parent; } @@ -167,7 +190,7 @@ public class RouteTemplateBeanDefinition { * @param script the script */ public RouteTemplateDefinition joor(String script) { - setLanguage("joor"); + setType("joor"); setScript(script); return parent; } @@ -182,7 +205,7 @@ public class RouteTemplateBeanDefinition { * @param script the script */ public RouteTemplateDefinition language(String language, String script) { - setLanguage(language); + setType(language); setScript(script); return parent; } @@ -196,7 +219,7 @@ public class RouteTemplateBeanDefinition { * @param script the script */ public RouteTemplateDefinition mvel(String script) { - setLanguage("mvel"); + setType("mvel"); setScript(script); return parent; } @@ -210,7 +233,7 @@ public class RouteTemplateBeanDefinition { * @param script the script */ public RouteTemplateDefinition ognl(String script) { - setLanguage("ognl"); + setType("ognl"); setScript(script); return parent; } diff --git a/core/camel-core-model/src/main/java/org/apache/camel/model/RouteTemplateDefinition.java b/core/camel-core-model/src/main/java/org/apache/camel/model/RouteTemplateDefinition.java index 987b635..88139fa 100644 --- a/core/camel-core-model/src/main/java/org/apache/camel/model/RouteTemplateDefinition.java +++ b/core/camel-core-model/src/main/java/org/apache/camel/model/RouteTemplateDefinition.java @@ -292,7 +292,7 @@ public class RouteTemplateDefinition extends OptionalIdentifiedDefinition { } RouteTemplateBeanDefinition def = new RouteTemplateBeanDefinition(); def.setName(name); - def.setLanguage(language); + def.setType(language); def.setScript(script); templateBeans.add(def); return this; 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 4f50fdf..196470d 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 @@ -548,7 +548,38 @@ public class RouteTemplateLocalBeanTest extends ContextTestSupport { context.stop(); } - private class BuilderProcessor implements Processor { + @Test + public void testLocalBeanClassExpressionFluent() throws Exception { + context.addRoutes(new RouteBuilder() { + @Override + public void configure() throws Exception { + routeTemplate("myTemplate").templateParameter("foo").templateParameter("bar") + .templateBean("myBar").beanClass(BuilderProcessor.class) + .from("direct:{{foo}}") + .to("bean:{{bar}}"); + } + }); + + context.start(); + + TemplatedRouteBuilder.builder(context, "myTemplate") + .parameter("foo", "one") + .parameter("bar", "myBar") + .routeId("myRoute") + .add(); + + assertEquals(1, context.getRoutes().size()); + + Object out = template.requestBody("direct:one", "World"); + assertEquals("Builder World", out); + + // should not be a global bean + assertNull(context.getRegistry().lookupByName("myBar")); + + context.stop(); + } + + public static class BuilderProcessor implements Processor { @Override public void process(Exchange exchange) throws Exception { @@ -556,7 +587,7 @@ public class RouteTemplateLocalBeanTest extends ContextTestSupport { } } - private class BuilderTwoProcessor implements Processor { + public static class BuilderTwoProcessor implements Processor { private String prefix = ""; diff --git a/core/camel-support/src/main/java/org/apache/camel/support/DefaultRegistry.java b/core/camel-support/src/main/java/org/apache/camel/support/DefaultRegistry.java index 7864fb7..a714b8b 100644 --- a/core/camel-support/src/main/java/org/apache/camel/support/DefaultRegistry.java +++ b/core/camel-support/src/main/java/org/apache/camel/support/DefaultRegistry.java @@ -165,22 +165,28 @@ public class DefaultRegistry extends ServiceSupport implements Registry, LocalBe @Override public void bind(String id, Class<?> type, Object bean) throws RuntimeCamelException { - // automatic inject camel context in bean if its aware - if (camelContext != null && bean instanceof CamelContextAware) { - ((CamelContextAware) bean).setCamelContext(camelContext); + if (bean != null) { + // automatic inject camel context in bean if its aware + if (camelContext != null && bean instanceof CamelContextAware) { + ((CamelContextAware) bean).setCamelContext(camelContext); + } + fallbackRegistry.bind(id, type, bean); } - fallbackRegistry.bind(id, type, bean); } @Override public void bind(String id, Class<?> type, Supplier<Object> bean) throws RuntimeCamelException { - // wrap in cached supplier (memorize) - supplierRegistry.bind(id, type, Suppliers.memorize(bean)); + if (bean != null) { + // wrap in cached supplier (memorize) + supplierRegistry.bind(id, type, Suppliers.memorize(bean)); + } } @Override public void bindAsPrototype(String id, Class<?> type, Supplier<Object> bean) throws RuntimeCamelException { - supplierRegistry.bind(id, type, bean); + if (bean != null) { + supplierRegistry.bind(id, type, bean); + } } @Override diff --git a/core/camel-support/src/main/java/org/apache/camel/support/SimpleRegistry.java b/core/camel-support/src/main/java/org/apache/camel/support/SimpleRegistry.java index 2e99abc..2c57e9b 100644 --- a/core/camel-support/src/main/java/org/apache/camel/support/SimpleRegistry.java +++ b/core/camel-support/src/main/java/org/apache/camel/support/SimpleRegistry.java @@ -101,7 +101,9 @@ public class SimpleRegistry extends LinkedHashMap<String, Map<Class<?>, Object>> @Override public void bind(String id, Class type, Object bean) { - computeIfAbsent(id, k -> new LinkedHashMap<>()).put(type, wrap(bean)); + if (bean != null) { + computeIfAbsent(id, k -> new LinkedHashMap<>()).put(type, wrap(bean)); + } } @Override diff --git a/core/camel-support/src/main/java/org/apache/camel/support/SupplierRegistry.java b/core/camel-support/src/main/java/org/apache/camel/support/SupplierRegistry.java index 851847b..a4683d2 100644 --- a/core/camel-support/src/main/java/org/apache/camel/support/SupplierRegistry.java +++ b/core/camel-support/src/main/java/org/apache/camel/support/SupplierRegistry.java @@ -112,6 +112,8 @@ public class SupplierRegistry extends SimpleRegistry { @Override public void bind(String id, Class<?> type, Supplier<Object> bean) { - computeIfAbsent(id, k -> new LinkedHashMap<>()).put(type, wrap(bean)); + if (bean != null) { + computeIfAbsent(id, k -> new LinkedHashMap<>()).put(type, wrap(bean)); + } } } 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 1413e68..5ac4a38 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 @@ -1023,8 +1023,8 @@ public class ModelParser extends BaseParser { protected RouteTemplateBeanDefinition doParseRouteTemplateBeanDefinition() throws IOException, XmlPullParserException { return doParse(new RouteTemplateBeanDefinition(), (def, key, val) -> { switch (key) { - case "language": def.setLanguage(val); break; case "name": def.setName(val); break; + case "type": def.setType(val); break; default: return false; } return true; 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 8992959..a8c0f4b 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 @@ -11739,9 +11739,9 @@ public final class ModelDeserializers extends YamlDeserializerSupport { order = org.apache.camel.dsl.yaml.common.YamlDeserializerResolver.ORDER_LOWEST - 1, nodes = "template-bean", properties = { - @YamlProperty(name = "language", type = "string", required = true), @YamlProperty(name = "name", type = "string", required = true), - @YamlProperty(name = "script", type = "string", required = true) + @YamlProperty(name = "script", type = "string"), + @YamlProperty(name = "type", type = "string", required = true) } ) public static class RouteTemplateBeanDefinitionDeserializer extends YamlDeserializerBase<RouteTemplateBeanDefinition> { @@ -11763,11 +11763,6 @@ public final class ModelDeserializers extends YamlDeserializerSupport { protected boolean setProperty(RouteTemplateBeanDefinition target, String propertyKey, String propertyName, Node node) { switch(propertyKey) { - case "language": { - String val = asText(node); - target.setLanguage(val); - break; - } case "name": { String val = asText(node); target.setName(val); @@ -11778,6 +11773,11 @@ public final class ModelDeserializers extends YamlDeserializerSupport { target.setScript(val); break; } + case "type": { + String val = asText(node); + target.setType(val); + break; + } default: { return false; } 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 53c4660..1eeb7d6 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 @@ -2065,18 +2065,18 @@ }, { "type" : "object", "properties" : { - "language" : { - "type" : "string" - }, "name" : { "type" : "string" }, "script" : { "type" : "string" + }, + "type" : { + "type" : "string" } } } ], - "required" : [ "language", "name", "script" ] + "required" : [ "name", "type" ] }, "org.apache.camel.model.RouteTemplateDefinition" : { "type" : "object",
