This is an automated email from the ASF dual-hosted git repository. acosentino pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/camel.git
commit 7fe950d4d257e38abdae63c096e9003e2cedc229 Author: Claus Ibsen <[email protected]> AuthorDate: Fri May 14 08:45:48 2021 +0200 Kamelet local bean - Created local bean should memorize so when using the bean multiple times its the same local bean --- .../java/org/apache/camel/impl/DefaultModel.java | 19 ++++++--- .../camel/builder/RouteTemplateLocalBeanTest.java | 46 ++++++++++++++++++++++ 2 files changed, 59 insertions(+), 6 deletions(-) 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 56196e7..b311748 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 @@ -66,6 +66,7 @@ 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; +import org.apache.camel.util.function.Suppliers; public class DefaultModel implements Model { @@ -366,7 +367,9 @@ public class DefaultModel implements Model { final ScriptingLanguage slan = lan instanceof ScriptingLanguage ? (ScriptingLanguage) lan : null; if (slan != null) { // scripting language should be evaluated with route template context as binding - routeTemplateContext.bind(b.getName(), clazz, () -> { + // and memorize so the script is only evaluated once and the local bean is the same + // if a route template refers to the local bean multiple times + routeTemplateContext.bind(b.getName(), clazz, Suppliers.memorize(() -> { Map<String, Object> bindings = new HashMap<>(); // use rtx as the short-hand name, as context would imply its CamelContext bindings.put("rtc", routeTemplateContext); @@ -375,10 +378,12 @@ public class DefaultModel implements Model { setPropertiesOnTarget(camelContext, local, props); } return local; - }); + })); } else { // exchange based languages needs a dummy exchange to be evaluated - routeTemplateContext.bind(b.getName(), clazz, () -> { + // and memorize so the script is only evaluated once and the local bean is the same + // if a route template refers to the local bean multiple times + routeTemplateContext.bind(b.getName(), clazz, Suppliers.memorize(() -> { ExchangeFactory ef = camelContext.adapt(ExtendedCamelContext.class).getExchangeFactory(); Exchange dummy = ef.create(false); try { @@ -396,20 +401,22 @@ public class DefaultModel implements Model { } finally { ef.release(dummy); } - }); + })); } } 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 + // and memorize so the bean is only created once and the local bean is the same + // if a route template refers to the local bean multiple times routeTemplateContext.bind(b.getName(), clazz, - () -> { + Suppliers.memorize(() -> { 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); 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 83337fb0..7228b50 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 @@ -23,6 +23,7 @@ import org.apache.camel.ContextTestSupport; import org.apache.camel.Exchange; import org.apache.camel.Processor; import org.apache.camel.RouteTemplateContext; +import org.apache.camel.component.mock.MockEndpoint; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -650,6 +651,47 @@ public class RouteTemplateLocalBeanTest extends ContextTestSupport { context.stop(); } + @Test + public void testLocalBeanMemorize() 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}}").typeClass(BuilderThreeProcessor.class).end() + .from("direct:{{foo}}") + // use unique endpoints to force referring the to bean twice + .to("bean:{{bar}}") + .to("bean:{{bar}}?method=process") + .to("mock:result"); + } + }); + + context.start(); + + TemplatedRouteBuilder.builder(context, "myTemplate") + .parameter("foo", "one") + .parameter("bar", "myBar") + .parameter("hi", "Davs") + .routeId("myRoute") + .add(); + + assertEquals(1, context.getRoutes().size()); + + MockEndpoint mock = getMockEndpoint("mock:result"); + mock.expectedBodiesReceived("DavsBuilder3 DavsBuilder3 World"); + mock.expectedHeaderReceived("counter", 2); + + Object out = template.requestBody("direct:one", "World"); + assertEquals("DavsBuilder3 DavsBuilder3 World", out); + + assertMockEndpointsSatisfied(); + + // should not be a global bean + assertNull(context.getRegistry().lookupByName("myBar")); + + context.stop(); + } + public static class BuilderTwoProcessor implements Processor { private String prefix = ""; @@ -670,6 +712,7 @@ public class RouteTemplateLocalBeanTest extends ContextTestSupport { public static class BuilderThreeProcessor implements Processor { private String prefix = ""; + private int counter; public String getPrefix() { return prefix; @@ -681,8 +724,11 @@ public class RouteTemplateLocalBeanTest extends ContextTestSupport { @Override public void process(Exchange exchange) throws Exception { + counter++; exchange.getMessage().setBody(prefix + "Builder3 " + exchange.getMessage().getBody()); + exchange.getMessage().setHeader("counter", counter); } + } public Processor createBuilderProcessor() {
