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

[camel] branch main updated (f3104f4f88c -> f3736179f2c)

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

davsclaus pushed a change to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git


    from f3104f4f88c CAMEL-17763: cleaned up unused exceptions in camel-swagger-java
     new 81c32ebe7af CAMEL-16834: error handler in DSL model
     new f3736179f2c Regen

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../camel/catalog/models/routeConfiguration.json   |   1 +
 .../apache/camel/catalog/schemas/camel-spring.xsd  |   1 +
 .../component/as2/api/protocol/ResponseMDN.java    |   3 +-
 .../camel/component/as2/AS2ClientManagerIT.java    |   3 +-
 .../component/olingo4/api/impl/Olingo4AppImpl.java |   6 +-
 .../salesforce/codegen/SchemaExecution.java        |   3 +-
 .../org/apache/camel/model/routeConfiguration.json |   1 +
 .../camel/model/RouteConfigurationDefinition.java  |  40 +++++-
 .../apache/camel/model/RouteDefinitionHelper.java  |  24 +++-
 .../org/apache/camel/model/RoutesDefinition.java   |  24 +++-
 .../core/xml/AbstractCamelContextFactoryBean.java  |  11 +-
 .../model/RoutesConfigurationErrorHandlerTest.java | 160 +++++++++++++++++++++
 .../java/org/apache/camel/xml/in/ModelParser.java  |   1 +
 .../modules/ROOT/pages/route-configuration.adoc    |  27 ++++
 .../RouteConfigurationDefinitionDeserializer.java  |   7 +
 .../src/generated/resources/camel-yaml-dsl.json    |   3 +
 .../src/generated/resources/camelYamlDsl.json      |   3 +
 .../camel/dsl/yaml/RouteConfigurationTest.groovy   |  42 ++++++
 18 files changed, 344 insertions(+), 16 deletions(-)
 create mode 100644 core/camel-core/src/test/java/org/apache/camel/model/RoutesConfigurationErrorHandlerTest.java


[camel] 02/02: Regen

Posted by da...@apache.org.
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

commit f3736179f2ce9c626d167e16e5b8ea7dc9e495ab
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Wed Apr 13 17:28:45 2022 +0200

    Regen
---
 .../org/apache/camel/component/as2/api/protocol/ResponseMDN.java    | 3 ++-
 .../java/org/apache/camel/component/as2/AS2ClientManagerIT.java     | 3 ++-
 .../org/apache/camel/component/olingo4/api/impl/Olingo4AppImpl.java | 6 ++++--
 .../apache/camel/component/salesforce/codegen/SchemaExecution.java  | 3 ++-
 4 files changed, 10 insertions(+), 5 deletions(-)

diff --git a/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/protocol/ResponseMDN.java b/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/protocol/ResponseMDN.java
index ba526ed7c11..ab1a32ba817 100644
--- a/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/protocol/ResponseMDN.java
+++ b/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/protocol/ResponseMDN.java
@@ -153,7 +153,8 @@ public class ResponseMDN implements HttpResponseInterceptor {
                     mdnMessageTemplate);
             multipartReportEntity = new DispositionNotificationMultipartReportEntity(
                     httpEntityEnclosingRequest, response, DispositionMode.AUTOMATIC_ACTION_MDN_SENT_AUTOMATICALLY,
-                    AS2DispositionType.PROCESSED, null, null, null, null, null, StandardCharsets.US_ASCII.name(), boundary, true,
+                    AS2DispositionType.PROCESSED, null, null, null, null, null, StandardCharsets.US_ASCII.name(), boundary,
+                    true,
                     decryptingPrivateKey, mdnMessage);
         }
 
diff --git a/components/camel-as2/camel-as2-component/src/test/java/org/apache/camel/component/as2/AS2ClientManagerIT.java b/components/camel-as2/camel-as2-component/src/test/java/org/apache/camel/component/as2/AS2ClientManagerIT.java
index a58d8c3159f..f055938ca76 100644
--- a/components/camel-as2/camel-as2-component/src/test/java/org/apache/camel/component/as2/AS2ClientManagerIT.java
+++ b/components/camel-as2/camel-as2-component/src/test/java/org/apache/camel/component/as2/AS2ClientManagerIT.java
@@ -702,7 +702,8 @@ public class AS2ClientManagerIT extends AbstractAS2ITSupport {
 
         // Create plain edi request message to acknowledge
         ApplicationEDIEntity ediEntity = EntityUtils.createEDIEntity(EDI_MESSAGE,
-                ContentType.create(AS2MediaType.APPLICATION_EDIFACT, StandardCharsets.US_ASCII), null, false, ATTACHED_FILE_NAME);
+                ContentType.create(AS2MediaType.APPLICATION_EDIFACT, StandardCharsets.US_ASCII), null, false,
+                ATTACHED_FILE_NAME);
         HttpEntityEnclosingRequest request = new BasicHttpEntityEnclosingRequest("POST", REQUEST_URI);
         HttpMessageUtils.setHeaderValue(request, AS2Header.SUBJECT, SUBJECT);
         String httpdate = DATE_GENERATOR.getCurrentDate();
diff --git a/components/camel-olingo4/camel-olingo4-api/src/main/java/org/apache/camel/component/olingo4/api/impl/Olingo4AppImpl.java b/components/camel-olingo4/camel-olingo4-api/src/main/java/org/apache/camel/component/olingo4/api/impl/Olingo4AppImpl.java
index d7f042efd5f..071d1e54b70 100644
--- a/components/camel-olingo4/camel-olingo4-api/src/main/java/org/apache/camel/component/olingo4/api/impl/Olingo4AppImpl.java
+++ b/components/camel-olingo4/camel-olingo4-api/src/main/java/org/apache/camel/component/olingo4/api/impl/Olingo4AppImpl.java
@@ -745,7 +745,8 @@ public final class Olingo4AppImpl implements Olingo4App {
                     batchRequestHeaderOutputStream.write(ODataStreamer.CRLF);
 
                     batchRequestHeaderOutputStream.write(
-                            (HttpGet.METHOD_NAME + " " + batchQueryUri + " " + HttpVersion.HTTP_1_1).getBytes(StandardCharsets.UTF_8));
+                            (HttpGet.METHOD_NAME + " " + batchQueryUri + " " + HttpVersion.HTTP_1_1)
+                                    .getBytes(StandardCharsets.UTF_8));
                     batchRequestHeaderOutputStream.write(ODataStreamer.CRLF);
                     final ContentType acceptType = getResourceContentType(uriInfo);
                     final String acceptCharset = acceptType.getParameter(ContentType.PARAMETER_CHARSET);
@@ -828,7 +829,8 @@ public final class Olingo4AppImpl implements Olingo4App {
         try {
             final Header[] contentHeaders = response.getHeaders(HttpHeader.CONTENT_TYPE);
             final ODataBatchLineIterator batchLineIterator
-                    = new ODataBatchLineIteratorImpl(IOUtils.lineIterator(response.getEntity().getContent(), StandardCharsets.UTF_8));
+                    = new ODataBatchLineIteratorImpl(
+                            IOUtils.lineIterator(response.getEntity().getContent(), StandardCharsets.UTF_8));
             final String batchBoundary = ODataBatchUtilities.getBoundaryFromHeader(getHeadersCollection(contentHeaders));
             final ODataBatchController batchController = new ODataBatchController(batchLineIterator, batchBoundary);
 
diff --git a/components/camel-salesforce/camel-salesforce-codegen/src/main/java/org/apache/camel/component/salesforce/codegen/SchemaExecution.java b/components/camel-salesforce/camel-salesforce-codegen/src/main/java/org/apache/camel/component/salesforce/codegen/SchemaExecution.java
index 303c9270a62..18e681e5e65 100644
--- a/components/camel-salesforce/camel-salesforce-codegen/src/main/java/org/apache/camel/component/salesforce/codegen/SchemaExecution.java
+++ b/components/camel-salesforce/camel-salesforce-codegen/src/main/java/org/apache/camel/component/salesforce/codegen/SchemaExecution.java
@@ -74,7 +74,8 @@ public class SchemaExecution extends AbstractSalesforceExecution {
         final Path schemaFilePath = outputDirectory.toPath().resolve(jsonSchemaFilename);
         try {
             Files.write(schemaFilePath,
-                    JsonUtils.getJsonSchemaString(schemaObjectMapper, allSchemas, jsonSchemaId).getBytes(StandardCharsets.UTF_8));
+                    JsonUtils.getJsonSchemaString(schemaObjectMapper, allSchemas, jsonSchemaId)
+                            .getBytes(StandardCharsets.UTF_8));
         } catch (final IOException e) {
             throw new RuntimeException("Unable to generate JSON Schema source file: " + schemaFilePath, e);
         }


[camel] 01/02: CAMEL-16834: error handler in DSL model

Posted by da...@apache.org.
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

commit 81c32ebe7af5624d0f29722297363a5498b65fb3
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Wed Apr 13 16:42:52 2022 +0200

    CAMEL-16834: error handler in DSL model
---
 .../camel/catalog/models/routeConfiguration.json   |   1 +
 .../apache/camel/catalog/schemas/camel-spring.xsd  |   1 +
 .../org/apache/camel/model/routeConfiguration.json |   1 +
 .../camel/model/RouteConfigurationDefinition.java  |  40 +++++-
 .../apache/camel/model/RouteDefinitionHelper.java  |  24 +++-
 .../org/apache/camel/model/RoutesDefinition.java   |  24 +++-
 .../core/xml/AbstractCamelContextFactoryBean.java  |  11 +-
 .../model/RoutesConfigurationErrorHandlerTest.java | 160 +++++++++++++++++++++
 .../java/org/apache/camel/xml/in/ModelParser.java  |   1 +
 .../modules/ROOT/pages/route-configuration.adoc    |  27 ++++
 .../RouteConfigurationDefinitionDeserializer.java  |   7 +
 .../src/generated/resources/camel-yaml-dsl.json    |   3 +
 .../src/generated/resources/camelYamlDsl.json      |   3 +
 .../camel/dsl/yaml/RouteConfigurationTest.groovy   |  42 ++++++
 14 files changed, 334 insertions(+), 11 deletions(-)

diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/routeConfiguration.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/routeConfiguration.json
index a1b45b6bb7c..5e560cdfaad 100644
--- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/routeConfiguration.json
+++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/routeConfiguration.json
@@ -12,6 +12,7 @@
     "output": false
   },
   "properties": {
+    "errorHandler": { "kind": "element", "displayName": "Error Handler", "required": false, "type": "object", "javaType": "org.apache.camel.model.ErrorHandlerDefinition", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the error handler to use, for routes that has not already been configured with an error handler." },
     "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" },
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 72e6d5fa578..0c731250a98 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
@@ -10535,6 +10535,7 @@ Reference to the route templates in the xml dsl.
     <xs:complexContent>
       <xs:extension base="tns:optionalIdentifiedDefinition">
         <xs:sequence>
+          <xs:element minOccurs="0" ref="tns:errorHandler"/>
           <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"/>
diff --git a/core/camel-core-model/src/generated/resources/org/apache/camel/model/routeConfiguration.json b/core/camel-core-model/src/generated/resources/org/apache/camel/model/routeConfiguration.json
index a1b45b6bb7c..5e560cdfaad 100644
--- a/core/camel-core-model/src/generated/resources/org/apache/camel/model/routeConfiguration.json
+++ b/core/camel-core-model/src/generated/resources/org/apache/camel/model/routeConfiguration.json
@@ -12,6 +12,7 @@
     "output": false
   },
   "properties": {
+    "errorHandler": { "kind": "element", "displayName": "Error Handler", "required": false, "type": "object", "javaType": "org.apache.camel.model.ErrorHandlerDefinition", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the error handler to use, for routes that has not already been configured with an error handler." },
     "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" },
diff --git a/core/camel-core-model/src/main/java/org/apache/camel/model/RouteConfigurationDefinition.java b/core/camel-core-model/src/main/java/org/apache/camel/model/RouteConfigurationDefinition.java
index 1a7b65f59a1..0d509cef27d 100644
--- a/core/camel-core-model/src/main/java/org/apache/camel/model/RouteConfigurationDefinition.java
+++ b/core/camel-core-model/src/main/java/org/apache/camel/model/RouteConfigurationDefinition.java
@@ -26,6 +26,8 @@ import javax.xml.bind.annotation.XmlAttribute;
 import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlRootElement;
 
+import org.apache.camel.ErrorHandlerFactory;
+import org.apache.camel.model.errorhandler.ErrorHandlerRefDefinition;
 import org.apache.camel.spi.Metadata;
 
 /**
@@ -37,8 +39,8 @@ import org.apache.camel.spi.Metadata;
 public class RouteConfigurationDefinition extends OptionalIdentifiedDefinition<RouteConfigurationDefinition>
         implements PreconditionContainer {
 
-    // TODO: Model for ErrorHandler (requires to move error handler model from spring-xml, blueprint to core)
-
+    @XmlElement
+    private ErrorHandlerDefinition errorHandler;
     @XmlElement(name = "intercept")
     private List<InterceptDefinition> intercepts = new ArrayList<>();
     @XmlElement(name = "interceptFrom")
@@ -71,6 +73,14 @@ public class RouteConfigurationDefinition extends OptionalIdentifiedDefinition<R
         return "RoutesConfiguration " + getId();
     }
 
+    public ErrorHandlerDefinition getErrorHandler() {
+        return errorHandler;
+    }
+
+    public void setErrorHandler(ErrorHandlerDefinition errorHandler) {
+        this.errorHandler = errorHandler;
+    }
+
     public List<OnExceptionDefinition> getOnExceptions() {
         return onExceptions;
     }
@@ -132,6 +142,32 @@ public class RouteConfigurationDefinition extends OptionalIdentifiedDefinition<R
     // Fluent API
     // -------------------------------------------------------------------------
 
+    /**
+     * Sets the error handler to use, for routes that has not already been configured with an error handler.
+     *
+     * @param  ref reference to existing error handler
+     * @return     the builder
+     */
+    public RouteConfigurationDefinition errorHandler(String ref) {
+        ErrorHandlerDefinition def = new ErrorHandlerDefinition();
+        def.setErrorHandlerType(new ErrorHandlerRefDefinition(ref));
+        setErrorHandler(def);
+        return this;
+    }
+
+    /**
+     * Sets the error handler to use, for routes that has not already been configured with an error handler.
+     *
+     * @param  errorHandler the error handler
+     * @return              the builder
+     */
+    public RouteConfigurationDefinition errorHandler(ErrorHandlerFactory errorHandler) {
+        ErrorHandlerDefinition def = new ErrorHandlerDefinition();
+        def.setErrorHandlerType(errorHandler);
+        setErrorHandler(def);
+        return this;
+    }
+
     /**
      * Sets the predicate of the precondition in simple language to evaluate in order to determine if this route
      * configuration should be included or not.
diff --git a/core/camel-core-model/src/main/java/org/apache/camel/model/RouteDefinitionHelper.java b/core/camel-core-model/src/main/java/org/apache/camel/model/RouteDefinitionHelper.java
index 98b9d1923f5..e1d072d2a29 100644
--- a/core/camel-core-model/src/main/java/org/apache/camel/model/RouteDefinitionHelper.java
+++ b/core/camel-core-model/src/main/java/org/apache/camel/model/RouteDefinitionHelper.java
@@ -307,7 +307,7 @@ public final class RouteDefinitionHelper {
      * @param route   the route
      */
     public static void prepareRoute(CamelContext context, RouteDefinition route) {
-        prepareRoute(context, route, null, null, null, null, null);
+        prepareRoute(context, route, null, null, null, null, null, null);
     }
 
     /**
@@ -317,6 +317,7 @@ public final class RouteDefinitionHelper {
      *
      * @param context                            the camel context
      * @param route                              the route
+     * @param errorHandler                       optional error handler
      * @param onExceptions                       optional list of onExceptions
      * @param intercepts                         optional list of interceptors
      * @param interceptFromDefinitions           optional list of interceptFroms
@@ -324,13 +325,16 @@ public final class RouteDefinitionHelper {
      * @param onCompletions                      optional list onCompletions
      */
     public static void prepareRoute(
-            CamelContext context, RouteDefinition route, List<OnExceptionDefinition> onExceptions,
+            CamelContext context, RouteDefinition route,
+            ErrorHandlerDefinition errorHandler,
+            List<OnExceptionDefinition> onExceptions,
             List<InterceptDefinition> intercepts,
             List<InterceptFromDefinition> interceptFromDefinitions,
             List<InterceptSendToEndpointDefinition> interceptSendToEndpointDefinitions,
             List<OnCompletionDefinition> onCompletions) {
 
-        prepareRouteImp(context, route, onExceptions, intercepts, interceptFromDefinitions, interceptSendToEndpointDefinitions,
+        prepareRouteImp(context, route, errorHandler, onExceptions, intercepts, interceptFromDefinitions,
+                interceptSendToEndpointDefinitions,
                 onCompletions);
     }
 
@@ -341,6 +345,7 @@ public final class RouteDefinitionHelper {
      *
      * @param context                            the camel context
      * @param route                              the route
+     * @param errorHandler                       optional error handler
      * @param onExceptions                       optional list of onExceptions
      * @param intercepts                         optional list of interceptors
      * @param interceptFromDefinitions           optional list of interceptFroms
@@ -348,7 +353,9 @@ public final class RouteDefinitionHelper {
      * @param onCompletions                      optional list onCompletions
      */
     private static void prepareRouteImp(
-            CamelContext context, RouteDefinition route, List<OnExceptionDefinition> onExceptions,
+            CamelContext context, RouteDefinition route,
+            ErrorHandlerDefinition errorHandler,
+            List<OnExceptionDefinition> onExceptions,
             List<InterceptDefinition> intercepts,
             List<InterceptFromDefinition> interceptFromDefinitions,
             List<InterceptSendToEndpointDefinition> interceptSendToEndpointDefinitions,
@@ -370,7 +377,7 @@ public final class RouteDefinitionHelper {
         RouteDefinitionHelper.prepareRouteForInit(route, abstracts, lower);
 
         // parent and error handler builder should be initialized first
-        initParentAndErrorHandlerBuilder(context, route, abstracts, onExceptions);
+        initParentAndErrorHandlerBuilder(context, route, errorHandler, abstracts, onExceptions);
         // validate top-level violations
         validateTopLevel(route.getOutputs());
         // then interceptors
@@ -440,10 +447,13 @@ public final class RouteDefinitionHelper {
     }
 
     private static void initParentAndErrorHandlerBuilder(
-            CamelContext context, RouteDefinition route, List<ProcessorDefinition<?>> abstracts,
+            CamelContext context, RouteDefinition route, ErrorHandlerDefinition errorHandler,
+            List<ProcessorDefinition<?>> abstracts,
             List<OnExceptionDefinition> onExceptions) {
 
-        if (context != null) {
+        if (errorHandler != null) {
+            route.setErrorHandlerFactoryIfNull(errorHandler.getErrorHandlerType());
+        } else if (context != null) {
             // let the route inherit the error handler builder from camel
             // context if none already set
 
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 f53235dc458..7c582c65bfb 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
@@ -18,6 +18,7 @@ package org.apache.camel.model;
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.concurrent.atomic.AtomicReference;
 
 import javax.xml.bind.annotation.XmlAccessType;
 import javax.xml.bind.annotation.XmlAccessorType;
@@ -241,6 +242,7 @@ public class RoutesDefinition extends OptionalIdentifiedDefinition<RoutesDefinit
         route.setResource(resource);
 
         // merge global and route scoped together
+        final AtomicReference<ErrorHandlerDefinition> gcErrorHandler = new AtomicReference<>();
         List<OnExceptionDefinition> oe = new ArrayList<>(onExceptions);
         List<InterceptDefinition> icp = new ArrayList<>(intercepts);
         List<InterceptFromDefinition> ifrom = new ArrayList<>(interceptFroms);
@@ -250,6 +252,7 @@ public class RoutesDefinition extends OptionalIdentifiedDefinition<RoutesDefinit
             List<RouteConfigurationDefinition> globalConfigurations
                     = getCamelContext().adapt(ModelCamelContext.class).getRouteConfigurationDefinitions();
             if (globalConfigurations != null) {
+
                 // if there are multiple ids configured then we should apply in that same order
                 String[] ids = route.getRouteConfigurationId() != null
                         ? route.getRouteConfigurationId().split(",") : new String[] { "*" };
@@ -266,6 +269,12 @@ public class RoutesDefinition extends OptionalIdentifiedDefinition<RoutesDefinit
                                 }
                             })
                             .forEach(g -> {
+                                // there can only be one global error handler, so override previous, meaning
+                                // that we will pick the last in the sort (take precedence)
+                                if (g.getErrorHandler() != null) {
+                                    gcErrorHandler.set(g.getErrorHandler());
+                                }
+
                                 String aid = g.getId() == null ? "<default>" : g.getId();
                                 // remember the id that was used on the route
                                 route.addAppliedRouteConfigurationId(aid);
@@ -276,11 +285,24 @@ public class RoutesDefinition extends OptionalIdentifiedDefinition<RoutesDefinit
                                 oc.addAll(g.getOnCompletions());
                             });
                 }
+
+                // set error handler before prepare
+                if (errorHandlerFactory == null && gcErrorHandler.get() != null) {
+                    ErrorHandlerDefinition ehd = gcErrorHandler.get();
+                    route.setErrorHandlerFactoryIfNull(ehd.getErrorHandlerType());
+                }
             }
         }
 
+        // if the route does not already have an error handler set then use route configured error handler
+        // if one was configured
+        ErrorHandlerDefinition ehd = null;
+        if (errorHandlerFactory == null && gcErrorHandler.get() != null) {
+            ehd = gcErrorHandler.get();
+        }
+
         // must prepare the route before we can add it to the routes list
-        RouteDefinitionHelper.prepareRoute(getCamelContext(), route, oe, icp, ifrom, ito, oc);
+        RouteDefinitionHelper.prepareRoute(getCamelContext(), route, ehd, oe, icp, ifrom, ito, oc);
 
         if (LOG.isDebugEnabled() && route.getAppliedRouteConfigurationIds() != null) {
             LOG.debug("Route: {} is using route configurations ids: {}", route.getId(),
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 adbd809e0c9..b9238c769fa 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
@@ -25,6 +25,7 @@ import java.util.Map.Entry;
 import java.util.Set;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicReference;
 
 import javax.xml.bind.annotation.XmlAccessType;
 import javax.xml.bind.annotation.XmlAccessorType;
@@ -57,6 +58,7 @@ import org.apache.camel.impl.engine.DefaultManagementStrategy;
 import org.apache.camel.impl.engine.TransformerKey;
 import org.apache.camel.impl.engine.ValidatorKey;
 import org.apache.camel.model.ContextScanDefinition;
+import org.apache.camel.model.ErrorHandlerDefinition;
 import org.apache.camel.model.FaultToleranceConfigurationDefinition;
 import org.apache.camel.model.FromDefinition;
 import org.apache.camel.model.GlobalOptionsDefinition;
@@ -590,6 +592,7 @@ public abstract class AbstractCamelContextFactoryBean<T extends ModelCamelContex
             route.resetPrepare();
 
             // merge global and route scoped together
+            AtomicReference<ErrorHandlerDefinition> errorHandler = new AtomicReference<>();
             List<OnExceptionDefinition> oe = new ArrayList<>(getOnExceptions());
             List<InterceptDefinition> icp = new ArrayList<>(getIntercepts());
             List<InterceptFromDefinition> ifrom = new ArrayList<>(getInterceptFroms());
@@ -615,6 +618,12 @@ public abstract class AbstractCamelContextFactoryBean<T extends ModelCamelContex
                                     }
                                 })
                                 .forEach(g -> {
+                                    // there can only be one global error handler, so override previous, meaning
+                                    // that we will pick the last in the sort (take precedence)
+                                    if (g.getErrorHandler() != null) {
+                                        errorHandler.set(g.getErrorHandler());
+                                    }
+
                                     String aid = g.getId() == null ? "<default>" : g.getId();
                                     // remember the id that was used on the route
                                     route.addAppliedRouteConfigurationId(aid);
@@ -629,7 +638,7 @@ public abstract class AbstractCamelContextFactoryBean<T extends ModelCamelContex
             }
 
             // must prepare the route before we can add it to the routes list
-            RouteDefinitionHelper.prepareRoute(getContext(), route, oe, icp, ifrom, ito, oc);
+            RouteDefinitionHelper.prepareRoute(getContext(), route, errorHandler.get(), oe, icp, ifrom, ito, oc);
 
             if (LOG.isDebugEnabled() && route.getAppliedRouteConfigurationIds() != null) {
                 LOG.debug("Route: {} is using route configurations ids: {}", route.getId(),
diff --git a/core/camel-core/src/test/java/org/apache/camel/model/RoutesConfigurationErrorHandlerTest.java b/core/camel-core/src/test/java/org/apache/camel/model/RoutesConfigurationErrorHandlerTest.java
new file mode 100644
index 00000000000..0dcc4ec67b7
--- /dev/null
+++ b/core/camel-core/src/test/java/org/apache/camel/model/RoutesConfigurationErrorHandlerTest.java
@@ -0,0 +1,160 @@
+/*
+ * 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;
+
+import static org.assertj.core.api.Fail.fail;
+
+public class RoutesConfigurationErrorHandlerTest extends ContextTestSupport {
+
+    @Override
+    public boolean isUseRouteBuilder() {
+        return false;
+    }
+
+    @Test
+    public void testGlobal() throws Exception {
+        context.addRoutes(new RouteConfigurationBuilder() {
+            @Override
+            public void configuration() throws Exception {
+                // global routes configuration
+                routeConfiguration().errorHandler(deadLetterChannel("mock:error"));
+
+            }
+        });
+        context.addRoutes(new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                from("direct:start")
+                        .throwException(new IllegalArgumentException("Foo"));
+
+                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();
+    }
+
+    @Test
+    public void testLocalOverride() throws Exception {
+        context.addRoutes(new RouteConfigurationBuilder() {
+            @Override
+            public void configuration() throws Exception {
+                // global routes configuration
+                routeConfiguration().errorHandler(deadLetterChannel("mock:error"));
+
+            }
+        });
+        context.addRoutes(new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                from("direct:start")
+                        .throwException(new IllegalArgumentException("Foo"));
+
+                from("direct:start2")
+                        .errorHandler(deadLetterChannel("mock:error2"))
+                        .throwException(new IllegalArgumentException("Foo2"));
+            }
+        });
+        context.start();
+
+        getMockEndpoint("mock:error").expectedBodiesReceived("Hello World");
+        getMockEndpoint("mock:error2").expectedBodiesReceived("Bye World");
+
+        template.sendBody("direct:start", "Hello World");
+        template.sendBody("direct:start2", "Bye World");
+
+        assertMockEndpointsSatisfied();
+    }
+
+    @Test
+    public void testLocalConfiguration() throws Exception {
+        context.addRoutes(new RouteConfigurationBuilder() {
+            @Override
+            public void configuration() throws Exception {
+                routeConfiguration("mylocal").errorHandler(deadLetterChannel("mock:error"));
+
+            }
+        });
+        context.addRoutes(new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                from("direct:start")
+                        .throwException(new IllegalArgumentException("Foo"));
+
+                from("direct:start2").routeConfigurationId("mylocal")
+                        .throwException(new IllegalArgumentException("Foo2"));
+            }
+        });
+        context.start();
+
+        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 testGlobalAndLocal() throws Exception {
+        context.addRoutes(new RouteConfigurationBuilder() {
+            @Override
+            public void configuration() throws Exception {
+                routeConfiguration().errorHandler(deadLetterChannel("mock:error"));
+                routeConfiguration("mylocal").errorHandler(deadLetterChannel("mock:error2"));
+
+            }
+        });
+        context.addRoutes(new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                from("direct:start")
+                        .throwException(new IllegalArgumentException("Foo"));
+
+                from("direct:start2").routeConfigurationId("mylocal")
+                        .throwException(new IllegalArgumentException("Foo2"));
+            }
+        });
+        context.start();
+
+        getMockEndpoint("mock:error").expectedBodiesReceived("Hello World");
+        getMockEndpoint("mock:error2").expectedBodiesReceived("Bye World");
+
+        template.sendBody("direct:start", "Hello World");
+        template.sendBody("direct:start2", "Bye World");
+
+        assertMockEndpointsSatisfied();
+    }
+
+}
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 78c3d65df2a..fe6144cae44 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
@@ -978,6 +978,7 @@ public class ModelParser extends BaseParser {
             return optionalIdentifiedDefinitionAttributeHandler().accept(def, key, val);
         }, (def, key) -> {
             switch (key) {
+                case "errorHandler": def.setErrorHandler(doParseErrorHandlerDefinition()); break;
                 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;
diff --git a/docs/user-manual/modules/ROOT/pages/route-configuration.adoc b/docs/user-manual/modules/ROOT/pages/route-configuration.adoc
index 2215ffb67f6..4a71d7c07c1 100644
--- a/docs/user-manual/modules/ROOT/pages/route-configuration.adoc
+++ b/docs/user-manual/modules/ROOT/pages/route-configuration.adoc
@@ -12,6 +12,7 @@ The route configuration is supported by all DSL's, so useable by: Java, XML, Gro
 
 In the route configuration you can setup common strategies for:
 
+- xref:error-handler.adoc[Error Handler]
 - xref:exception-clause.adoc[OnException]
 - xref:oncompletion.adoc[OnCompletion]
 - xref:components:eips:intercept.adoc[Intercept]
@@ -176,6 +177,32 @@ 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 with Error Handler
+
+Each route configuration can also have a specific error handler configured, as shown below:
+
+[source,java]
+----
+public class MyJavaErrorHandler extends RouteConfigurationBuilder {
+
+    @Override
+    public void configuration() throws Exception {
+        routeConfiguration()
+            .errorHandler(deadLetterChannel("mock:dead"));
+
+        routeConfiguration("retryError")
+            .onException(Exception.class).maximumRedeliveries(5);
+    }
+}
+----
+
+In the example above, the _nameless_ configuration has an error handler with a dead letter queue.
+And the route configuration with id _retryError_ does not, and instead it will attempt
+to retry the failing message up till 5 times before giving up (exhausted). Because this
+route configuration does not have any error handler assigned, then Camel will use the default error handler.
+
+IMPORTANT: Routes that have a local error handler defined, will always use this error handler,
+instead of the error handler from route configurations. A route can only have 1 error handler.
 
 == Route Configuration in XML
 
diff --git a/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/main/java/org/apache/camel/dsl/yaml/deserializers/RouteConfigurationDefinitionDeserializer.java b/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/main/java/org/apache/camel/dsl/yaml/deserializers/RouteConfigurationDefinitionDeserializer.java
index 5b99d26a339..1123731de60 100644
--- a/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/main/java/org/apache/camel/dsl/yaml/deserializers/RouteConfigurationDefinitionDeserializer.java
+++ b/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/main/java/org/apache/camel/dsl/yaml/deserializers/RouteConfigurationDefinitionDeserializer.java
@@ -20,6 +20,7 @@ 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.dsl.yaml.common.exception.UnsupportedFieldException;
+import org.apache.camel.model.ErrorHandlerDefinition;
 import org.apache.camel.model.InterceptDefinition;
 import org.apache.camel.model.InterceptFromDefinition;
 import org.apache.camel.model.InterceptSendToEndpointDefinition;
@@ -41,6 +42,7 @@ import org.snakeyaml.engine.v2.nodes.SequenceNode;
           properties = {
                   @YamlProperty(name = "id", type = "string"),
                   @YamlProperty(name = "precondition", type = "string"),
+                  @YamlProperty(name = "error-handler", type = "object:org.apache.camel.model.ErrorHandlerDefinition.class"),
                   @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",
@@ -79,6 +81,11 @@ public class RouteConfigurationDefinitionDeserializer extends YamlDeserializerBa
                     case "precondition":
                         target.setPrecondition(asText(val));
                         break;
+                    case "error-handler":
+                        setDeserializationContext(val, dc);
+                        ErrorHandlerDefinition ehd = asType(val, ErrorHandlerDefinition.class);
+                        target.setErrorHandler(ehd);
+                        break;
                     case "on-exception":
                         setDeserializationContext(val, dc);
                         OnExceptionDefinition oed = asType(val, OnExceptionDefinition.class);
diff --git a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/camel-yaml-dsl.json b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/camel-yaml-dsl.json
index 24e65a97bef..260ec1996de 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
@@ -2324,6 +2324,9 @@
         }, {
           "type" : "object",
           "properties" : {
+            "error-handler" : {
+              "$ref" : "#/items/definitions/org.apache.camel.model.ErrorHandlerDefinition.class"
+            },
             "id" : {
               "type" : "string"
             },
diff --git a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/camelYamlDsl.json b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/camelYamlDsl.json
index ac348b5ee5f..62c0864d508 100644
--- a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/camelYamlDsl.json
+++ b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/camelYamlDsl.json
@@ -2228,6 +2228,9 @@
         }, {
           "type" : "object",
           "properties" : {
+            "errorHandler" : {
+              "$ref" : "#/items/definitions/org.apache.camel.model.ErrorHandlerDefinition.class"
+            },
             "id" : {
               "type" : "string"
             },
diff --git a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/RouteConfigurationTest.groovy b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/RouteConfigurationTest.groovy
index 04ff381cb6e..bba80b12c80 100644
--- a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/RouteConfigurationTest.groovy
+++ b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/RouteConfigurationTest.groovy
@@ -223,4 +223,46 @@ class RouteConfigurationTest extends YamlTestSupport {
         Assertions.assertTrue(out2.isFailed())
     }
 
+    def "route-configuration-error-handler"() {
+        setup:
+        // global configurations
+        loadRoutes """
+                - beans:
+                  - name: myFailingProcessor
+                    type: ${MyFailingProcessor.name}
+                - route-configuration:
+                    - error-handler:
+                        dead-letter-channel: 
+                          dead-letter-uri: "mock:on-error"
+            """
+        // routes
+        loadRoutes """
+                - from:
+                    uri: "direct:start"
+                    steps:
+                      - process: 
+                          ref: "myFailingProcessor"            
+                - from:
+                    uri: "direct:start2"
+                    steps:
+                      - process: 
+                          ref: "myFailingProcessor"            
+            """
+
+        withMock('mock:on-error') {
+            expectedBodiesReceived 'hello', 'hello2'
+        }
+
+        when:
+        context.start()
+
+        withTemplate {
+            to('direct:start').withBody('hello').send()
+            to('direct:start2').withBody('hello2').send()
+        }
+        then:
+        MockEndpoint.assertIsSatisfied(context)
+    }
+
+
 }