This is an automated email from the ASF dual-hosted git repository. nfilotto pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/camel.git
The following commit(s) were added to refs/heads/main by this push: new 7acfb27 CAMEL-17555: Flag to include/exclude routes in route templates (#7091) 7acfb27 is described below commit 7acfb273005770b01fae31a394ee44b13c2a8036 Author: Nicolas Filotto <essob...@users.noreply.github.com> AuthorDate: Thu Mar 3 11:31:15 2022 +0100 CAMEL-17555: Flag to include/exclude routes in route templates (#7091) ## Motivation To make route templates (aka kamelets) more flexible it can benefit that we allow to declare routes whether they should be included or excluded. This allows to parameterize these routes and therefore only include them if the template has a parameter included for this. ## Modifications * Add a new parameter called `precondition` allowing to provide a predicate in Simple language to evaluate in order to know if a given route should be excluded or not. * Remove the definition of the route if the `precondition` fails --- .../apache/camel/catalog/schemas/camel-spring.xsd | 1 + .../apache/camel/spring/RoutePreconditionTest.java | 53 +++++++++++ .../camel/spring/RoutePreconditionTest.properties | 18 ++++ .../apache/camel/spring/RoutePreconditionTest.xml | 51 ++++++++++ .../org/apache/camel/impl/DefaultCamelContext.java | 68 ++++++++++--- .../org/apache/camel/model/RouteDefinition.java | 31 ++++++ .../camel/model/RouteTemplateDefinition.java | 2 +- .../builder/RouteTemplatePreconditionTest.java | 92 ++++++++++++++++++ .../camel/processor/RoutePreconditionTest.java | 106 +++++++++++++++++++++ .../java/org/apache/camel/xml/in/ModelParser.java | 1 + docs/user-manual/modules/ROOT/pages/routes.adoc | 38 ++++++++ .../deserializers/RouteDefinitionDeserializer.java | 4 + .../src/generated/resources/camel-yaml-dsl.json | 3 + .../src/generated/resources/camelYamlDsl.json | 3 + .../org/apache/camel/dsl/yaml/RoutesTest.groovy | 27 ++++++ 15 files changed, 484 insertions(+), 14 deletions(-) diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/schemas/camel-spring.xsd b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/schemas/camel-spring.xsd index b600499..c1742f1 100644 --- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/schemas/camel-spring.xsd +++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/schemas/camel-spring.xsd @@ -10762,6 +10762,7 @@ Whether message history is enabled on this route. Default value: true ]]></xs:documentation> </xs:annotation> </xs:attribute> + <xs:attribute name="precondition" type="xs:string"/> <xs:attribute name="rest" type="xs:boolean"/> <xs:attribute name="routeConfigurationId" type="xs:string"/> <xs:attribute name="routePolicyRef" type="xs:string"> diff --git a/components/camel-spring-xml/src/test/java/org/apache/camel/spring/RoutePreconditionTest.java b/components/camel-spring-xml/src/test/java/org/apache/camel/spring/RoutePreconditionTest.java new file mode 100644 index 0000000..9d910bb --- /dev/null +++ b/components/camel-spring-xml/src/test/java/org/apache/camel/spring/RoutePreconditionTest.java @@ -0,0 +1,53 @@ +/* + * 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.spring; + +import org.junit.jupiter.api.Test; +import org.springframework.context.support.AbstractXmlApplicationContext; +import org.springframework.context.support.ClassPathXmlApplicationContext; + +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; + +/** + * The test ensuring that the precondition set on a rule determines if the route is included or not. + */ +class RoutePreconditionTest extends SpringTestSupport { + + @Override + protected AbstractXmlApplicationContext createApplicationContext() { + return new ClassPathXmlApplicationContext("org/apache/camel/spring/RoutePreconditionTest.xml"); + } + + @Test + void testRoutesAreIncludedOrExcludedAsExpected() throws Exception { + assertCollectionSize(context.getRouteDefinitions(), 2); + assertCollectionSize(context.getRoutes(), 2); + assertNotNull(context.getRoute("templatedRouteIncluded")); + assertNotNull(context.getRoute("routeIncluded")); + assertNull(context.getRoute("templatedRouteExcluded")); + assertNull(context.getRoute("routeExcluded")); + + getMockEndpoint("mock:out").expectedMessageCount(1); + getMockEndpoint("mock:outT").expectedMessageCount(1); + + template.sendBody("direct:in", "Hello Included Route"); + template.sendBody("direct:inT", "Hello Included Templated Route"); + + assertMockEndpointsSatisfied(); + } +} diff --git a/components/camel-spring-xml/src/test/resources/org/apache/camel/spring/RoutePreconditionTest.properties b/components/camel-spring-xml/src/test/resources/org/apache/camel/spring/RoutePreconditionTest.properties new file mode 100644 index 0000000..2148b1e --- /dev/null +++ b/components/camel-spring-xml/src/test/resources/org/apache/camel/spring/RoutePreconditionTest.properties @@ -0,0 +1,18 @@ +## --------------------------------------------------------------------------- +## 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. +## --------------------------------------------------------------------------- + +activate=true diff --git a/components/camel-spring-xml/src/test/resources/org/apache/camel/spring/RoutePreconditionTest.xml b/components/camel-spring-xml/src/test/resources/org/apache/camel/spring/RoutePreconditionTest.xml new file mode 100644 index 0000000..03e6a66 --- /dev/null +++ b/components/camel-spring-xml/src/test/resources/org/apache/camel/spring/RoutePreconditionTest.xml @@ -0,0 +1,51 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + + 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. + +--> +<beans xmlns="http://www.springframework.org/schema/beans" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation=" + http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd + http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> + + <camelContext xmlns="http://camel.apache.org/schema/spring"> + <propertyPlaceholder id="properties" location="classpath:org/apache/camel/spring/RoutePreconditionTest.properties"/> + <routeTemplate id="myTemplate"> + <templateParameter name="activateT"/> + <route precondition="{{activateT}}"> + <from uri="direct:inT"/> + <to uri="mock:outT"/> + </route> + </routeTemplate> + <templatedRoute routeTemplateRef="myTemplate" routeId="templatedRouteIncluded"> + <parameter name="activateT" value="true"/> + </templatedRoute> + <templatedRoute routeTemplateRef="myTemplate" routeId="templatedRouteExcluded"> + <parameter name="activateT" value="false"/> + </templatedRoute> + <route precondition="{{activate}}" id="routeIncluded"> + <from uri="direct:in"/> + <to uri="mock:out"/> + </route> + <route precondition="{{!activate}}" id="routeExcluded"> + <from uri="direct:in"/> + <to uri="mock:out"/> + </route> + </camelContext> + +</beans> 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 dbe23bf..8a25e37 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 @@ -16,6 +16,7 @@ */ package org.apache.camel.impl; +import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; @@ -64,6 +65,7 @@ import org.apache.camel.model.RoutesDefinition; import org.apache.camel.model.TemplatedRouteDefinition; import org.apache.camel.model.cloud.ServiceCallConfigurationDefinition; import org.apache.camel.model.language.ExpressionDefinition; +import org.apache.camel.model.language.SimpleExpression; import org.apache.camel.model.rest.RestDefinition; import org.apache.camel.model.rest.RestsDefinition; import org.apache.camel.model.transformer.TransformerDefinition; @@ -83,6 +85,7 @@ import org.apache.camel.spi.Transformer; import org.apache.camel.spi.UuidGenerator; import org.apache.camel.spi.Validator; import org.apache.camel.support.CamelContextHelper; +import org.apache.camel.support.DefaultExchange; import org.apache.camel.support.DefaultRegistry; import org.apache.camel.support.LocalBeanRegistry; import org.apache.camel.support.SimpleUuidGenerator; @@ -796,6 +799,7 @@ public class DefaultCamelContext extends SimpleCamelContext implements ModelCame } try { RouteDefinitionHelper.forceAssignIds(getCamelContextReference(), routeDefinitions); + List<RouteDefinition> routeDefinitionsToRemove = null; for (RouteDefinition routeDefinition : routeDefinitions) { // assign ids to the routes and validate that the id's is all unique String duplicate = RouteDefinitionHelper.validateUniqueIds(routeDefinition, routeDefinitions); @@ -871,28 +875,40 @@ public class DefaultCamelContext extends SimpleCamelContext implements ModelCame // need to reset auto assigned ids, so there is no clash when creating routes ProcessorDefinitionHelper.resetAllAutoAssignedNodeIds(routeDefinition); } + // Check if the route is included + if (includedRoute(routeDefinition)) { + // must ensure route is prepared, before we can start it + if (!routeDefinition.isPrepared()) { + RouteDefinitionHelper.prepareRoute(getCamelContextReference(), routeDefinition); + routeDefinition.markPrepared(); + } - // must ensure route is prepared, before we can start it - if (!routeDefinition.isPrepared()) { - RouteDefinitionHelper.prepareRoute(getCamelContextReference(), routeDefinition); - routeDefinition.markPrepared(); + StartupStepRecorder recorder + = getCamelContextReference().adapt(ExtendedCamelContext.class).getStartupStepRecorder(); + StartupStep step = recorder.beginStep(Route.class, routeDefinition.getRouteId(), "Create Route"); + Route route = model.getModelReifierFactory().createRoute(this, routeDefinition); + recorder.endStep(step); + + RouteService routeService = new RouteService(route); + startRouteService(routeService, true); + } else { + // Add the definition to the list of definitions to remove as the route is excluded + if (routeDefinitionsToRemove == null) { + routeDefinitionsToRemove = new ArrayList<>(routeDefinitions.size()); + } + routeDefinitionsToRemove.add(routeDefinition); } - StartupStepRecorder recorder - = getCamelContextReference().adapt(ExtendedCamelContext.class).getStartupStepRecorder(); - StartupStep step = recorder.beginStep(Route.class, routeDefinition.getRouteId(), "Create Route"); - Route route = model.getModelReifierFactory().createRoute(this, routeDefinition); - recorder.endStep(step); - - RouteService routeService = new RouteService(route); - startRouteService(routeService, true); - // clear local after the route is created via the reifier pc.setLocalProperties(null); if (localBeans != null) { localBeans.setLocalBeanRepository(null); } } + if (routeDefinitionsToRemove != null) { + // Remove all the excluded routes + model.removeRouteDefinitions(routeDefinitionsToRemove); + } } finally { if (!alreadyStartingRoutes) { setStartingRoutes(false); @@ -975,6 +991,32 @@ public class DefaultCamelContext extends SimpleCamelContext implements ModelCame return removed; } + /** + * Indicates whether the route should be included according to the precondition. + * + * @param definition the definition of the route to check. + * @return {@code true} if the route should be included, {@code false} otherwise. + */ + private boolean includedRoute(RouteDefinition definition) { + final String precondition = definition.getPrecondition(); + if (precondition == null) { + LOG.trace("No precondition found, the route is included by default"); + return true; + } + final ExpressionDefinition expression = new SimpleExpression(precondition); + expression.initPredicate(this); + + Predicate predicate = expression.getPredicate(); + predicate.initPredicate(this); + + boolean matches = predicate.matches(new DefaultExchange(this)); + if (LOG.isTraceEnabled()) { + LOG.trace("The precondition has been evaluated to {}, consequently the route is {}", matches, + matches ? "included" : "excluded"); + } + return matches; + } + private static ValueHolder<String> createTransformerKey(TransformerDefinition def) { return ObjectHelper.isNotEmpty(def.getScheme()) ? new TransformerKey(def.getScheme()) diff --git a/core/camel-core-model/src/main/java/org/apache/camel/model/RouteDefinition.java b/core/camel-core-model/src/main/java/org/apache/camel/model/RouteDefinition.java index 2444d35..c639ce2 100644 --- a/core/camel-core-model/src/main/java/org/apache/camel/model/RouteDefinition.java +++ b/core/camel-core-model/src/main/java/org/apache/camel/model/RouteDefinition.java @@ -90,6 +90,7 @@ public class RouteDefinition extends OutputDefinition<RouteDefinition> implement private Map<String, Object> templateParameters; private RouteTemplateContext routeTemplateContext; private Resource resource; + private String precondition; public RouteDefinition() { } @@ -457,6 +458,18 @@ public class RouteDefinition extends OutputDefinition<RouteDefinition> implement } /** + * Sets the predicate of the precondition in simple language to evaluate in order to determine if this route should + * be included or not. + * + * @param precondition the predicate corresponding to the test to evaluate. + * @return the builder + */ + public RouteDefinition precondition(String precondition) { + setPrecondition(precondition); + return this; + } + + /** * Configures the startup order for this route * <p/> * Camel will reorder routes and star them ordered by 0..N where 0 is the lowest number and N the highest number. @@ -913,6 +926,24 @@ public class RouteDefinition extends OutputDefinition<RouteDefinition> implement } /** + * The predicate of the precondition in simple language to evaluate in order to determine if this given route should + * be included or not. + */ + public String getPrecondition() { + return precondition; + } + + /** + * The predicate of the precondition in simple language to evaluate in order to determine if this route should be + * included or not. + */ + @XmlAttribute + @Metadata(label = "advanced") + public void setPrecondition(String precondition) { + this.precondition = precondition; + } + + /** * To configure the ordering of the routes being started */ public Integer getStartupOrder() { 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 8e69ebd..f700c69 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 @@ -417,7 +417,7 @@ public class RouteTemplateDefinition extends OptionalIdentifiedDefinition { } else { copy.setDescription(getDescription()); } - + copy.setPrecondition(route.getPrecondition()); return copy; } diff --git a/core/camel-core/src/test/java/org/apache/camel/builder/RouteTemplatePreconditionTest.java b/core/camel-core/src/test/java/org/apache/camel/builder/RouteTemplatePreconditionTest.java new file mode 100644 index 0000000..ba35b01 --- /dev/null +++ b/core/camel-core/src/test/java/org/apache/camel/builder/RouteTemplatePreconditionTest.java @@ -0,0 +1,92 @@ +/* + * 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 org.apache.camel.ContextTestSupport; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; + +/** + * The test ensuring that the precondition set on a rule determines if the route is included or not + */ +class RouteTemplatePreconditionTest extends ContextTestSupport { + + @Test + void testRouteIncluded() throws Exception { + TemplatedRouteBuilder.builder(context, "myTemplateWithPrecondition") + .parameter("protocol", "json") + .routeId("myRoute") + .add(); + + assertCollectionSize(context.getRouteDefinitions(), 1); + assertCollectionSize(context.getRoutes(), 1); + assertNotNull(context.getRoute("myRoute")); + + getMockEndpoint("mock:out").expectedMessageCount(1); + + template.sendBody("direct:in", "Hello Included Route"); + + assertMockEndpointsSatisfied(); + } + + @Test + void testRouteExcluded() { + TemplatedRouteBuilder.builder(context, "myTemplateWithPrecondition") + .parameter("protocol", "avro") + .routeId("myRoute") + .add(); + + assertCollectionSize(context.getRouteDefinitions(), 0); + assertCollectionSize(context.getRoutes(), 0); + assertNull(context.getRoute("myRoute")); + } + + @Test + void testRouteIncludedByDefault() throws Exception { + TemplatedRouteBuilder.builder(context, "myTemplateWithoutPrecondition") + .routeId("myRoute") + .add(); + + assertCollectionSize(context.getRouteDefinitions(), 1); + assertCollectionSize(context.getRoutes(), 1); + assertNotNull(context.getRoute("myRoute")); + + getMockEndpoint("mock:out").expectedMessageCount(1); + + template.sendBody("direct:in", "Hello Included Route"); + + assertMockEndpointsSatisfied(); + } + + @Override + protected RouteBuilder createRouteBuilder() throws Exception { + return new RouteBuilder() { + @Override + public void configure() throws Exception { + routeTemplate("myTemplateWithPrecondition") + .templateParameter("protocol") + .from("direct:in").precondition("'{{protocol}}' == 'json'") + .to("mock:out"); + routeTemplate("myTemplateWithoutPrecondition") + .from("direct:in") + .to("mock:out"); + } + }; + } +} diff --git a/core/camel-core/src/test/java/org/apache/camel/processor/RoutePreconditionTest.java b/core/camel-core/src/test/java/org/apache/camel/processor/RoutePreconditionTest.java new file mode 100644 index 0000000..508fa3c --- /dev/null +++ b/core/camel-core/src/test/java/org/apache/camel/processor/RoutePreconditionTest.java @@ -0,0 +1,106 @@ +/* + * 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.processor; + +import java.util.Properties; + +import org.apache.camel.ContextTestSupport; +import org.apache.camel.builder.RouteBuilder; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; + +/** + * The test ensuring that the precondition set on a rule determines if the route is included or not + */ +class RoutePreconditionTest extends ContextTestSupport { + + @Override + public boolean isUseRouteBuilder() { + return false; + } + + @Test + void testRouteIncluded() throws Exception { + Properties init = new Properties(); + init.setProperty("protocol", "json"); + context.getPropertiesComponent().setInitialProperties(init); + + context.addRoutes(createRouteBuilder()); + context.start(); + + assertCollectionSize(context.getRouteDefinitions(), 2); + assertCollectionSize(context.getRoutes(), 2); + assertNotNull(context.getRoute("myRoute")); + assertNotNull(context.getRoute("myRouteNP")); + + getMockEndpoint("mock:out").expectedMessageCount(1); + + template.sendBody("direct:in", "Hello Included Route"); + + assertMockEndpointsSatisfied(); + } + + @Test + void testRouteExcluded() throws Exception { + Properties init = new Properties(); + init.setProperty("protocol", "avro"); + context.getPropertiesComponent().setInitialProperties(init); + + context.addRoutes(createRouteBuilder()); + context.start(); + + assertCollectionSize(context.getRouteDefinitions(), 1); + assertCollectionSize(context.getRoutes(), 1); + assertNull(context.getRoute("myRoute")); + assertNotNull(context.getRoute("myRouteNP")); + } + + @Test + void testRouteIncludedByDefault() throws Exception { + Properties init = new Properties(); + init.setProperty("protocol", "foo"); + context.getPropertiesComponent().setInitialProperties(init); + + context.addRoutes(createRouteBuilder()); + context.start(); + + assertCollectionSize(context.getRouteDefinitions(), 1); + assertCollectionSize(context.getRoutes(), 1); + assertNotNull(context.getRoute("myRouteNP")); + + getMockEndpoint("mock:outNP").expectedMessageCount(1); + + template.sendBody("direct:inNP", "Hello Included Route"); + + assertMockEndpointsSatisfied(); + } + + @Override + protected RouteBuilder createRouteBuilder() { + return new RouteBuilder() { + public void configure() { + from("direct:in").routeId("myRoute").precondition("'{{protocol}}' == 'json'") + .to("mock:out"); + from("direct:inNP").routeId("myRouteNP") + .to("mock:outNP"); + } + }; + } + +} diff --git a/core/camel-xml-io/src/generated/java/org/apache/camel/xml/in/ModelParser.java b/core/camel-xml-io/src/generated/java/org/apache/camel/xml/in/ModelParser.java index 5b9047b..b6d537ef 100644 --- a/core/camel-xml-io/src/generated/java/org/apache/camel/xml/in/ModelParser.java +++ b/core/camel-xml-io/src/generated/java/org/apache/camel/xml/in/ModelParser.java @@ -1048,6 +1048,7 @@ public class ModelParser extends BaseParser { case "group": def.setGroup(val); break; case "logMask": def.setLogMask(val); break; case "messageHistory": def.setMessageHistory(val); break; + case "precondition": def.setPrecondition(val); break; case "routeConfigurationId": def.setRouteConfigurationId(val); break; case "routePolicyRef": def.setRoutePolicyRef(val); break; case "shutdownRoute": def.setShutdownRoute(val); break; diff --git a/docs/user-manual/modules/ROOT/pages/routes.adoc b/docs/user-manual/modules/ROOT/pages/routes.adoc index 5aca179..6adf101 100644 --- a/docs/user-manual/modules/ROOT/pages/routes.adoc +++ b/docs/user-manual/modules/ROOT/pages/routes.adoc @@ -54,6 +54,44 @@ rb -> rb.from("kafka:cheese").to("jms:queue:foo"); There is a bit more to this as the lambda route must be coded in a Java method that returns an instance of `LambdaRouteBuilder`. See more at the xref:lambda-route-builder.adoc[LambdaRouteBuilder] documentation. +== Route Precondition + +The routes can be included or not according to the result of a test expressed in simple language that is evaluated only once during the initialization phase. + +In the next example, the route is only included if the parameter `format` has been set to `xml`. + +[source,java] +---- +from("direct:in").precondition("'{{format}}' == 'xml'") + .unmarshal().jaxb() + .to("direct:out"); +---- + +And the same example using XML DSL: + +[source,xml] +---- +<route precondition="'{{format}}' == 'xml'"> + <from uri="direct:in"/> + <unmarshal><jaxb/></unmarshal> + <to uri="direct:out"/> +</route> +---- + +And in YAML DSL: + +[source,yaml] +---- +- route: + precondition: "'{{format}}' == 'xml'" + from: + uri: "direct:in" + steps: + - unmarshal: + jaxb: {} + - to: "direct:out" +---- + == More Information See xref:route-builder.adoc[RouteBuilder] and xref:dsl.adoc[DSL] for a list of supported languages you can use for coding Camel routes. diff --git a/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/main/java/org/apache/camel/dsl/yaml/deserializers/RouteDefinitionDeserializer.java b/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/main/java/org/apache/camel/dsl/yaml/deserializers/RouteDefinitionDeserializer.java index 18fc980..8e49bb1 100644 --- a/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/main/java/org/apache/camel/dsl/yaml/deserializers/RouteDefinitionDeserializer.java +++ b/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/main/java/org/apache/camel/dsl/yaml/deserializers/RouteDefinitionDeserializer.java @@ -38,6 +38,7 @@ import org.snakeyaml.engine.v2.nodes.NodeTuple; properties = { @YamlProperty(name = "id", type = "string"), @YamlProperty(name = "description", type = "string"), + @YamlProperty(name = "precondition", type = "string"), @YamlProperty(name = "group", type = "string"), @YamlProperty(name = "route-configuration-id", type = "string"), @YamlProperty(name = "from", type = "object:org.apache.camel.model.FromDefinition", required = true) @@ -70,6 +71,9 @@ public class RouteDefinitionDeserializer extends YamlDeserializerBase<RouteDefin case "description": target.setDescription(new DescriptionDefinition(asText(val))); break; + case "precondition": + target.setPrecondition(asText(val)); + break; case "group": target.setGroup(asText(val)); break; diff --git a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/camel-yaml-dsl.json b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/camel-yaml-dsl.json index ac4fdc1..9ca79c9 100644 --- a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/camel-yaml-dsl.json +++ b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/camel-yaml-dsl.json @@ -2514,6 +2514,9 @@ "id" : { "type" : "string" }, + "precondition" : { + "type" : "string" + }, "route-configuration-id" : { "type" : "string" } diff --git a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/camelYamlDsl.json b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/camelYamlDsl.json index cf4c823..f67dbf4 100644 --- a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/camelYamlDsl.json +++ b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/camelYamlDsl.json @@ -2415,6 +2415,9 @@ "id" : { "type" : "string" }, + "precondition" : { + "type" : "string" + }, "routeConfigurationId" : { "type" : "string" } diff --git a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/RoutesTest.groovy b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/RoutesTest.groovy index c2d7abf..baeb051e 100644 --- a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/RoutesTest.groovy +++ b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/RoutesTest.groovy @@ -186,4 +186,31 @@ class RoutesTest extends YamlTestSupport { } } } + + def "load route description with precondition"() { + when: + loadRoutes ''' + - route: + id: demo-route + description: something cool + precondition: "{{?red}}" + from: + uri: "direct:info" + steps: + - log: "message" + ''' + then: + context.routeDefinitions.size() == 1 + + with(context.routeDefinitions[0], RouteDefinition) { + routeId == 'demo-route' + description.text == 'something cool' + input.endpointUri == 'direct:info' + precondition == '{{?red}}' + + with (outputs[0], LogDefinition) { + message == 'message' + } + } + } }