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