You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by da...@apache.org on 2022/03/08 06:23:10 UTC

[camel] branch main updated: CAMEL-17754: Precondition to hard exclude route configurations (#7142)

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

davsclaus 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 c40f110  CAMEL-17754: Precondition to hard exclude route configurations (#7142)
c40f110 is described below

commit c40f110ea316011e7334bcc040db64655191dc1c
Author: Nicolas Filotto <es...@users.noreply.github.com>
AuthorDate: Tue Mar 8 07:21:52 2022 +0100

    CAMEL-17754: Precondition to hard exclude route configurations (#7142)
---
 .../camel/catalog/models/routeConfiguration.json   |  1 +
 .../apache/camel/catalog/schemas/camel-spring.xsd  |  8 +++
 ...ava => RouteConfigurationPreconditionTest.java} | 25 +++-----
 .../apache/camel/spring/RoutePreconditionTest.java |  2 +-
 ...Test.properties => PreconditionTest.properties} |  0
 .../spring/RouteConfigurationPreconditionTest.xml  | 75 ++++++++++++++++++++++
 .../apache/camel/spring/RoutePreconditionTest.xml  |  2 +-
 .../org/apache/camel/impl/DefaultCamelContext.java | 20 +-----
 .../java/org/apache/camel/impl/DefaultModel.java   | 12 +++-
 .../org/apache/camel/impl/PreconditionHelper.java  | 67 +++++++++++++++++++
 .../org/apache/camel/model/routeConfiguration.json |  1 +
 .../apache/camel/model/PreconditionContainer.java  | 37 +++++++++++
 .../camel/model/RouteConfigurationDefinition.java  | 37 ++++++++++-
 .../org/apache/camel/model/RouteDefinition.java    | 11 ++--
 ...ava => RouteConfigurationPreconditionTest.java} | 71 +++++++++-----------
 .../camel/processor/RoutePreconditionTest.java     |  2 +-
 .../java/org/apache/camel/xml/in/ModelParser.java  |  9 ++-
 .../modules/ROOT/pages/route-configuration.adoc    | 45 +++++++++++++
 .../RouteConfigurationDefinitionDeserializer.java  |  4 ++
 .../src/generated/resources/camel-yaml-dsl.json    |  3 +
 .../src/generated/resources/camelYamlDsl.json      |  3 +
 .../camel/dsl/yaml/RouteConfigurationTest.groovy   | 59 ++++++++++++++++-
 22 files changed, 407 insertions(+), 87 deletions(-)

diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/routeConfiguration.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/routeConfiguration.json
index 29af0d6..a1b45b6 100644
--- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/routeConfiguration.json
+++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/routeConfiguration.json
@@ -17,6 +17,7 @@
     "interceptSendToEndpoint": { "kind": "element", "displayName": "Intercept Send To Endpoint", "required": false, "type": "array", "javaType": "java.util.List<org.apache.camel.model.InterceptSendToEndpointDefinition>", "deprecated": false, "autowired": false, "secret": false, "description": "Applies a route for an interceptor if an exchange is send to the given endpoint" },
     "onException": { "kind": "element", "displayName": "On Exception", "required": false, "type": "array", "javaType": "java.util.List<org.apache.camel.model.OnExceptionDefinition>", "deprecated": false, "autowired": false, "secret": false, "description": "Exception clause for catching certain exceptions and handling them." },
     "onCompletion": { "kind": "element", "displayName": "On Completion", "required": false, "type": "array", "javaType": "java.util.List<org.apache.camel.model.OnCompletionDefinition>", "deprecated": false, "autowired": false, "secret": false, "description": "On completion callback for doing custom routing when the org.apache.camel.Exchange is complete." },
+    "precondition": { "kind": "attribute", "displayName": "Precondition", "label": "advanced", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "The predicate of the precondition in simple language to evaluate in order to determine if this route configuration should be included or not." },
     "id": { "kind": "attribute", "displayName": "Id", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the id of this node" },
     "description": { "kind": "element", "displayName": "Description", "required": false, "type": "object", "javaType": "org.apache.camel.model.DescriptionDefinition", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the description of this node" }
   }
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 6dd00d4..d06f7df 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
@@ -10612,6 +10612,14 @@ Reference to the route templates in the xml dsl.
           <xs:element maxOccurs="unbounded" minOccurs="0" ref="tns:onException"/>
           <xs:element maxOccurs="unbounded" minOccurs="0" ref="tns:onCompletion"/>
         </xs:sequence>
+        <xs:attribute name="precondition" type="xs:string">
+          <xs:annotation>
+            <xs:documentation xml:lang="en"><![CDATA[
+The predicate of the precondition in simple language to evaluate in order to
+determine if this route configuration should be included or not.
+            ]]></xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
       </xs:extension>
     </xs:complexContent>
   </xs:complexType>
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/RouteConfigurationPreconditionTest.java
similarity index 60%
copy from components/camel-spring-xml/src/test/java/org/apache/camel/spring/RoutePreconditionTest.java
copy to components/camel-spring-xml/src/test/java/org/apache/camel/spring/RouteConfigurationPreconditionTest.java
index 9d910bb..9e3e45b 100644
--- 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/RouteConfigurationPreconditionTest.java
@@ -20,33 +20,28 @@ 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.
+ * The test ensuring that the precondition set on a route configuration determines if the route configuration is
+ * included or not
  */
-class RoutePreconditionTest extends SpringTestSupport {
+class RouteConfigurationPreconditionTest extends SpringTestSupport {
 
     @Override
     protected AbstractXmlApplicationContext createApplicationContext() {
-        return new ClassPathXmlApplicationContext("org/apache/camel/spring/RoutePreconditionTest.xml");
+        return new ClassPathXmlApplicationContext("org/apache/camel/spring/RouteConfigurationPreconditionTest.xml");
     }
 
     @Test
-    void testRoutesAreIncludedOrExcludedAsExpected() throws Exception {
+    void testRouteConfigurationAreIncludedOrExcludedAsExpected() throws Exception {
+        assertCollectionSize(context.getRouteConfigurationDefinitions(), 2);
         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);
+        getMockEndpoint("mock:error").expectedMessageCount(2);
+        getMockEndpoint("mock:error").expectedBodiesReceived("Activated", "Default");
 
-        template.sendBody("direct:in", "Hello Included Route");
-        template.sendBody("direct:inT", "Hello Included Templated Route");
+        template.sendBody("direct:start", "Hello Activated Route Config");
+        template.sendBody("direct:start2", "Hello Not Activated Route Config");
 
         assertMockEndpointsSatisfied();
     }
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
index 9d910bb..f02994e 100644
--- 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
@@ -24,7 +24,7 @@ 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.
+ * The test ensuring that the precondition set on a route determines if the route is included or not.
  */
 class RoutePreconditionTest extends SpringTestSupport {
 
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/PreconditionTest.properties
similarity index 100%
rename from components/camel-spring-xml/src/test/resources/org/apache/camel/spring/RoutePreconditionTest.properties
rename to components/camel-spring-xml/src/test/resources/org/apache/camel/spring/PreconditionTest.properties
diff --git a/components/camel-spring-xml/src/test/resources/org/apache/camel/spring/RouteConfigurationPreconditionTest.xml b/components/camel-spring-xml/src/test/resources/org/apache/camel/spring/RouteConfigurationPreconditionTest.xml
new file mode 100644
index 0000000..4b46716
--- /dev/null
+++ b/components/camel-spring-xml/src/test/resources/org/apache/camel/spring/RouteConfigurationPreconditionTest.xml
@@ -0,0 +1,75 @@
+<?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/PreconditionTest.properties"/>
+        <routeConfiguration>
+            <onException>
+                <exception>java.lang.Exception</exception>
+                <handled>
+                    <constant>true</constant>
+                </handled>
+                <transform>
+                    <constant>Default</constant>
+                </transform>
+                <to uri="mock:error"/>
+            </onException>
+        </routeConfiguration>
+        <routeConfiguration precondition="{{activate}}">
+            <onException>
+                <exception>java.lang.IllegalArgumentException</exception>
+                <handled>
+                    <constant>true</constant>
+                </handled>
+                <transform>
+                    <constant>Activated</constant>
+                </transform>
+                <to uri="mock:error"/>
+            </onException>
+        </routeConfiguration>
+        <routeConfiguration precondition="{{!activate}}">
+            <onException>
+                <exception>java.lang.IllegalArgumentException</exception>
+                <handled>
+                    <constant>true</constant>
+                </handled>
+                <transform>
+                    <constant>Not Activated</constant>
+                </transform>
+                <to uri="mock:error"/>
+            </onException>
+        </routeConfiguration>
+
+        <route>
+            <from uri="direct:start"/>
+            <throwException exceptionType="java.lang.IllegalArgumentException" message="Foo"/>
+        </route>
+        <route>
+            <from uri="direct:start2"/>
+            <throwException exceptionType="java.lang.RuntimeException" message="Foo"/>
+        </route>
+    </camelContext>
+
+</beans>
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
index 03e6a66..45694d7 100644
--- 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
@@ -24,7 +24,7 @@
             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"/>
+        <propertyPlaceholder id="properties" location="classpath:org/apache/camel/spring/PreconditionTest.properties"/>
         <routeTemplate id="myTemplate">
             <templateParameter name="activateT"/>
             <route precondition="{{activateT}}">
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 8a25e37..d2b4dcb 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
@@ -65,7 +65,6 @@ 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;
@@ -85,7 +84,6 @@ 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;
@@ -998,23 +996,7 @@ public class DefaultCamelContext extends SimpleCamelContext implements ModelCame
      * @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;
+        return PreconditionHelper.included(definition, this);
     }
 
     private static ValueHolder<String> createTransformerKey(TransformerDefinition def) {
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 fcb834f..179cc44 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
@@ -122,7 +122,8 @@ public class DefaultModel implements Model {
 
     @Override
     public void addRouteConfiguration(RouteConfigurationDefinition routesConfiguration) {
-        if (routesConfiguration == null) {
+        // Ensure that the route configuration should be included
+        if (routesConfiguration == null || !includedRouteConfiguration(routesConfiguration)) {
             return;
         }
         // only add if not already exists (route-loader may let Java DSL add route configuration twice
@@ -925,4 +926,13 @@ public class DefaultModel implements Model {
         }
     }
 
+    /**
+     * Indicates whether the route configuration should be included according to the precondition.
+     *
+     * @param  definition the definition of the route configuration to check.
+     * @return            {@code true} if the route configuration should be included, {@code false} otherwise.
+     */
+    private boolean includedRouteConfiguration(RouteConfigurationDefinition definition) {
+        return PreconditionHelper.included(definition, camelContext);
+    }
 }
diff --git a/core/camel-core-engine/src/main/java/org/apache/camel/impl/PreconditionHelper.java b/core/camel-core-engine/src/main/java/org/apache/camel/impl/PreconditionHelper.java
new file mode 100644
index 0000000..588ef29
--- /dev/null
+++ b/core/camel-core-engine/src/main/java/org/apache/camel/impl/PreconditionHelper.java
@@ -0,0 +1,67 @@
+/*
+ * 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.impl;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.Predicate;
+import org.apache.camel.model.PreconditionContainer;
+import org.apache.camel.model.language.ExpressionDefinition;
+import org.apache.camel.model.language.SimpleExpression;
+import org.apache.camel.support.DefaultExchange;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Helper class for preconditions.
+ */
+final class PreconditionHelper {
+
+    /**
+     * The logger.
+     */
+    private static final Logger LOG = LoggerFactory.getLogger(PreconditionHelper.class);
+
+    private PreconditionHelper() {
+    }
+
+    /**
+     * Indicates whether the given {@link PreconditionContainer} should be included according to the precondition.
+     *
+     * @param  container the {@link PreconditionContainer} for which the precondition should be evaluated.
+     * @param  context   the camel context in which the precondition should be evaluated.
+     * @return           {@code true} if the {@link PreconditionContainer} should be included, {@code false} otherwise.
+     */
+    static boolean included(PreconditionContainer container, CamelContext context) {
+        final String precondition = container.getPrecondition();
+        if (precondition == null) {
+            LOG.trace("No precondition found, the {} is included by default", container.getLabel());
+            return true;
+        }
+        final ExpressionDefinition expression = new SimpleExpression(precondition);
+        expression.initPredicate(context);
+
+        Predicate predicate = expression.getPredicate();
+        predicate.initPredicate(context);
+
+        boolean matches = predicate.matches(new DefaultExchange(context));
+        if (LOG.isTraceEnabled()) {
+            LOG.trace("The precondition has been evaluated to {}, consequently the {} is {}", matches, container.getLabel(),
+                    matches ? "included" : "excluded");
+        }
+        return matches;
+    }
+}
diff --git a/core/camel-core-model/src/generated/resources/org/apache/camel/model/routeConfiguration.json b/core/camel-core-model/src/generated/resources/org/apache/camel/model/routeConfiguration.json
index 29af0d6..a1b45b6 100644
--- a/core/camel-core-model/src/generated/resources/org/apache/camel/model/routeConfiguration.json
+++ b/core/camel-core-model/src/generated/resources/org/apache/camel/model/routeConfiguration.json
@@ -17,6 +17,7 @@
     "interceptSendToEndpoint": { "kind": "element", "displayName": "Intercept Send To Endpoint", "required": false, "type": "array", "javaType": "java.util.List<org.apache.camel.model.InterceptSendToEndpointDefinition>", "deprecated": false, "autowired": false, "secret": false, "description": "Applies a route for an interceptor if an exchange is send to the given endpoint" },
     "onException": { "kind": "element", "displayName": "On Exception", "required": false, "type": "array", "javaType": "java.util.List<org.apache.camel.model.OnExceptionDefinition>", "deprecated": false, "autowired": false, "secret": false, "description": "Exception clause for catching certain exceptions and handling them." },
     "onCompletion": { "kind": "element", "displayName": "On Completion", "required": false, "type": "array", "javaType": "java.util.List<org.apache.camel.model.OnCompletionDefinition>", "deprecated": false, "autowired": false, "secret": false, "description": "On completion callback for doing custom routing when the org.apache.camel.Exchange is complete." },
+    "precondition": { "kind": "attribute", "displayName": "Precondition", "label": "advanced", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "The predicate of the precondition in simple language to evaluate in order to determine if this route configuration should be included or not." },
     "id": { "kind": "attribute", "displayName": "Id", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the id of this node" },
     "description": { "kind": "element", "displayName": "Description", "required": false, "type": "object", "javaType": "org.apache.camel.model.DescriptionDefinition", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the description of this node" }
   }
diff --git a/core/camel-core-model/src/main/java/org/apache/camel/model/PreconditionContainer.java b/core/camel-core-model/src/main/java/org/apache/camel/model/PreconditionContainer.java
new file mode 100644
index 0000000..b8662d3
--- /dev/null
+++ b/core/camel-core-model/src/main/java/org/apache/camel/model/PreconditionContainer.java
@@ -0,0 +1,37 @@
+/*
+ * 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.model;
+
+import org.apache.camel.NamedNode;
+
+/**
+ * Indicates that the configuration element holds a precondition to determine if it should be included or not.
+ */
+public interface PreconditionContainer extends NamedNode {
+
+    /**
+     * The predicate of the precondition in simple language to evaluate in order to determine if it should be included
+     * or not.
+     */
+    String getPrecondition();
+
+    /**
+     * The predicate of the precondition in simple language to evaluate in order to determine if it should be included
+     * or not.
+     */
+    void setPrecondition(String precondition);
+}
diff --git a/core/camel-core-model/src/main/java/org/apache/camel/model/RouteConfigurationDefinition.java b/core/camel-core-model/src/main/java/org/apache/camel/model/RouteConfigurationDefinition.java
index 56df20c..1a7b65f 100644
--- a/core/camel-core-model/src/main/java/org/apache/camel/model/RouteConfigurationDefinition.java
+++ b/core/camel-core-model/src/main/java/org/apache/camel/model/RouteConfigurationDefinition.java
@@ -22,6 +22,7 @@ import java.util.List;
 
 import javax.xml.bind.annotation.XmlAccessType;
 import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlAttribute;
 import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlRootElement;
 
@@ -33,7 +34,8 @@ import org.apache.camel.spi.Metadata;
 @Metadata(label = "configuration")
 @XmlRootElement(name = "routeConfiguration")
 @XmlAccessorType(XmlAccessType.FIELD)
-public class RouteConfigurationDefinition extends OptionalIdentifiedDefinition<RouteConfigurationDefinition> {
+public class RouteConfigurationDefinition extends OptionalIdentifiedDefinition<RouteConfigurationDefinition>
+        implements PreconditionContainer {
 
     // TODO: Model for ErrorHandler (requires to move error handler model from spring-xml, blueprint to core)
 
@@ -47,6 +49,9 @@ public class RouteConfigurationDefinition extends OptionalIdentifiedDefinition<R
     private List<OnExceptionDefinition> onExceptions = new ArrayList<>();
     @XmlElement(name = "onCompletion")
     private List<OnCompletionDefinition> onCompletions = new ArrayList<>();
+    @XmlAttribute
+    @Metadata(label = "advanced")
+    private String precondition;
 
     public RouteConfigurationDefinition() {
     }
@@ -106,10 +111,40 @@ public class RouteConfigurationDefinition extends OptionalIdentifiedDefinition<R
         this.interceptSendTos = interceptSendTos;
     }
 
+    /**
+     * The predicate of the precondition in simple language to evaluate in order to determine if this route
+     * configuration should be included or not.
+     */
+    @Override
+    public String getPrecondition() {
+        return precondition;
+    }
+
+    /**
+     * The predicate of the precondition in simple language to evaluate in order to determine if this route
+     * configuration should be included or not.
+     */
+    @Override
+    public void setPrecondition(String precondition) {
+        this.precondition = precondition;
+    }
+
     // Fluent API
     // -------------------------------------------------------------------------
 
     /**
+     * Sets the predicate of the precondition in simple language to evaluate in order to determine if this route
+     * configuration should be included or not.
+     *
+     * @param  precondition the predicate corresponding to the test to evaluate.
+     * @return              the builder
+     */
+    public RouteConfigurationDefinition precondition(String precondition) {
+        setPrecondition(precondition);
+        return this;
+    }
+
+    /**
      * <a href="http://camel.apache.org/exception-clause.html">Exception clause</a> for catching certain exceptions and
      * handling them.
      *
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 c639ce2..c7e2d3e 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
@@ -34,6 +34,7 @@ import javax.xml.bind.annotation.XmlRootElement;
 import javax.xml.bind.annotation.XmlTransient;
 import javax.xml.bind.annotation.XmlType;
 
+import org.apache.camel.CamelContext;
 import org.apache.camel.Endpoint;
 import org.apache.camel.ErrorHandlerFactory;
 import org.apache.camel.NamedRoute;
@@ -57,7 +58,7 @@ import org.apache.camel.spi.RoutePolicy;
 @XmlType(propOrder = { "input", "inputType", "outputType", "outputs", "routeProperties" })
 @XmlAccessorType(XmlAccessType.PROPERTY)
 // must use XmlAccessType.PROPERTY as there is some custom logic needed to be executed in the setter methods
-public class RouteDefinition extends OutputDefinition<RouteDefinition> implements NamedRoute {
+public class RouteDefinition extends OutputDefinition<RouteDefinition> implements NamedRoute, PreconditionContainer {
     private final AtomicBoolean prepared = new AtomicBoolean();
     private FromDefinition input;
     private String routeConfigurationId;
@@ -117,7 +118,7 @@ public class RouteDefinition extends OutputDefinition<RouteDefinition> implement
      * Check if the route has been prepared
      *
      * @return whether the route has been prepared or not
-     * @see    RouteDefinitionHelper#prepareRoute(ModelCamelContext, RouteDefinition)
+     * @see    RouteDefinitionHelper#prepareRoute(CamelContext, RouteDefinition)
      */
     public boolean isPrepared() {
         return prepared.get();
@@ -926,9 +927,10 @@ 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.
+     * The predicate of the precondition in simple language to evaluate in order to determine if this route should be
+     * included or not.
      */
+    @Override
     public String getPrecondition() {
         return precondition;
     }
@@ -939,6 +941,7 @@ public class RouteDefinition extends OutputDefinition<RouteDefinition> implement
      */
     @XmlAttribute
     @Metadata(label = "advanced")
+    @Override
     public void setPrecondition(String precondition) {
         this.precondition = precondition;
     }
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/RouteConfigurationPreconditionTest.java
similarity index 51%
copy from core/camel-core/src/test/java/org/apache/camel/processor/RoutePreconditionTest.java
copy to core/camel-core/src/test/java/org/apache/camel/processor/RouteConfigurationPreconditionTest.java
index 508fa3c..bb11a29 100644
--- a/core/camel-core/src/test/java/org/apache/camel/processor/RoutePreconditionTest.java
+++ b/core/camel-core/src/test/java/org/apache/camel/processor/RouteConfigurationPreconditionTest.java
@@ -20,15 +20,14 @@ import java.util.Properties;
 
 import org.apache.camel.ContextTestSupport;
 import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.builder.RouteConfigurationBuilder;
 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
+ * The test ensuring that the precondition set on a route configuration determines if the route configuration is
+ * included or not
  */
-class RoutePreconditionTest extends ContextTestSupport {
+class RouteConfigurationPreconditionTest extends ContextTestSupport {
 
     @Override
     public boolean isUseRouteBuilder() {
@@ -36,71 +35,61 @@ class RoutePreconditionTest extends ContextTestSupport {
     }
 
     @Test
-    void testRouteIncluded() throws Exception {
+    void testRouteConfigurationIncluded() throws Exception {
         Properties init = new Properties();
-        init.setProperty("protocol", "json");
+        init.setProperty("activate", "true");
         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"));
+        assertCollectionSize(context.getRouteConfigurationDefinitions(), 2);
+        assertCollectionSize(context.getRouteDefinitions(), 1);
+        assertCollectionSize(context.getRoutes(), 1);
 
-        getMockEndpoint("mock:out").expectedMessageCount(1);
+        getMockEndpoint("mock:error").expectedMessageCount(1);
+        getMockEndpoint("mock:error").expectedBodiesReceived("Activated");
 
-        template.sendBody("direct:in", "Hello Included Route");
+        template.sendBody("direct:start", "Hello Activated Route Config");
 
         assertMockEndpointsSatisfied();
     }
 
     @Test
-    void testRouteExcluded() throws Exception {
+    void testRouteConfigurationExcluded() throws Exception {
         Properties init = new Properties();
-        init.setProperty("protocol", "avro");
+        init.setProperty("activate", "false");
         context.getPropertiesComponent().setInitialProperties(init);
 
         context.addRoutes(createRouteBuilder());
         context.start();
 
+        assertCollectionSize(context.getRouteConfigurationDefinitions(), 1);
         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);
+        getMockEndpoint("mock:error").expectedMessageCount(1);
+        getMockEndpoint("mock:error").expectedBodiesReceived("Default");
 
-        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");
+        template.sendBody("direct:start", "Hello Not Activated Route Config");
 
         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");
+    protected RouteBuilder createRouteBuilder() throws Exception {
+        return new RouteConfigurationBuilder() {
+            @Override
+            public void configuration() {
+                from("direct:start")
+                        .throwException(new IllegalArgumentException("Foo"));
+                routeConfiguration().precondition("{{activate}}").onException(IllegalArgumentException.class).handled(true)
+                        .transform(constant("Activated"))
+                        .to("mock:error");
+                routeConfiguration().onException(Exception.class).handled(true)
+                        .transform(constant("Default"))
+                        .to("mock:error");
             }
         };
     }
-
 }
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
index 508fa3c..f295238 100644
--- 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
@@ -26,7 +26,7 @@ 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
+ * The test ensuring that the precondition set on a route determines if the route is included or not
  */
 class RoutePreconditionTest extends ContextTestSupport {
 
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 bd2d248..4aaca5f 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
@@ -984,8 +984,13 @@ public class ModelParser extends BaseParser {
         }, noElementHandler(), noValueHandler());
     }
     protected RouteConfigurationDefinition doParseRouteConfigurationDefinition() throws IOException, XmlPullParserException {
-        return doParse(new RouteConfigurationDefinition(),
-            optionalIdentifiedDefinitionAttributeHandler(), (def, key) -> {
+        return doParse(new RouteConfigurationDefinition(), (def, key, val) -> {
+            if ("precondition".equals(key)) {
+                def.setPrecondition(val);
+                return true;
+            }
+            return optionalIdentifiedDefinitionAttributeHandler().accept(def, key, val);
+        }, (def, key) -> {
             switch (key) {
                 case "interceptFrom": doAdd(doParseInterceptFromDefinition(), def.getInterceptFroms(), def::setInterceptFroms); break;
                 case "interceptSendToEndpoint": doAdd(doParseInterceptSendToEndpointDefinition(), def.getInterceptSendTos(), def::setInterceptSendTos); break;
diff --git a/docs/user-manual/modules/ROOT/pages/route-configuration.adoc b/docs/user-manual/modules/ROOT/pages/route-configuration.adoc
index de16d2d..2215ffb 100644
--- a/docs/user-manual/modules/ROOT/pages/route-configuration.adoc
+++ b/docs/user-manual/modules/ROOT/pages/route-configuration.adoc
@@ -323,6 +323,51 @@ And in Camel Main / Quarkus:
 camel.main.startup-summary-level = verbose
 ----
 
+== Route Precondition
+
+The route configurations 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 configuration is only included if the parameter `activate` has been set to `true`.
+
+[source,java]
+----
+routeConfiguration().precondition("{{activate}}")
+    .onException(IllegalArgumentException.class)
+    .handled(true)
+    .log("WARN: ${exception.message}");
+----
+
+And the same example using XML DSL:
+
+[source,xml]
+----
+<routeConfiguration precondition="{{activate}}">
+    <onException>
+        <exception>java.lang.IllegalArgumentException</exception>
+        <handled>
+            <constant>true</constant>
+        </handled>
+        <log message="XML WARN: ${exception.message}"/>
+    </onException>
+</routeConfiguration>
+----
+
+And in YAML DSL:
+
+[source,yaml]
+----
+- route-configuration:
+    - precondition: "{{activate}}"
+    - on-exception:
+        exception:
+          - "java.lang.IllegalArgumentException"
+        handled:
+          constant: "true"
+        steps:
+          - log:
+              message: "YAML WARN ${exception.message}"
+----
+
 == More Information
 
 See these examples:
diff --git a/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/main/java/org/apache/camel/dsl/yaml/deserializers/RouteConfigurationDefinitionDeserializer.java b/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/main/java/org/apache/camel/dsl/yaml/deserializers/RouteConfigurationDefinitionDeserializer.java
index 1fcb898..5b99d26 100644
--- a/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/main/java/org/apache/camel/dsl/yaml/deserializers/RouteConfigurationDefinitionDeserializer.java
+++ b/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/main/java/org/apache/camel/dsl/yaml/deserializers/RouteConfigurationDefinitionDeserializer.java
@@ -40,6 +40,7 @@ import org.snakeyaml.engine.v2.nodes.SequenceNode;
           nodes = { "route-configuration", "routeConfiguration" },
           properties = {
                   @YamlProperty(name = "id", type = "string"),
+                  @YamlProperty(name = "precondition", type = "string"),
                   @YamlProperty(name = "intercept", type = "array:org.apache.camel.model.InterceptDefinition"),
                   @YamlProperty(name = "intercept-from", type = "array:org.apache.camel.model.InterceptFromDefinition"),
                   @YamlProperty(name = "intercept-send-to-endpoint",
@@ -75,6 +76,9 @@ public class RouteConfigurationDefinitionDeserializer extends YamlDeserializerBa
                         target.setId(asText(val));
                         break;
                     }
+                    case "precondition":
+                        target.setPrecondition(asText(val));
+                        break;
                     case "on-exception":
                         setDeserializationContext(val, dc);
                         OnExceptionDefinition oed = asType(val, OnExceptionDefinition.class);
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 b96eb2e..e7ac7f4 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
@@ -2482,6 +2482,9 @@
               "items" : {
                 "$ref" : "#/items/definitions/org.apache.camel.model.OnExceptionDefinition"
               }
+            },
+            "precondition" : {
+              "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 a7c11d0..7179ecf 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
@@ -2383,6 +2383,9 @@
               "items" : {
                 "$ref" : "#/items/definitions/org.apache.camel.model.OnExceptionDefinition"
               }
+            },
+            "precondition" : {
+              "type" : "string"
             }
           }
         } ]
diff --git a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/RouteConfigurationTest.groovy b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/RouteConfigurationTest.groovy
index ba7e9a8..04ff381 100644
--- a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/RouteConfigurationTest.groovy
+++ b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/RouteConfigurationTest.groovy
@@ -21,8 +21,10 @@ import org.apache.camel.component.mock.MockEndpoint
 import org.apache.camel.dsl.yaml.support.YamlTestSupport
 import org.apache.camel.dsl.yaml.support.model.MyException
 import org.apache.camel.dsl.yaml.support.model.MyFailingProcessor
+import org.apache.camel.model.RouteConfigurationDefinition
 import org.junit.jupiter.api.Assertions
-import org.junit.jupiter.api.Disabled
+
+import static org.apache.camel.util.PropertiesHelper.asProperties
 
 class RouteConfigurationTest extends YamlTestSupport {
     def "route-configuration"() {
@@ -62,6 +64,61 @@ class RouteConfigurationTest extends YamlTestSupport {
         MockEndpoint.assertIsSatisfied(context)
     }
 
+    def "route-configuration-precondition"() {
+        setup:
+        context.getPropertiesComponent().setInitialProperties(asProperties("activate", "true"))
+        loadRoutes """
+                - beans:
+                  - name: myFailingProcessor
+                    type: ${MyFailingProcessor.name}
+                - route-configuration:
+                    - precondition: "{{!activate}}"
+                    - on-exception:
+                        handled:
+                          constant: "true"
+                        exception:
+                          - ${MyException.name}
+                        steps:
+                          - transform:
+                              constant: "Not Activated"
+                          - to: "mock:on-exception"  
+                - route-configuration:
+                    - precondition: "{{activate}}"
+                    - on-exception:
+                        handled:
+                          constant: "true"
+                        exception:
+                          - ${MyException.name}
+                        steps:
+                          - transform:
+                              constant: "Activated"
+                          - to: "mock:on-exception"  
+                - from:
+                    uri: "direct:start"
+                    steps:
+                      - process: 
+                          ref: "myFailingProcessor"            
+            """
+
+        withMock('mock:on-exception') {
+            expectedBodiesReceived 'Activated'
+        }
+
+        when:
+        context.start()
+
+        withTemplate {
+            to('direct:start').withBody('hello').send()
+        }
+        then:
+        MockEndpoint.assertIsSatisfied(context)
+        context.getRouteConfigurationDefinitions().size() == 1
+
+        with(context.getRouteConfigurationDefinitions().get(0), RouteConfigurationDefinition) {
+            precondition == '{{activate}}'
+        }
+    }
+
     def "route-configuration-separate"() {
         setup:
         // global configurations