You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by da...@apache.org on 2021/05/05 15:11:33 UTC

[camel] 01/05: CAMEL-16394: Route Template local beans. WIP

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

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

commit db8f3367f9e1883b3ddb87398520405b0420b597
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Wed May 5 16:18:07 2021 +0200

    CAMEL-16394: Route Template local beans. WIP
---
 .../org/apache/camel/RouteTemplateContext.java     | 10 +++
 .../java/org/apache/camel/impl/DefaultModel.java   |  5 ++
 .../camel/model/DefaultRouteTemplateContext.java   |  7 ++
 .../camel/model/RouteTemplateDefinition.java       | 20 ++++++
 .../camel/builder/RouteTemplateLocalBeanTest.java  | 80 +++++++++++++++++++++-
 5 files changed, 120 insertions(+), 2 deletions(-)

diff --git a/core/camel-api/src/main/java/org/apache/camel/RouteTemplateContext.java b/core/camel-api/src/main/java/org/apache/camel/RouteTemplateContext.java
index 3db1612..3e36a7e 100644
--- a/core/camel-api/src/main/java/org/apache/camel/RouteTemplateContext.java
+++ b/core/camel-api/src/main/java/org/apache/camel/RouteTemplateContext.java
@@ -91,6 +91,16 @@ public interface RouteTemplateContext {
     Object getProperty(String name);
 
     /**
+     * Gets the property with the given name
+     *
+     * @param  name                    name of property
+     * @param  type                    the type of the property
+     * @return                         the property value or <tt>null</tt> if no property exists
+     * @throws TypeConversionException is thrown if error during type conversion
+     */
+    <T> T getProperty(String name, Class<?> type);
+
+    /**
      * Sets a parameter
      *
      * @param name  the parameter name
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 e7bfc13..80ec4fb 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
@@ -246,6 +246,11 @@ public class DefaultModel implements Model {
             throw new IllegalArgumentException("Cannot find RouteTemplate with id " + routeTemplateId);
         }
 
+        // apply configurer if any present
+        if (target.getConfigurer() != null) {
+            target.getConfigurer().accept(routeTemplateContext);
+        }
+
         final Map<String, Object> prop = new HashMap<>();
         // include default values first from the template (and validate that we have inputs for all required parameters)
         if (target.getTemplateParameters() != null) {
diff --git a/core/camel-core-model/src/main/java/org/apache/camel/model/DefaultRouteTemplateContext.java b/core/camel-core-model/src/main/java/org/apache/camel/model/DefaultRouteTemplateContext.java
index a91da2c..5a9df3e 100644
--- a/core/camel-core-model/src/main/java/org/apache/camel/model/DefaultRouteTemplateContext.java
+++ b/core/camel-core-model/src/main/java/org/apache/camel/model/DefaultRouteTemplateContext.java
@@ -67,6 +67,13 @@ public final class DefaultRouteTemplateContext implements RouteTemplateContext {
     }
 
     @Override
+    @SuppressWarnings("unchecked")
+    public <T> T getProperty(String name, Class<?> type) {
+        Object value = parameters.get(name);
+        return (T) camelContext.getTypeConverter().tryConvertTo(type, value);
+    }
+
+    @Override
     public void setParameter(String name, Object value) {
         parameters.put(name, value);
     }
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 cadb574..8fd4f84 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
@@ -19,14 +19,17 @@ package org.apache.camel.model;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
+import java.util.function.Consumer;
 
 import javax.xml.bind.annotation.XmlAccessType;
 import javax.xml.bind.annotation.XmlAccessorType;
 import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlTransient;
 import javax.xml.bind.annotation.XmlType;
 
 import org.apache.camel.Endpoint;
+import org.apache.camel.RouteTemplateContext;
 import org.apache.camel.builder.EndpointConsumerBuilder;
 import org.apache.camel.spi.AsEndpointUri;
 import org.apache.camel.spi.Metadata;
@@ -44,11 +47,17 @@ public class RouteTemplateDefinition extends OptionalIdentifiedDefinition {
     private List<RouteTemplateParameterDefinition> templateParameters;
     @XmlElement(name = "route", required = true)
     private RouteDefinition route = new RouteDefinition();
+    @XmlTransient
+    private Consumer<RouteTemplateContext> configurer;
 
     public List<RouteTemplateParameterDefinition> getTemplateParameters() {
         return templateParameters;
     }
 
+    public Consumer<RouteTemplateContext> getConfigurer() {
+        return configurer;
+    }
+
     public void setTemplateParameters(List<RouteTemplateParameterDefinition> templateParameters) {
         this.templateParameters = templateParameters;
     }
@@ -151,6 +160,17 @@ public class RouteTemplateDefinition extends OptionalIdentifiedDefinition {
         return this;
     }
 
+    /**
+     * Sets a configurer which allows to do configuration while the route template is being used to create a route. This
+     * gives control over the creating process, such as binding local beans and doing other kind of customization.
+     *
+     * @param configurer the configurer with callback to invoke with the given route template context
+     */
+    public RouteTemplateDefinition configure(Consumer<RouteTemplateContext> configurer) {
+        this.configurer = configurer;
+        return this;
+    }
+
     @Override
     public String getShortName() {
         return "routeTemplate";
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 2e5e39a..6693ebf 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
@@ -21,6 +21,8 @@ import org.apache.camel.Exchange;
 import org.apache.camel.Processor;
 import org.junit.jupiter.api.Test;
 
+import java.util.concurrent.atomic.AtomicInteger;
+
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
 import static org.junit.jupiter.api.Assertions.assertNull;
@@ -196,8 +198,9 @@ public class RouteTemplateLocalBeanTest extends ContextTestSupport {
                 .parameter("foo", "two")
                 .parameter("bar", "myBar")
                 .configure(rtc -> {
-                    rtc.bind("myBar", (Processor) ex -> ex.getMessage().setBody("Configure2 " + ex.getMessage().getBody()
-                                                                                + " from " + rtc.getProperty("foo")));
+                    rtc.bind("myBar", Processor.class,
+                            (Processor) ex -> ex.getMessage().setBody("Configure2 " + ex.getMessage().getBody()
+                                                                      + " from " + rtc.getProperty("foo")));
                 })
                 .routeId("myRoute2")
                 .add();
@@ -215,6 +218,79 @@ public class RouteTemplateLocalBeanTest extends ContextTestSupport {
         context.stop();
     }
 
+    @Test
+    public void testLocalBeanInTemplate() throws Exception {
+        context.addRoutes(new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                routeTemplate("myTemplate").templateParameter("foo").templateParameter("bar")
+                        .configure(rtc -> rtc.bind("myBar", (Processor) ex -> ex.getMessage().setBody("Builder " + ex.getMessage().getBody())))
+                        .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();
+    }
+
+    @Test
+    public void testLocalBeanInTemplateTwo() throws Exception {
+        final AtomicInteger counter = new AtomicInteger();
+
+        context.addRoutes(new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                routeTemplate("myTemplate").templateParameter("foo").templateParameter("bar")
+                        .configure(rtc -> rtc.bind("myBar", (Processor) ex -> ex.getMessage().setBody("Builder" +
+                                counter.incrementAndGet() + " " + ex.getMessage().getBody())))
+                        .from("direct:{{foo}}")
+                        .to("bean:{{bar}}");
+            }
+        });
+
+        context.start();
+
+        TemplatedRouteBuilder.builder(context, "myTemplate")
+                .parameter("foo", "one")
+                .parameter("bar", "myBar")
+                .routeId("myRoute")
+                .add();
+
+        TemplatedRouteBuilder.builder(context, "myTemplate")
+                .parameter("foo", "two")
+                .parameter("bar", "myBar")
+                .routeId("myRoute2")
+                .add();
+
+        assertEquals(2, context.getRoutes().size());
+
+        Object out = template.requestBody("direct:one", "World");
+        assertEquals("Builder1 World", out);
+        Object out2 = template.requestBody("direct:two", "Camel");
+        assertEquals("Builder2 Camel", out2);
+
+        // should not be a global bean
+        assertNull(context.getRegistry().lookupByName("myBar"));
+
+        context.stop();
+    }
+
     private class BuilderProcessor implements Processor {
 
         @Override