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 2021/08/03 14:09:27 UTC
[camel] branch main updated: CAMEL-16757: Route configuration for
separated, reusable and shareable configuration across all DSLs (#5917)
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 148ce23 CAMEL-16757: Route configuration for separated, reusable and shareable configuration across all DSLs (#5917)
148ce23 is described below
commit 148ce23162cd59b4c9548f00175f1749fac06d30
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Tue Aug 3 16:09:03 2021 +0200
CAMEL-16757: Route configuration for separated, reusable and shareable configuration across all DSLs (#5917)
---
.../org/apache/camel/catalog/models.properties | 3 +-
.../apache/camel/catalog/models/camelContext.json | 1 +
.../camel/catalog/models/routeConfiguration.json | 22 ++
.../camel/catalog/models/routeConfigurations.json | 16 ++
.../camel/catalog/models/templateBeanFactory.json | 17 --
.../apache/camel/catalog/schemas/camel-spring.xsd | 38 +++
.../camel/cdi/xml/CamelContextFactoryBean.java | 14 +
.../camel/cdi/test/XmlRouteConfigurationTest.java | 77 +++++
.../resources/camel-context-routeConfiguration.xml | 49 ++++
.../org/apache/camel/spring/xml/camelContext.json | 1 +
.../camel/spring/xml/CamelContextFactoryBean.java | 18 ++
.../spring/xml/handler/CamelNamespaceHandler.java | 1 +
...gRoutesConfigurationBuilderIdOrPatternTest.java | 48 ++++
...ngRoutesConfigurationBuilderIdOrPatternTest.xml | 52 ++++
.../apache/camel/test/junit5/CamelTestSupport.java | 8 +
.../apache/camel/test/junit4/CamelTestSupport.java | 10 +-
...ZooKeeperServiceDiscoveryFactoryConfigurer.java | 6 +-
.../main/java/org/apache/camel/CamelContext.java | 8 +
.../java/org/apache/camel/CamelContextAware.java | 2 +-
.../src/main/java/org/apache/camel/Route.java | 11 +
...yLevel.java => RouteConfigurationsBuilder.java} | 20 +-
.../java/org/apache/camel/StartupSummaryLevel.java | 1 +
.../java/org/apache/camel/spi/RoutesLoader.java | 19 +-
.../camel/impl/engine/AbstractCamelContext.java | 39 ++-
.../org/apache/camel/impl/engine/DefaultRoute.java | 6 +
.../engine/DefaultSupervisingRouteController.java | 25 +-
.../org/apache/camel/impl/DefaultCamelContext.java | 22 ++
.../java/org/apache/camel/impl/DefaultModel.java | 40 +++
.../camel/impl/lw/LightweightCamelContext.java | 22 ++
.../impl/lw/LightweightRuntimeCamelContext.java | 6 +
.../services/org/apache/camel/model.properties | 3 +-
.../resources/org/apache/camel/model/jaxb.index | 2 +
.../org/apache/camel/model/routeConfiguration.json | 22 ++
.../apache/camel/model/routeConfigurations.json | 16 ++
.../apache/camel/model/templateBeanFactory.json | 17 --
.../java/org/apache/camel/builder/AdviceWith.java | 4 +
.../org/apache/camel/builder/BuilderSupport.java | 33 ++-
.../apache/camel/builder/LambdaRouteBuilder.java | 2 +-
.../org/apache/camel/builder/RouteBuilder.java | 35 ++-
.../camel/builder/RouteConfigurationBuilder.java | 91 ++++++
.../main/java/org/apache/camel/model/Model.java | 21 ++
...ainer.java => RouteConfigurationContainer.java} | 16 +-
.../camel/model/RouteConfigurationDefinition.java | 198 +++++++++++++
...ion.java => RouteConfigurationsDefinition.java} | 87 +++---
.../org/apache/camel/model/RouteContainer.java | 2 +-
.../org/apache/camel/model/RouteDefinition.java | 30 ++
.../apache/camel/model/RouteTemplateContainer.java | 2 +-
.../camel/model/RouteTemplatesDefinition.java | 3 +-
.../org/apache/camel/model/RoutesDefinition.java | 52 +++-
.../apache/camel/model/rest/RestsDefinition.java | 3 +-
.../org/apache/camel/reifier/RouteReifier.java | 5 +-
.../core/xml/AbstractCamelContextFactoryBean.java | 45 ++-
.../java/org/apache/camel/ContextTestSupport.java | 13 +-
.../RoutesConfigurationBuilderIdOrPatternTest.java | 243 ++++++++++++++++
.../model/RoutesConfigurationBuilderTest.java | 310 +++++++++++++++++++++
...outesConfigurationMultipleRouteBuilderTest.java | 65 +++++
.../camel/model/RoutesConfigurationTest.java | 59 ++++
.../builder/endpoint/EndpointRouteBuilder.java | 6 +-
.../EndpointRouteConfigurationBuilder.java | 91 ++++++
.../endpoint/LambdaEndpointRouteBuilder.java} | 10 +-
.../endpoint/EndpointRoutesConfigurationTest.java | 57 ++++
.../endpoint/LambdaEndpointRouteBuilderTest.java | 86 ++++++
.../org/apache/camel/main/RoutesConfigurer.java | 39 ++-
.../api/management/mbean/ManagedRouteMBean.java | 3 +
.../camel/management/mbean/ManagedRoute.java | 15 +-
.../java/org/apache/camel/xml/in/ModelParser.java | 48 ++++
docs/user-manual/modules/ROOT/nav.adoc | 1 +
docs/user-manual/modules/ROOT/pages/index.adoc | 1 +
.../modules/ROOT/pages/route-configuration.adoc | 294 +++++++++++++++++++
.../dsl/support/RouteBuilderLoaderSupport.java | 2 +
.../camel/dsl/xml/io/XmlRoutesBuilderLoader.java | 34 ++-
.../dsl/xml/jaxb/JaxbXmlRoutesBuilderLoader.java | 13 +-
.../camel-yaml-dsl-deserializers/pom.xml | 2 +
.../dsl/yaml/deserializers/CustomResolver.java | 3 +
.../RouteConfigurationDefinitionDeserializer.java | 93 +++++++
.../deserializers/RouteDefinitionDeserializer.java | 4 +
.../src/generated/resources/camel-yaml-dsl.json | 45 +++
.../camel/dsl/yaml/YamlRoutesBuilderLoader.java | 22 +-
.../camel/dsl/yaml/RouteConfigurationTest.groovy | 169 +++++++++++
.../packaging/ModelXmlParserGeneratorMojo.java | 4 +-
80 files changed, 2836 insertions(+), 187 deletions(-)
diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models.properties b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models.properties
index d0d5f2f..e0d7e06 100644
--- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models.properties
+++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models.properties
@@ -145,6 +145,8 @@ rollback
roundRobin
route
routeBuilder
+routeConfiguration
+routeConfigurations
routeContext
routeContextRef
routeTemplate
@@ -187,7 +189,6 @@ syslog
tarfile
template
templateBean
-templateBeanFactory
templateParameter
templateScript
threadPool
diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/camelContext.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/camelContext.json
index fb39212..9a6507f 100644
--- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/camelContext.json
+++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/camelContext.json
@@ -80,6 +80,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": "Configuration of interceptors that triggers sending messages to endpoints." },
"restConfiguration": { "kind": "element", "displayName": "Rest Configuration", "required": false, "type": "object", "javaType": "org.apache.camel.model.rest.RestConfigurationDefinition", "deprecated": false, "autowired": false, "secret": false, "description": "Configuration for rest-dsl" },
"rest": { "kind": "element", "displayName": "Rest", "required": false, "type": "array", "javaType": "java.util.List<org.apache.camel.model.rest.RestDefinition>", "deprecated": false, "autowired": false, "secret": false, "description": "Contains the rest services defined using the rest-dsl" },
+ "routeConfiguration": { "kind": "element", "displayName": "Route Configuration", "required": false, "type": "array", "javaType": "java.util.List<org.apache.camel.model.RouteConfigurationDefinition>", "deprecated": false, "autowired": false, "secret": false, "description": "Contains the Camel route configurations" },
"routeTemplate": { "kind": "element", "displayName": "Route Template", "required": false, "type": "array", "javaType": "java.util.List<org.apache.camel.model.RouteTemplateDefinition>", "deprecated": false, "autowired": false, "secret": false, "description": "Contains the Camel route templates" },
"route": { "kind": "element", "displayName": "Route", "required": false, "type": "array", "javaType": "java.util.List<org.apache.camel.model.RouteDefinition>", "deprecated": false, "autowired": false, "secret": false, "description": "Contains the Camel routes" },
"id": { "kind": "attribute", "displayName": "Id", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "The id of this node" }
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
new file mode 100644
index 0000000..bdb0150
--- /dev/null
+++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/routeConfiguration.json
@@ -0,0 +1,22 @@
+{
+ "model": {
+ "kind": "model",
+ "name": "routeConfiguration",
+ "title": "Route Configuration",
+ "description": "Reusable configuration for Camel route(s).",
+ "deprecated": false,
+ "label": "configuration",
+ "javaType": "org.apache.camel.model.RouteConfigurationDefinition",
+ "input": false,
+ "output": false
+ },
+ "properties": {
+ "intercept": { "kind": "element", "displayName": "Intercept", "required": false, "type": "array", "javaType": "java.util.List<org.apache.camel.model.InterceptDefinition>", "deprecated": false, "autowired": false, "secret": false, "description": "Adds a route for an interceptor that intercepts every processing step." },
+ "interceptFrom": { "kind": "element", "displayName": "Intercept From", "required": false, "type": "array", "javaType": "java.util.List<org.apache.camel.model.InterceptFromDefinition>", "deprecated": false, "autowired": false, "secret": false, "description": "Adds a route for an interceptor that intercepts incoming messages on the given endpoint." },
+ "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." },
+ "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/models/routeConfigurations.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/routeConfigurations.json
new file mode 100644
index 0000000..d9d128f
--- /dev/null
+++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/routeConfigurations.json
@@ -0,0 +1,16 @@
+{
+ "model": {
+ "kind": "model",
+ "name": "routeConfigurations",
+ "title": "Route Configurations",
+ "description": "A series of route configurations",
+ "deprecated": false,
+ "label": "configuration",
+ "javaType": "org.apache.camel.model.RouteConfigurationsDefinition",
+ "input": false,
+ "output": false
+ },
+ "properties": {
+
+ }
+}
diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/templateBeanFactory.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/templateBeanFactory.json
deleted file mode 100644
index 538a54b..0000000
--- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/templateBeanFactory.json
+++ /dev/null
@@ -1,17 +0,0 @@
-{
- "model": {
- "kind": "model",
- "name": "templateBeanFactory",
- "title": "Template Bean Factory",
- "description": "A route template bean factory (local bean)",
- "deprecated": false,
- "label": "configuration",
- "javaType": "org.apache.camel.model.RouteTemplateBeanFactoryDefinition",
- "input": false,
- "output": false
- },
- "properties": {
- "language": { "kind": "attribute", "displayName": "Language", "required": false, "type": "enum", "javaType": "java.lang.String", "enum": [ "bean", "groovy", "joor", "language", "mvel", "ognl" ], "deprecated": false, "autowired": false, "secret": false, "description": "The language to use for creating the bean (such as groovy, joor)" },
- "script": { "kind": "value", "displayName": "Script", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "The script to execute that creates the bean. If the script use the prefix resource: such as resource:classpath:com\/foo\/myscript.groovy, resource:file:\/var\/myscript.groovy, then its loaded from the external resource." }
- }
-}
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 1e8e59c..359ec7d 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
@@ -1265,6 +1265,22 @@ To refer to a Java org.apache.camel.builder.RouteBuilder instance to use.
</xs:annotation>
</xs:element>
+ <xs:element name="routeConfiguration" type="tns:routeConfigurationDefinition">
+ <xs:annotation>
+ <xs:documentation xml:lang="en"><![CDATA[
+Reusable configuration for Camel route(s).
+ ]]></xs:documentation>
+ </xs:annotation>
+ </xs:element>
+
+ <xs:element name="routeConfigurations" type="tns:routeConfigurationsDefinition">
+ <xs:annotation>
+ <xs:documentation xml:lang="en"><![CDATA[
+A series of route configurations
+ ]]></xs:documentation>
+ </xs:annotation>
+ </xs:element>
+
<xs:element name="routeContext" type="tns:camelRouteContextFactoryBean">
<xs:annotation>
<xs:documentation xml:lang="en"><![CDATA[
@@ -10611,6 +10627,26 @@ Reference to the route builder instance.
</xs:complexContent>
</xs:complexType>
+ <xs:complexType name="routeConfigurationDefinition">
+ <xs:complexContent>
+ <xs:extension base="tns:optionalIdentifiedDefinition">
+ <xs:sequence>
+ <xs:element maxOccurs="unbounded" minOccurs="0" ref="tns:intercept"/>
+ <xs:element maxOccurs="unbounded" minOccurs="0" ref="tns:interceptFrom"/>
+ <xs:element maxOccurs="unbounded" minOccurs="0" ref="tns:interceptSendToEndpoint"/>
+ <xs:element maxOccurs="unbounded" minOccurs="0" ref="tns:onException"/>
+ <xs:element maxOccurs="unbounded" minOccurs="0" ref="tns:onCompletion"/>
+ </xs:sequence>
+ </xs:extension>
+ </xs:complexContent>
+ </xs:complexType>
+
+ <xs:complexType name="routeConfigurationsDefinition">
+ <xs:sequence>
+ <xs:element maxOccurs="unbounded" minOccurs="0" ref="tns:routeConfiguration"/>
+ </xs:sequence>
+ </xs:complexType>
+
<xs:complexType name="routeContextRefDefinition">
<xs:sequence/>
<xs:attribute name="ref" type="xs:string" use="required">
@@ -10743,6 +10779,7 @@ Whether message history is enabled on this route. Default value: true
</xs:annotation>
</xs:attribute>
<xs:attribute name="rest" type="xs:boolean"/>
+ <xs:attribute name="routeConfigurationId" type="xs:string"/>
<xs:attribute name="routePolicyRef" type="xs:string">
<xs:annotation>
<xs:documentation xml:lang="en"><![CDATA[
@@ -15066,6 +15103,7 @@ MicroProfile Circuit Breaker EIP configurations.
<xs:element maxOccurs="unbounded" minOccurs="0" ref="tns:interceptSendToEndpoint"/>
<xs:element minOccurs="0" ref="tns:restConfiguration"/>
<xs:element maxOccurs="unbounded" minOccurs="0" ref="tns:rest"/>
+ <xs:element maxOccurs="unbounded" minOccurs="0" ref="tns:routeConfiguration"/>
<xs:element maxOccurs="unbounded" minOccurs="0" ref="tns:routeTemplate"/>
<xs:element maxOccurs="unbounded" minOccurs="0" ref="tns:route"/>
</xs:sequence>
diff --git a/components/camel-cdi/src/main/java/org/apache/camel/cdi/xml/CamelContextFactoryBean.java b/components/camel-cdi/src/main/java/org/apache/camel/cdi/xml/CamelContextFactoryBean.java
index 001012d..96b7170 100644
--- a/components/camel-cdi/src/main/java/org/apache/camel/cdi/xml/CamelContextFactoryBean.java
+++ b/components/camel-cdi/src/main/java/org/apache/camel/cdi/xml/CamelContextFactoryBean.java
@@ -59,6 +59,7 @@ import org.apache.camel.model.PackageScanDefinition;
import org.apache.camel.model.Resilience4jConfigurationDefinition;
import org.apache.camel.model.RestContextRefDefinition;
import org.apache.camel.model.RouteBuilderDefinition;
+import org.apache.camel.model.RouteConfigurationDefinition;
import org.apache.camel.model.RouteContextRefDefinition;
import org.apache.camel.model.RouteDefinition;
import org.apache.camel.model.RouteTemplateContextRefDefinition;
@@ -296,6 +297,9 @@ public class CamelContextFactoryBean extends AbstractCamelContextFactoryBean<Def
@XmlElement(name = "rest")
private List<RestDefinition> rests = new ArrayList<>();
+ @XmlElement(name = "routeConfiguration")
+ private List<RouteConfigurationDefinition> routeConfigurations = new ArrayList<>();
+
@XmlElement(name = "routeTemplate")
private List<RouteTemplateDefinition> routeTemplates = new ArrayList<>();
@@ -492,6 +496,16 @@ public class CamelContextFactoryBean extends AbstractCamelContextFactoryBean<Def
}
@Override
+ public List<RouteConfigurationDefinition> getRouteConfigurations() {
+ return routeConfigurations;
+ }
+
+ @Override
+ public void setRouteConfigurations(List<RouteConfigurationDefinition> routeConfigurations) {
+ this.routeConfigurations = routeConfigurations;
+ }
+
+ @Override
public List<RouteTemplateDefinition> getRouteTemplates() {
return routeTemplates;
}
diff --git a/components/camel-cdi/src/test/java/org/apache/camel/cdi/test/XmlRouteConfigurationTest.java b/components/camel-cdi/src/test/java/org/apache/camel/cdi/test/XmlRouteConfigurationTest.java
new file mode 100644
index 0000000..7bbcb0d
--- /dev/null
+++ b/components/camel-cdi/src/test/java/org/apache/camel/cdi/test/XmlRouteConfigurationTest.java
@@ -0,0 +1,77 @@
+/*
+ * 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.cdi.test;
+
+import java.nio.file.Paths;
+
+import javax.inject.Inject;
+
+import org.apache.camel.ProducerTemplate;
+import org.apache.camel.cdi.CdiCamelExtension;
+import org.apache.camel.cdi.ImportResource;
+import org.apache.camel.cdi.Uri;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.jboss.arquillian.container.test.api.Deployment;
+import org.jboss.arquillian.junit.Arquillian;
+import org.jboss.shrinkwrap.api.Archive;
+import org.jboss.shrinkwrap.api.ShrinkWrap;
+import org.jboss.shrinkwrap.api.asset.EmptyAsset;
+import org.jboss.shrinkwrap.api.spec.JavaArchive;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static org.junit.Assert.fail;
+
+@RunWith(Arquillian.class)
+@ImportResource("imported-context.xml")
+public class XmlRouteConfigurationTest {
+
+ @Inject
+ private ProducerTemplate template;
+
+ @Inject
+ @Uri("mock:error")
+ private MockEndpoint mock;
+
+ @Deployment
+ public static Archive<?> deployment() {
+ return ShrinkWrap.create(JavaArchive.class)
+ // Camel CDI
+ .addPackage(CdiCamelExtension.class.getPackage())
+ // Test Camel XML
+ .addAsResource(
+ Paths.get("src/test/resources/camel-context-routeConfiguration.xml").toFile(),
+ "imported-context.xml")
+ // Bean archive deployment descriptor
+ .addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml");
+ }
+
+ @Test
+ public void testRoutesConfigurationOnException() throws Exception {
+ mock.expectedBodiesReceived("Bye World");
+
+ try {
+ template.sendBody("direct:start", "Hello World");
+ fail("Should throw exception");
+ } catch (Exception e) {
+ // expected
+ }
+ template.sendBody("direct:start2", "Bye World");
+
+ mock.assertIsSatisfied();
+ }
+}
diff --git a/components/camel-cdi/src/test/resources/camel-context-routeConfiguration.xml b/components/camel-cdi/src/test/resources/camel-context-routeConfiguration.xml
new file mode 100644
index 0000000..a77cae3
--- /dev/null
+++ b/components/camel-cdi/src/test/resources/camel-context-routeConfiguration.xml
@@ -0,0 +1,49 @@
+<?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://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
+ http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd">
+
+ <camelContext xmlns="http://camel.apache.org/schema/spring">
+
+ <routeConfiguration id="handleError">
+ <onException>
+ <exception>java.lang.Exception</exception>
+ <handled>
+ <constant>true</constant>
+ </handled>
+ <to uri="mock:error"/>
+ </onException>
+ </routeConfiguration>
+
+ <route>
+ <from uri="direct:start"/>
+ <throwException exceptionType="java.lang.IllegalArgumentException" message="Foo"/>
+ </route>
+
+ <route routeConfigurationId="handleError">
+ <from uri="direct:start2"/>
+ <throwException exceptionType="java.lang.IllegalArgumentException" message="Foo2"/>
+ </route>
+
+ </camelContext>
+
+</beans>
diff --git a/components/camel-spring-xml/src/generated/resources/org/apache/camel/spring/xml/camelContext.json b/components/camel-spring-xml/src/generated/resources/org/apache/camel/spring/xml/camelContext.json
index fb39212..9a6507f 100644
--- a/components/camel-spring-xml/src/generated/resources/org/apache/camel/spring/xml/camelContext.json
+++ b/components/camel-spring-xml/src/generated/resources/org/apache/camel/spring/xml/camelContext.json
@@ -80,6 +80,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": "Configuration of interceptors that triggers sending messages to endpoints." },
"restConfiguration": { "kind": "element", "displayName": "Rest Configuration", "required": false, "type": "object", "javaType": "org.apache.camel.model.rest.RestConfigurationDefinition", "deprecated": false, "autowired": false, "secret": false, "description": "Configuration for rest-dsl" },
"rest": { "kind": "element", "displayName": "Rest", "required": false, "type": "array", "javaType": "java.util.List<org.apache.camel.model.rest.RestDefinition>", "deprecated": false, "autowired": false, "secret": false, "description": "Contains the rest services defined using the rest-dsl" },
+ "routeConfiguration": { "kind": "element", "displayName": "Route Configuration", "required": false, "type": "array", "javaType": "java.util.List<org.apache.camel.model.RouteConfigurationDefinition>", "deprecated": false, "autowired": false, "secret": false, "description": "Contains the Camel route configurations" },
"routeTemplate": { "kind": "element", "displayName": "Route Template", "required": false, "type": "array", "javaType": "java.util.List<org.apache.camel.model.RouteTemplateDefinition>", "deprecated": false, "autowired": false, "secret": false, "description": "Contains the Camel route templates" },
"route": { "kind": "element", "displayName": "Route", "required": false, "type": "array", "javaType": "java.util.List<org.apache.camel.model.RouteDefinition>", "deprecated": false, "autowired": false, "secret": false, "description": "Contains the Camel routes" },
"id": { "kind": "attribute", "displayName": "Id", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "The id of this node" }
diff --git a/components/camel-spring-xml/src/main/java/org/apache/camel/spring/xml/CamelContextFactoryBean.java b/components/camel-spring-xml/src/main/java/org/apache/camel/spring/xml/CamelContextFactoryBean.java
index 87a990e..4aa862d 100644
--- a/components/camel-spring-xml/src/main/java/org/apache/camel/spring/xml/CamelContextFactoryBean.java
+++ b/components/camel-spring-xml/src/main/java/org/apache/camel/spring/xml/CamelContextFactoryBean.java
@@ -57,6 +57,7 @@ import org.apache.camel.model.PackageScanDefinition;
import org.apache.camel.model.Resilience4jConfigurationDefinition;
import org.apache.camel.model.RestContextRefDefinition;
import org.apache.camel.model.RouteBuilderDefinition;
+import org.apache.camel.model.RouteConfigurationDefinition;
import org.apache.camel.model.RouteContextRefDefinition;
import org.apache.camel.model.RouteDefinition;
import org.apache.camel.model.RouteTemplateContextRefDefinition;
@@ -263,6 +264,8 @@ public class CamelContextFactoryBean extends AbstractCamelContextFactoryBean<Spr
private RestConfigurationDefinition restConfiguration;
@XmlElement(name = "rest")
private List<RestDefinition> rests = new ArrayList<>();
+ @XmlElement(name = "routeConfiguration")
+ private List<RouteConfigurationDefinition> routeConfigurations = new ArrayList<>();
@XmlElement(name = "routeTemplate")
private List<RouteTemplateDefinition> routeTemplates = new ArrayList<>();
@XmlElement(name = "route")
@@ -557,6 +560,20 @@ public class CamelContextFactoryBean extends AbstractCamelContextFactoryBean<Spr
this.routes = routes;
}
+ @Override
+ public List<RouteConfigurationDefinition> getRouteConfigurations() {
+ return routeConfigurations;
+ }
+
+ /**
+ * Contains the Camel route configurations
+ */
+ @Override
+ public void setRouteConfigurations(List<RouteConfigurationDefinition> routeConfigurations) {
+ this.routeConfigurations = routeConfigurations;
+ }
+
+ @Override
public List<RouteTemplateDefinition> getRouteTemplates() {
return routeTemplates;
}
@@ -564,6 +581,7 @@ public class CamelContextFactoryBean extends AbstractCamelContextFactoryBean<Spr
/**
* Contains the Camel route templates
*/
+ @Override
public void setRouteTemplates(List<RouteTemplateDefinition> routeTemplates) {
this.routeTemplates = routeTemplates;
}
diff --git a/components/camel-spring-xml/src/main/java/org/apache/camel/spring/xml/handler/CamelNamespaceHandler.java b/components/camel-spring-xml/src/main/java/org/apache/camel/spring/xml/handler/CamelNamespaceHandler.java
index d7272be..fed1bba 100644
--- a/components/camel-spring-xml/src/main/java/org/apache/camel/spring/xml/handler/CamelNamespaceHandler.java
+++ b/components/camel-spring-xml/src/main/java/org/apache/camel/spring/xml/handler/CamelNamespaceHandler.java
@@ -390,6 +390,7 @@ public class CamelNamespaceHandler extends NamespaceHandlerSupport {
builder.addPropertyValue("implicitId", implicitId);
builder.addPropertyValue("restConfiguration", factoryBean.getRestConfiguration());
builder.addPropertyValue("rests", factoryBean.getRests());
+ builder.addPropertyValue("routeConfigurations", factoryBean.getRouteConfigurations());
builder.addPropertyValue("routeTemplates", factoryBean.getRouteTemplates());
builder.addPropertyValue("routes", factoryBean.getRoutes());
builder.addPropertyValue("intercepts", factoryBean.getIntercepts());
diff --git a/components/camel-spring-xml/src/test/java/org/apache/camel/spring/SpringRoutesConfigurationBuilderIdOrPatternTest.java b/components/camel-spring-xml/src/test/java/org/apache/camel/spring/SpringRoutesConfigurationBuilderIdOrPatternTest.java
new file mode 100644
index 0000000..5e9a316
--- /dev/null
+++ b/components/camel-spring-xml/src/test/java/org/apache/camel/spring/SpringRoutesConfigurationBuilderIdOrPatternTest.java
@@ -0,0 +1,48 @@
+/*
+ * 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.fail;
+
+public class SpringRoutesConfigurationBuilderIdOrPatternTest extends SpringTestSupport {
+
+ @Override
+ protected AbstractXmlApplicationContext createApplicationContext() {
+ return new ClassPathXmlApplicationContext(
+ "org/apache/camel/spring/SpringRoutesConfigurationBuilderIdOrPatternTest.xml");
+ }
+
+ @Test
+ public void testRoutesConfigurationOnException() throws Exception {
+ getMockEndpoint("mock:error").expectedBodiesReceived("Bye World");
+
+ try {
+ template.sendBody("direct:start", "Hello World");
+ fail("Should throw exception");
+ } catch (Exception e) {
+ // expected
+ }
+ template.sendBody("direct:start2", "Bye World");
+
+ assertMockEndpointsSatisfied();
+ }
+
+}
diff --git a/components/camel-spring-xml/src/test/resources/org/apache/camel/spring/SpringRoutesConfigurationBuilderIdOrPatternTest.xml b/components/camel-spring-xml/src/test/resources/org/apache/camel/spring/SpringRoutesConfigurationBuilderIdOrPatternTest.xml
new file mode 100644
index 0000000..f8b4d43
--- /dev/null
+++ b/components/camel-spring-xml/src/test/resources/org/apache/camel/spring/SpringRoutesConfigurationBuilderIdOrPatternTest.xml
@@ -0,0 +1,52 @@
+<?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://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
+ http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd
+ ">
+
+
+ <camelContext xmlns="http://camel.apache.org/schema/spring">
+
+ <routeConfiguration id="handleError">
+ <onException>
+ <exception>java.lang.Exception</exception>
+ <handled>
+ <constant>true</constant>
+ </handled>
+ <to uri="mock:error"/>
+ </onException>
+ </routeConfiguration>
+
+ <route>
+ <from uri="direct:start"/>
+ <throwException exceptionType="java.lang.IllegalArgumentException" message="Foo"/>
+ </route>
+
+ <route routeConfigurationId="handleError">
+ <from uri="direct:start2"/>
+ <throwException exceptionType="java.lang.IllegalArgumentException" message="Foo2"/>
+ </route>
+
+ </camelContext>
+
+</beans>
diff --git a/components/camel-test/camel-test-junit5/src/main/java/org/apache/camel/test/junit5/CamelTestSupport.java b/components/camel-test/camel-test-junit5/src/main/java/org/apache/camel/test/junit5/CamelTestSupport.java
index 0a93950..7e6aaa8 100644
--- a/components/camel-test/camel-test-junit5/src/main/java/org/apache/camel/test/junit5/CamelTestSupport.java
+++ b/components/camel-test/camel-test-junit5/src/main/java/org/apache/camel/test/junit5/CamelTestSupport.java
@@ -40,6 +40,7 @@ import org.apache.camel.NoSuchEndpointException;
import org.apache.camel.Predicate;
import org.apache.camel.Processor;
import org.apache.camel.ProducerTemplate;
+import org.apache.camel.RouteConfigurationsBuilder;
import org.apache.camel.RoutesBuilder;
import org.apache.camel.RuntimeCamelException;
import org.apache.camel.Service;
@@ -506,6 +507,13 @@ public abstract class CamelTestSupport
if (isUseRouteBuilder()) {
RoutesBuilder[] builders = createRouteBuilders();
+ // add configuration before routes
+ for (RoutesBuilder builder : builders) {
+ if (builder instanceof RouteConfigurationsBuilder) {
+ LOG.debug("Using created route configuration: {}", builder);
+ context.addRoutesConfigurations((RouteConfigurationsBuilder) builder);
+ }
+ }
for (RoutesBuilder builder : builders) {
LOG.debug("Using created route builder: {}", builder);
context.addRoutes(builder);
diff --git a/components/camel-test/camel-test/src/main/java/org/apache/camel/test/junit4/CamelTestSupport.java b/components/camel-test/camel-test/src/main/java/org/apache/camel/test/junit4/CamelTestSupport.java
index fd83f71..687d301 100644
--- a/components/camel-test/camel-test/src/main/java/org/apache/camel/test/junit4/CamelTestSupport.java
+++ b/components/camel-test/camel-test/src/main/java/org/apache/camel/test/junit4/CamelTestSupport.java
@@ -56,6 +56,7 @@ import org.apache.camel.Predicate;
import org.apache.camel.Processor;
import org.apache.camel.ProducerTemplate;
import org.apache.camel.Route;
+import org.apache.camel.RouteConfigurationsBuilder;
import org.apache.camel.RoutesBuilder;
import org.apache.camel.RuntimeCamelException;
import org.apache.camel.Service;
@@ -444,8 +445,15 @@ public abstract class CamelTestSupport extends TestSupport {
if (isUseRouteBuilder()) {
RoutesBuilder[] builders = createRouteBuilders();
+ // add configuration before routes
for (RoutesBuilder builder : builders) {
- LOG.debug("Using created route builder: {}", builder);
+ if (builder instanceof RouteConfigurationsBuilder) {
+ log.debug("Using created route configuration: {}", builder);
+ context.addRoutesConfigurations((RouteConfigurationsBuilder) builder);
+ }
+ }
+ for (RoutesBuilder builder : builders) {
+ log.debug("Using created route builder: {}", builder);
context.addRoutes(builder);
}
replaceFromEndpoints();
diff --git a/components/camel-zookeeper/src/generated/java/org/apache/camel/component/zookeeper/cloud/ZooKeeperServiceDiscoveryFactoryConfigurer.java b/components/camel-zookeeper/src/generated/java/org/apache/camel/component/zookeeper/cloud/ZooKeeperServiceDiscoveryFactoryConfigurer.java
index a06cb94..6202e1d 100644
--- a/components/camel-zookeeper/src/generated/java/org/apache/camel/component/zookeeper/cloud/ZooKeeperServiceDiscoveryFactoryConfigurer.java
+++ b/components/camel-zookeeper/src/generated/java/org/apache/camel/component/zookeeper/cloud/ZooKeeperServiceDiscoveryFactoryConfigurer.java
@@ -40,7 +40,7 @@ public class ZooKeeperServiceDiscoveryFactoryConfigurer extends org.apache.camel
case "namespace":
case "Namespace": target.setNamespace(property(camelContext, java.lang.String.class, value)); return true;
case "nodes":
- case "Nodes": target.setNodes(property(camelContext, java.lang.String.class, value)); return true;
+ case "Nodes": target.setNodes(property(camelContext, java.util.List.class, value)); return true;
case "reconnectbasesleeptime":
case "ReconnectBaseSleepTime": target.setReconnectBaseSleepTime(property(camelContext, long.class, value)); return true;
case "reconnectbasesleeptimeunit":
@@ -83,7 +83,7 @@ public class ZooKeeperServiceDiscoveryFactoryConfigurer extends org.apache.camel
case "namespace":
case "Namespace": return java.lang.String.class;
case "nodes":
- case "Nodes": return java.lang.String.class;
+ case "Nodes": return java.util.List.class;
case "reconnectbasesleeptime":
case "ReconnectBaseSleepTime": return long.class;
case "reconnectbasesleeptimeunit":
@@ -153,6 +153,8 @@ public class ZooKeeperServiceDiscoveryFactoryConfigurer extends org.apache.camel
switch (ignoreCase ? name.toLowerCase() : name) {
case "authinfolist":
case "AuthInfoList": return org.apache.curator.framework.AuthInfo.class;
+ case "nodes":
+ case "Nodes": return java.lang.String.class;
default: return null;
}
}
diff --git a/core/camel-api/src/main/java/org/apache/camel/CamelContext.java b/core/camel-api/src/main/java/org/apache/camel/CamelContext.java
index 31843c0..27ac7e9 100644
--- a/core/camel-api/src/main/java/org/apache/camel/CamelContext.java
+++ b/core/camel-api/src/main/java/org/apache/camel/CamelContext.java
@@ -573,6 +573,14 @@ public interface CamelContext extends CamelContextLifecycle, RuntimeConfiguratio
void addRoutes(RoutesBuilder builder) throws Exception;
/**
+ * Adds the routes configurations (global configuration for all routes) from the routes builder.
+ *
+ * @param builder the builder which has routes configurations
+ * @throws Exception if the routes configurations could not be created for whatever reason
+ */
+ void addRoutesConfigurations(RouteConfigurationsBuilder builder) throws Exception;
+
+ /**
* Removes the given route (the route <b>must</b> be stopped before it can be removed).
* <p/>
* A route which is removed will be unregistered from JMX, have its services stopped/shutdown and the route
diff --git a/core/camel-api/src/main/java/org/apache/camel/CamelContextAware.java b/core/camel-api/src/main/java/org/apache/camel/CamelContextAware.java
index ee565ff..4188fa6 100644
--- a/core/camel-api/src/main/java/org/apache/camel/CamelContextAware.java
+++ b/core/camel-api/src/main/java/org/apache/camel/CamelContextAware.java
@@ -25,7 +25,7 @@ public interface CamelContextAware {
* Set the {@link CamelContext} context if the object is an instance of {@link CamelContextAware}.
*/
static <T> T trySetCamelContext(T object, CamelContext camelContext) {
- if (object instanceof CamelContextAware) {
+ if (camelContext != null && object instanceof CamelContextAware) {
((CamelContextAware) object).setCamelContext(camelContext);
}
diff --git a/core/camel-api/src/main/java/org/apache/camel/Route.java b/core/camel-api/src/main/java/org/apache/camel/Route.java
index 808dc35..27e5e84 100644
--- a/core/camel-api/src/main/java/org/apache/camel/Route.java
+++ b/core/camel-api/src/main/java/org/apache/camel/Route.java
@@ -44,6 +44,7 @@ public interface Route extends RuntimeConfiguration {
String REST_PROPERTY = "rest";
String TEMPLATE_PROPERTY = "template";
String DESCRIPTION_PROPERTY = "description";
+ String CONFIGURATION_ID_PROPERTY = "configurationId";
/**
* Gets the route id
@@ -116,6 +117,16 @@ public interface Route extends RuntimeConfiguration {
String getDescription();
/**
+ * Gets the route configuration id(s) (if any has been configured).
+ * <p/>
+ * The configuration ids is configured using the {@link #CONFIGURATION_ID_PROPERTY} as key in the
+ * {@link #getProperties()}.
+ *
+ * @return the configuration, or <tt>null</tt> if no configuration has been configured.
+ */
+ String getConfigurationId();
+
+ /**
* Gets the camel context
*
* @return the camel context
diff --git a/core/camel-api/src/main/java/org/apache/camel/StartupSummaryLevel.java b/core/camel-api/src/main/java/org/apache/camel/RouteConfigurationsBuilder.java
similarity index 64%
copy from core/camel-api/src/main/java/org/apache/camel/StartupSummaryLevel.java
copy to core/camel-api/src/main/java/org/apache/camel/RouteConfigurationsBuilder.java
index d025d67..d9e95d5 100644
--- a/core/camel-api/src/main/java/org/apache/camel/StartupSummaryLevel.java
+++ b/core/camel-api/src/main/java/org/apache/camel/RouteConfigurationsBuilder.java
@@ -16,19 +16,17 @@
*/
package org.apache.camel;
-import javax.xml.bind.annotation.XmlEnum;
-
/**
- * Controls the level of information logged during startup (and shutdown) of {@link CamelContext}.
+ * A route configurations builder is capable of building route configurations using the builder and model classes.
*/
-@XmlEnum
-public enum StartupSummaryLevel {
+public interface RouteConfigurationsBuilder {
- Classic,
- Verbose,
- Default,
- Brief,
- Oneline,
- Off
+ /**
+ * Adds the route configurations from this builder to the CamelContext.
+ *
+ * @param context the Camel context
+ * @throws Exception is thrown if initialization of route configurations failed
+ */
+ void addRouteConfigurationsToCamelContext(CamelContext context) throws Exception;
}
diff --git a/core/camel-api/src/main/java/org/apache/camel/StartupSummaryLevel.java b/core/camel-api/src/main/java/org/apache/camel/StartupSummaryLevel.java
index d025d67..8f20f6a 100644
--- a/core/camel-api/src/main/java/org/apache/camel/StartupSummaryLevel.java
+++ b/core/camel-api/src/main/java/org/apache/camel/StartupSummaryLevel.java
@@ -24,6 +24,7 @@ import javax.xml.bind.annotation.XmlEnum;
@XmlEnum
public enum StartupSummaryLevel {
+ @Deprecated
Classic,
Verbose,
Default,
diff --git a/core/camel-api/src/main/java/org/apache/camel/spi/RoutesLoader.java b/core/camel-api/src/main/java/org/apache/camel/spi/RoutesLoader.java
index 1c64dff..b75a01e 100644
--- a/core/camel-api/src/main/java/org/apache/camel/spi/RoutesLoader.java
+++ b/core/camel-api/src/main/java/org/apache/camel/spi/RoutesLoader.java
@@ -20,6 +20,7 @@ import java.util.Arrays;
import java.util.Collection;
import org.apache.camel.CamelContextAware;
+import org.apache.camel.RouteConfigurationsBuilder;
import org.apache.camel.RoutesBuilder;
/**
@@ -39,7 +40,14 @@ public interface RoutesLoader extends CamelContextAware {
* @param resources the resources to be loaded.
*/
default void loadRoutes(Collection<Resource> resources) throws Exception {
- for (RoutesBuilder builder : findRoutesBuilders(resources)) {
+ Collection<RoutesBuilder> builders = findRoutesBuilders(resources);
+ // add configuration first before the routes
+ for (RoutesBuilder builder : builders) {
+ if (builder instanceof RouteConfigurationsBuilder) {
+ getCamelContext().addRoutesConfigurations((RouteConfigurationsBuilder) builder);
+ }
+ }
+ for (RoutesBuilder builder : builders) {
getCamelContext().addRoutes(builder);
}
}
@@ -51,7 +59,14 @@ public interface RoutesLoader extends CamelContextAware {
* @param resources the resources to be loaded.
*/
default void loadRoutes(Resource... resources) throws Exception {
- for (RoutesBuilder builder : findRoutesBuilders(resources)) {
+ Collection<RoutesBuilder> builders = findRoutesBuilders(resources);
+ // add configuration first before the routes
+ for (RoutesBuilder builder : builders) {
+ if (builder instanceof RouteConfigurationsBuilder) {
+ getCamelContext().addRoutesConfigurations((RouteConfigurationsBuilder) builder);
+ }
+ }
+ for (RoutesBuilder builder : builders) {
getCamelContext().addRoutes(builder);
}
}
diff --git a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/AbstractCamelContext.java b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/AbstractCamelContext.java
index 6f9026d..1fbad34 100644
--- a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/AbstractCamelContext.java
+++ b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/AbstractCamelContext.java
@@ -64,6 +64,7 @@ import org.apache.camel.ProducerTemplate;
import org.apache.camel.ResolveEndpointFailedException;
import org.apache.camel.Route;
import org.apache.camel.RouteAware;
+import org.apache.camel.RouteConfigurationsBuilder;
import org.apache.camel.RoutesBuilder;
import org.apache.camel.RuntimeCamelException;
import org.apache.camel.Service;
@@ -1143,7 +1144,12 @@ public abstract class AbstractCamelContext extends BaseService
}
@Override
- public void addRoutes(final RoutesBuilder builder) throws Exception {
+ public void addRoutes(RoutesBuilder builder) throws Exception {
+ // in case the builder is also a route configuration builder
+ // then we need to add the configuration first
+ if (builder instanceof RouteConfigurationsBuilder) {
+ addRoutesConfigurations((RouteConfigurationsBuilder) builder);
+ }
try (LifecycleHelper helper = new LifecycleHelper()) {
build();
LOG.debug("Adding routes from builder: {}", builder);
@@ -1151,6 +1157,15 @@ public abstract class AbstractCamelContext extends BaseService
}
}
+ @Override
+ public void addRoutesConfigurations(RouteConfigurationsBuilder builder) throws Exception {
+ try (LifecycleHelper helper = new LifecycleHelper()) {
+ build();
+ LOG.debug("Adding route configurations from builder: {}", builder);
+ builder.addRouteConfigurationsToCamelContext(AbstractCamelContext.this);
+ }
+ }
+
public ServiceStatus getRouteStatus(String key) {
RouteService routeService = routeServices.get(key);
if (routeService != null) {
@@ -2857,7 +2872,7 @@ public abstract class AbstractCamelContext extends BaseService
}
}
- // ant duplicate components in use?
+ // duplicate components in use?
logDuplicateComponents();
// log startup summary
@@ -2950,6 +2965,7 @@ public abstract class AbstractCamelContext extends BaseService
int total = 0;
int disabled = 0;
List<String> lines = new ArrayList<>();
+ List<String> configs = new ArrayList<>();
routeStartupOrder.sort(Comparator.comparingInt(RouteStartupOrder::getStartupOrder));
for (RouteStartupOrder order : routeStartupOrder) {
total++;
@@ -2962,6 +2978,11 @@ public abstract class AbstractCamelContext extends BaseService
String uri = order.getRoute().getEndpoint().getEndpointBaseUri();
uri = URISupport.sanitizeUri(uri);
lines.add(String.format(" %s %s (%s)", status, id, uri));
+
+ String cid = order.getRoute().getConfigurationId();
+ if (cid != null) {
+ configs.add(String.format(" %s (%s)", id, cid));
+ }
}
for (Route route : routes) {
if (!route.isAutoStartup()) {
@@ -2976,6 +2997,11 @@ public abstract class AbstractCamelContext extends BaseService
String uri = route.getEndpoint().getEndpointBaseUri();
uri = URISupport.sanitizeUri(uri);
lines.add(String.format(" %s %s (%s)", status, id, uri));
+
+ String cid = route.getConfigurationId();
+ if (cid != null) {
+ configs.add(String.format(" %s (%s)", id, cid));
+ }
}
}
if (disabled > 0) {
@@ -2988,6 +3014,12 @@ public abstract class AbstractCamelContext extends BaseService
for (String line : lines) {
LOG.info(line);
}
+ if (startupSummaryLevel == StartupSummaryLevel.Verbose) {
+ LOG.info("Routes configuration summary");
+ for (String line : configs) {
+ LOG.info(line);
+ }
+ }
}
}
@@ -3006,8 +3038,7 @@ public abstract class AbstractCamelContext extends BaseService
protected void doStartCamel() throws Exception {
if (!adapt(ExtendedCamelContext.class).getBeanPostProcessor().isEnabled()) {
- LOG.info(
- "BeanPostProcessor is disabled. This means features such as dependency injection of Camel annotations in beans is not supported.");
+ LOG.info("BeanPostProcessor is disabled. Dependency injection of Camel annotations in beans is not supported.");
}
if (LOG.isDebugEnabled()) {
LOG.debug(
diff --git a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultRoute.java b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultRoute.java
index fd877b0..3d39dbf 100644
--- a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultRoute.java
+++ b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultRoute.java
@@ -157,6 +157,12 @@ public class DefaultRoute extends ServiceSupport implements Route {
}
@Override
+ public String getConfigurationId() {
+ Object value = properties.get(Route.CONFIGURATION_ID_PROPERTY);
+ return value != null ? (String) value : null;
+ }
+
+ @Override
public void initializeServices() throws Exception {
// gather all the services for this route
gatherServices(services);
diff --git a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultSupervisingRouteController.java b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultSupervisingRouteController.java
index ece2f9b..158dbe3 100644
--- a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultSupervisingRouteController.java
+++ b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultSupervisingRouteController.java
@@ -481,6 +481,7 @@ public class DefaultSupervisingRouteController extends DefaultRouteController im
int restarting = 0;
int exhausted = 0;
List<String> lines = new ArrayList<>();
+ List<String> configs = new ArrayList<>();
for (RouteHolder route : routes) {
String id = route.getId();
String status = getRouteStatus(id).name();
@@ -491,7 +492,11 @@ public class DefaultSupervisingRouteController extends DefaultRouteController im
// use basic endpoint uri to not log verbose details or potential sensitive data
String uri = route.get().getEndpoint().getEndpointBaseUri();
uri = URISupport.sanitizeUri(uri);
- lines.add(String.format("\t%s %s (%s)", status, id, uri));
+ lines.add(String.format(" %s %s (%s)", status, id, uri));
+ String cid = route.get().getConfigurationId();
+ if (cid != null) {
+ configs.add(String.format(" %s (%s)", id, cid));
+ }
}
}
for (RouteHolder route : routeManager.routes.keySet()) {
@@ -503,7 +508,11 @@ public class DefaultSupervisingRouteController extends DefaultRouteController im
String uri = route.get().getEndpoint().getEndpointBaseUri();
uri = URISupport.sanitizeUri(uri);
BackOff backOff = getBackOff(id);
- lines.add(String.format("\t%s %s (%s) with %s", status, id, uri, backOff));
+ lines.add(String.format(" %s %s (%s) with %s", status, id, uri, backOff));
+ String cid = route.get().getConfigurationId();
+ if (cid != null) {
+ configs.add(String.format(" %s (%s)", id, cid));
+ }
}
for (RouteHolder route : routeManager.exhausted.keySet()) {
total++;
@@ -513,7 +522,11 @@ public class DefaultSupervisingRouteController extends DefaultRouteController im
// use basic endpoint uri to not log verbose details or potential sensitive data
String uri = route.get().getEndpoint().getEndpointBaseUri();
uri = URISupport.sanitizeUri(uri);
- lines.add(String.format("\t%s %s (%s)", status, id, uri));
+ lines.add(String.format(" %s %s (%s)", status, id, uri));
+ String cid = route.get().getConfigurationId();
+ if (cid != null) {
+ configs.add(String.format(" %s (%s)", id, cid));
+ }
}
if (restarting == 0 && exhausted == 0) {
@@ -527,6 +540,12 @@ public class DefaultSupervisingRouteController extends DefaultRouteController im
for (String line : lines) {
LOG.info(line);
}
+ if (getCamelContext().getStartupSummaryLevel() == StartupSummaryLevel.Verbose) {
+ LOG.info("Routes configuration summary");
+ for (String line : configs) {
+ LOG.info(line);
+ }
+ }
}
}
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 8544303..69cd55b 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
@@ -54,6 +54,7 @@ import org.apache.camel.model.ModelLifecycleStrategy;
import org.apache.camel.model.ProcessorDefinition;
import org.apache.camel.model.ProcessorDefinitionHelper;
import org.apache.camel.model.Resilience4jConfigurationDefinition;
+import org.apache.camel.model.RouteConfigurationDefinition;
import org.apache.camel.model.RouteDefinition;
import org.apache.camel.model.RouteDefinitionHelper;
import org.apache.camel.model.RouteTemplateDefinition;
@@ -287,6 +288,27 @@ public class DefaultCamelContext extends SimpleCamelContext implements ModelCame
}
@Override
+ public void addRouteConfiguration(RouteConfigurationDefinition routesConfiguration) {
+ if (model == null && isLightweight()) {
+ throw new IllegalStateException("Access to model not supported in lightweight mode");
+ }
+ model.addRouteConfiguration(routesConfiguration);
+ }
+
+ @Override
+ public void addRouteConfigurations(List<RouteConfigurationDefinition> routesConfigurations) {
+ if (model == null && isLightweight()) {
+ throw new IllegalStateException("Access to model not supported in lightweight mode");
+ }
+ model.addRouteConfigurations(routesConfigurations);
+ }
+
+ @Override
+ public List<RouteConfigurationDefinition> getRouteConfigurationDefinitions() {
+ return model.getRouteConfigurationDefinitions();
+ }
+
+ @Override
public List<RouteDefinition> getRouteDefinitions() {
if (model == null && isLightweight()) {
throw new IllegalStateException("Access to model not supported in lightweight mode");
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 5802e61..b658b6b 100644
--- a/core/camel-core-engine/src/main/java/org/apache/camel/impl/DefaultModel.java
+++ b/core/camel-core-engine/src/main/java/org/apache/camel/impl/DefaultModel.java
@@ -46,6 +46,7 @@ import org.apache.camel.model.ModelLifecycleStrategy;
import org.apache.camel.model.ProcessorDefinition;
import org.apache.camel.model.ProcessorDefinitionHelper;
import org.apache.camel.model.Resilience4jConfigurationDefinition;
+import org.apache.camel.model.RouteConfigurationDefinition;
import org.apache.camel.model.RouteDefinition;
import org.apache.camel.model.RouteDefinitionHelper;
import org.apache.camel.model.RouteFilters;
@@ -79,6 +80,7 @@ public class DefaultModel implements Model {
private ModelReifierFactory modelReifierFactory = new DefaultModelReifierFactory();
private final List<ModelLifecycleStrategy> modelLifecycleStrategies = new ArrayList<>();
+ private final List<RouteConfigurationDefinition> routesConfigurations = new ArrayList<>();
private final List<RouteDefinition> routeDefinitions = new ArrayList<>();
private final List<RouteTemplateDefinition> routeTemplateDefinitions = new ArrayList<>();
private final List<RestDefinition> restDefinitions = new ArrayList<>();
@@ -114,6 +116,44 @@ public class DefaultModel implements Model {
}
@Override
+ public void addRouteConfiguration(RouteConfigurationDefinition routesConfiguration) {
+ if (routesConfiguration == null) {
+ return;
+ }
+ // only add if not already exists (route-loader may let Java DSL add route configuration twice
+ // because it extends RouteBuilder as base class)
+ if (!this.routesConfigurations.contains(routesConfiguration)) {
+ // check that there is no id clash
+ if (routesConfiguration.getId() != null) {
+ boolean clash = this.routesConfigurations.stream()
+ .anyMatch(r -> ObjectHelper.equal(r.getId(), routesConfiguration.getId()));
+ if (clash) {
+ throw new IllegalArgumentException(
+ "Route configuration already exists with id: " + routesConfiguration.getId());
+ }
+ }
+ this.routesConfigurations.add(routesConfiguration);
+ }
+ }
+
+ @Override
+ public void addRouteConfigurations(List<RouteConfigurationDefinition> routesConfigurations) {
+ if (routesConfigurations == null || routesConfigurations.isEmpty()) {
+ return;
+ }
+ // only add if not already exists (route-loader may let Java DSL add route configuration twice
+ // because it extends RouteBuilder as base class)
+ for (RouteConfigurationDefinition rc : routesConfigurations) {
+ addRouteConfiguration(rc);
+ }
+ }
+
+ @Override
+ public List<RouteConfigurationDefinition> getRouteConfigurationDefinitions() {
+ return routesConfigurations;
+ }
+
+ @Override
public synchronized void addRouteDefinitions(Collection<RouteDefinition> routeDefinitions) throws Exception {
if (routeDefinitions == null || routeDefinitions.isEmpty()) {
return;
diff --git a/core/camel-core-engine/src/main/java/org/apache/camel/impl/lw/LightweightCamelContext.java b/core/camel-core-engine/src/main/java/org/apache/camel/impl/lw/LightweightCamelContext.java
index e56983b..516b4ce 100644
--- a/core/camel-core-engine/src/main/java/org/apache/camel/impl/lw/LightweightCamelContext.java
+++ b/core/camel-core-engine/src/main/java/org/apache/camel/impl/lw/LightweightCamelContext.java
@@ -41,6 +41,7 @@ import org.apache.camel.Predicate;
import org.apache.camel.Processor;
import org.apache.camel.ProducerTemplate;
import org.apache.camel.Route;
+import org.apache.camel.RouteConfigurationsBuilder;
import org.apache.camel.RouteTemplateContext;
import org.apache.camel.RoutesBuilder;
import org.apache.camel.Service;
@@ -61,6 +62,7 @@ import org.apache.camel.model.ModelCamelContext;
import org.apache.camel.model.ModelLifecycleStrategy;
import org.apache.camel.model.ProcessorDefinition;
import org.apache.camel.model.Resilience4jConfigurationDefinition;
+import org.apache.camel.model.RouteConfigurationDefinition;
import org.apache.camel.model.RouteDefinition;
import org.apache.camel.model.RouteTemplateDefinition;
import org.apache.camel.model.cloud.ServiceCallConfigurationDefinition;
@@ -552,6 +554,11 @@ public class LightweightCamelContext implements ExtendedCamelContext, CatalogCam
}
@Override
+ public void addRoutesConfigurations(RouteConfigurationsBuilder builder) throws Exception {
+ delegate.addRoutesConfigurations(builder);
+ }
+
+ @Override
public boolean removeRoute(String routeId) throws Exception {
return delegate.removeRoute(routeId);
}
@@ -1687,6 +1694,21 @@ public class LightweightCamelContext implements ExtendedCamelContext, CatalogCam
}
@Override
+ public void addRouteConfiguration(RouteConfigurationDefinition routesConfiguration) {
+ getModelCamelContext().addRouteConfiguration(routesConfiguration);
+ }
+
+ @Override
+ public void addRouteConfigurations(List<RouteConfigurationDefinition> routesConfigurations) {
+ getModelCamelContext().addRouteConfigurations(routesConfigurations);
+ }
+
+ @Override
+ public List<RouteConfigurationDefinition> getRouteConfigurationDefinitions() {
+ return getModelCamelContext().getRouteConfigurationDefinitions();
+ }
+
+ @Override
public List<RouteDefinition> getRouteDefinitions() {
return getModelCamelContext().getRouteDefinitions();
}
diff --git a/core/camel-core-engine/src/main/java/org/apache/camel/impl/lw/LightweightRuntimeCamelContext.java b/core/camel-core-engine/src/main/java/org/apache/camel/impl/lw/LightweightRuntimeCamelContext.java
index fc84451..60db540 100644
--- a/core/camel-core-engine/src/main/java/org/apache/camel/impl/lw/LightweightRuntimeCamelContext.java
+++ b/core/camel-core-engine/src/main/java/org/apache/camel/impl/lw/LightweightRuntimeCamelContext.java
@@ -49,6 +49,7 @@ import org.apache.camel.Processor;
import org.apache.camel.ProducerTemplate;
import org.apache.camel.ResolveEndpointFailedException;
import org.apache.camel.Route;
+import org.apache.camel.RouteConfigurationsBuilder;
import org.apache.camel.RouteTemplateContext;
import org.apache.camel.RoutesBuilder;
import org.apache.camel.RuntimeCamelException;
@@ -1863,6 +1864,11 @@ public class LightweightRuntimeCamelContext implements ExtendedCamelContext, Cat
}
@Override
+ public void addRoutesConfigurations(RouteConfigurationsBuilder builder) throws Exception {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
public boolean removeRoute(String routeId) throws Exception {
throw new UnsupportedOperationException();
}
diff --git a/core/camel-core-model/src/generated/resources/META-INF/services/org/apache/camel/model.properties b/core/camel-core-model/src/generated/resources/META-INF/services/org/apache/camel/model.properties
index 2b03f53..9a05154 100644
--- a/core/camel-core-model/src/generated/resources/META-INF/services/org/apache/camel/model.properties
+++ b/core/camel-core-model/src/generated/resources/META-INF/services/org/apache/camel/model.properties
@@ -137,6 +137,8 @@ rollback
roundRobin
route
routeBuilder
+routeConfiguration
+routeConfigurations
routeContextRef
routeTemplate
routeTemplateContextRef
@@ -174,7 +176,6 @@ stream-config
syslog
tarfile
templateBean
-templateBeanFactory
templateParameter
templateScript
threadPoolProfile
diff --git a/core/camel-core-model/src/generated/resources/org/apache/camel/model/jaxb.index b/core/camel-core-model/src/generated/resources/org/apache/camel/model/jaxb.index
index c134380..45b5e93 100644
--- a/core/camel-core-model/src/generated/resources/org/apache/camel/model/jaxb.index
+++ b/core/camel-core-model/src/generated/resources/org/apache/camel/model/jaxb.index
@@ -63,6 +63,8 @@ Resilience4jConfigurationDefinition
RestContextRefDefinition
RollbackDefinition
RouteBuilderDefinition
+RouteConfigurationDefinition
+RouteConfigurationsDefinition
RouteContextRefDefinition
RouteDefinition
RouteTemplateBeanDefinition
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
new file mode 100644
index 0000000..bdb0150
--- /dev/null
+++ b/core/camel-core-model/src/generated/resources/org/apache/camel/model/routeConfiguration.json
@@ -0,0 +1,22 @@
+{
+ "model": {
+ "kind": "model",
+ "name": "routeConfiguration",
+ "title": "Route Configuration",
+ "description": "Reusable configuration for Camel route(s).",
+ "deprecated": false,
+ "label": "configuration",
+ "javaType": "org.apache.camel.model.RouteConfigurationDefinition",
+ "input": false,
+ "output": false
+ },
+ "properties": {
+ "intercept": { "kind": "element", "displayName": "Intercept", "required": false, "type": "array", "javaType": "java.util.List<org.apache.camel.model.InterceptDefinition>", "deprecated": false, "autowired": false, "secret": false, "description": "Adds a route for an interceptor that intercepts every processing step." },
+ "interceptFrom": { "kind": "element", "displayName": "Intercept From", "required": false, "type": "array", "javaType": "java.util.List<org.apache.camel.model.InterceptFromDefinition>", "deprecated": false, "autowired": false, "secret": false, "description": "Adds a route for an interceptor that intercepts incoming messages on the given endpoint." },
+ "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." },
+ "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/generated/resources/org/apache/camel/model/routeConfigurations.json b/core/camel-core-model/src/generated/resources/org/apache/camel/model/routeConfigurations.json
new file mode 100644
index 0000000..d9d128f
--- /dev/null
+++ b/core/camel-core-model/src/generated/resources/org/apache/camel/model/routeConfigurations.json
@@ -0,0 +1,16 @@
+{
+ "model": {
+ "kind": "model",
+ "name": "routeConfigurations",
+ "title": "Route Configurations",
+ "description": "A series of route configurations",
+ "deprecated": false,
+ "label": "configuration",
+ "javaType": "org.apache.camel.model.RouteConfigurationsDefinition",
+ "input": false,
+ "output": false
+ },
+ "properties": {
+
+ }
+}
diff --git a/core/camel-core-model/src/generated/resources/org/apache/camel/model/templateBeanFactory.json b/core/camel-core-model/src/generated/resources/org/apache/camel/model/templateBeanFactory.json
deleted file mode 100644
index 538a54b..0000000
--- a/core/camel-core-model/src/generated/resources/org/apache/camel/model/templateBeanFactory.json
+++ /dev/null
@@ -1,17 +0,0 @@
-{
- "model": {
- "kind": "model",
- "name": "templateBeanFactory",
- "title": "Template Bean Factory",
- "description": "A route template bean factory (local bean)",
- "deprecated": false,
- "label": "configuration",
- "javaType": "org.apache.camel.model.RouteTemplateBeanFactoryDefinition",
- "input": false,
- "output": false
- },
- "properties": {
- "language": { "kind": "attribute", "displayName": "Language", "required": false, "type": "enum", "javaType": "java.lang.String", "enum": [ "bean", "groovy", "joor", "language", "mvel", "ognl" ], "deprecated": false, "autowired": false, "secret": false, "description": "The language to use for creating the bean (such as groovy, joor)" },
- "script": { "kind": "value", "displayName": "Script", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "The script to execute that creates the bean. If the script use the prefix resource: such as resource:classpath:com\/foo\/myscript.groovy, resource:file:\/var\/myscript.groovy, then its loaded from the external resource." }
- }
-}
diff --git a/core/camel-core-model/src/main/java/org/apache/camel/builder/AdviceWith.java b/core/camel-core-model/src/main/java/org/apache/camel/builder/AdviceWith.java
index 81ddafd..b7c23b5 100644
--- a/core/camel-core-model/src/main/java/org/apache/camel/builder/AdviceWith.java
+++ b/core/camel-core-model/src/main/java/org/apache/camel/builder/AdviceWith.java
@@ -229,6 +229,10 @@ public final class AdviceWith {
// mixed in correctly as well
RouteDefinition merged = routes.route(definition);
+ // must re-prepare the merged route before it can be used
+ merged.markUnprepared();
+ routes.prepareRoute(merged);
+
// add the new merged route
model.getRouteDefinitions().add(0, merged);
diff --git a/core/camel-core-model/src/main/java/org/apache/camel/builder/BuilderSupport.java b/core/camel-core-model/src/main/java/org/apache/camel/builder/BuilderSupport.java
index 2b2bcfc..8aa028e 100644
--- a/core/camel-core-model/src/main/java/org/apache/camel/builder/BuilderSupport.java
+++ b/core/camel-core-model/src/main/java/org/apache/camel/builder/BuilderSupport.java
@@ -21,6 +21,7 @@ import java.util.Arrays;
import java.util.List;
import org.apache.camel.CamelContext;
+import org.apache.camel.CamelContextAware;
import org.apache.camel.Endpoint;
import org.apache.camel.Expression;
import org.apache.camel.NoSuchEndpointException;
@@ -36,15 +37,15 @@ import org.apache.camel.util.ObjectHelper;
* Base class for implementation inheritance for different clauses in the
* <a href="http://camel.apache.org/dsl.html">Java DSL</a>
*/
-public abstract class BuilderSupport {
- private CamelContext context;
+public abstract class BuilderSupport implements CamelContextAware {
+ private CamelContext camelContext;
private ErrorHandlerBuilder errorHandlerBuilder;
protected BuilderSupport() {
}
protected BuilderSupport(CamelContext context) {
- this.context = context;
+ this.camelContext = context;
}
// Builder methods
@@ -451,13 +452,33 @@ public abstract class BuilderSupport {
// Properties
// -------------------------------------------------------------------------
+ @Override
+ public CamelContext getCamelContext() {
+ return camelContext;
+ }
+
+ @Override
+ public void setCamelContext(CamelContext camelContext) {
+ if (camelContext != null) {
+ this.camelContext = camelContext;
+ }
+ }
+
+ /**
+ * Get the {@link CamelContext}
+ *
+ * @return camelContext the Camel context
+ */
public CamelContext getContext() {
- return context;
+ return getCamelContext();
}
+ /**
+ * @deprecated use {@link #setCamelContext(CamelContext)}
+ */
+ @Deprecated
public void setContext(CamelContext context) {
- ObjectHelper.notNull(context, "CamelContext", this);
- this.context = context;
+ setCamelContext(context);
}
public boolean hasErrorHandlerBuilder() {
diff --git a/core/camel-core-model/src/main/java/org/apache/camel/builder/LambdaRouteBuilder.java b/core/camel-core-model/src/main/java/org/apache/camel/builder/LambdaRouteBuilder.java
index 48cf43c..55886bc 100644
--- a/core/camel-core-model/src/main/java/org/apache/camel/builder/LambdaRouteBuilder.java
+++ b/core/camel-core-model/src/main/java/org/apache/camel/builder/LambdaRouteBuilder.java
@@ -24,7 +24,7 @@ import org.apache.camel.util.function.ThrowingConsumer;
*
* <pre>
* RouteBuilder.addRoutes(context, rb ->
- * rb.from("direct:inbound").bean(ProduceTemplateBean.class)));
+ * rb.from("direct:inbound").bean(MyBean.class)));
* </pre>
*
* @see RouteBuilder#addRoutes(CamelContext, LambdaRouteBuilder)
diff --git a/core/camel-core-model/src/main/java/org/apache/camel/builder/RouteBuilder.java b/core/camel-core-model/src/main/java/org/apache/camel/builder/RouteBuilder.java
index 5f9c6db..d5185c8d 100644
--- a/core/camel-core-model/src/main/java/org/apache/camel/builder/RouteBuilder.java
+++ b/core/camel-core-model/src/main/java/org/apache/camel/builder/RouteBuilder.java
@@ -36,6 +36,7 @@ import org.apache.camel.model.InterceptSendToEndpointDefinition;
import org.apache.camel.model.Model;
import org.apache.camel.model.OnCompletionDefinition;
import org.apache.camel.model.OnExceptionDefinition;
+import org.apache.camel.model.RouteConfigurationDefinition;
import org.apache.camel.model.RouteDefinition;
import org.apache.camel.model.RouteTemplateDefinition;
import org.apache.camel.model.RouteTemplatesDefinition;
@@ -85,7 +86,7 @@ public abstract class RouteBuilder extends BuilderSupport implements RoutesBuild
*
* <pre>
* RouteBuilder.addRoutes(context, rb ->
- * rb.from("direct:inbound").bean(ProduceTemplateBean.class)));
+ * rb.from("direct:inbound").bean(MyBean.class)));
* </pre>
*
* @param context the camel context to add routes
@@ -167,6 +168,16 @@ public abstract class RouteBuilder extends BuilderSupport implements RoutesBuild
public abstract void configure() throws Exception;
/**
+ * <b>Called on initialization to build routes configuration (global routes configurations) using the fluent builder
+ * syntax.</b>
+ *
+ * @throws Exception can be thrown during configuration
+ */
+ public void configuration() throws Exception {
+ // noop
+ }
+
+ /**
* Binds the bean to the repository (if possible).
*
* @param id the id of the bean
@@ -462,12 +473,16 @@ public abstract class RouteBuilder extends BuilderSupport implements RoutesBuild
configureRoutes(context);
configureRests(context);
- // but populate rests before routes, as we want to turn rests into
- // routes
+ // but populate rests before routes, as we want to turn rests into routes
populateRests();
populateTransformers();
populateValidators();
populateRouteTemplates();
+
+ // ensure routes are prepared before being populated
+ for (RouteDefinition route : routeCollection.getRoutes()) {
+ routeCollection.prepareRoute(route);
+ }
populateRoutes();
if (this instanceof OnCamelContextEvent) {
@@ -483,7 +498,7 @@ public abstract class RouteBuilder extends BuilderSupport implements RoutesBuild
* @throws Exception can be thrown during configuration
*/
public RoutesDefinition configureRoutes(CamelContext context) throws Exception {
- setContext(context);
+ setCamelContext(context);
checkInitialized();
routeCollection.setCamelContext(context);
return routeCollection;
@@ -497,7 +512,7 @@ public abstract class RouteBuilder extends BuilderSupport implements RoutesBuild
* @throws Exception can be thrown during configuration
*/
public RestsDefinition configureRests(CamelContext context) throws Exception {
- setContext(context);
+ setCamelContext(context);
restCollection.setCamelContext(context);
return restCollection;
}
@@ -539,10 +554,10 @@ public abstract class RouteBuilder extends BuilderSupport implements RoutesBuild
}
configure();
- // mark all route definitions as custom prepared because
- // a route builder prepares the route definitions correctly already
+
for (RouteDefinition route : getRouteCollection().getRoutes()) {
- route.markPrepared();
+ // ensure the route is prepared after configure method is complete
+ getRouteCollection().prepareRoute(route);
}
for (RouteBuilderLifecycleStrategy interceptor : lifecycleInterceptors) {
@@ -673,4 +688,8 @@ public abstract class RouteBuilder extends BuilderSupport implements RoutesBuild
protected void configureRouteTemplate(RouteTemplateDefinition routeTemplate) {
// noop
}
+
+ protected void configureRouteConfiguration(RouteConfigurationDefinition routesConfiguration) {
+ // noop
+ }
}
diff --git a/core/camel-core-model/src/main/java/org/apache/camel/builder/RouteConfigurationBuilder.java b/core/camel-core-model/src/main/java/org/apache/camel/builder/RouteConfigurationBuilder.java
new file mode 100644
index 0000000..a9cb26e
--- /dev/null
+++ b/core/camel-core-model/src/main/java/org/apache/camel/builder/RouteConfigurationBuilder.java
@@ -0,0 +1,91 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.builder;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.RouteConfigurationsBuilder;
+import org.apache.camel.model.Model;
+import org.apache.camel.model.RouteConfigurationDefinition;
+import org.apache.camel.model.RouteConfigurationsDefinition;
+
+/**
+ * A <a href="http://camel.apache.org/dsl.html">Java DSL</a> which is used for building route configuration(s).
+ */
+public abstract class RouteConfigurationBuilder extends RouteBuilder implements RouteConfigurationsBuilder {
+
+ private final AtomicBoolean initializedConfiguration = new AtomicBoolean();
+ private RouteConfigurationsDefinition routeConfigurationCollection = new RouteConfigurationsDefinition();
+
+ @Override
+ public void configure() throws Exception {
+ // noop
+ }
+
+ public abstract void configuration() throws Exception;
+
+ public RouteConfigurationsDefinition getRouteConfigurationCollection() {
+ return routeConfigurationCollection;
+ }
+
+ public void setRouteConfigurationCollection(RouteConfigurationsDefinition routeConfigurationCollection) {
+ this.routeConfigurationCollection = routeConfigurationCollection;
+ }
+
+ /**
+ * Creates a new route configuration
+ *
+ * @return the builder
+ */
+ public RouteConfigurationDefinition routeConfiguration() {
+ return routeConfiguration(null);
+ }
+
+ /**
+ * Creates a new route configuration
+ *
+ * @return the builder
+ */
+ public RouteConfigurationDefinition routeConfiguration(String id) {
+ getRouteConfigurationCollection().setCamelContext(getCamelContext());
+ RouteConfigurationDefinition answer = getRouteConfigurationCollection().routeConfiguration(id);
+ configureRouteConfiguration(answer);
+ return answer;
+ }
+
+ @Override
+ public void addRouteConfigurationsToCamelContext(CamelContext context) throws Exception {
+ setCamelContext(context);
+ routeConfigurationCollection.setCamelContext(context);
+ if (initializedConfiguration.compareAndSet(false, true)) {
+ configuration();
+ }
+ populateRoutesConfiguration();
+ }
+
+ protected void populateRoutesConfiguration() throws Exception {
+ CamelContext camelContext = getContext();
+ if (camelContext == null) {
+ throw new IllegalArgumentException("CamelContext has not been injected!");
+ }
+ getRouteConfigurationCollection().setCamelContext(camelContext);
+ camelContext.getExtension(Model.class)
+ .addRouteConfigurations(getRouteConfigurationCollection().getRouteConfigurations());
+ }
+
+}
diff --git a/core/camel-core-model/src/main/java/org/apache/camel/model/Model.java b/core/camel-core-model/src/main/java/org/apache/camel/model/Model.java
index 041881b..225965d 100644
--- a/core/camel-core-model/src/main/java/org/apache/camel/model/Model.java
+++ b/core/camel-core-model/src/main/java/org/apache/camel/model/Model.java
@@ -50,6 +50,27 @@ public interface Model {
List<ModelLifecycleStrategy> getModelLifecycleStrategies();
/**
+ * Adds a collection of route configuration definitions to the context
+ *
+ * @param routesConfigurations the route configuration(s) definition to add
+ */
+ void addRouteConfigurations(List<RouteConfigurationDefinition> routesConfigurations);
+
+ /**
+ * Adds a single route configuration definition to the context
+ *
+ * @param routesConfiguration the route configuration to add
+ */
+ void addRouteConfiguration(RouteConfigurationDefinition routesConfiguration);
+
+ /**
+ * Returns a list of the current route configuration definitions
+ *
+ * @return list of the current route configuration definitions
+ */
+ List<RouteConfigurationDefinition> getRouteConfigurationDefinitions();
+
+ /**
* Returns a list of the current route definitions
*
* @return list of the current route definitions
diff --git a/core/camel-core-model/src/main/java/org/apache/camel/model/RouteTemplateContainer.java b/core/camel-core-model/src/main/java/org/apache/camel/model/RouteConfigurationContainer.java
similarity index 69%
copy from core/camel-core-model/src/main/java/org/apache/camel/model/RouteTemplateContainer.java
copy to core/camel-core-model/src/main/java/org/apache/camel/model/RouteConfigurationContainer.java
index ae4e8c8..c46aabe 100644
--- a/core/camel-core-model/src/main/java/org/apache/camel/model/RouteTemplateContainer.java
+++ b/core/camel-core-model/src/main/java/org/apache/camel/model/RouteConfigurationContainer.java
@@ -21,22 +21,22 @@ import java.util.List;
import javax.xml.bind.annotation.XmlElementRef;
/**
- * Container to hold {@link RouteTemplateDefinition Route}.
+ * Container to hold {@link RouteConfigurationDefinition route configurations}.
*/
-public interface RouteTemplateContainer {
+public interface RouteConfigurationContainer {
/**
- * Returns the route templates
+ * Returns the route configurations
*
- * @return the route templates
+ * @return the route configurations
*/
@XmlElementRef
- List<RouteTemplateDefinition> getRouteTemplates();
+ List<RouteConfigurationDefinition> getRouteConfigurations();
/**
- * Sets the route templates to use
+ * Sets the route configurations to use
*
- * @param routes the route templates
+ * @param routes the route configurations
*/
- void setRouteTemplates(List<RouteTemplateDefinition> routes);
+ void setRouteConfigurations(List<RouteConfigurationDefinition> routes);
}
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
new file mode 100644
index 0000000..3a61534
--- /dev/null
+++ b/core/camel-core-model/src/main/java/org/apache/camel/model/RouteConfigurationDefinition.java
@@ -0,0 +1,198 @@
+/*
+ * 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 java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+
+import org.apache.camel.spi.Metadata;
+
+/**
+ * Reusable configuration for Camel route(s).
+ */
+@Metadata(label = "configuration")
+@XmlRootElement(name = "routeConfiguration")
+@XmlAccessorType(XmlAccessType.FIELD)
+public class RouteConfigurationDefinition extends OptionalIdentifiedDefinition<RouteConfigurationDefinition> {
+
+ // TODO: Model for ErrorHandler (requires to move error handler model from spring-xml, blueprint to core)
+
+ @XmlElement(name = "intercept")
+ private List<InterceptDefinition> intercepts = new ArrayList<>();
+ @XmlElement(name = "interceptFrom")
+ private List<InterceptFromDefinition> interceptFroms = new ArrayList<>();
+ @XmlElement(name = "interceptSendToEndpoint")
+ private List<InterceptSendToEndpointDefinition> interceptSendTos = new ArrayList<>();
+ @XmlElement(name = "onException")
+ private List<OnExceptionDefinition> onExceptions = new ArrayList<>();
+ @XmlElement(name = "onCompletion")
+ private List<OnCompletionDefinition> onCompletions = new ArrayList<>();
+
+ public RouteConfigurationDefinition() {
+ }
+
+ @Override
+ public String toString() {
+ return "RoutesConfiguration: " + getId();
+ }
+
+ @Override
+ public String getShortName() {
+ return "routesConfiguration";
+ }
+
+ @Override
+ public String getLabel() {
+ return "RoutesConfiguration " + getId();
+ }
+
+ public List<OnExceptionDefinition> getOnExceptions() {
+ return onExceptions;
+ }
+
+ public void setOnExceptions(List<OnExceptionDefinition> onExceptions) {
+ this.onExceptions = onExceptions;
+ }
+
+ public List<OnCompletionDefinition> getOnCompletions() {
+ return onCompletions;
+ }
+
+ public void setOnCompletions(List<OnCompletionDefinition> onCompletions) {
+ this.onCompletions = onCompletions;
+ }
+
+ public List<InterceptDefinition> getIntercepts() {
+ return intercepts;
+ }
+
+ public void setIntercepts(List<InterceptDefinition> intercepts) {
+ this.intercepts = intercepts;
+ }
+
+ public List<InterceptFromDefinition> getInterceptFroms() {
+ return interceptFroms;
+ }
+
+ public void setInterceptFroms(List<InterceptFromDefinition> interceptFroms) {
+ this.interceptFroms = interceptFroms;
+ }
+
+ public List<InterceptSendToEndpointDefinition> getInterceptSendTos() {
+ return interceptSendTos;
+ }
+
+ public void setInterceptSendTos(List<InterceptSendToEndpointDefinition> interceptSendTos) {
+ this.interceptSendTos = interceptSendTos;
+ }
+
+ // Fluent API
+ // -------------------------------------------------------------------------
+
+ /**
+ * <a href="http://camel.apache.org/exception-clause.html">Exception clause</a> for catching certain exceptions and
+ * handling them.
+ *
+ * @param exceptionType the exception to catch
+ * @return the exception builder to configure
+ */
+ public OnExceptionDefinition onException(Class<? extends Throwable> exceptionType) {
+ OnExceptionDefinition answer = new OnExceptionDefinition(exceptionType);
+ onExceptions.add(answer);
+ return answer;
+ }
+
+ /**
+ * <a href="http://camel.apache.org/exception-clause.html">Exception clause</a> for catching certain exceptions and
+ * handling them.
+ *
+ * @param exceptions list of exceptions to catch
+ * @return the exception builder to configure
+ */
+ public OnExceptionDefinition onException(Class<? extends Throwable>... exceptions) {
+ OnExceptionDefinition answer = new OnExceptionDefinition(Arrays.asList(exceptions));
+ onExceptions.add(answer);
+ return answer;
+ }
+
+ /**
+ * <a href="http://camel.apache.org/oncompletion.html">On completion</a> callback for doing custom routing when the
+ * {@link org.apache.camel.Exchange} is complete.
+ *
+ * @return the on completion builder to configure
+ */
+ public OnCompletionDefinition onCompletion() {
+ OnCompletionDefinition answer = new OnCompletionDefinition();
+ // is global scoped by default
+ answer.setRouteScoped(false);
+ onCompletions.add(answer);
+ return answer;
+ }
+
+ /**
+ * Adds a route for an interceptor that intercepts every processing step.
+ *
+ * @return the builder
+ */
+ public InterceptDefinition intercept() {
+ InterceptDefinition answer = new InterceptDefinition();
+ intercepts.add(answer);
+ return answer;
+ }
+
+ /**
+ * Adds a route for an interceptor that intercepts incoming messages on any inputs in this route
+ *
+ * @return the builder
+ */
+ public InterceptFromDefinition interceptFrom() {
+ InterceptFromDefinition answer = new InterceptFromDefinition();
+ interceptFroms.add(answer);
+ return answer;
+ }
+
+ /**
+ * Adds a route for an interceptor that intercepts incoming messages on the given endpoint.
+ *
+ * @param uri endpoint uri
+ * @return the builder
+ */
+ public InterceptFromDefinition interceptFrom(String uri) {
+ InterceptFromDefinition answer = new InterceptFromDefinition(uri);
+ interceptFroms.add(answer);
+ return answer;
+ }
+
+ /**
+ * Applies a route for an interceptor if an exchange is send to the given endpoint
+ *
+ * @param uri endpoint uri
+ * @return the builder
+ */
+ public InterceptSendToEndpointDefinition interceptSendToEndpoint(String uri) {
+ InterceptSendToEndpointDefinition answer = new InterceptSendToEndpointDefinition(uri);
+ interceptSendTos.add(answer);
+ return answer;
+ }
+
+}
diff --git a/core/camel-core-model/src/main/java/org/apache/camel/model/rest/RestsDefinition.java b/core/camel-core-model/src/main/java/org/apache/camel/model/RouteConfigurationsDefinition.java
similarity index 51%
copy from core/camel-core-model/src/main/java/org/apache/camel/model/rest/RestsDefinition.java
copy to core/camel-core-model/src/main/java/org/apache/camel/model/RouteConfigurationsDefinition.java
index 06f272e..92ec02c 100644
--- a/core/camel-core-model/src/main/java/org/apache/camel/model/rest/RestsDefinition.java
+++ b/core/camel-core-model/src/main/java/org/apache/camel/model/RouteConfigurationsDefinition.java
@@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.camel.model.rest;
+package org.apache.camel.model;
import java.util.ArrayList;
import java.util.List;
@@ -26,53 +26,35 @@ import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlTransient;
import org.apache.camel.CamelContext;
-import org.apache.camel.model.OptionalIdentifiedDefinition;
import org.apache.camel.spi.Metadata;
/**
- * A series of rest services defined using the rest-dsl
+ * A series of route configurations
*/
-@Metadata(label = "rest")
-@XmlRootElement(name = "rests")
+@Metadata(label = "configuration")
+@XmlRootElement(name = "routeConfigurations")
@XmlAccessorType(XmlAccessType.FIELD)
-public class RestsDefinition extends OptionalIdentifiedDefinition<RestsDefinition> implements RestContainer {
+public class RouteConfigurationsDefinition implements RouteConfigurationContainer {
+
@XmlElementRef
- private List<RestDefinition> rests = new ArrayList<>();
+ private List<RouteConfigurationDefinition> routeConfigurations = new ArrayList<>();
@XmlTransient
private CamelContext camelContext;
- public RestsDefinition() {
+ public RouteConfigurationsDefinition() {
}
@Override
public String toString() {
- return "Rests: " + rests;
- }
-
- @Override
- public String getShortName() {
- return "rests";
+ return "RouteConfigurations";
}
- @Override
- public String getLabel() {
- return "Rest " + getId();
+ public List<RouteConfigurationDefinition> getRouteConfigurations() {
+ return routeConfigurations;
}
- // Properties
- // -----------------------------------------------------------------------
-
- @Override
- public List<RestDefinition> getRests() {
- return rests;
- }
-
- /**
- * The rest services
- */
- @Override
- public void setRests(List<RestDefinition> rests) {
- this.rests = rests;
+ public void setRouteConfigurations(List<RouteConfigurationDefinition> routeConfigurations) {
+ this.routeConfigurations = routeConfigurations;
}
public CamelContext getCamelContext() {
@@ -87,37 +69,46 @@ public class RestsDefinition extends OptionalIdentifiedDefinition<RestsDefinitio
// -------------------------------------------------------------------------
/**
- * Creates a rest DSL
+ * Creates a new route configuration
+ *
+ * @return the builder
*/
- public RestDefinition rest() {
- RestDefinition rest = createRest();
- return rest(rest);
+ public RouteConfigurationDefinition routeConfiguration() {
+ RouteConfigurationDefinition config = createRouteConfiguration(null);
+ getRouteConfigurations().add(config);
+ return config;
}
/**
- * Creates a rest DSL
+ * Creates a new route configuration
*
- * @param uri the rest path
+ * @return the builder
*/
- public RestDefinition rest(String uri) {
- RestDefinition rest = createRest();
- rest.setPath(uri);
- return rest(rest);
+ public RouteConfigurationDefinition routeConfiguration(String id) {
+ RouteConfigurationDefinition config = createRouteConfiguration(id);
+ getRouteConfigurations().add(config);
+ return config;
}
/**
- * Adds the {@link org.apache.camel.model.rest.RestsDefinition}
+ * Adds the route configuration
+ *
+ * @return the builder
*/
- public RestDefinition rest(RestDefinition rest) {
- getRests().add(rest);
- return rest;
+ public RouteConfigurationDefinition routeConfiguration(RouteConfigurationDefinition config) {
+ getRouteConfigurations().add(config);
+ return config;
}
// Implementation methods
// -------------------------------------------------------------------------
- protected RestDefinition createRest() {
- RestDefinition rest = new RestDefinition();
- return rest;
+
+ protected RouteConfigurationDefinition createRouteConfiguration(String id) {
+ RouteConfigurationDefinition config = new RouteConfigurationDefinition();
+ if (id != null) {
+ config.setId(id);
+ }
+ return config;
}
}
diff --git a/core/camel-core-model/src/main/java/org/apache/camel/model/RouteContainer.java b/core/camel-core-model/src/main/java/org/apache/camel/model/RouteContainer.java
index 5e4ba8e..ba548f2 100644
--- a/core/camel-core-model/src/main/java/org/apache/camel/model/RouteContainer.java
+++ b/core/camel-core-model/src/main/java/org/apache/camel/model/RouteContainer.java
@@ -21,7 +21,7 @@ import java.util.List;
import javax.xml.bind.annotation.XmlElementRef;
/**
- * Container to hold {@link org.apache.camel.model.RouteDefinition Route}.
+ * Container to hold {@link org.apache.camel.model.RouteDefinition routes}.
*/
public interface RouteContainer {
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 e6a3d0d..40ef2e1 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
@@ -57,6 +57,7 @@ import org.apache.camel.spi.RoutePolicy;
public class RouteDefinition extends OutputDefinition<RouteDefinition> implements NamedRoute {
private final AtomicBoolean prepared = new AtomicBoolean();
private FromDefinition input;
+ private String routeConfigurationId;
private String group;
private String streamCache;
private String trace;
@@ -203,6 +204,18 @@ public class RouteDefinition extends OutputDefinition<RouteDefinition> implement
}
/**
+ * The route configuration id or pattern this route should use for configuration. Multiple id/pattern can be
+ * separated by comma.
+ *
+ * @param routeConfigurationId id or pattern
+ * @return the builder
+ */
+ public RouteDefinition routeConfigurationId(String routeConfigurationId) {
+ setRouteConfigurationId(routeConfigurationId);
+ return this;
+ }
+
+ /**
* Set the group name for this route
*
* @param name the group name
@@ -718,6 +731,23 @@ public class RouteDefinition extends OutputDefinition<RouteDefinition> implement
}
/**
+ * The route configuration id or pattern this route should use for configuration. Multiple id/pattern can be
+ * separated by comma.
+ */
+ public String getRouteConfigurationId() {
+ return routeConfigurationId;
+ }
+
+ /**
+ * The route configuration id or pattern this route should use for configuration. Multiple id/pattern can be
+ * separated by comma.
+ */
+ @XmlAttribute
+ public void setRouteConfigurationId(String routeConfigurationId) {
+ this.routeConfigurationId = routeConfigurationId;
+ }
+
+ /**
* The group that this route belongs to; could be the name of the RouteBuilder class or be explicitly configured in
* the XML.
* <p/>
diff --git a/core/camel-core-model/src/main/java/org/apache/camel/model/RouteTemplateContainer.java b/core/camel-core-model/src/main/java/org/apache/camel/model/RouteTemplateContainer.java
index ae4e8c8..b2715c8 100644
--- a/core/camel-core-model/src/main/java/org/apache/camel/model/RouteTemplateContainer.java
+++ b/core/camel-core-model/src/main/java/org/apache/camel/model/RouteTemplateContainer.java
@@ -21,7 +21,7 @@ import java.util.List;
import javax.xml.bind.annotation.XmlElementRef;
/**
- * Container to hold {@link RouteTemplateDefinition Route}.
+ * Container to hold {@link RouteTemplateDefinition route templates}.
*/
public interface RouteTemplateContainer {
diff --git a/core/camel-core-model/src/main/java/org/apache/camel/model/RouteTemplatesDefinition.java b/core/camel-core-model/src/main/java/org/apache/camel/model/RouteTemplatesDefinition.java
index c06a722..0beaddd 100644
--- a/core/camel-core-model/src/main/java/org/apache/camel/model/RouteTemplatesDefinition.java
+++ b/core/camel-core-model/src/main/java/org/apache/camel/model/RouteTemplatesDefinition.java
@@ -26,6 +26,7 @@ import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlTransient;
import org.apache.camel.CamelContext;
+import org.apache.camel.CamelContextAware;
import org.apache.camel.ErrorHandlerFactory;
import org.apache.camel.spi.Metadata;
@@ -36,7 +37,7 @@ import org.apache.camel.spi.Metadata;
@XmlRootElement(name = "routeTemplates")
@XmlAccessorType(XmlAccessType.FIELD)
public class RouteTemplatesDefinition extends OptionalIdentifiedDefinition<RouteTemplatesDefinition>
- implements RouteTemplateContainer {
+ implements RouteTemplateContainer, CamelContextAware {
@XmlElementRef
private List<RouteTemplateDefinition> routeTemplates = new ArrayList<>();
@XmlTransient
diff --git a/core/camel-core-model/src/main/java/org/apache/camel/model/RoutesDefinition.java b/core/camel-core-model/src/main/java/org/apache/camel/model/RoutesDefinition.java
index b62df39..f978ab4 100644
--- a/core/camel-core-model/src/main/java/org/apache/camel/model/RoutesDefinition.java
+++ b/core/camel-core-model/src/main/java/org/apache/camel/model/RoutesDefinition.java
@@ -26,11 +26,15 @@ import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlTransient;
import org.apache.camel.CamelContext;
+import org.apache.camel.CamelContextAware;
import org.apache.camel.Endpoint;
import org.apache.camel.ErrorHandlerFactory;
import org.apache.camel.builder.EndpointConsumerBuilder;
import org.apache.camel.spi.AsEndpointUri;
import org.apache.camel.spi.Metadata;
+import org.apache.camel.support.PatternHelper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
/**
* A series of Camel routes
@@ -38,7 +42,11 @@ import org.apache.camel.spi.Metadata;
@Metadata(label = "configuration")
@XmlRootElement(name = "routes")
@XmlAccessorType(XmlAccessType.FIELD)
-public class RoutesDefinition extends OptionalIdentifiedDefinition<RoutesDefinition> implements RouteContainer {
+public class RoutesDefinition extends OptionalIdentifiedDefinition<RoutesDefinition>
+ implements RouteContainer, CamelContextAware {
+
+ private static final Logger LOG = LoggerFactory.getLogger(RoutesDefinition.class);
+
@XmlElementRef
private List<RouteDefinition> routes = new ArrayList<>();
@XmlTransient
@@ -201,15 +209,49 @@ public class RoutesDefinition extends OptionalIdentifiedDefinition<RoutesDefinit
if (handler != null) {
route.setErrorHandlerFactoryIfNull(handler);
}
+ getRoutes().add(route);
+ return route;
+ }
+
+ public void prepareRoute(RouteDefinition route) {
+ if (route.isPrepared()) {
+ return;
+ }
+
+ // merge global and route scoped together
+ List<OnExceptionDefinition> oe = new ArrayList<>(onExceptions);
+ List<InterceptDefinition> icp = new ArrayList<>(intercepts);
+ List<InterceptFromDefinition> ifrom = new ArrayList<>(interceptFroms);
+ List<InterceptSendToEndpointDefinition> ito = new ArrayList<>(interceptSendTos);
+ List<OnCompletionDefinition> oc = new ArrayList<>(onCompletions);
+ if (getCamelContext() != null) {
+ List<RouteConfigurationDefinition> globalConfigurations
+ = getCamelContext().adapt(ModelCamelContext.class).getRouteConfigurationDefinitions();
+ if (globalConfigurations != null) {
+ globalConfigurations.stream()
+ // global configurations have no id assigned or is a wildcard
+ // if the route has a route configuration assigned then use pattern matching
+ .filter(g -> (g.getId() == null || g.getId().equals("*"))
+ || (PatternHelper.matchPattern(g.getId(), route.getRouteConfigurationId())))
+ .forEach(g -> {
+ oe.addAll(g.getOnExceptions());
+ icp.addAll(g.getIntercepts());
+ ifrom.addAll(g.getInterceptFroms());
+ ito.addAll(g.getInterceptSendTos());
+ oc.addAll(g.getOnCompletions());
+ });
+ }
+ }
// must prepare the route before we can add it to the routes list
- RouteDefinitionHelper.prepareRoute(getCamelContext(), route, getOnExceptions(), getIntercepts(), getInterceptFroms(),
- getInterceptSendTos(), getOnCompletions());
+ RouteDefinitionHelper.prepareRoute(getCamelContext(), route, oe, icp, ifrom, ito, oc);
+
+ if (LOG.isDebugEnabled() && route.getRouteConfigurationId() != null) {
+ LOG.debug("Route: {} is using routeConfigurationsId: {}", route.getId(), route.getRouteConfigurationId());
+ }
- getRoutes().add(route);
// mark this route as prepared
route.markPrepared();
- return route;
}
/**
diff --git a/core/camel-core-model/src/main/java/org/apache/camel/model/rest/RestsDefinition.java b/core/camel-core-model/src/main/java/org/apache/camel/model/rest/RestsDefinition.java
index 06f272e..3b8b150 100644
--- a/core/camel-core-model/src/main/java/org/apache/camel/model/rest/RestsDefinition.java
+++ b/core/camel-core-model/src/main/java/org/apache/camel/model/rest/RestsDefinition.java
@@ -26,6 +26,7 @@ import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlTransient;
import org.apache.camel.CamelContext;
+import org.apache.camel.CamelContextAware;
import org.apache.camel.model.OptionalIdentifiedDefinition;
import org.apache.camel.spi.Metadata;
@@ -35,7 +36,7 @@ import org.apache.camel.spi.Metadata;
@Metadata(label = "rest")
@XmlRootElement(name = "rests")
@XmlAccessorType(XmlAccessType.FIELD)
-public class RestsDefinition extends OptionalIdentifiedDefinition<RestsDefinition> implements RestContainer {
+public class RestsDefinition extends OptionalIdentifiedDefinition<RestsDefinition> implements RestContainer, CamelContextAware {
@XmlElementRef
private List<RestDefinition> rests = new ArrayList<>();
@XmlTransient
diff --git a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/RouteReifier.java b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/RouteReifier.java
index 10ede58..f921817 100644
--- a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/RouteReifier.java
+++ b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/RouteReifier.java
@@ -58,7 +58,7 @@ public class RouteReifier extends ProcessorReifier<RouteDefinition> {
private static final String[] RESERVED_PROPERTIES = new String[] {
Route.ID_PROPERTY, Route.CUSTOM_ID_PROPERTY, Route.PARENT_PROPERTY,
Route.DESCRIPTION_PROPERTY, Route.GROUP_PROPERTY,
- Route.REST_PROPERTY };
+ Route.REST_PROPERTY, Route.CONFIGURATION_ID_PROPERTY };
public RouteReifier(CamelContext camelContext, ProcessorDefinition<?> definition) {
super(camelContext, (RouteDefinition) definition);
@@ -373,6 +373,9 @@ public class RouteReifier extends ProcessorReifier<RouteDefinition> {
routeProperties.put(Route.REST_PROPERTY, rest);
String template = Boolean.toString(definition.isTemplate() != null && definition.isTemplate());
routeProperties.put(Route.TEMPLATE_PROPERTY, template);
+ if (definition.getRouteConfigurationId() != null) {
+ routeProperties.put(Route.CONFIGURATION_ID_PROPERTY, definition.getRouteConfigurationId());
+ }
List<PropertyDefinition> properties = definition.getRouteProperties();
if (properties != null) {
diff --git a/core/camel-core-xml/src/main/java/org/apache/camel/core/xml/AbstractCamelContextFactoryBean.java b/core/camel-core-xml/src/main/java/org/apache/camel/core/xml/AbstractCamelContextFactoryBean.java
index 2e88712..9b62c51 100644
--- a/core/camel-core-xml/src/main/java/org/apache/camel/core/xml/AbstractCamelContextFactoryBean.java
+++ b/core/camel-core-xml/src/main/java/org/apache/camel/core/xml/AbstractCamelContextFactoryBean.java
@@ -72,6 +72,8 @@ import org.apache.camel.model.PackageScanDefinition;
import org.apache.camel.model.Resilience4jConfigurationDefinition;
import org.apache.camel.model.RestContextRefDefinition;
import org.apache.camel.model.RouteBuilderDefinition;
+import org.apache.camel.model.RouteConfigurationContainer;
+import org.apache.camel.model.RouteConfigurationDefinition;
import org.apache.camel.model.RouteContainer;
import org.apache.camel.model.RouteContextRefDefinition;
import org.apache.camel.model.RouteDefinition;
@@ -132,6 +134,7 @@ import org.apache.camel.spi.UuidGenerator;
import org.apache.camel.spi.Validator;
import org.apache.camel.support.CamelContextHelper;
import org.apache.camel.support.ObjectHelper;
+import org.apache.camel.support.PatternHelper;
import org.apache.camel.util.StringHelper;
import org.apache.camel.util.concurrent.ThreadPoolRejectedPolicy;
import org.slf4j.Logger;
@@ -143,7 +146,7 @@ import org.slf4j.LoggerFactory;
*/
@XmlAccessorType(XmlAccessType.FIELD)
public abstract class AbstractCamelContextFactoryBean<T extends ModelCamelContext> extends IdentifiedType
- implements RouteTemplateContainer, RouteContainer, RestContainer {
+ implements RouteTemplateContainer, RouteConfigurationContainer, RouteContainer, RestContainer {
private static final Logger LOG = LoggerFactory.getLogger(AbstractCamelContextFactoryBean.class);
@@ -444,6 +447,9 @@ public abstract class AbstractCamelContextFactoryBean<T extends ModelCamelContex
// mark that we are setting up routes
getContext().adapt(ExtendedCamelContext.class).setupRoutes(false);
+ // add route configurations
+ getContext().addRouteConfigurations(getRouteConfigurations());
+
// init route templates
initRouteTemplateRefs();
@@ -546,9 +552,37 @@ public abstract class AbstractCamelContextFactoryBean<T extends ModelCamelContex
// sanity check first as the route is created using XML
RouteDefinitionHelper.sanityCheckRoute(route);
- // leverage logic from route definition helper to prepare the route
- RouteDefinitionHelper.prepareRoute(getContext(), route, getOnExceptions(), getIntercepts(), getInterceptFroms(),
- getInterceptSendToEndpoints(), getOnCompletions());
+ // merge global and route scoped together
+ List<OnExceptionDefinition> oe = new ArrayList<>(getOnExceptions());
+ List<InterceptDefinition> icp = new ArrayList<>(getIntercepts());
+ List<InterceptFromDefinition> ifrom = new ArrayList<>(getInterceptFroms());
+ List<InterceptSendToEndpointDefinition> ito = new ArrayList<>(getInterceptSendToEndpoints());
+ List<OnCompletionDefinition> oc = new ArrayList<>(getOnCompletions());
+ if (getContext() != null) {
+ List<RouteConfigurationDefinition> globalConfigurations
+ = getContext().adapt(ModelCamelContext.class).getRouteConfigurationDefinitions();
+ if (globalConfigurations != null) {
+ globalConfigurations.stream()
+ // global configurations have no id assigned or is a wildcard
+ // if the route has a route configuration assigned then use pattern matching
+ .filter(g -> (g.getId() == null || g.getId().equals("*"))
+ || (PatternHelper.matchPattern(g.getId(), route.getRouteConfigurationId())))
+ .forEach(g -> {
+ oe.addAll(g.getOnExceptions());
+ icp.addAll(g.getIntercepts());
+ ifrom.addAll(g.getInterceptFroms());
+ ito.addAll(g.getInterceptSendTos());
+ oc.addAll(g.getOnCompletions());
+ });
+ }
+ }
+
+ // must prepare the route before we can add it to the routes list
+ RouteDefinitionHelper.prepareRoute(getContext(), route, oe, icp, ifrom, ito, oc);
+
+ if (LOG.isDebugEnabled() && route.getRouteConfigurationId() != null) {
+ LOG.debug("Route: {} is using routeConfigurationsId: {}", route.getId(), route.getRouteConfigurationId());
+ }
// mark the route as prepared now
route.markPrepared();
@@ -857,6 +891,9 @@ public abstract class AbstractCamelContextFactoryBean<T extends ModelCamelContex
public abstract List<RouteTemplateDefinition> getRouteTemplates();
@Override
+ public abstract List<RouteConfigurationDefinition> getRouteConfigurations();
+
+ @Override
public abstract List<RouteDefinition> getRoutes();
@Override
diff --git a/core/camel-core/src/test/java/org/apache/camel/ContextTestSupport.java b/core/camel-core/src/test/java/org/apache/camel/ContextTestSupport.java
index d3843f8..5b0817c 100644
--- a/core/camel-core/src/test/java/org/apache/camel/ContextTestSupport.java
+++ b/core/camel-core/src/test/java/org/apache/camel/ContextTestSupport.java
@@ -115,9 +115,18 @@ public abstract class ContextTestSupport extends TestSupport {
if (isUseRouteBuilder()) {
RouteBuilder[] builders = createRouteBuilders();
+ // add configuration before routes
for (RouteBuilder builder : builders) {
- log.debug("Using created route builder: {}", builder);
- context.addRoutes(builder);
+ if (builder instanceof RouteConfigurationsBuilder) {
+ log.debug("Using created route configuration: {}", builder);
+ context.addRoutesConfigurations((RouteConfigurationsBuilder) builder);
+ }
+ }
+ for (RouteBuilder builder : builders) {
+ if (!(builder instanceof RouteConfigurationsBuilder)) {
+ log.debug("Using created route builder: {}", builder);
+ context.addRoutes(builder);
+ }
}
} else {
log.debug("isUseRouteBuilder() is false");
diff --git a/core/camel-core/src/test/java/org/apache/camel/model/RoutesConfigurationBuilderIdOrPatternTest.java b/core/camel-core/src/test/java/org/apache/camel/model/RoutesConfigurationBuilderIdOrPatternTest.java
new file mode 100644
index 0000000..d79b4d0
--- /dev/null
+++ b/core/camel-core/src/test/java/org/apache/camel/model/RoutesConfigurationBuilderIdOrPatternTest.java
@@ -0,0 +1,243 @@
+/*
+ * 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 java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.camel.ContextTestSupport;
+import org.apache.camel.RouteConfigurationsBuilder;
+import org.apache.camel.RoutesBuilder;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.builder.RouteConfigurationBuilder;
+import org.apache.camel.support.OrderedComparator;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.fail;
+
+public class RoutesConfigurationBuilderIdOrPatternTest extends ContextTestSupport {
+
+ @Override
+ public boolean isUseRouteBuilder() {
+ return false;
+ }
+
+ @Test
+ public void testRoutesConfigurationOnException() throws Exception {
+ List<RoutesBuilder> routes = new ArrayList<>();
+
+ routes.add(new RouteBuilder() {
+ @Override
+ public void configure() throws Exception {
+ from("direct:start")
+ .throwException(new IllegalArgumentException("Foo"));
+ }
+ });
+ routes.add(new RouteBuilder() {
+ @Override
+ public void configure() throws Exception {
+ from("direct:start2")
+ .routeConfigurationId("handleError")
+ .throwException(new IllegalArgumentException("Foo2"));
+ }
+ });
+ routes.add(new RouteConfigurationBuilder() {
+ @Override
+ public void configuration() throws Exception {
+ // named routes configuration
+ routeConfiguration("handleError").onException(Exception.class).handled(true).to("mock:error");
+ }
+ });
+ context.start();
+
+ // sort routes according to ordered
+ routes.sort(OrderedComparator.get());
+
+ // first add the routes configurations as they are globally for all routes
+ for (RoutesBuilder builder : routes) {
+ if (builder instanceof RouteConfigurationsBuilder) {
+ RouteConfigurationsBuilder rcb = (RouteConfigurationsBuilder) builder;
+ context.addRoutesConfigurations(rcb);
+ }
+ }
+ // then add the routes
+ for (RoutesBuilder builder : routes) {
+ context.addRoutes(builder);
+ }
+
+ getMockEndpoint("mock:error").expectedBodiesReceived("Bye World");
+
+ try {
+ template.sendBody("direct:start", "Hello World");
+ fail("Should throw exception");
+ } catch (Exception e) {
+ // expected
+ }
+ template.sendBody("direct:start2", "Bye World");
+
+ assertMockEndpointsSatisfied();
+ }
+
+ @Test
+ public void testRoutesConfigurationOnExceptionPattern() throws Exception {
+ List<RoutesBuilder> routes = new ArrayList<>();
+
+ routes.add(new RouteBuilder() {
+ @Override
+ public void configure() throws Exception {
+ from("direct:start")
+ .routeConfigurationId("general*")
+ .throwException(new IllegalArgumentException("Foo"));
+ }
+ });
+ routes.add(new RouteBuilder() {
+ @Override
+ public void configure() throws Exception {
+ from("direct:start2")
+ .routeConfigurationId("io*")
+ .throwException(new IOException("Foo2"));
+ }
+ });
+ routes.add(new RouteConfigurationBuilder() {
+ @Override
+ public void configuration() throws Exception {
+ // named routes configuration
+ routeConfiguration("generalError").onException(Exception.class).handled(true).to("mock:error");
+ routeConfiguration("ioError").onException(IOException.class).maximumRedeliveries(3).redeliveryDelay(0)
+ .handled(true).to("mock:io");
+ }
+ });
+ context.start();
+
+ // sort routes according to ordered
+ routes.sort(OrderedComparator.get());
+
+ // first add the routes configurations as they are globally for all routes
+ for (RoutesBuilder builder : routes) {
+ if (builder instanceof RouteConfigurationsBuilder) {
+ RouteConfigurationsBuilder rcb = (RouteConfigurationsBuilder) builder;
+ context.addRoutesConfigurations(rcb);
+ }
+ }
+ // then add the routes
+ for (RoutesBuilder builder : routes) {
+ context.addRoutes(builder);
+ }
+
+ getMockEndpoint("mock:error").expectedBodiesReceived("Hello World");
+ getMockEndpoint("mock:io").expectedBodiesReceived("Bye World");
+
+ template.sendBody("direct:start", "Hello World");
+ template.sendBody("direct:start2", "Bye World");
+
+ assertMockEndpointsSatisfied();
+ }
+
+ @Test
+ public void testRoutesConfigurationOnExceptionDefault() throws Exception {
+ List<RoutesBuilder> routes = new ArrayList<>();
+
+ routes.add(new RouteBuilder() {
+ @Override
+ public void configure() throws Exception {
+ from("direct:start").routeId("foo")
+ .throwException(new IllegalArgumentException("Foo"));
+ }
+ });
+ routes.add(new RouteBuilder() {
+ @Override
+ public void configure() throws Exception {
+ from("direct:start2").routeId("foo2")
+ .throwException(new IOException("Foo2"));
+ }
+ });
+ routes.add(new RouteConfigurationBuilder() {
+ @Override
+ public void configuration() throws Exception {
+ // has no name so its the default
+ routeConfiguration().onException(Exception.class).handled(true).to("mock:error");
+ // special for io, but only if included
+ routeConfiguration("ioError").onException(IOException.class).maximumRedeliveries(3).redeliveryDelay(0)
+ .handled(true).to("mock:io");
+ }
+ });
+ context.start();
+
+ // sort routes according to ordered
+ routes.sort(OrderedComparator.get());
+
+ // first add the routes configurations as they are globally for all routes
+ for (RoutesBuilder builder : routes) {
+ if (builder instanceof RouteConfigurationsBuilder) {
+ RouteConfigurationsBuilder rcb = (RouteConfigurationsBuilder) builder;
+ context.addRoutesConfigurations(rcb);
+ }
+ }
+ // then add the routes
+ for (RoutesBuilder builder : routes) {
+ context.addRoutes(builder);
+ }
+
+ getMockEndpoint("mock:error").expectedBodiesReceived("Hello World", "Bye World");
+ getMockEndpoint("mock:io").expectedMessageCount(0);
+ template.sendBody("direct:start", "Hello World");
+ template.sendBody("direct:start2", "Bye World");
+ assertMockEndpointsSatisfied();
+
+ context.removeRoute("foo2");
+
+ // now re-configure route2 to use ioError route configuration
+ context.addRoutes(new RouteBuilder() {
+ @Override
+ public void configure() throws Exception {
+ from("direct:start2").routeId("foo2")
+ .routeConfigurationId("ioError")
+ .throwException(new IOException("Foo2"));
+ }
+ });
+ // try again
+ resetMocks();
+ getMockEndpoint("mock:error").expectedBodiesReceived("Hello World");
+ getMockEndpoint("mock:io").expectedBodiesReceived("Bye World");
+ template.sendBody("direct:start", "Hello World");
+ template.sendBody("direct:start2", "Bye World");
+ assertMockEndpointsSatisfied();
+ }
+
+ @Test
+ public void testRoutesConfigurationIdClash() throws Exception {
+ RouteConfigurationBuilder rcb = new RouteConfigurationBuilder() {
+ @Override
+ public void configuration() throws Exception {
+ routeConfiguration().onException(Exception.class).handled(true).to("mock:foo");
+ routeConfiguration("foo").onException(IOException.class).handled(true).to("mock:foo");
+ routeConfiguration("bar").onException(FileNotFoundException.class).handled(true).to("mock:bar");
+ routeConfiguration("foo").onException(IllegalArgumentException.class).handled(true).to("mock:foo");
+ }
+ };
+ try {
+ context.addRoutesConfigurations(rcb);
+ fail("Should throw exception");
+ } catch (IllegalArgumentException e) {
+ assertEquals("Route configuration already exists with id: foo", e.getMessage());
+ }
+ }
+
+}
diff --git a/core/camel-core/src/test/java/org/apache/camel/model/RoutesConfigurationBuilderTest.java b/core/camel-core/src/test/java/org/apache/camel/model/RoutesConfigurationBuilderTest.java
new file mode 100644
index 0000000..5e70d18
--- /dev/null
+++ b/core/camel-core/src/test/java/org/apache/camel/model/RoutesConfigurationBuilderTest.java
@@ -0,0 +1,310 @@
+/*
+ * 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 java.util.ArrayList;
+import java.util.List;
+
+import org.apache.camel.ContextTestSupport;
+import org.apache.camel.RouteConfigurationsBuilder;
+import org.apache.camel.RoutesBuilder;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.builder.RouteConfigurationBuilder;
+import org.apache.camel.support.OrderedComparator;
+import org.junit.jupiter.api.Test;
+
+public class RoutesConfigurationBuilderTest extends ContextTestSupport {
+
+ @Override
+ public boolean isUseRouteBuilder() {
+ return false;
+ }
+
+ @Test
+ public void testRoutesConfigurationOnException() throws Exception {
+ List<RoutesBuilder> routes = new ArrayList<>();
+
+ routes.add(new RouteBuilder() {
+ @Override
+ public void configure() throws Exception {
+ from("direct:start")
+ .throwException(new IllegalArgumentException("Foo"));
+ }
+ });
+ routes.add(new RouteBuilder() {
+ @Override
+ public void configure() throws Exception {
+ from("direct:start2")
+ .throwException(new IllegalArgumentException("Foo2"));
+ }
+ });
+ routes.add(new RouteConfigurationBuilder() {
+ @Override
+ public void configuration() throws Exception {
+ // global routes configuration
+ routeConfiguration().onException(Exception.class).handled(true).to("mock:error");
+ }
+ });
+ context.start();
+
+ // sort routes according to ordered
+ routes.sort(OrderedComparator.get());
+
+ // first add the routes configurations as they are globally for all routes
+ for (RoutesBuilder builder : routes) {
+ if (builder instanceof RouteConfigurationsBuilder) {
+ RouteConfigurationsBuilder rcb = (RouteConfigurationsBuilder) builder;
+ context.addRoutesConfigurations(rcb);
+ }
+ }
+ // then add the routes
+ for (RoutesBuilder builder : routes) {
+ context.addRoutes(builder);
+ }
+
+ getMockEndpoint("mock:error").expectedBodiesReceived("Hello World", "Bye World");
+
+ template.sendBody("direct:start", "Hello World");
+ template.sendBody("direct:start2", "Bye World");
+
+ assertMockEndpointsSatisfied();
+ }
+
+ @Test
+ public void testRoutesConfigurationOnCompletion() throws Exception {
+ List<RoutesBuilder> routes = new ArrayList<>();
+
+ routes.add(new RouteBuilder() {
+ @Override
+ public void configure() throws Exception {
+ from("direct:start")
+ .to("mock:result");
+ }
+ });
+ routes.add(new RouteBuilder() {
+ @Override
+ public void configure() throws Exception {
+ from("direct:start2")
+ // route scoped that overrides the global scoped
+ .onCompletion().to("mock:done2").end()
+ .to("mock:result");
+ }
+ });
+ routes.add(new RouteConfigurationBuilder() {
+ @Override
+ public void configuration() throws Exception {
+ // global routes configuration
+ routeConfiguration().onCompletion().to("mock:done");
+ }
+ });
+ context.start();
+
+ // sort routes according to ordered
+ routes.sort(OrderedComparator.get());
+
+ // first add the routes configurations as they are globally for all routes
+ for (RoutesBuilder builder : routes) {
+ if (builder instanceof RouteConfigurationsBuilder) {
+ RouteConfigurationsBuilder rcb = (RouteConfigurationsBuilder) builder;
+ context.addRoutesConfigurations(rcb);
+ }
+ }
+ // then add the routes
+ for (RoutesBuilder builder : routes) {
+ context.addRoutes(builder);
+ }
+
+ getMockEndpoint("mock:result").expectedMessageCount(2);
+ getMockEndpoint("mock:done").expectedBodiesReceived("Hello World");
+ getMockEndpoint("mock:done2").expectedBodiesReceived("Bye World");
+
+ template.sendBody("direct:start", "Hello World");
+ template.sendBody("direct:start2", "Bye World");
+
+ assertMockEndpointsSatisfied();
+ }
+
+ @Test
+ public void testRoutesConfigurationIntercept() throws Exception {
+ List<RoutesBuilder> routes = new ArrayList<>();
+
+ routes.add(new RouteBuilder() {
+ @Override
+ public void configure() throws Exception {
+ from("direct:start")
+ .setBody(constant("A"))
+ .setBody(constant("B"))
+ .to("mock:result");
+ }
+ });
+ routes.add(new RouteBuilder() {
+ @Override
+ public void configure() throws Exception {
+ from("direct:start2")
+ .setBody(constant("C"))
+ .setBody(constant("D"))
+ .to("mock:result");
+ }
+ });
+ routes.add(new RouteConfigurationBuilder() {
+ @Override
+ public void configuration() throws Exception {
+ // global routes configuration
+ routeConfiguration().intercept().to("mock:step");
+ }
+ });
+ context.start();
+
+ // sort routes according to ordered
+ routes.sort(OrderedComparator.get());
+
+ // first add the routes configurations as they are globally for all routes
+ for (RoutesBuilder builder : routes) {
+ if (builder instanceof RouteConfigurationsBuilder) {
+ RouteConfigurationsBuilder rcb = (RouteConfigurationsBuilder) builder;
+ context.addRoutesConfigurations(rcb);
+ }
+ }
+ // then add the routes
+ for (RoutesBuilder builder : routes) {
+ context.addRoutes(builder);
+ }
+
+ getMockEndpoint("mock:result").expectedMessageCount(2);
+ getMockEndpoint("mock:step").expectedBodiesReceived("Hello World", "A", "B", "Bye World", "C", "D");
+
+ template.sendBody("direct:start", "Hello World");
+ template.sendBody("direct:start2", "Bye World");
+
+ assertMockEndpointsSatisfied();
+ }
+
+ @Test
+ public void testRoutesConfigurationInterceptFrom() throws Exception {
+ List<RoutesBuilder> routes = new ArrayList<>();
+
+ routes.add(new RouteBuilder() {
+ @Override
+ public void configure() throws Exception {
+ from("seda:start")
+ .setBody(constant("A"))
+ .setBody(constant("B"))
+ .to("mock:result");
+ }
+ });
+ routes.add(new RouteBuilder() {
+ @Override
+ public void configure() throws Exception {
+ from("direct:start2")
+ .setBody(constant("C"))
+ .setBody(constant("D"))
+ .to("mock:result");
+ }
+ });
+ routes.add(new RouteConfigurationBuilder() {
+ @Override
+ public void configuration() throws Exception {
+ // global routes configuration
+ routeConfiguration().interceptFrom("direct*").to("mock:step");
+ }
+ });
+ context.start();
+
+ // sort routes according to ordered
+ routes.sort(OrderedComparator.get());
+
+ // first add the routes configurations as they are globally for all routes
+ for (RoutesBuilder builder : routes) {
+ if (builder instanceof RouteConfigurationsBuilder) {
+ RouteConfigurationsBuilder rcb = (RouteConfigurationsBuilder) builder;
+ context.addRoutesConfigurations(rcb);
+ }
+ }
+ // then add the routes
+ for (RoutesBuilder builder : routes) {
+ context.addRoutes(builder);
+ }
+
+ getMockEndpoint("mock:result").expectedMessageCount(2);
+ getMockEndpoint("mock:step").expectedBodiesReceived("Bye World");
+
+ template.sendBody("seda:start", "Hello World");
+ template.sendBody("direct:start2", "Bye World");
+
+ assertMockEndpointsSatisfied();
+ }
+
+ @Test
+ public void testRoutesConfigurationInterceptSendTo() throws Exception {
+ List<RoutesBuilder> routes = new ArrayList<>();
+
+ routes.add(new RouteBuilder() {
+ @Override
+ public void configure() throws Exception {
+ from("direct:start")
+ .setBody(constant("A"))
+ .to("mock:foo")
+ .setBody(constant("B"))
+ .to("mock:bar")
+ .to("mock:result");
+ }
+ });
+ routes.add(new RouteBuilder() {
+ @Override
+ public void configure() throws Exception {
+ from("direct:start2")
+ .setBody(constant("C"))
+ .to("mock:foo")
+ .setBody(constant("D"))
+ .to("mock:bar")
+ .to("mock:result");
+ }
+ });
+ routes.add(new RouteConfigurationBuilder() {
+ @Override
+ public void configuration() throws Exception {
+ // global routes configuration
+ routeConfiguration().interceptSendToEndpoint("mock:foo").to("mock:step");
+ }
+ });
+ context.start();
+
+ // sort routes according to ordered
+ routes.sort(OrderedComparator.get());
+
+ // first add the routes configurations as they are globally for all routes
+ for (RoutesBuilder builder : routes) {
+ if (builder instanceof RouteConfigurationsBuilder) {
+ RouteConfigurationsBuilder rcb = (RouteConfigurationsBuilder) builder;
+ context.addRoutesConfigurations(rcb);
+ }
+ }
+ // then add the routes
+ for (RoutesBuilder builder : routes) {
+ context.addRoutes(builder);
+ }
+
+ getMockEndpoint("mock:result").expectedMessageCount(2);
+ getMockEndpoint("mock:step").expectedBodiesReceived("A", "C");
+
+ template.sendBody("direct:start", "Hello World");
+ template.sendBody("direct:start2", "Bye World");
+
+ assertMockEndpointsSatisfied();
+ }
+
+}
diff --git a/core/camel-core/src/test/java/org/apache/camel/model/RoutesConfigurationMultipleRouteBuilderTest.java b/core/camel-core/src/test/java/org/apache/camel/model/RoutesConfigurationMultipleRouteBuilderTest.java
new file mode 100644
index 0000000..d4fe65a
--- /dev/null
+++ b/core/camel-core/src/test/java/org/apache/camel/model/RoutesConfigurationMultipleRouteBuilderTest.java
@@ -0,0 +1,65 @@
+/*
+ * 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.ContextTestSupport;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.builder.RouteConfigurationBuilder;
+import org.junit.jupiter.api.Test;
+
+public class RoutesConfigurationMultipleRouteBuilderTest extends ContextTestSupport {
+
+ @Override
+ public boolean isUseRouteBuilder() {
+ return false;
+ }
+
+ @Test
+ public void testRoutesConfiguration() throws Exception {
+ context.addRoutesConfigurations(new RouteConfigurationBuilder() {
+ @Override
+ public void configuration() throws Exception {
+ // global configuration for all routes
+ routeConfiguration().onException(Exception.class).handled(true).to("mock:error");
+ }
+ });
+ context.addRoutes(new RouteBuilder() {
+ @Override
+ public void configure() throws Exception {
+ from("direct:start")
+ .throwException(new IllegalArgumentException("Foo"));
+ }
+ });
+ context.addRoutes(new RouteBuilder() {
+ @Override
+ public void configure() throws Exception {
+ from("direct:start2")
+ .throwException(new IllegalArgumentException("Foo2"));
+ }
+ });
+
+ context.start();
+
+ getMockEndpoint("mock:error").expectedBodiesReceived("Hello World", "Bye World");
+
+ template.sendBody("direct:start", "Hello World");
+ template.sendBody("direct:start2", "Bye World");
+
+ assertMockEndpointsSatisfied();
+ }
+
+}
diff --git a/core/camel-core/src/test/java/org/apache/camel/model/RoutesConfigurationTest.java b/core/camel-core/src/test/java/org/apache/camel/model/RoutesConfigurationTest.java
new file mode 100644
index 0000000..a737fc1
--- /dev/null
+++ b/core/camel-core/src/test/java/org/apache/camel/model/RoutesConfigurationTest.java
@@ -0,0 +1,59 @@
+/*
+ * 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.ContextTestSupport;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.builder.RouteConfigurationBuilder;
+import org.junit.jupiter.api.Test;
+
+public class RoutesConfigurationTest extends ContextTestSupport {
+
+ @Test
+ public void testRoutesConfiguration() throws Exception {
+ getMockEndpoint("mock:error").expectedBodiesReceived("Hello World", "Bye World");
+
+ template.sendBody("direct:start", "Hello World");
+ template.sendBody("direct:start2", "Bye World");
+
+ assertMockEndpointsSatisfied();
+ }
+
+ @Override
+ protected RouteBuilder[] createRouteBuilders() throws Exception {
+ return new RouteBuilder[] {
+ new RouteBuilder() {
+ @Override
+ public void configure() throws Exception {
+ from("direct:start")
+ .throwException(new IllegalArgumentException("Foo"));
+
+ from("direct:start2")
+ .throwException(new IllegalArgumentException("Foo2"));
+ }
+ },
+ new RouteConfigurationBuilder() {
+ @Override
+ public void configuration() throws Exception {
+ // global routes configuration
+ routeConfiguration().onException(Exception.class).handled(true).to("mock:error");
+ }
+ }
+ };
+ }
+
+}
diff --git a/core/camel-endpointdsl/src/main/java/org/apache/camel/builder/endpoint/EndpointRouteBuilder.java b/core/camel-endpointdsl/src/main/java/org/apache/camel/builder/endpoint/EndpointRouteBuilder.java
index f9e9190..77ad7fc 100644
--- a/core/camel-endpointdsl/src/main/java/org/apache/camel/builder/endpoint/EndpointRouteBuilder.java
+++ b/core/camel-endpointdsl/src/main/java/org/apache/camel/builder/endpoint/EndpointRouteBuilder.java
@@ -41,15 +41,15 @@ public abstract class EndpointRouteBuilder extends RouteBuilder implements Endpo
* Add routes to a context using a lambda expression. It can be used as following:
*
* <pre>
- * RouteBuilder.addRoutes(context, rb ->
- * rb.from("direct:inbound").bean(ProduceTemplateBean.class)));
+ * EndpointRouteBuilder.addEndpointRoutes(context, rb ->
+ * rb.from(rb.direct("inbound")).bean(MyBean.class)));
* </pre>
*
* @param context the camel context to add routes
* @param rbc a lambda expression receiving the {@code RouteBuilder} to use for creating routes
* @throws Exception if an error occurs
*/
- public static void addEndpointRoutes(CamelContext context, ThrowingConsumer<EndpointRouteBuilder, Exception> rbc)
+ public static void addEndpointRoutes(CamelContext context, LambdaEndpointRouteBuilder rbc)
throws Exception {
context.addRoutes(new EndpointRouteBuilder(context) {
@Override
diff --git a/core/camel-endpointdsl/src/main/java/org/apache/camel/builder/endpoint/EndpointRouteConfigurationBuilder.java b/core/camel-endpointdsl/src/main/java/org/apache/camel/builder/endpoint/EndpointRouteConfigurationBuilder.java
new file mode 100644
index 0000000..7122067
--- /dev/null
+++ b/core/camel-endpointdsl/src/main/java/org/apache/camel/builder/endpoint/EndpointRouteConfigurationBuilder.java
@@ -0,0 +1,91 @@
+/*
+ * 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.endpoint;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.RouteConfigurationsBuilder;
+import org.apache.camel.model.Model;
+import org.apache.camel.model.RouteConfigurationDefinition;
+import org.apache.camel.model.RouteConfigurationsDefinition;
+
+/**
+ * A <a href="http://camel.apache.org/dsl.html">Java DSL</a> which is used for building route configuration(s).
+ */
+public abstract class EndpointRouteConfigurationBuilder extends EndpointRouteBuilder implements RouteConfigurationsBuilder {
+
+ private final AtomicBoolean initializedConfiguration = new AtomicBoolean();
+ private RouteConfigurationsDefinition routeConfigurationCollection = new RouteConfigurationsDefinition();
+
+ @Override
+ public void configure() throws Exception {
+ // noop
+ }
+
+ public abstract void configuration() throws Exception;
+
+ public RouteConfigurationsDefinition getRouteConfigurationCollection() {
+ return routeConfigurationCollection;
+ }
+
+ public void setRouteConfigurationCollection(RouteConfigurationsDefinition routeConfigurationCollection) {
+ this.routeConfigurationCollection = routeConfigurationCollection;
+ }
+
+ /**
+ * Creates a new route configuration
+ *
+ * @return the builder
+ */
+ public RouteConfigurationDefinition routeConfiguration() {
+ return routeConfiguration(null);
+ }
+
+ /**
+ * Creates a new route configuration
+ *
+ * @return the builder
+ */
+ public RouteConfigurationDefinition routeConfiguration(String id) {
+ getRouteConfigurationCollection().setCamelContext(getCamelContext());
+ RouteConfigurationDefinition answer = getRouteConfigurationCollection().routeConfiguration(id);
+ configureRouteConfiguration(answer);
+ return answer;
+ }
+
+ @Override
+ public void addRouteConfigurationsToCamelContext(CamelContext context) throws Exception {
+ setCamelContext(context);
+ routeConfigurationCollection.setCamelContext(context);
+ if (initializedConfiguration.compareAndSet(false, true)) {
+ configuration();
+ }
+ populateRoutesConfiguration();
+ }
+
+ protected void populateRoutesConfiguration() throws Exception {
+ CamelContext camelContext = getContext();
+ if (camelContext == null) {
+ throw new IllegalArgumentException("CamelContext has not been injected!");
+ }
+ getRouteConfigurationCollection().setCamelContext(camelContext);
+ camelContext.getExtension(Model.class)
+ .addRouteConfigurations(getRouteConfigurationCollection().getRouteConfigurations());
+ }
+
+}
diff --git a/core/camel-core-model/src/main/java/org/apache/camel/builder/LambdaRouteBuilder.java b/core/camel-endpointdsl/src/main/java/org/apache/camel/builder/endpoint/LambdaEndpointRouteBuilder.java
similarity index 75%
copy from core/camel-core-model/src/main/java/org/apache/camel/builder/LambdaRouteBuilder.java
copy to core/camel-endpointdsl/src/main/java/org/apache/camel/builder/endpoint/LambdaEndpointRouteBuilder.java
index 48cf43c..d03121c 100644
--- a/core/camel-core-model/src/main/java/org/apache/camel/builder/LambdaRouteBuilder.java
+++ b/core/camel-endpointdsl/src/main/java/org/apache/camel/builder/endpoint/LambdaEndpointRouteBuilder.java
@@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.camel.builder;
+package org.apache.camel.builder.endpoint;
import org.apache.camel.CamelContext;
import org.apache.camel.util.function.ThrowingConsumer;
@@ -23,13 +23,13 @@ import org.apache.camel.util.function.ThrowingConsumer;
* Functional interface for adding routes to a context using a lambda expression. It can be used as following:
*
* <pre>
- * RouteBuilder.addRoutes(context, rb ->
- * rb.from("direct:inbound").bean(ProduceTemplateBean.class)));
+ * EndpointRouteBuilder.addEndpointRoutes(context, rb ->
+ * rb.from(rb.direct("inbound")).bean(MyBean.class)));
* </pre>
*
- * @see RouteBuilder#addRoutes(CamelContext, LambdaRouteBuilder)
+ * @see EndpointRouteBuilder#addEndpointRoutes(CamelContext, LambdaEndpointRouteBuilder)
*/
@FunctionalInterface
-public interface LambdaRouteBuilder extends ThrowingConsumer<RouteBuilder, Exception> {
+public interface LambdaEndpointRouteBuilder extends ThrowingConsumer<EndpointRouteBuilder, Exception> {
}
diff --git a/core/camel-endpointdsl/src/test/java/org/apache/camel/builder/endpoint/EndpointRoutesConfigurationTest.java b/core/camel-endpointdsl/src/test/java/org/apache/camel/builder/endpoint/EndpointRoutesConfigurationTest.java
new file mode 100644
index 0000000..a67e5a7
--- /dev/null
+++ b/core/camel-endpointdsl/src/test/java/org/apache/camel/builder/endpoint/EndpointRoutesConfigurationTest.java
@@ -0,0 +1,57 @@
+/*
+ * 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.endpoint;
+
+import org.apache.camel.builder.RouteBuilder;
+import org.junit.jupiter.api.Test;
+
+public class EndpointRoutesConfigurationTest extends BaseEndpointDslTest {
+
+ @Test
+ public void testEndpointRoutesConfiguration() throws Exception {
+ getMockEndpoint("mock:error").expectedBodiesReceived("Hello World", "Bye World");
+
+ template.sendBody("direct:start", "Hello World");
+ template.sendBody("direct:start2", "Bye World");
+
+ assertMockEndpointsSatisfied();
+ }
+
+ @Override
+ protected RouteBuilder[] createRouteBuilders() throws Exception {
+ return new RouteBuilder[] {
+ new EndpointRouteBuilder() {
+ @Override
+ public void configure() throws Exception {
+ from(direct("start"))
+ .throwException(new IllegalArgumentException("Foo"));
+
+ from(direct("start2"))
+ .throwException(new IllegalArgumentException("Foo2"));
+ }
+ },
+ new EndpointRouteConfigurationBuilder() {
+ @Override
+ public void configuration() throws Exception {
+ // global routes configuration
+ routeConfiguration().onException(Exception.class).handled(true).to(mock("error"));
+ }
+ }
+ };
+ }
+
+}
diff --git a/core/camel-endpointdsl/src/test/java/org/apache/camel/builder/endpoint/LambdaEndpointRouteBuilderTest.java b/core/camel-endpointdsl/src/test/java/org/apache/camel/builder/endpoint/LambdaEndpointRouteBuilderTest.java
new file mode 100644
index 0000000..fad48ee
--- /dev/null
+++ b/core/camel-endpointdsl/src/test/java/org/apache/camel/builder/endpoint/LambdaEndpointRouteBuilderTest.java
@@ -0,0 +1,86 @@
+/*
+ * 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.endpoint;
+
+import org.apache.camel.component.mock.MockEndpoint;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+public class LambdaEndpointRouteBuilderTest extends BaseEndpointDslTest {
+
+ @Test
+ public void testLambda() throws Exception {
+ assertEquals(0, context.getRoutesSize());
+
+ LambdaEndpointRouteBuilder builder = rb -> rb.from(rb.direct("start")).to(rb.mock("result"));
+ context.addRoutes(new EndpointRouteBuilder(context) {
+ @Override
+ public void configure() throws Exception {
+ builder.accept(this);
+ }
+ });
+ context.start();
+
+ assertEquals(1, context.getRoutesSize());
+
+ MockEndpoint mock = getMockEndpoint("mock:result");
+ mock.expectedBodiesReceived("Hello World");
+
+ template.sendBody("direct:start", "Hello World");
+
+ assertMockEndpointsSatisfied();
+ }
+
+ @Test
+ public void testLambdaTwo() throws Exception {
+ assertEquals(0, context.getRoutesSize());
+
+ EndpointRouteBuilder.addEndpointRoutes(context, rb -> rb.from(rb.direct("start")).to(rb.mock("result")));
+
+ context.start();
+
+ assertEquals(1, context.getRoutesSize());
+
+ MockEndpoint mock = getMockEndpoint("mock:result");
+ mock.expectedBodiesReceived("Hello World");
+
+ template.sendBody("direct:start", "Hello World");
+
+ assertMockEndpointsSatisfied();
+ }
+
+ @Test
+ public void testLambdaSimple() throws Exception {
+ assertEquals(0, context.getRoutesSize());
+
+ EndpointRouteBuilder.addEndpointRoutes(context,
+ rb -> rb.from(rb.direct("start")).transform(rb.simple("Hello ${body}")).to(rb.mock("result")));
+
+ context.start();
+
+ assertEquals(1, context.getRoutesSize());
+
+ MockEndpoint mock = getMockEndpoint("mock:result");
+ mock.expectedBodiesReceived("Hello World");
+
+ template.sendBody("direct:start", "World");
+
+ assertMockEndpointsSatisfied();
+ }
+
+}
diff --git a/core/camel-main/src/main/java/org/apache/camel/main/RoutesConfigurer.java b/core/camel-main/src/main/java/org/apache/camel/main/RoutesConfigurer.java
index 4440dfb..1a543b1 100644
--- a/core/camel-main/src/main/java/org/apache/camel/main/RoutesConfigurer.java
+++ b/core/camel-main/src/main/java/org/apache/camel/main/RoutesConfigurer.java
@@ -23,6 +23,7 @@ import java.util.Set;
import org.apache.camel.CamelContext;
import org.apache.camel.ExtendedCamelContext;
+import org.apache.camel.RouteConfigurationsBuilder;
import org.apache.camel.RoutesBuilder;
import org.apache.camel.RuntimeCamelException;
import org.apache.camel.spi.CamelBeanPostProcessor;
@@ -143,7 +144,6 @@ public class RoutesConfigurer {
// lets use Camel's injector so the class has some support for dependency injection
RoutesBuilder builder = camelContext.getInjector().newInstance(routeClazz);
-
routes.add(builder);
}
}
@@ -153,7 +153,6 @@ public class RoutesConfigurer {
Set<Class<?>> set = camelContext.adapt(ExtendedCamelContext.class)
.getPackageScanClassResolver()
.findImplementations(RoutesBuilder.class, pkgs);
-
for (Class<?> routeClazz : set) {
Object builder = camelContext.getInjector().newInstance(routeClazz);
if (builder instanceof RoutesBuilder) {
@@ -175,6 +174,11 @@ public class RoutesConfigurer {
getJavaRoutesIncludePattern());
routes.addAll(routesFromRegistry);
+ if (LOG.isDebugEnabled() && !routesFromRegistry.isEmpty()) {
+ LOG.debug("Discovered {} additional RoutesBuilder from registry: {}", routesFromRegistry.size(),
+ getRoutesIncludePattern());
+ }
+
// add discovered routes from directories
StopWatch watch = new StopWatch();
Collection<RoutesBuilder> routesFromDirectory = getRoutesCollector().collectRoutesFromDirectory(
@@ -183,8 +187,8 @@ public class RoutesConfigurer {
getRoutesIncludePattern());
routes.addAll(routesFromDirectory);
- if (!routesFromDirectory.isEmpty()) {
- LOG.info("Loaded {} additional RoutesBuilder from: {} (took {})", routesFromDirectory.size(),
+ if (LOG.isDebugEnabled() && !routesFromDirectory.isEmpty()) {
+ LOG.debug("Loaded {} additional RoutesBuilder from: {} (took {})", routesFromDirectory.size(),
getRoutesIncludePattern(), TimeUtils.printDuration(watch.taken()));
}
} catch (Exception e) {
@@ -195,26 +199,39 @@ public class RoutesConfigurer {
if (getBeanPostProcessor() != null) {
// lets use Camel's bean post processor on any existing route builder classes
// so the instance has some support for dependency injection
-
for (RoutesBuilder routeBuilder : routes) {
getBeanPostProcessor().postProcessBeforeInitialization(routeBuilder, routeBuilder.getClass().getName());
getBeanPostProcessor().postProcessAfterInitialization(routeBuilder, routeBuilder.getClass().getName());
}
}
+ // add the discovered routes
+ addDiscoveredRoutes(camelContext, routes);
+
+ // then discover and add templates
+ Set<ConfigureRouteTemplates> set = camelContext.getRegistry().findByType(ConfigureRouteTemplates.class);
+ for (ConfigureRouteTemplates crt : set) {
+ LOG.debug("Configuring route templates via: {}", crt);
+ crt.configure(camelContext);
+ }
+ }
+
+ private void addDiscoveredRoutes(CamelContext camelContext, List<RoutesBuilder> routes) throws Exception {
// sort routes according to ordered
routes.sort(OrderedComparator.get());
+ // first add the routes configurations as they are globally for all routes
+ for (RoutesBuilder builder : routes) {
+ if (builder instanceof RouteConfigurationsBuilder) {
+ RouteConfigurationsBuilder rcb = (RouteConfigurationsBuilder) builder;
+ LOG.debug("Adding routes configurations into CamelContext from RouteConfigurationsBuilder: {}", rcb);
+ camelContext.addRoutesConfigurations(rcb);
+ }
+ }
// then add the routes
for (RoutesBuilder builder : routes) {
LOG.debug("Adding routes into CamelContext from RoutesBuilder: {}", builder);
camelContext.addRoutes(builder);
}
-
- Set<ConfigureRouteTemplates> set = camelContext.getRegistry().findByType(ConfigureRouteTemplates.class);
- for (ConfigureRouteTemplates crt : set) {
- LOG.debug("Configuring route templates via: {}", crt);
- crt.configure(camelContext);
- }
}
}
diff --git a/core/camel-management-api/src/main/java/org/apache/camel/api/management/mbean/ManagedRouteMBean.java b/core/camel-management-api/src/main/java/org/apache/camel/api/management/mbean/ManagedRouteMBean.java
index 304998a..e019e88 100644
--- a/core/camel-management-api/src/main/java/org/apache/camel/api/management/mbean/ManagedRouteMBean.java
+++ b/core/camel-management-api/src/main/java/org/apache/camel/api/management/mbean/ManagedRouteMBean.java
@@ -35,6 +35,9 @@ public interface ManagedRouteMBean extends ManagedPerformanceCounterMBean {
@ManagedAttribute(description = "Route Description")
String getDescription();
+ @ManagedAttribute(description = "Route Configuration ID")
+ String getRouteConfigurationId();
+
@ManagedAttribute(description = "Route Endpoint URI", mask = true)
String getEndpointUri();
diff --git a/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedRoute.java b/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedRoute.java
index 87ab081..988dc20 100644
--- a/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedRoute.java
+++ b/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedRoute.java
@@ -71,6 +71,7 @@ public class ManagedRoute extends ManagedPerformanceCounter implements TimerList
protected final Route route;
protected final String description;
+ protected final String configurationId;
protected final CamelContext context;
private final LoadTriplet load = new LoadTriplet();
private final String jmxDomain;
@@ -79,6 +80,7 @@ public class ManagedRoute extends ManagedPerformanceCounter implements TimerList
this.route = route;
this.context = context;
this.description = route.getDescription();
+ this.configurationId = route.getConfigurationId();
this.jmxDomain = context.getManagementStrategy().getManagementAgent().getMBeanObjectDomainName();
}
@@ -143,6 +145,11 @@ public class ManagedRoute extends ManagedPerformanceCounter implements TimerList
}
@Override
+ public String getRouteConfigurationId() {
+ return configurationId;
+ }
+
+ @Override
public String getEndpointUri() {
if (route.getEndpoint() != null) {
return route.getEndpoint().getEndpointUri();
@@ -171,10 +178,6 @@ public class ManagedRoute extends ManagedPerformanceCounter implements TimerList
return route.getUptimeMillis();
}
- public Integer getInflightExchanges() {
- return (int) super.getExchangesInflight();
- }
-
@Override
public String getCamelId() {
return context.getName();
@@ -646,6 +649,10 @@ public class ManagedRoute extends ManagedPerformanceCounter implements TimerList
}
}
+ private Integer getInflightExchanges() {
+ return (int) super.getExchangesInflight();
+ }
+
/**
* Used for sorting the processor mbeans accordingly to their index.
*/
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 d444e5e..b33981d 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
@@ -936,6 +936,53 @@ public class ModelParser extends BaseParser {
return identifiedTypeAttributeHandler().accept(def, key, val);
}, noElementHandler(), noValueHandler());
}
+ protected RouteConfigurationDefinition doParseRouteConfigurationDefinition() throws IOException, XmlPullParserException {
+ return doParse(new RouteConfigurationDefinition(),
+ optionalIdentifiedDefinitionAttributeHandler(), (def, key) -> {
+ switch (key) {
+ case "interceptFrom": doAdd(doParseInterceptFromDefinition(), def.getInterceptFroms(), def::setInterceptFroms); break;
+ case "interceptSendToEndpoint": doAdd(doParseInterceptSendToEndpointDefinition(), def.getInterceptSendTos(), def::setInterceptSendTos); break;
+ case "intercept": doAdd(doParseInterceptDefinition(), def.getIntercepts(), def::setIntercepts); break;
+ case "onCompletion": doAdd(doParseOnCompletionDefinition(), def.getOnCompletions(), def::setOnCompletions); break;
+ case "onException": doAdd(doParseOnExceptionDefinition(), def.getOnExceptions(), def::setOnExceptions); break;
+ default: return optionalIdentifiedDefinitionElementHandler().accept(def, key);
+ }
+ return true;
+ }, noValueHandler());
+ }
+ public Optional<RouteConfigurationsDefinition> parseRouteConfigurationsDefinition()
+ throws IOException, XmlPullParserException {
+ String tag = getNextTag("routeConfigurations", "routeConfiguration");
+ if (tag != null) {
+ switch (tag) {
+ case "routeConfigurations" : return Optional.of(doParseRouteConfigurationsDefinition());
+ case "routeConfiguration" : return parseSingleRouteConfigurationsDefinition();
+ }
+ }
+ return Optional.empty();
+ }
+ private Optional<RouteConfigurationsDefinition> parseSingleRouteConfigurationsDefinition()
+ throws IOException, XmlPullParserException {
+ Optional<RouteConfigurationDefinition> single = Optional.of(doParseRouteConfigurationDefinition());
+ if (single.isPresent()) {
+ List<RouteConfigurationDefinition> list = new ArrayList<>();
+ list.add(single.get());
+ RouteConfigurationsDefinition def = new RouteConfigurationsDefinition();
+ def.setRouteConfigurations(list);
+ return Optional.of(def);
+ }
+ return Optional.empty();
+ }
+ protected RouteConfigurationsDefinition doParseRouteConfigurationsDefinition() throws IOException, XmlPullParserException {
+ return doParse(new RouteConfigurationsDefinition(),
+ noAttributeHandler(), (def, key) -> {
+ if ("routeConfiguration".equals(key)) {
+ doAdd(doParseRouteConfigurationDefinition(), def.getRouteConfigurations(), def::setRouteConfigurations);
+ return true;
+ }
+ return false;
+ }, noValueHandler());
+ }
protected RouteContextRefDefinition doParseRouteContextRefDefinition() throws IOException, XmlPullParserException {
return doParse(new RouteContextRefDefinition(), (def, key, val) -> {
if ("ref".equals(key)) {
@@ -954,6 +1001,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 "routeConfigurationId": def.setRouteConfigurationId(val); break;
case "routePolicyRef": def.setRoutePolicyRef(val); break;
case "shutdownRoute": def.setShutdownRoute(val); break;
case "shutdownRunningTask": def.setShutdownRunningTask(val); break;
diff --git a/docs/user-manual/modules/ROOT/nav.adoc b/docs/user-manual/modules/ROOT/nav.adoc
index 4facacc..e877c00 100644
--- a/docs/user-manual/modules/ROOT/nav.adoc
+++ b/docs/user-manual/modules/ROOT/nav.adoc
@@ -82,6 +82,7 @@
** xref:lambda-route-builder.adoc[LambdaRouteBuilder]
** xref:route-controller.adoc[RouteController]
** xref:route-policy.adoc[RoutePolicy]
+** xref:route-configuration.adoc[RouteConfiguration]
** xref:route-template.adoc[RouteTemplate]
** xref:routes.adoc[Routes]
** xref:stream-caching.adoc[Stream caching]
diff --git a/docs/user-manual/modules/ROOT/pages/index.adoc b/docs/user-manual/modules/ROOT/pages/index.adoc
index 86bce1c..36a57b0 100644
--- a/docs/user-manual/modules/ROOT/pages/index.adoc
+++ b/docs/user-manual/modules/ROOT/pages/index.adoc
@@ -117,6 +117,7 @@ camel routes without them knowing
* xref:lambda-route-builder.adoc[LambdaRouteBuilder]
* xref:route-controller.adoc[RouteController]
* xref:route-policy.adoc[RoutePolicy]
+* xref:route-configuration.adoc[RouteConfiguration]
* xref:route-template.adoc[RouteTemplate]
* xref:routes.adoc[Routes]
* xref:stream-caching.adoc[Stream caching]
diff --git a/docs/user-manual/modules/ROOT/pages/route-configuration.adoc b/docs/user-manual/modules/ROOT/pages/route-configuration.adoc
new file mode 100644
index 0000000..f0c5acb
--- /dev/null
+++ b/docs/user-manual/modules/ROOT/pages/route-configuration.adoc
@@ -0,0 +1,294 @@
+[[RouteConfiguration]]
+= Route Configuration
+
+Camel 3.12 introduces route configuration which is used for separating configurations
+from the routes. This can be used in situations such as configuring different error handling across a set of routes.
+In previous versions of Camel this was more cumbersome to do, as you would either have
+to copy the same configuration to a set of routes or rely on global error handling configuration.
+
+Now you can configure a number of route configurations, and then specify on each route
+which configuration to use (you can use match by ids, wildcards, and regular expression).
+
+The route configuration is supported by all DSL's, so useable by: Java, XML, Groovy, XML, Kotlin and so forth.
+
+In the route configuration you can setup common strategies for:
+
+- error handling via `onException`
+- interceptors via `intercept`, `interceptFrom`, `interceptSendTo`
+- on completions via `onCompletion`
+
+
+== Route Configuration Builder in Java DSL
+
+With Java DSL you can use `RouteConfigurationBuilder` to specify the configuration as shown below.
+The builder is similar to `RouteBuilder` so its familiar how to use.
+
+[source,java]
+----
+public class MyJavaErrorHandler extends RouteConfigurationBuilder {
+
+ @Override
+ public void configuration() throws Exception {
+ routeConfiguration("javaError")
+ .onException(Exception.class).handled(true)
+ .log("Java WARN: ${exception.message}");
+ }
+}
+----
+
+NOTE: The `RouteConfigurationBuilder` uses `configuration` as the method where the configuration is coded.
+This is on purpose to not use the `configure` method which the regular Java DSL `RouteBuilder`
+uses for coding Camel routes.
+
+In the example above, then there is only one route configuration which has been assigned the ID _javaError_.
+This ID allows us to refer to this configuration later when you want to assign which routes are using the configuration.
+
+This configuration is a basic configuration that just catches and handles all exceptions and logs a WARN message.
+
+=== Assigning route configurations to routes
+
+To use this configuration in your routes, then you can assign it with `routeConfigurationId` as shown:
+
+[source,java]
+----
+public class MyJavaRouteBuilder extends RouteBuilder {
+
+ @Override
+ public void configure() throws Exception {
+ from("timer:java?period=2s")
+ // refer to the route configuration by the id to use for this route
+ .routeConfigurationId("javaError")
+ .setBody(method(MyJavaRouteBuilder.class, "randomNumber"))
+ .log("Random number ${body}")
+ .filter(simple("${body} < 30"))
+ .throwException(new IllegalArgumentException("The number is too low"));
+ }
+
+ public static int randomNumber() {
+ return new Random().nextInt(100);
+ }
+}
+----
+
+In the `routeConfigurationId` the configuration to use is specified by the ID, eg _javaError_.
+
+Multiple configurations can be assigned (separated by comma), such as:
+
+[source,java]
+----
+.routeConfigurationId("javaError,myAudit")
+----
+
+The route configurations supports matching by:
+
+- match by exact ID name. This is the sample we have seen above.
+- match by wildcard
+- match by regular expression.
+
+Wildcards is match that the text before the * is matched against the given configuration and if it also starts with the same characters its a match. For instance you can do:
+
+[source,java]
+----
+.routeConfigurationId("java*,myAudit")
+----
+
+Here we use wildcard in _java*_ which means any configuration that starts with java is a match.
+
+Match by regular expression is just like match by wildcard but using regex instead.
+
+[source,java]
+----
+.routeConfigurationId(".*error.*")
+----
+
+Here we want to match any routes that has _error_ in the name.
+
+=== Adding route configurations to CamelContext
+
+Because a `RouteConfigurationBuilder` is also a `RouteBuilder` then you add route configurations
+the same way for `RouteBuilder` such as using the API on `CamelContext`
+
+[source,java]
+----
+CamelContext context = ...
+// add the route configuration
+context.addRoutes(new MyJavaErrorHandler());
+// add the regular route
+context.addRoutes(new MyJavaRouteBuilder());
+----
+
+If you use Spring Boot, then your Camel routes and route configurations can be auto-discovered
+by the spring boot component scanning. This requires to add `@Component` annotation to the class.
+
+See the example https://github.com/apache/camel-spring-boot-examples/tree/main/routes-configuration[camel-example-spring-boot-routes-configuration].
+
+
+=== Route configuration with Endpoint DSL
+
+The xref:Endpoint-dsl.adoc[Endpoint DSL] can also be used for route configurations.
+This requires to add `camel-endpointdsl` to the classpath, and then use
+`org.apache.camel.builder.endpoint.EndpointRouteConfigurationBuilder`,
+which offers the _type safe_ DSL for Camel endpoints.
+
+
+== Default route configurations
+
+Route configurations are either given an explicit unique ID, or the configuration is _nameless_.
+A _nameless_ configuration is used as default/fallback configuration, for routes which has *NOT*
+been explicit assigned route configurations.
+
+Suppose you have one _nameless_ configuration and another named _javaError_:
+
+[source,java]
+----
+public class MyJavaErrorHandler extends RouteConfigurationBuilder {
+
+ @Override
+ public void configuration() throws Exception {
+ routeConfiguration()
+ .onException(Exception.class).handled(true)
+ .log("WARN: ${exception.message}");
+
+ routeConfiguration("retryError")
+ .onException(Exception.class).maximumRedeliveries(5);
+ }
+}
+----
+
+And the follow two routes:
+
+[source,java]
+----
+ from("file:cheese").routeId("cheese")
+ .to("kafka:cheese");
+
+ from("file:beer").routeId("beer")
+ .routeConfigurationId("retryError")
+ .to("jms:beer");
+----
+
+In the example above, then the _cheese_ route has no route configurations assigned, so the route
+will use the default configuration, which in case of an exception will log a warning.
+
+The _beer_ route on the other hand have route configuration _retryError_ assigned, and this
+configuration will in case of an exception retry again up till 5 times and then if still an error
+then fail and rollback.
+
+If you add more routes, then those routes can also be assigned the _retryError_ configuration
+if they should also retry in case of error.
+
+
+== Route Configuration in XML
+
+When using XML DSL then you can code your route configurations in XML files as shown below:
+
+[source,xml]
+----
+<routeConfiguration id="xmlError">
+ <onException>
+ <exception>java.lang.Exception</exception>
+ <handled><constant>true</constant></handled>
+ <log message="XML WARN: ${exception.message}"/>
+ </onException>
+</routeConfiguration>
+----
+
+And in the XML routes you can assign which configurations to use:
+
+[source,xml]
+----
+<route routeConfigurationId="xmlError">
+ <from uri="timer:xml?period=5s"/>
+ <log message="I am XML"/>
+ <throwException exceptionType="java.lang.Exception" message="Some kind of XML error"/>
+</route>
+----
+
+In this example the route is assigned the _xmlError_ route configuration by the exact ID.
+
+
+== Route Configuration in YAML
+
+When using YAML DSL then you can code your route configurations in YAML files as shown below:
+
+[source,yaml]
+----
+- route-configuration:
+ - id: "yamlError"
+ - on-exception:
+ handled:
+ constant: "true"
+ exception:
+ - "java.lang.Exception"
+ steps:
+ - log:
+ message: "YAML WARN ${exception.message}"
+----
+
+And in the YAML routes you can assign which configurations to use:
+
+[source,yaml]
+----
+- route:
+ # refer to the route configuration by the id to use for this route
+ route-configuration-id: "yamlError"
+ from: "timer:yaml?period=3s"
+ steps:
+ - set-body:
+ simple: "Timer fired ${header.CamelTimerCounter} times"
+ - to:
+ uri: "log:yaml"
+ parameters:
+ show-body-type: false
+ show-exchange-pattern: false
+ - throw-exception:
+ exception-type: "java.lang.IllegalArgumentException"
+ message: "Error from yaml"
+----
+
+In this example the route is assigned the _yamlError_ route configuration by the exact ID.
+
+== Mixing DSLs
+
+Routes and route configuration is not requires to use the same language. For example you can code
+route configurations in Java, and then use XML DSL for the routes, and they would work together.
+
+== Packaging route configurations in reusable JARs
+
+You can package common route configurations into JARs which you can then use together with
+your Camel applications, by adding the JARs as dependencies to the classpath (such as in Maven pom.xml file).
+
+This allows for example to use a _common practice_ among your Camel applications.
+
+== Logging Summary
+
+If you set `startup-summary-level=verbose` then Camel will log on for each route which route configurations they have been assigned.
+
+This option can be configured via Java API and also in `application.properties` for Camel on Spring Boot, Quarkus, and Camel standalone via `camel-main`
+
+[source,java]
+----
+camelContext.setStartupSummaryLevel(StartupSummaryLevel.Verbose);
+----
+
+And with Spring Boot:
+
+[source,properties]
+----
+camel.spring-boot.startup-summary-level = verbose
+----
+
+And in Camel Main / Quarkus:
+
+[source,properties]
+----
+camel.main.startup-summary-level = verbose
+----
+
+== See Also
+
+See the examples:
+
+- https://github.com/apache/camel-examples/tree/main/examples/routes-configuration[camel-example-routes-configuration]
+- https://github.com/apache/camel-spring-boot-examples/tree/main/routes-configuration[camel-example-spring-boot-routes-configuration]
+
diff --git a/dsl/camel-dsl-support/src/main/java/org/apache/camel/dsl/support/RouteBuilderLoaderSupport.java b/dsl/camel-dsl-support/src/main/java/org/apache/camel/dsl/support/RouteBuilderLoaderSupport.java
index 021d007..b0b846e 100644
--- a/dsl/camel-dsl-support/src/main/java/org/apache/camel/dsl/support/RouteBuilderLoaderSupport.java
+++ b/dsl/camel-dsl-support/src/main/java/org/apache/camel/dsl/support/RouteBuilderLoaderSupport.java
@@ -16,6 +16,7 @@
*/
package org.apache.camel.dsl.support;
+import org.apache.camel.CamelContextAware;
import org.apache.camel.ExtendedCamelContext;
import org.apache.camel.RoutesBuilder;
import org.apache.camel.StartupStep;
@@ -57,6 +58,7 @@ public abstract class RouteBuilderLoaderSupport extends RoutesBuilderLoaderSuppo
@Override
public RoutesBuilder loadRoutesBuilder(Resource resource) throws Exception {
final RouteBuilder builder = doLoadRouteBuilder(resource);
+ CamelContextAware.trySetCamelContext(builder, getCamelContext());
if (recorder != null) {
StartupStep step = recorder.beginStep(
diff --git a/dsl/camel-xml-io-dsl/src/main/java/org/apache/camel/dsl/xml/io/XmlRoutesBuilderLoader.java b/dsl/camel-xml-io-dsl/src/main/java/org/apache/camel/dsl/xml/io/XmlRoutesBuilderLoader.java
index 816b71a..27cab1d 100644
--- a/dsl/camel-xml-io-dsl/src/main/java/org/apache/camel/dsl/xml/io/XmlRoutesBuilderLoader.java
+++ b/dsl/camel-xml-io-dsl/src/main/java/org/apache/camel/dsl/xml/io/XmlRoutesBuilderLoader.java
@@ -18,11 +18,15 @@ package org.apache.camel.dsl.xml.io;
import java.io.InputStream;
+import org.apache.camel.CamelContextAware;
import org.apache.camel.api.management.ManagedResource;
import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.builder.RouteConfigurationBuilder;
import org.apache.camel.dsl.support.RouteBuilderLoaderSupport;
+import org.apache.camel.model.ModelCamelContext;
+import org.apache.camel.model.RouteConfigurationDefinition;
+import org.apache.camel.model.RouteConfigurationsDefinition;
import org.apache.camel.model.RouteDefinition;
-import org.apache.camel.model.RouteDefinitionHelper;
import org.apache.camel.model.RoutesDefinition;
import org.apache.camel.spi.Resource;
import org.apache.camel.spi.annotations.RoutesLoader;
@@ -40,7 +44,7 @@ public class XmlRoutesBuilderLoader extends RouteBuilderLoaderSupport {
@Override
public RouteBuilder doLoadRouteBuilder(Resource resource) throws Exception {
- return new RouteBuilder() {
+ return new RouteConfigurationBuilder() {
@Override
public void configure() throws Exception {
// we use configure to load the routes (with namespace and without namespace)
@@ -76,14 +80,30 @@ public class XmlRoutesBuilderLoader extends RouteBuilderLoaderSupport {
}
}
+ @Override
+ public void configuration() throws Exception {
+ try (InputStream is = resource.getInputStream()) {
+ new ModelParser(is)
+ .parseRouteConfigurationsDefinition()
+ .ifPresent(this::addConfigurations);
+ }
+ }
+
private void addRoutes(RoutesDefinition routes) {
- // xml routes must be marked as un-prepared as camel-core
- // must do special handling for XML DSL
+ CamelContextAware.trySetCamelContext(getRouteCollection(), getCamelContext());
+
+ // xml routes must be prepared in the same way java-dsl (via RoutesDefinition)
+ // so create a copy and use the fluent builder to add the route
for (RouteDefinition route : routes.getRoutes()) {
- RouteDefinitionHelper.prepareRoute(getCamelContext(), route);
- route.markPrepared();
+ getRouteCollection().route(route);
+ }
+ }
+
+ private void addConfigurations(RouteConfigurationsDefinition configurations) {
+ CamelContextAware.trySetCamelContext(getRouteCollection(), getCamelContext());
+ for (RouteConfigurationDefinition config : configurations.getRouteConfigurations()) {
+ getCamelContext().adapt(ModelCamelContext.class).addRouteConfiguration(config);
}
- setRouteCollection(routes);
}
};
}
diff --git a/dsl/camel-xml-jaxb-dsl/src/main/java/org/apache/camel/dsl/xml/jaxb/JaxbXmlRoutesBuilderLoader.java b/dsl/camel-xml-jaxb-dsl/src/main/java/org/apache/camel/dsl/xml/jaxb/JaxbXmlRoutesBuilderLoader.java
index c07a26b..024ac43 100644
--- a/dsl/camel-xml-jaxb-dsl/src/main/java/org/apache/camel/dsl/xml/jaxb/JaxbXmlRoutesBuilderLoader.java
+++ b/dsl/camel-xml-jaxb-dsl/src/main/java/org/apache/camel/dsl/xml/jaxb/JaxbXmlRoutesBuilderLoader.java
@@ -18,11 +18,11 @@ package org.apache.camel.dsl.xml.jaxb;
import java.io.InputStream;
+import org.apache.camel.CamelContextAware;
import org.apache.camel.api.management.ManagedResource;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.dsl.support.RouteBuilderLoaderSupport;
import org.apache.camel.model.RouteDefinition;
-import org.apache.camel.model.RouteDefinitionHelper;
import org.apache.camel.model.RouteTemplatesDefinition;
import org.apache.camel.model.RoutesDefinition;
import org.apache.camel.model.rest.RestsDefinition;
@@ -65,15 +65,12 @@ public class JaxbXmlRoutesBuilderLoader extends RouteBuilderLoaderSupport {
try (InputStream is = resource.getInputStream()) {
RoutesDefinition routes = loadRoutesDefinition(getCamelContext(), is);
if (routes != null) {
- // xml routes must be marked as un-prepared as camel-core
- // must do special handling for XML DSL
+ CamelContextAware.trySetCamelContext(getRouteCollection(), getCamelContext());
+ // xml routes must be prepared in the same way java-dsl (via RoutesDefinition)
+ // so create a copy and use the fluent builder to add the route
for (RouteDefinition route : routes.getRoutes()) {
- RouteDefinitionHelper.prepareRoute(getCamelContext(), route);
- route.markPrepared();
+ getRouteCollection().route(route);
}
-
- routes.getRoutes().forEach(RouteDefinition::markUnprepared);
- setRouteCollection(routes);
}
}
}
diff --git a/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/pom.xml b/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/pom.xml
index 3ccadeb..876ef1c 100644
--- a/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/pom.xml
+++ b/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/pom.xml
@@ -134,6 +134,8 @@
<bannedDefinition>org.apache.camel.model.RouteTemplateBeanDefinition</bannedDefinition>
<bannedDefinition>org.apache.camel.model.RoutesDefinition</bannedDefinition>
<bannedDefinition>org.apache.camel.model.RestsDefinition</bannedDefinition>
+ <bannedDefinition>org.apache.camel.model.RouteConfigurationDefinition</bannedDefinition>
+ <bannedDefinition>org.apache.camel.model.RouteConfigurationsDefinition</bannedDefinition>
</bannedDefinitions>
<additionalDefinitions>
<!-- saga -->
diff --git a/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/main/java/org/apache/camel/dsl/yaml/deserializers/CustomResolver.java b/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/main/java/org/apache/camel/dsl/yaml/deserializers/CustomResolver.java
index 08ac067..b69ff69 100644
--- a/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/main/java/org/apache/camel/dsl/yaml/deserializers/CustomResolver.java
+++ b/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/main/java/org/apache/camel/dsl/yaml/deserializers/CustomResolver.java
@@ -38,6 +38,9 @@ public class CustomResolver implements YamlDeserializerResolver {
case "route":
case "org.apache.camel.model.RouteDefinition":
return new RouteDefinitionDeserializer();
+ case "route-configuration":
+ case "org.apache.camel.model.RouteConfigurationDefinition":
+ return new RouteConfigurationDefinitionDeserializer();
case "template":
case "org.apache.camel.model.RouteTemplateDefinition":
return new RouteTemplateDefinitionDeserializer();
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
new file mode 100644
index 0000000..9311269
--- /dev/null
+++ b/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/main/java/org/apache/camel/dsl/yaml/deserializers/RouteConfigurationDefinitionDeserializer.java
@@ -0,0 +1,93 @@
+package org.apache.camel.dsl.yaml.deserializers;
+
+import org.apache.camel.dsl.yaml.common.YamlDeserializationContext;
+import org.apache.camel.dsl.yaml.common.YamlDeserializerBase;
+import org.apache.camel.dsl.yaml.common.YamlDeserializerResolver;
+import org.apache.camel.model.InterceptDefinition;
+import org.apache.camel.model.InterceptFromDefinition;
+import org.apache.camel.model.InterceptSendToEndpointDefinition;
+import org.apache.camel.model.OnCompletionDefinition;
+import org.apache.camel.model.OnExceptionDefinition;
+import org.apache.camel.model.RouteConfigurationDefinition;
+import org.apache.camel.spi.annotations.YamlProperty;
+import org.apache.camel.spi.annotations.YamlType;
+import org.snakeyaml.engine.v2.nodes.MappingNode;
+import org.snakeyaml.engine.v2.nodes.Node;
+import org.snakeyaml.engine.v2.nodes.NodeTuple;
+import org.snakeyaml.engine.v2.nodes.SequenceNode;
+
+@YamlType(
+ inline = true,
+ types = org.apache.camel.model.RouteConfigurationDefinition.class,
+ order = YamlDeserializerResolver.ORDER_DEFAULT,
+ nodes = "route-configuration",
+ properties = {
+ @YamlProperty(name = "id", 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",
+ type = "array:org.apache.camel.model.InterceptSendToEndpointDefinition"),
+ @YamlProperty(name = "on-completion", type = "array:org.apache.camel.model.OnCompletionDefinition"),
+ @YamlProperty(name = "on-exception", type = "array:org.apache.camel.model.OnExceptionDefinition")
+ })
+public class RouteConfigurationDefinitionDeserializer extends YamlDeserializerBase<RouteConfigurationDefinition> {
+ public RouteConfigurationDefinitionDeserializer() {
+ super(RouteConfigurationDefinition.class);
+ }
+
+ @Override
+ protected RouteConfigurationDefinition newInstance() {
+ return new RouteConfigurationDefinition();
+ }
+
+ @Override
+ public Object construct(Node node) {
+ final RouteConfigurationDefinition target = newInstance();
+
+ final YamlDeserializationContext dc = getDeserializationContext(node);
+ final SequenceNode sn = asSequenceNode(node);
+ for (Node item : sn.getValue()) {
+ final MappingNode bn = asMappingNode(item);
+ setDeserializationContext(item, dc);
+
+ for (NodeTuple tuple : bn.getValue()) {
+ final String key = asText(tuple.getKeyNode());
+ final Node val = tuple.getValueNode();
+ switch (key) {
+ case "id": {
+ target.setId(asText(val));
+ break;
+ }
+ case "on-exception":
+ setDeserializationContext(val, dc);
+ OnExceptionDefinition oed = asType(val, OnExceptionDefinition.class);
+ target.getOnExceptions().add(oed);
+ break;
+ case "on-completion":
+ setDeserializationContext(val, dc);
+ OnCompletionDefinition ocd = asType(val, OnCompletionDefinition.class);
+ target.getOnCompletions().add(ocd);
+ break;
+ case "intercept":
+ setDeserializationContext(val, dc);
+ InterceptDefinition id = asType(val, InterceptDefinition.class);
+ target.getIntercepts().add(id);
+ break;
+ case "intercept-from":
+ setDeserializationContext(val, dc);
+ InterceptFromDefinition ifd = asType(val, InterceptFromDefinition.class);
+ target.getInterceptFroms().add(ifd);
+ break;
+ case "intercept-send-to-endpoint":
+ setDeserializationContext(val, dc);
+ InterceptSendToEndpointDefinition isted = asType(val, InterceptSendToEndpointDefinition.class);
+ target.getInterceptSendTos().add(isted);
+ break;
+ }
+ }
+ }
+
+ return target;
+ }
+
+}
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 9170fcb..da7ca89 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
@@ -37,6 +37,7 @@ import org.snakeyaml.engine.v2.nodes.NodeTuple;
properties = {
@YamlProperty(name = "id", 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),
@YamlProperty(name = "steps", type = "array:org.apache.camel.model.ProcessorDefinition", required = true)
})
@@ -70,6 +71,9 @@ public class RouteDefinitionDeserializer extends YamlDeserializerBase<RouteDefin
case "group":
target.setGroup(asText(val));
break;
+ case "route-configuration-id":
+ target.setRouteConfigurationId(asText(val));
+ break;
case "from":
target.setInput(asType(val, FromDefinition.class));
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 39f7343..10e7ac6 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
@@ -2035,6 +2035,48 @@
} ],
"required" : [ "ref" ]
},
+ "org.apache.camel.model.RouteConfigurationDefinition" : {
+ "oneOf" : [ {
+ "type" : "string"
+ }, {
+ "type" : "object",
+ "properties" : {
+ "id" : {
+ "type" : "string"
+ },
+ "intercept" : {
+ "type" : "array",
+ "items" : {
+ "$ref" : "#/items/definitions/org.apache.camel.model.InterceptDefinition"
+ }
+ },
+ "intercept-from" : {
+ "type" : "array",
+ "items" : {
+ "$ref" : "#/items/definitions/org.apache.camel.model.InterceptFromDefinition"
+ }
+ },
+ "intercept-send-to-endpoint" : {
+ "type" : "array",
+ "items" : {
+ "$ref" : "#/items/definitions/org.apache.camel.model.InterceptSendToEndpointDefinition"
+ }
+ },
+ "on-completion" : {
+ "type" : "array",
+ "items" : {
+ "$ref" : "#/items/definitions/org.apache.camel.model.OnCompletionDefinition"
+ }
+ },
+ "on-exception" : {
+ "type" : "array",
+ "items" : {
+ "$ref" : "#/items/definitions/org.apache.camel.model.OnExceptionDefinition"
+ }
+ }
+ }
+ } ]
+ },
"org.apache.camel.model.RouteContextRefDefinition" : {
"type" : "object",
"properties" : {
@@ -2056,6 +2098,9 @@
"id" : {
"type" : "string"
},
+ "route-configuration-id" : {
+ "type" : "string"
+ },
"steps" : {
"type" : "array",
"items" : {
diff --git a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/main/java/org/apache/camel/dsl/yaml/YamlRoutesBuilderLoader.java b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/main/java/org/apache/camel/dsl/yaml/YamlRoutesBuilderLoader.java
index d16728d..50348b5 100644
--- a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/main/java/org/apache/camel/dsl/yaml/YamlRoutesBuilderLoader.java
+++ b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/main/java/org/apache/camel/dsl/yaml/YamlRoutesBuilderLoader.java
@@ -16,11 +16,14 @@
*/
package org.apache.camel.dsl.yaml;
+import org.apache.camel.CamelContextAware;
import org.apache.camel.api.management.ManagedResource;
import org.apache.camel.builder.ErrorHandlerBuilder;
import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.builder.RouteConfigurationBuilder;
import org.apache.camel.dsl.yaml.deserializers.OutputAwareFromDefinition;
import org.apache.camel.model.OnExceptionDefinition;
+import org.apache.camel.model.RouteConfigurationDefinition;
import org.apache.camel.model.RouteDefinition;
import org.apache.camel.model.RouteTemplateDefinition;
import org.apache.camel.model.rest.RestConfigurationDefinition;
@@ -42,7 +45,7 @@ public class YamlRoutesBuilderLoader extends YamlRoutesBuilderLoaderSupport {
}
protected RouteBuilder builder(Node root) {
- return new RouteBuilder() {
+ return new RouteConfigurationBuilder() {
@Override
public void configure() throws Exception {
for (Node node : asSequenceNode(root).getValue()) {
@@ -52,8 +55,11 @@ public class YamlRoutesBuilderLoader extends YamlRoutesBuilderLoaderSupport {
RouteDefinition route = new RouteDefinition();
route.setInput(((OutputAwareFromDefinition) item).getDelegate());
route.setOutputs(((OutputAwareFromDefinition) item).getOutputs());
+
+ CamelContextAware.trySetCamelContext(getRouteCollection(), getCamelContext());
getRouteCollection().route(route);
} else if (item instanceof RouteDefinition) {
+ CamelContextAware.trySetCamelContext(getRouteCollection(), getCamelContext());
getRouteCollection().route((RouteDefinition) item);
} else if (item instanceof CamelContextCustomizer) {
((CamelContextCustomizer) item).configure(getCamelContext());
@@ -62,6 +68,7 @@ public class YamlRoutesBuilderLoader extends YamlRoutesBuilderLoaderSupport {
throw new IllegalArgumentException(
"onException must be defined before any routes in the RouteBuilder");
}
+ CamelContextAware.trySetCamelContext(getRouteCollection(), getCamelContext());
getRouteCollection().getOnExceptions().add((OnExceptionDefinition) item);
} else if (item instanceof ErrorHandlerBuilder) {
if (!getRouteCollection().getRoutes().isEmpty()) {
@@ -70,12 +77,14 @@ public class YamlRoutesBuilderLoader extends YamlRoutesBuilderLoaderSupport {
}
errorHandler((ErrorHandlerBuilder) item);
} else if (item instanceof RouteTemplateDefinition) {
+ CamelContextAware.trySetCamelContext(getRouteTemplateCollection(), getCamelContext());
getRouteTemplateCollection().routeTemplate((RouteTemplateDefinition) item);
} else if (item instanceof RestDefinition) {
RestDefinition definition = (RestDefinition) item;
for (VerbDefinition verb : definition.getVerbs()) {
verb.setRest(definition);
}
+ CamelContextAware.trySetCamelContext(getRestCollection(), getCamelContext());
getRestCollection().rest(definition);
} else if (item instanceof RestConfigurationDefinition) {
((RestConfigurationDefinition) item).asRestConfiguration(
@@ -84,6 +93,17 @@ public class YamlRoutesBuilderLoader extends YamlRoutesBuilderLoaderSupport {
}
}
}
+
+ @Override
+ public void configuration() throws Exception {
+ for (Node node : asSequenceNode(root).getValue()) {
+ Object item = getDeserializationContext().mandatoryResolve(node).construct(node);
+ if (item instanceof RouteConfigurationDefinition) {
+ CamelContextAware.trySetCamelContext(getRouteConfigurationCollection(), getCamelContext());
+ getRouteConfigurationCollection().routeConfiguration((RouteConfigurationDefinition) item);
+ }
+ }
+ }
};
}
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
new file mode 100644
index 0000000..15550bf
--- /dev/null
+++ b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/RouteConfigurationTest.groovy
@@ -0,0 +1,169 @@
+/*
+ * 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.dsl.yaml
+
+import org.apache.camel.Exchange
+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.junit.jupiter.api.Assertions
+import org.junit.jupiter.api.Disabled
+
+class RouteConfigurationTest extends YamlTestSupport {
+ def "route-configuration"() {
+ setup:
+ loadRoutes """
+ - beans:
+ - name: myFailingProcessor
+ type: ${MyFailingProcessor.name}
+ - route-configuration:
+ - on-exception:
+ handled:
+ constant: "true"
+ exception:
+ - ${MyException.name}
+ steps:
+ - transform:
+ constant: "Sorry"
+ - to: "mock:on-exception"
+ - from:
+ uri: "direct:start"
+ steps:
+ - process:
+ ref: "myFailingProcessor"
+ """
+
+ withMock('mock:on-exception') {
+ expectedBodiesReceived 'Sorry'
+ }
+
+ when:
+ context.start()
+
+ withTemplate {
+ to('direct:start').withBody('hello').send()
+ }
+ then:
+ MockEndpoint.assertIsSatisfied(context)
+ }
+
+ def "route-configuration-separate"() {
+ setup:
+ // global configurations
+ loadRoutes """
+ - beans:
+ - name: myFailingProcessor
+ type: ${MyFailingProcessor.name}
+ - route-configuration:
+ - on-exception:
+ handled:
+ constant: "true"
+ exception:
+ - ${MyException.name}
+ steps:
+ - transform:
+ constant: "Sorry"
+ - to: "mock:on-exception"
+ """
+ // routes
+ loadRoutes """
+ - from:
+ uri: "direct:start"
+ steps:
+ - process:
+ ref: "myFailingProcessor"
+ - from:
+ uri: "direct:start2"
+ steps:
+ - process:
+ ref: "myFailingProcessor"
+ """
+
+ withMock('mock:on-exception') {
+ expectedBodiesReceived 'Sorry', 'Sorry'
+ }
+
+ when:
+ context.start()
+
+ withTemplate {
+ to('direct:start').withBody('hello').send()
+ to('direct:start2').withBody('hello2').send()
+ }
+ then:
+ MockEndpoint.assertIsSatisfied(context)
+ }
+
+ def "route-configuration-id"() {
+ setup:
+ // global configurations
+ loadRoutes """
+ - beans:
+ - name: myFailingProcessor
+ type: ${MyFailingProcessor.name}
+ - route-configuration:
+ - id: handleError
+ - on-exception:
+ handled:
+ constant: "true"
+ exception:
+ - ${MyException.name}
+ steps:
+ - transform:
+ constant: "Sorry"
+ - to: "mock:on-exception"
+ """
+ // routes
+ loadRoutes """
+ - route:
+ route-configuration-id: handleError
+ from:
+ uri: "direct:start"
+ steps:
+ - process:
+ ref: "myFailingProcessor"
+ - route:
+ from:
+ uri: "direct:start2"
+ steps:
+ - process:
+ ref: "myFailingProcessor"
+ """
+
+ withMock('mock:on-exception') {
+ expectedBodiesReceived 'Sorry'
+ }
+
+ when:
+ context.start()
+
+ Exchange out1
+ Exchange out2
+ withTemplate {
+ out1 = to('direct:start').withBody('hello').send()
+ out2 = to('direct:start2').withBody('hello2').send()
+ }
+
+ then:
+ MockEndpoint.assertIsSatisfied(context)
+
+ Assertions.assertFalse(out1.isFailed())
+ Assertions.assertTrue(out2.isFailed())
+ }
+
+}
diff --git a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/ModelXmlParserGeneratorMojo.java b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/ModelXmlParserGeneratorMojo.java
index bfc4cece..601dbf3 100644
--- a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/ModelXmlParserGeneratorMojo.java
+++ b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/ModelXmlParserGeneratorMojo.java
@@ -101,6 +101,7 @@ public class ModelXmlParserGeneratorMojo extends AbstractGeneratorMojo {
private Class<?> outputDefinitionClass;
private Class<?> expressionDefinitionClass;
private Class<?> routesDefinitionClass;
+ private Class<?> routeConfigurationsDefinitionClass;
private Class<?> routeTemplatesDefinitionClass;
private Class<?> restsDefinitionClass;
private Class<?> processorDefinitionClass;
@@ -134,6 +135,7 @@ public class ModelXmlParserGeneratorMojo extends AbstractGeneratorMojo {
outputDefinitionClass = loadClass(classLoader, MODEL_PACKAGE + ".OutputDefinition");
routesDefinitionClass = loadClass(classLoader, MODEL_PACKAGE + ".RoutesDefinition");
+ routeConfigurationsDefinitionClass = loadClass(classLoader, MODEL_PACKAGE + ".RouteConfigurationsDefinition");
routeTemplatesDefinitionClass = loadClass(classLoader, MODEL_PACKAGE + ".RouteTemplatesDefinition");
dataFormatDefinitionClass = loadClass(classLoader, MODEL_PACKAGE + ".DataFormatDefinition");
processorDefinitionClass = loadClass(classLoader, MODEL_PACKAGE + ".ProcessorDefinition");
@@ -476,7 +478,7 @@ public class ModelXmlParserGeneratorMojo extends AbstractGeneratorMojo {
}
return " noValueHandler()";
});
- if (clazz == routesDefinitionClass || clazz == routeTemplatesDefinitionClass || clazz == restsDefinitionClass) {
+ if (clazz == routesDefinitionClass || clazz == routeTemplatesDefinitionClass || clazz == restsDefinitionClass || clazz == routeConfigurationsDefinitionClass) {
// for routes/rests/routeTemplates we want to support single-mode as well, this means
// we check that the tag name is either plural or singular and parse accordingly