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 <[email protected]>
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].