This is an automated email from the ASF dual-hosted git repository. lburgazzoli 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 5029d32 CAMEL-15590: route templates: add an hook to further customize the RouteDefinition computed out of a template 5029d32 is described below commit 5029d32302fbd5e8d2688b82b0dc66637633ef62 Author: Luca Burgazzoli <lburgazz...@gmail.com> AuthorDate: Tue Sep 29 11:30:19 2020 +0200 CAMEL-15590: route templates: add an hook to further customize the RouteDefinition computed out of a template --- .../org/apache/camel/impl/DefaultCamelContext.java | 6 +- .../java/org/apache/camel/impl/DefaultModel.java | 65 +++++++--- .../camel/impl/lw/LightweightCamelContext.java | 5 + .../main/java/org/apache/camel/model/Model.java | 9 ++ .../camel/model/RouteTemplateDefinition.java | 5 + .../camel/builder/RouteTemplateConverterTest.java | 136 +++++++++++++++++++++ 6 files changed, 205 insertions(+), 21 deletions(-) diff --git a/core/camel-core-engine/src/main/java/org/apache/camel/impl/DefaultCamelContext.java b/core/camel-core-engine/src/main/java/org/apache/camel/impl/DefaultCamelContext.java index c4ead09..b6d16d9 100644 --- a/core/camel-core-engine/src/main/java/org/apache/camel/impl/DefaultCamelContext.java +++ b/core/camel-core-engine/src/main/java/org/apache/camel/impl/DefaultCamelContext.java @@ -183,6 +183,11 @@ public class DefaultCamelContext extends SimpleCamelContext implements ModelCame } @Override + public void addRouteTemplateDefinitionConverter(String templateIdPattern, RouteTemplateDefinition.Converter converter) { + model.addRouteTemplateDefinitionConverter(templateIdPattern, converter); + } + + @Override public String addRouteFromTemplate(String routeId, String routeTemplateId, Map<String, Object> parameters) throws Exception { return model.addRouteFromTemplate(routeId, routeTemplateId, parameters); @@ -487,5 +492,4 @@ public class DefaultCamelContext extends SimpleCamelContext implements ModelCame ? new TransformerKey(def.getScheme()) : new TransformerKey(new DataType(def.getFromType()), new DataType(def.getToType())); } - } 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 bdaf469..f545d28 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 @@ -46,6 +46,7 @@ import org.apache.camel.model.cloud.ServiceCallConfigurationDefinition; import org.apache.camel.model.rest.RestDefinition; import org.apache.camel.model.transformer.TransformerDefinition; import org.apache.camel.model.validator.ValidatorDefinition; +import org.apache.camel.util.AntPathMatcher; public class DefaultModel implements Model { @@ -55,6 +56,7 @@ public class DefaultModel implements Model { private final List<RouteDefinition> routeDefinitions = new ArrayList<>(); private final List<RouteTemplateDefinition> routeTemplateDefinitions = new ArrayList<>(); private final List<RestDefinition> restDefinitions = new ArrayList<>(); + private final Map<String, RouteTemplateDefinition.Converter> routeTemplateConverters = new ConcurrentHashMap<>(); private Map<String, DataFormatDefinition> dataFormats = new HashMap<>(); private List<TransformerDefinition> transformers = new ArrayList<>(); private List<ValidatorDefinition> validators = new ArrayList<>(); @@ -68,6 +70,15 @@ public class DefaultModel implements Model { this.camelContext = camelContext; } + protected static <T> T lookup(CamelContext context, String ref, Class<T> type) { + try { + return context.getRegistry().lookupByNameAndType(ref, type); + } catch (Exception e) { + // need to ignore not same type and return it as null + return null; + } + } + public CamelContext getCamelContext() { return camelContext; } @@ -194,6 +205,11 @@ public class DefaultModel implements Model { } @Override + public void addRouteTemplateDefinitionConverter(String templateIdPattern, RouteTemplateDefinition.Converter converter) { + routeTemplateConverters.put(templateIdPattern, converter); + } + + @Override public String addRouteFromTemplate(final String routeId, final String routeTemplateId, final Map<String, Object> parameters) throws Exception { RouteTemplateDefinition target = null; @@ -208,7 +224,7 @@ public class DefaultModel implements Model { } StringJoiner templatesBuilder = new StringJoiner(", "); - final Map<String, Object> prop = new HashMap(); + 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) { for (RouteTemplateParameterDefinition temp : target.getTemplateParameters()) { @@ -232,7 +248,25 @@ public class DefaultModel implements Model { prop.putAll(parameters); } - RouteDefinition def = target.asRouteDefinition(); + RouteTemplateDefinition.Converter converter = RouteTemplateDefinition::asRouteDefinition; + + for (Map.Entry<String, RouteTemplateDefinition.Converter> entry : routeTemplateConverters.entrySet()) { + final String key = entry.getKey(); + final String templateId = target.getId(); + + if ("*".equals(key) || templateId.equals(key)) { + converter = entry.getValue(); + break; + } else if (AntPathMatcher.INSTANCE.match(key, templateId)) { + converter = entry.getValue(); + break; + } else if (templateId.matches(key)) { + converter = entry.getValue(); + break; + } + } + + RouteDefinition def = converter.apply(target); if (routeId != null) { def.setId(routeId); } @@ -411,18 +445,13 @@ public class DefaultModel implements Model { } @Override - public void setDataFormats(Map<String, DataFormatDefinition> dataFormats) { - this.dataFormats = dataFormats; - } - - @Override public Map<String, DataFormatDefinition> getDataFormats() { return dataFormats; } @Override - public void setTransformers(List<TransformerDefinition> transformers) { - this.transformers = transformers; + public void setDataFormats(Map<String, DataFormatDefinition> dataFormats) { + this.dataFormats = dataFormats; } @Override @@ -431,8 +460,8 @@ public class DefaultModel implements Model { } @Override - public void setValidators(List<ValidatorDefinition> validators) { - this.validators = validators; + public void setTransformers(List<TransformerDefinition> transformers) { + this.transformers = transformers; } @Override @@ -441,6 +470,11 @@ public class DefaultModel implements Model { } @Override + public void setValidators(List<ValidatorDefinition> validators) { + this.validators = validators; + } + + @Override public void setRouteFilterPattern(String include, String exclude) { setRouteFilter(RouteFilters.filterByPattern(include, exclude)); } @@ -462,13 +496,4 @@ public class DefaultModel implements Model { return camelContext.isStarted() && !camelContext.isStarting(); } - protected static <T> T lookup(CamelContext context, String ref, Class<T> type) { - try { - return context.getRegistry().lookupByNameAndType(ref, type); - } catch (Exception e) { - // need to ignore not same type and return it as null - return null; - } - } - } diff --git a/core/camel-core-engine/src/main/java/org/apache/camel/impl/lw/LightweightCamelContext.java b/core/camel-core-engine/src/main/java/org/apache/camel/impl/lw/LightweightCamelContext.java index f2fc22d..3fc21ce 100644 --- a/core/camel-core-engine/src/main/java/org/apache/camel/impl/lw/LightweightCamelContext.java +++ b/core/camel-core-engine/src/main/java/org/apache/camel/impl/lw/LightweightCamelContext.java @@ -1554,6 +1554,11 @@ public class LightweightCamelContext implements ExtendedCamelContext, CatalogCam } @Override + public void addRouteTemplateDefinitionConverter(String templateIdPattern, RouteTemplateDefinition.Converter converter) { + getModelCamelContext().addRouteTemplateDefinitionConverter(templateIdPattern, converter); + } + + @Override public String addRouteFromTemplate(String routeId, String routeTemplateId, Map<String, Object> parameters) throws Exception { return getModelCamelContext().addRouteFromTemplate(routeId, routeTemplateId, parameters); diff --git a/core/camel-core-engine/src/main/java/org/apache/camel/model/Model.java b/core/camel-core-engine/src/main/java/org/apache/camel/model/Model.java index 956fab8..4981706 100644 --- a/core/camel-core-engine/src/main/java/org/apache/camel/model/Model.java +++ b/core/camel-core-engine/src/main/java/org/apache/camel/model/Model.java @@ -156,6 +156,15 @@ public interface Model { void removeRouteTemplateDefinition(RouteTemplateDefinition routeTemplateDefinition) throws Exception; /** + * Add a converter to translate a {@link RouteTemplateDefinition} to a {@link RouteDefinition}. + * + * @param templateIdPattern the route template ut to whom a pattern should eb applied + * @param converter the {@link RouteTemplateDefinition.Converter} used to convert a + * {@link RouteTemplateDefinition} to a {@link RouteDefinition} + */ + void addRouteTemplateDefinitionConverter(String templateIdPattern, RouteTemplateDefinition.Converter converter); + + /** * Adds a new route from a given route template * * @param routeId the id of the new route to add (optional) diff --git a/core/camel-core-engine/src/main/java/org/apache/camel/model/RouteTemplateDefinition.java b/core/camel-core-engine/src/main/java/org/apache/camel/model/RouteTemplateDefinition.java index 5871cd0..c4c1252 100644 --- a/core/camel-core-engine/src/main/java/org/apache/camel/model/RouteTemplateDefinition.java +++ b/core/camel-core-engine/src/main/java/org/apache/camel/model/RouteTemplateDefinition.java @@ -30,6 +30,7 @@ import org.apache.camel.Endpoint; import org.apache.camel.builder.EndpointConsumerBuilder; import org.apache.camel.spi.AsEndpointUri; import org.apache.camel.spi.Metadata; +import org.apache.camel.util.function.ThrowingFunction; /** * Defines a route template (parameterized routes) @@ -213,4 +214,8 @@ public class RouteTemplateDefinition extends OptionalIdentifiedDefinition { return copy; } + + @FunctionalInterface + public interface Converter extends ThrowingFunction<RouteTemplateDefinition, RouteDefinition, Exception> { + } } diff --git a/core/camel-core/src/test/java/org/apache/camel/builder/RouteTemplateConverterTest.java b/core/camel-core/src/test/java/org/apache/camel/builder/RouteTemplateConverterTest.java new file mode 100644 index 0000000..c884969 --- /dev/null +++ b/core/camel-core/src/test/java/org/apache/camel/builder/RouteTemplateConverterTest.java @@ -0,0 +1,136 @@ +/* + * 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.stream.IntStream; + +import org.apache.camel.ContextTestSupport; +import org.apache.camel.model.FromDefinition; +import org.apache.camel.model.RouteDefinition; +import org.apache.camel.model.RouteTemplateDefinition; +import org.junit.jupiter.api.Test; + +import static org.apache.camel.util.CollectionHelper.mapOf; +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class RouteTemplateConverterTest extends ContextTestSupport { + @Test + public void testCreateRouteFromRouteTemplateWithDefaultConverter() throws Exception { + context.addRouteTemplateDefinitionConverter("myTemplate1", RouteTemplateDefinition::asRouteDefinition); + context.addRouteFromTemplate("first", "myTemplate1", mapOf("foo", "one", "bar", "cheese")); + + assertEquals(1, context.getRouteDefinitions().size()); + assertEquals(1, context.getRoutes().size()); + + assertEquals("direct:{{foo}}", context.getRouteDefinition("first").getInput().getEndpointUri()); + assertEquals("direct://one", context.getRoute("first").getEndpoint().getEndpointUri()); + } + + @Test + public void testCreateRouteFromRouteTemplateWithCustomConverter() throws Exception { + context.addRouteTemplateDefinitionConverter("myTemplate1", template -> { + final RouteDefinition def = template.asRouteDefinition(); + final String inUri = def.getInput().getEndpointUri(); + def.setInput(null); + def.setInput(new FromDefinition(inUri + "?timeout=60s")); + return def; + }); + + context.addRouteFromTemplate("first", "myTemplate1", mapOf("foo", "one", "bar", "cheese")); + + assertEquals(1, context.getRouteDefinitions().size()); + assertEquals(1, context.getRoutes().size()); + + assertEquals("direct:{{foo}}?timeout=60s", context.getRouteDefinition("first").getInput().getEndpointUri()); + assertEquals("direct://one?timeout=60s", context.getRoute("first").getEndpoint().getEndpointUri()); + } + + @Test + public void testCreateRouteFromRouteTemplateWithCustomConverterPatter() throws Exception { + context.addRouteTemplateDefinitionConverter("myTemplate[12]", template -> { + final RouteDefinition def = template.asRouteDefinition(); + final String inUri = def.getInput().getEndpointUri(); + def.setInput(null); + def.setInput(new FromDefinition(inUri + "?timeout=60s")); + return def; + }); + + IntStream.of(1, 2, 3).mapToObj(Integer::toString).forEach(index -> { + try { + context.addRouteFromTemplate(index, "myTemplate" + index, mapOf("foo", index, "bar", "cheese")); + } catch (Exception e) { + throw new RuntimeException(e); + } + }); + + assertEquals(3, context.getRouteDefinitions().size()); + assertEquals(3, context.getRoutes().size()); + + assertEquals("direct:{{foo}}?timeout=60s", context.getRouteDefinition("1").getInput().getEndpointUri()); + assertEquals("direct://1?timeout=60s", context.getRoute("1").getEndpoint().getEndpointUri()); + assertEquals("direct:{{foo}}?timeout=60s", context.getRouteDefinition("2").getInput().getEndpointUri()); + assertEquals("direct://2?timeout=60s", context.getRoute("2").getEndpoint().getEndpointUri()); + assertEquals("direct:{{foo}}", context.getRouteDefinition("3").getInput().getEndpointUri()); + assertEquals("direct://3", context.getRoute("3").getEndpoint().getEndpointUri()); + } + + @Test + public void testCreateRouteFromRouteTemplateWithCustomConverterGlob() { + context.addRouteTemplateDefinitionConverter("*", template -> { + final RouteDefinition def = template.asRouteDefinition(); + final String inUri = def.getInput().getEndpointUri(); + def.setInput(null); + def.setInput(new FromDefinition(inUri + "?timeout=60s")); + return def; + }); + + IntStream.of(1, 2, 3).mapToObj(Integer::toString).forEach(index -> { + try { + context.addRouteFromTemplate(index, "myTemplate" + index, mapOf("foo", index, "bar", "cheese")); + + assertEquals("direct:{{foo}}?timeout=60s", context.getRouteDefinition(index).getInput().getEndpointUri()); + assertEquals("direct://" + index + "?timeout=60s", context.getRoute(index).getEndpoint().getEndpointUri()); + } catch (Exception e) { + throw new RuntimeException(e); + } + }); + } + + @Override + protected RouteBuilder createRouteBuilder() throws Exception { + return new RouteBuilder() { + @Override + public void configure() throws Exception { + routeTemplate("myTemplate1") + .templateParameter("foo") + .templateParameter("bar") + .from("direct:{{foo}}") + .to("mock:{{bar}}"); + routeTemplate("myTemplate2") + .templateParameter("foo") + .templateParameter("bar") + .from("direct:{{foo}}") + .to("mock:{{bar}}"); + routeTemplate("myTemplate3") + .templateParameter("foo") + .templateParameter("bar") + .from("direct:{{foo}}") + .to("mock:{{bar}}"); + } + }; + } +}