This is an automated email from the ASF dual-hosted git repository. davsclaus pushed a commit to branch CAMEL-15270 in repository https://gitbox.apache.org/repos/asf/camel.git
commit cca972075801e96fc525be390fae63cda2a7b480 Author: Claus Ibsen <claus.ib...@gmail.com> AuthorDate: Thu Jul 16 13:40:00 2020 +0200 CAMEL-15270: camel-main can configure route templates from properties files. --- .../builder/endpoint/StaticEndpointBuilders.java | 8 +-- .../org/apache/camel/main/BaseMainSupport.java | 58 +++++++++++++++++++++ .../java/org/apache/camel/main/MainListener.java | 1 + .../org/apache/camel/main/MainListenerSupport.java | 1 + .../apache/camel/main/MainRouteTemplateTest.java | 60 ++++++++++++++++++++++ .../src/test/resources/mytemplate.properties | 24 +++++++++ 6 files changed, 148 insertions(+), 4 deletions(-) diff --git a/core/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/StaticEndpointBuilders.java b/core/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/StaticEndpointBuilders.java index 91f1cc0..0fe1a4c 100644 --- a/core/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/StaticEndpointBuilders.java +++ b/core/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/StaticEndpointBuilders.java @@ -11639,7 +11639,7 @@ public class StaticEndpointBuilders { * * @param path stream */ - public static org.apache.camel.builder.endpoint.dsl.ReactiveStreamsEndpointBuilderFactory.ReactiveStreamsEndpointBuilder reactiveStreams( + static org.apache.camel.builder.endpoint.dsl.ReactiveStreamsEndpointBuilderFactory.ReactiveStreamsEndpointBuilder reactiveStreams( String path) { return org.apache.camel.builder.endpoint.dsl.ReactiveStreamsEndpointBuilderFactory.endpointBuilder("reactive-streams", path); } @@ -11661,7 +11661,7 @@ public class StaticEndpointBuilders { * instead of the default name * @param path stream */ - public static org.apache.camel.builder.endpoint.dsl.ReactiveStreamsEndpointBuilderFactory.ReactiveStreamsEndpointBuilder reactiveStreams( + static org.apache.camel.builder.endpoint.dsl.ReactiveStreamsEndpointBuilderFactory.ReactiveStreamsEndpointBuilder reactiveStreams( String componentName, String path) { return org.apache.camel.builder.endpoint.dsl.ReactiveStreamsEndpointBuilderFactory.endpointBuilder(componentName, path); @@ -15381,7 +15381,7 @@ public class StaticEndpointBuilders { * * @param path serverUrls/path */ - static org.apache.camel.builder.endpoint.dsl.ZooKeeperEndpointBuilderFactory.ZooKeeperEndpointBuilder zookeeper( + public static org.apache.camel.builder.endpoint.dsl.ZooKeeperEndpointBuilderFactory.ZooKeeperEndpointBuilder zookeeper( String path) { return org.apache.camel.builder.endpoint.dsl.ZooKeeperEndpointBuilderFactory.endpointBuilder("zookeeper", path); } @@ -15405,7 +15405,7 @@ public class StaticEndpointBuilders { * instead of the default name * @param path serverUrls/path */ - static org.apache.camel.builder.endpoint.dsl.ZooKeeperEndpointBuilderFactory.ZooKeeperEndpointBuilder zookeeper( + public static org.apache.camel.builder.endpoint.dsl.ZooKeeperEndpointBuilderFactory.ZooKeeperEndpointBuilder zookeeper( String componentName, String path) { return org.apache.camel.builder.endpoint.dsl.ZooKeeperEndpointBuilderFactory.endpointBuilder(componentName, path); 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 a43419e..35307f7 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,7 +22,9 @@ 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; @@ -33,6 +35,8 @@ 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; @@ -42,6 +46,7 @@ import org.apache.camel.ExtendedCamelContext; import org.apache.camel.NoSuchLanguageException; import org.apache.camel.ProducerTemplate; import org.apache.camel.PropertyBindingException; +import org.apache.camel.RouteTemplateParameterBuilder; import org.apache.camel.RoutesBuilder; import org.apache.camel.RuntimeCamelException; import org.apache.camel.builder.ThreadPoolProfileBuilder; @@ -776,6 +781,7 @@ public abstract class BaseMainSupport extends BaseService { Map<String, Object> threadPoolProperties = new LinkedHashMap<>(); Map<String, Object> healthProperties = new LinkedHashMap<>(); Map<String, Object> lraProperties = new LinkedHashMap<>(); + Map<String, Object> routeTemplateProperties = new LinkedHashMap<>(); Map<String, Object> beansProperties = new LinkedHashMap<>(); for (String key : prop.stringPropertyNames()) { if (key.startsWith("camel.context.")) { @@ -826,6 +832,12 @@ public abstract class BaseMainSupport extends BaseService { String option = key.substring(10); validateOptionAndValue(key, option, value); lraProperties.put(optionKey(option), value); + } else if (key.startsWith("camel.routetemplate")) { + // grab the value + String value = prop.getProperty(key); + String option = key.substring(19); + validateOptionAndValue(key, option, value); + routeTemplateProperties.put(optionKey(option), value); } else if (key.startsWith("camel.beans.")) { // grab the value String value = prop.getProperty(key); @@ -904,6 +916,10 @@ public abstract class BaseMainSupport extends BaseService { LOG.debug("Auto-configuring HealthCheck from loaded properties: {}", healthProperties.size()); setHealthCheckProperties(camelContext, healthProperties, mainConfigurationProperties.isAutoConfigurationFailFast(), autoConfiguredProperties); } + if (!routeTemplateProperties.isEmpty()) { + LOG.debug("Auto-configuring Route templates from loaded properties: {}", routeTemplateProperties.size()); + setRouteTemplateProperties(camelContext, routeTemplateProperties, mainConfigurationProperties.isAutoConfigurationFailFast(), autoConfiguredProperties); + } if (!lraProperties.isEmpty()) { LOG.debug("Auto-configuring Saga LRA from loaded properties: {}", lraProperties.size()); setLraCheckProperties(camelContext, lraProperties, mainConfigurationProperties.isAutoConfigurationFailFast(), autoConfiguredProperties); @@ -950,6 +966,11 @@ public abstract class BaseMainSupport extends BaseService { LOG.warn("Property not auto-configured: camel.health.{}={}", k, v); }); } + if (!routeTemplateProperties.isEmpty()) { + routeTemplateProperties.forEach((k, v) -> { + LOG.warn("Property not auto-configured: camel.routetemplate.{}={}", k, v); + }); + } if (!lraProperties.isEmpty()) { lraProperties.forEach((k, v) -> { LOG.warn("Property not auto-configured: camel.lra.{}={}", k, v); @@ -1018,6 +1039,43 @@ 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<>(); + 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()); + } + + // lets sort by keys + Map<String, Object> sorted = new TreeMap<>(routeTemplateProperties); + sorted.forEach((k, v) -> { + autoConfiguredProperties.put("camel.routetemplate" + 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, boolean failIfNotSet, Map<String, String> autoConfiguredProperties) throws Exception { diff --git a/core/camel-main/src/main/java/org/apache/camel/main/MainListener.java b/core/camel-main/src/main/java/org/apache/camel/main/MainListener.java index ae19f3a..ba703c4 100644 --- a/core/camel-main/src/main/java/org/apache/camel/main/MainListener.java +++ b/core/camel-main/src/main/java/org/apache/camel/main/MainListener.java @@ -22,6 +22,7 @@ import org.apache.camel.CamelContext; * A lifecycle listener to receive callbacks when the Main is started and stopped. */ public interface MainListener { + /** * Callback invoked after the the CamelContext has been created and before the * auto-configured step starts. diff --git a/core/camel-main/src/main/java/org/apache/camel/main/MainListenerSupport.java b/core/camel-main/src/main/java/org/apache/camel/main/MainListenerSupport.java index b5ea730..8c88099 100644 --- a/core/camel-main/src/main/java/org/apache/camel/main/MainListenerSupport.java +++ b/core/camel-main/src/main/java/org/apache/camel/main/MainListenerSupport.java @@ -22,6 +22,7 @@ import org.apache.camel.CamelContext; * A useful base class for {@link org.apache.camel.main.MainListener} implementations. */ public class MainListenerSupport implements MainListener { + @Override public void beforeInitialize(BaseMainSupport main) { // noop diff --git a/core/camel-main/src/test/java/org/apache/camel/main/MainRouteTemplateTest.java b/core/camel-main/src/test/java/org/apache/camel/main/MainRouteTemplateTest.java new file mode 100644 index 0000000..272bc00 --- /dev/null +++ b/core/camel-main/src/test/java/org/apache/camel/main/MainRouteTemplateTest.java @@ -0,0 +1,60 @@ +/* + * 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 org.apache.camel.CamelContext; +import org.apache.camel.ProducerTemplate; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.component.mock.MockEndpoint; +import org.apache.camel.model.ModelCamelContext; +import org.junit.Assert; +import org.junit.jupiter.api.Test; + +public class MainRouteTemplateTest { + + @Test + public void testMain() throws Exception { + Main main = new Main(); + main.setPropertyPlaceholderLocations("mytemplate.properties"); + main.configure().addRoutesBuilder(new RouteBuilder() { + @Override + public void configure() throws Exception { + routeTemplate("mytemplate") + .from("direct:{{input}}") + .to("mock:{{result}}"); + } + }); + + main.start(); + + CamelContext context = main.getCamelContext(); + Assert.assertEquals(1, context.adapt(ModelCamelContext.class).getRouteTemplateDefinitions().size()); + Assert.assertEquals("mytemplate", context.adapt(ModelCamelContext.class).getRouteTemplateDefinitions().get(0).getId()); + + MockEndpoint mock = context.getEndpoint("mock:cheese", MockEndpoint.class); + mock.expectedBodiesReceived("Hello Camel", "Hello World"); + + ProducerTemplate template = context.createProducerTemplate(); + template.sendBody("direct:foo", "Hello Camel"); + template.sendBody("direct:bar", "Hello World"); + + mock.assertIsSatisfied(); + + main.stop(); + } + +} diff --git a/core/camel-main/src/test/resources/mytemplate.properties b/core/camel-main/src/test/resources/mytemplate.properties new file mode 100644 index 0000000..a440508 --- /dev/null +++ b/core/camel-main/src/test/resources/mytemplate.properties @@ -0,0 +1,24 @@ +## --------------------------------------------------------------------------- +## 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. +## --------------------------------------------------------------------------- + +camel.routetemplate[one].template-id=mytemplate +camel.routetemplate[one].input=foo +camel.routetemplate[one].result=cheese + +camel.routetemplate[two].template-id=mytemplate +camel.routetemplate[two].input=bar +camel.routetemplate[two].result=cheese