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

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


The following commit(s) were added to refs/heads/master by this push:
     new 7fd193d  CAMEL-15308: RouteTemplate SPI for parameter sources
7fd193d is described below

commit 7fd193dcabdf0c8e5fee002cb7785347d1513da1
Author: Claus Ibsen <claus.ib...@gmail.com>
AuthorDate: Wed Jul 29 13:34:18 2020 +0200

    CAMEL-15308: RouteTemplate SPI for parameter sources
---
 .../camel/spi/RouteTemplateParameterSource.java    | 42 ++++++++++
 .../camel/impl/engine/AbstractCamelContext.java    | 19 +++++
 .../impl/lw/LightweightRuntimeCamelContext.java    |  2 +
 .../builder/RouteTemplateCustomSourceTest.java     | 90 ++++++++++++++++++++++
 .../org/apache/camel/main/BaseMainSupport.java     | 30 ++------
 .../PropertiesRouteTemplateParametersSource.java   | 46 +++++++++++
 .../src/test/resources/mytemplate.properties       |  2 +-
 .../modules/ROOT/pages/route-template.adoc         | 10 +++
 8 files changed, 215 insertions(+), 26 deletions(-)

diff --git 
a/core/camel-api/src/main/java/org/apache/camel/spi/RouteTemplateParameterSource.java
 
b/core/camel-api/src/main/java/org/apache/camel/spi/RouteTemplateParameterSource.java
new file mode 100644
index 0000000..1901c67
--- /dev/null
+++ 
b/core/camel-api/src/main/java/org/apache/camel/spi/RouteTemplateParameterSource.java
@@ -0,0 +1,42 @@
+/*
+ * 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.spi;
+
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Source for parameters used when creating routes from route templates.
+ */
+public interface RouteTemplateParameterSource {
+
+    String TEMPLATE_ID = "templateId";
+
+    /**
+     * The parameters for the given route
+     *
+     * @param routeId          the route id
+     * @return the parameters for the route
+     */
+    Map<String, Object> parameters(String routeId);
+
+    /**
+     * Gets the route ids as a set.
+     */
+    Set<String> routeIds();
+
+}
diff --git 
a/core/camel-base/src/main/java/org/apache/camel/impl/engine/AbstractCamelContext.java
 
b/core/camel-base/src/main/java/org/apache/camel/impl/engine/AbstractCamelContext.java
index e6b8b54..557e0cf 100644
--- 
a/core/camel-base/src/main/java/org/apache/camel/impl/engine/AbstractCamelContext.java
+++ 
b/core/camel-base/src/main/java/org/apache/camel/impl/engine/AbstractCamelContext.java
@@ -131,6 +131,7 @@ import org.apache.camel.spi.RouteController;
 import org.apache.camel.spi.RouteError.Phase;
 import org.apache.camel.spi.RoutePolicyFactory;
 import org.apache.camel.spi.RouteStartupOrder;
+import org.apache.camel.spi.RouteTemplateParameterSource;
 import org.apache.camel.spi.RuntimeEndpointRegistry;
 import org.apache.camel.spi.ShutdownStrategy;
 import org.apache.camel.spi.StreamCachingStrategy;
@@ -2605,6 +2606,24 @@ public abstract class AbstractCamelContext extends 
BaseService
         // start components
         ServiceHelper.initService(components.values());
 
+        // create routes from route templates if we have any sources
+        for (RouteTemplateParameterSource source : 
getRegistry().findByType(RouteTemplateParameterSource.class)) {
+            for (String routeId : source.routeIds()) {
+                // do a defensive copy of the parameters
+                Map<String, Object> map = new 
HashMap<>(source.parameters(routeId));
+                Object templateId = 
map.remove(RouteTemplateParameterSource.TEMPLATE_ID);
+                if (templateId == null) {
+                    // use alternative style as well
+                    templateId = map.remove("template-id");
+                }
+                final String id = templateId != null ? templateId.toString() : 
null;
+                if (id == null) {
+                    throw new 
IllegalArgumentException("RouteTemplateParameterSource with routeId: " + 
routeId + " has no templateId defined");
+                }
+                addRouteFromTemplate(routeId, id, map);
+            }
+        }
+
         // start the route definitions before the routes is started
         startRouteDefinitions();
 
diff --git 
a/core/camel-core-engine/src/main/java/org/apache/camel/impl/lw/LightweightRuntimeCamelContext.java
 
b/core/camel-core-engine/src/main/java/org/apache/camel/impl/lw/LightweightRuntimeCamelContext.java
index d8789e3..3944a89 100644
--- 
a/core/camel-core-engine/src/main/java/org/apache/camel/impl/lw/LightweightRuntimeCamelContext.java
+++ 
b/core/camel-core-engine/src/main/java/org/apache/camel/impl/lw/LightweightRuntimeCamelContext.java
@@ -39,6 +39,7 @@ import org.apache.camel.ConsumerTemplate;
 import org.apache.camel.Endpoint;
 import org.apache.camel.ErrorHandlerFactory;
 import org.apache.camel.ExchangeConstantProvider;
+import org.apache.camel.Experimental;
 import org.apache.camel.ExtendedCamelContext;
 import org.apache.camel.FluentProducerTemplate;
 import org.apache.camel.GlobalEndpointConfiguration;
@@ -140,6 +141,7 @@ import org.apache.camel.util.URISupport;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+@Experimental
 public class LightweightRuntimeCamelContext implements ExtendedCamelContext, 
CatalogCamelContext {
 
     private static final Logger LOG = 
LoggerFactory.getLogger(LightweightRuntimeCamelContext.class);
diff --git 
a/core/camel-core/src/test/java/org/apache/camel/builder/RouteTemplateCustomSourceTest.java
 
b/core/camel-core/src/test/java/org/apache/camel/builder/RouteTemplateCustomSourceTest.java
new file mode 100644
index 0000000..669abe9
--- /dev/null
+++ 
b/core/camel-core/src/test/java/org/apache/camel/builder/RouteTemplateCustomSourceTest.java
@@ -0,0 +1,90 @@
+/*
+ * 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.builder;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.ContextTestSupport;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.spi.RouteTemplateParameterSource;
+import org.junit.jupiter.api.Test;
+
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+public class RouteTemplateCustomSourceTest extends ContextTestSupport {
+
+    @Override
+    protected CamelContext createCamelContext() throws Exception {
+        CamelContext context = super.createCamelContext();
+        context.getRegistry().bind("mySource", new 
MyRouteTemplateParameterSource());
+        return context;
+    }
+
+    @Test
+    public void testCreateRouteFromRouteTemplateMissingParameter() throws 
Exception {
+        assertEquals(1, context.getRouteTemplateDefinitions().size());
+
+        assertEquals(2, context.getRoutes().size());
+
+        MockEndpoint mock = getMockEndpoint("mock:cheese");
+        mock.expectedBodiesReceived("Hello Foo", "Hello Bar");
+
+        template.sendBody("direct:one", "Hello Foo");
+        template.sendBody("direct:two", "Hello Bar");
+
+        assertMockEndpointsSatisfied();
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                
routeTemplate("myTemplate").templateParameter("foo").templateParameter("bar")
+                    .from("direct:{{foo}}")
+                    .to("mock:{{bar}}");
+            }
+        };
+    }
+
+    private class MyRouteTemplateParameterSource implements 
RouteTemplateParameterSource {
+
+        @Override
+        public Map<String, Object> parameters(String routeId) {
+            Map<String, Object> map = new HashMap<>();
+            map.put(TEMPLATE_ID, "myTemplate");
+            map.put("bar", "cheese");
+            if ("A".equals(routeId)) {
+                map.put("foo", "one");
+            } else {
+                map.put("foo", "two");
+            }
+            return map;
+        }
+
+        @Override
+        public Set<String> routeIds() {
+            return Stream.of("A", "B").collect(Collectors.toSet());
+        }
+    }
+}
diff --git 
a/core/camel-main/src/main/java/org/apache/camel/main/BaseMainSupport.java 
b/core/camel-main/src/main/java/org/apache/camel/main/BaseMainSupport.java
index 8c499b5..99c6b9b 100644
--- a/core/camel-main/src/main/java/org/apache/camel/main/BaseMainSupport.java
+++ b/core/camel-main/src/main/java/org/apache/camel/main/BaseMainSupport.java
@@ -22,9 +22,7 @@ import java.io.InputStream;
 import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
 import java.util.ArrayList;
-import java.util.Collection;
 import java.util.Collections;
-import java.util.Comparator;
 import java.util.HashMap;
 import java.util.LinkedHashMap;
 import java.util.LinkedHashSet;
@@ -35,7 +33,6 @@ import java.util.Objects;
 import java.util.Optional;
 import java.util.Properties;
 import java.util.Set;
-import java.util.SortedMap;
 import java.util.TreeMap;
 import java.util.function.Function;
 import java.util.stream.Collectors;
@@ -67,7 +64,7 @@ import org.apache.camel.spi.Language;
 import org.apache.camel.spi.PropertiesComponent;
 import org.apache.camel.spi.PropertyConfigurer;
 import org.apache.camel.spi.PropertyConfigurerGetter;
-import org.apache.camel.spi.RestConfiguration;
+import org.apache.camel.spi.RouteTemplateParameterSource;
 import org.apache.camel.spi.ThreadPoolProfile;
 import org.apache.camel.support.CamelContextHelper;
 import org.apache.camel.support.LifecycleStrategySupport;
@@ -1042,13 +1039,14 @@ public abstract class BaseMainSupport extends 
BaseService {
     private void setRouteTemplateProperties(CamelContext camelContext, 
Map<String, Object> routeTemplateProperties,
                                             boolean failIfNotSet, Map<String, 
String> autoConfiguredProperties) throws Exception {
 
-        Map<String, Map<String, String>> rtConfigs = new HashMap<>();
+        // store the route template parameters as a source and register it on 
the camel context
+        PropertiesRouteTemplateParametersSource source = new 
PropertiesRouteTemplateParametersSource();
         for (Map.Entry<String, Object> entry : 
routeTemplateProperties.entrySet()) {
             String id = StringHelper.between(entry.getKey(), "[", "]");
             String key = StringHelper.after(entry.getKey(), "].");
-            Map<String, String> map = rtConfigs.computeIfAbsent(id, k -> new 
HashMap<>());
-            map.put(key, entry.getValue().toString());
+            source.addParameter(id, key, entry.getValue());
         }
+        
camelContext.getRegistry().bind("CamelMainRouteTemplateParametersSource", 
RouteTemplateParameterSource.class, source);
 
         // lets sort by keys
         Map<String, Object> sorted = new TreeMap<>(routeTemplateProperties);
@@ -1056,24 +1054,6 @@ public abstract class BaseMainSupport extends 
BaseService {
             autoConfiguredProperties.put("camel.route-template" + k, 
v.toString());
         });
         routeTemplateProperties.clear();
-
-        // create route templates
-        for (Map<String, String> map : rtConfigs.values()) {
-            String templateId = map.remove("templateId");
-            if (templateId == null) {
-                templateId = map.remove("template-id");
-            }
-            // need to add route templates after configure as the templates 
must be present first
-            final String id = templateId;
-            addMainListener(new MainListenerSupport() {
-                @Override
-                public void afterConfigure(BaseMainSupport main) {
-                    RouteTemplateParameterBuilder builder = 
camelContext.addRouteFromTemplate(id);
-                    map.forEach(builder::parameter);
-                    builder.build();
-                }
-            });
-        }
     }
 
     private void setHealthCheckProperties(CamelContext camelContext, 
Map<String, Object> healthCheckProperties,
diff --git 
a/core/camel-main/src/main/java/org/apache/camel/main/PropertiesRouteTemplateParametersSource.java
 
b/core/camel-main/src/main/java/org/apache/camel/main/PropertiesRouteTemplateParametersSource.java
new file mode 100644
index 0000000..26eea62
--- /dev/null
+++ 
b/core/camel-main/src/main/java/org/apache/camel/main/PropertiesRouteTemplateParametersSource.java
@@ -0,0 +1,46 @@
+/*
+ * 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.main;
+
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.camel.spi.RouteTemplateParameterSource;
+
+public class PropertiesRouteTemplateParametersSource implements 
RouteTemplateParameterSource {
+
+    private final Map<String, Map<String, Object>> parameters = new 
LinkedHashMap<>();
+
+    @Override
+    public Map<String, Object> parameters(String routeId) {
+        // return a copy
+        return new HashMap<>(parameters.get(routeId));
+    }
+
+    @Override
+    public Set<String> routeIds() {
+        return parameters.keySet();
+    }
+
+    public void addParameter(String routeId, String name, Object value) {
+        Map<String, Object> map = parameters.computeIfAbsent(routeId, k -> new 
HashMap<>());
+        map.put(name, value);
+    }
+
+}
diff --git a/core/camel-main/src/test/resources/mytemplate.properties 
b/core/camel-main/src/test/resources/mytemplate.properties
index 51b7e3c..427000c 100644
--- a/core/camel-main/src/test/resources/mytemplate.properties
+++ b/core/camel-main/src/test/resources/mytemplate.properties
@@ -19,6 +19,6 @@ camel.route-template[one].template-id=mytemplate
 camel.route-template[one].input=foo
 camel.route-template[one].result=cheese
 
-camel.route-template[two].template-id=mytemplate
+camel.route-template[two].templateId=mytemplate
 camel.route-template[two].input=bar
 camel.route-template[two].result=cheese
diff --git a/docs/user-manual/modules/ROOT/pages/route-template.adoc 
b/docs/user-manual/modules/ROOT/pages/route-template.adoc
index 3712999..fd6e6fd 100644
--- a/docs/user-manual/modules/ROOT/pages/route-template.adoc
+++ b/docs/user-manual/modules/ROOT/pages/route-template.adoc
@@ -166,6 +166,16 @@ camel.route-template[1].input=bar
 camel.route-template[1].result=cheese
 ----
 
+== Creating routes from custom sources of template parameters
+
+The SPI interface `org.apache.camel.spi.RouteTemplateParameterSource` can be 
used to implement custom sources that
+are used during startup of Camel to create routes via the templates with 
parameters from the custom source(s).
+
+For example a custom source can be implemented that reads parameters from a 
shared database that Camel uses during staring
+by creating routes. This allows to externalize these parameters and as well to 
easily add more routes with varying parameters.
+
+To let Camel discover custom sources then register the source into the Camel 
registry.
+
 == See Also
 
 See the example 
https://github.com/apache/camel-examples/tree/master/examples/camel-example-routetemplate[camel-example-routetemplate].

Reply via email to