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 9de62afad05 Align DSL for Java, XML and YAML for error handler and stream caching (#13780) 9de62afad05 is described below commit 9de62afad05220f6fd413bbbc71c5c3ae2a66daf Author: Claus Ibsen <claus.ib...@gmail.com> AuthorDate: Sat Apr 13 12:41:44 2024 +0200 Align DSL for Java, XML and YAML for error handler and stream caching (#13780) * CAMEL-20666: Add errorHandler on route for EIP model (XML and YAML DSL) to be consistent. * CAMEL-20665: YAML DSL Inconsistency - StreamCaching vs streamCache. Also mark some DSL in Java DSL as deprecated to make the DSLs consistent so Java DSL does not have special options. * CAMEL-20665: YAML DSL Inconsistency - StreamCaching vs streamCache. Also mark some DSL in Java DSL as deprecated to make the DSLs consistent so Java DSL does not have special options. --- .../org/apache/camel/catalog/models/route.json | 9 +-- .../apache/camel/catalog/schemas/camel-spring.xsd | 1 + .../camel/spring/config/ErrorHandlerRouteTest.java | 58 +++++++++++++++++ .../camel/spring/config/errorHandlerRoute.xml | 41 ++++++++++++ .../java/org/apache/camel/impl/DefaultModel.java | 2 +- .../META-INF/org/apache/camel/model/route.json | 9 +-- .../org/apache/camel/model/RouteDefinition.java | 74 +++++++++++++++++++++- .../camel/model/RouteTemplateDefinition.java | 1 + .../java/org/apache/camel/xml/in/ModelParser.java | 1 + .../java/org/apache/camel/xml/out/ModelWriter.java | 1 + .../test/resources/routeInlinedErrorHandler.xml | 32 ++++++++++ .../org/apache/camel/yaml/out/ModelWriter.java | 1 + .../ROOT/pages/camel-4x-upgrade-guide-4_6.adoc | 30 ++++++++- .../modules/ROOT/pages/error-handler.adoc | 20 +++++- .../deserializers/RouteDefinitionDeserializer.java | 11 +++- .../generated/resources/schema/camelYamlDsl.json | 2 +- .../apache/camel/dsl/yaml/PipeLoaderTest.groovy | 2 +- .../apache/camel/dsl/yaml/RouteTemplateTest.groovy | 2 +- .../org/apache/camel/dsl/yaml/RoutesTest.groovy | 6 +- .../kamelets/route-timer-source.kamelet.yaml | 2 +- .../camel/maven/packaging/SchemaGeneratorMojo.java | 8 +++ 21 files changed, 292 insertions(+), 21 deletions(-) diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/route.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/route.json index 8c9a21bbb1c..0451e8ceeb8 100644 --- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/route.json +++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/route.json @@ -29,9 +29,10 @@ "shutdownRoute": { "index": 14, "kind": "attribute", "displayName": "Shutdown Route", "label": "advanced", "required": false, "type": "enum", "javaType": "org.apache.camel.ShutdownRoute", "enum": [ "Default", "Defer" ], "deprecated": false, "autowired": false, "secret": false, "description": "To control how to shutdown the route." }, "shutdownRunningTask": { "index": 15, "kind": "attribute", "displayName": "Shutdown Running Task", "label": "advanced", "required": false, "type": "enum", "javaType": "org.apache.camel.ShutdownRunningTask", "enum": [ "CompleteCurrentTaskOnly", "CompleteAllTasks" ], "deprecated": false, "autowired": false, "secret": false, "description": "To control how to shut down the route." }, "precondition": { "index": 16, "kind": "attribute", "displayName": "Precondition", "label": "advanced", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "The predicate of the precondition in simple language to evaluate in order to determine if this route should be included or not." }, - "inputType": { "index": 17, "kind": "element", "displayName": "Input Type", "label": "advanced", "required": false, "type": "object", "javaType": "org.apache.camel.model.InputTypeDefinition", "deprecated": false, "autowired": false, "secret": false, "description": "Declare the expected data type of the input message. If the actual message type is different at runtime, camel look for a required org.apache.camel.spi.Transformer and apply if exists. The type name consists of two parts, [...] - "outputType": { "index": 18, "kind": "element", "displayName": "Output Type", "label": "advanced", "required": false, "type": "object", "javaType": "org.apache.camel.model.OutputTypeDefinition", "deprecated": false, "autowired": false, "secret": false, "description": "Declare the expected data type of the output message. If the actual message type is different at runtime, camel look for a required org.apache.camel.spi.Transformer and apply if exists. The type name consists of two par [...] - "input": { "index": 19, "kind": "element", "displayName": "Input", "required": true, "type": "object", "javaType": "org.apache.camel.model.FromDefinition", "oneOf": [ "from" ], "deprecated": false, "autowired": false, "secret": false, "description": "Input to the route." }, - "outputs": { "index": 20, "kind": "element", "displayName": "Outputs", "required": true, "type": "array", "javaType": "java.util.List<org.apache.camel.model.ProcessorDefinition<?>>", "oneOf": [ "aggregate", "bean", "choice", "circuitBreaker", "claimCheck", "convertBodyTo", "convertHeaderTo", "convertVariableTo", "delay", "doCatch", "doFinally", "doTry", "dynamicRouter", "enrich", "filter", "idempotentConsumer", "intercept", "interceptFrom", "interceptSendToEndpoint", "kamelet", "load [...] + "errorHandler": { "index": 17, "kind": "element", "displayName": "Error Handler", "label": "error", "required": false, "type": "object", "javaType": "org.apache.camel.model.ErrorHandlerDefinition", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the error handler to use for this route" }, + "inputType": { "index": 18, "kind": "element", "displayName": "Input Type", "label": "advanced", "required": false, "type": "object", "javaType": "org.apache.camel.model.InputTypeDefinition", "deprecated": false, "autowired": false, "secret": false, "description": "Declare the expected data type of the input message. If the actual message type is different at runtime, camel look for a required org.apache.camel.spi.Transformer and apply if exists. The type name consists of two parts, [...] + "outputType": { "index": 19, "kind": "element", "displayName": "Output Type", "label": "advanced", "required": false, "type": "object", "javaType": "org.apache.camel.model.OutputTypeDefinition", "deprecated": false, "autowired": false, "secret": false, "description": "Declare the expected data type of the output message. If the actual message type is different at runtime, camel look for a required org.apache.camel.spi.Transformer and apply if exists. The type name consists of two par [...] + "input": { "index": 20, "kind": "element", "displayName": "Input", "required": true, "type": "object", "javaType": "org.apache.camel.model.FromDefinition", "oneOf": [ "from" ], "deprecated": false, "autowired": false, "secret": false, "description": "Input to the route." }, + "outputs": { "index": 21, "kind": "element", "displayName": "Outputs", "required": true, "type": "array", "javaType": "java.util.List<org.apache.camel.model.ProcessorDefinition<?>>", "oneOf": [ "aggregate", "bean", "choice", "circuitBreaker", "claimCheck", "convertBodyTo", "convertHeaderTo", "convertVariableTo", "delay", "doCatch", "doFinally", "doTry", "dynamicRouter", "enrich", "filter", "idempotentConsumer", "intercept", "interceptFrom", "interceptSendToEndpoint", "kamelet", "load [...] } } 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 96c6a29de58..b31aac91b34 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 @@ -12176,6 +12176,7 @@ Reference to the routes in the xml dsl. <xs:extension base="tns:output"> <xs:sequence> <xs:element maxOccurs="unbounded" minOccurs="0" name="routeProperty" type="tns:propertyDefinition"/> + <xs:element minOccurs="0" ref="tns:errorHandler"/> <xs:element minOccurs="0" ref="tns:from"/> <xs:element minOccurs="0" ref="tns:inputType"/> <xs:element minOccurs="0" ref="tns:outputType"/> diff --git a/components/camel-spring-xml/src/test/java/org/apache/camel/spring/config/ErrorHandlerRouteTest.java b/components/camel-spring-xml/src/test/java/org/apache/camel/spring/config/ErrorHandlerRouteTest.java new file mode 100644 index 00000000000..d62267dc49c --- /dev/null +++ b/components/camel-spring-xml/src/test/java/org/apache/camel/spring/config/ErrorHandlerRouteTest.java @@ -0,0 +1,58 @@ +/* + * 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.config; + +import java.util.List; + +import org.apache.camel.Channel; +import org.apache.camel.Route; +import org.apache.camel.impl.engine.DefaultRoute; +import org.apache.camel.processor.errorhandler.DeadLetterChannel; +import org.apache.camel.processor.errorhandler.RedeliveryPolicy; +import org.apache.camel.spring.SpringCamelContext; +import org.apache.camel.spring.SpringTestSupport; +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.assertEquals; + +public class ErrorHandlerRouteTest extends SpringTestSupport { + + @Override + protected AbstractXmlApplicationContext createApplicationContext() { + return new ClassPathXmlApplicationContext("org/apache/camel/spring/config/errorHandlerRoute.xml"); + } + + @Test + public void testEndpointConfiguration() throws Exception { + SpringCamelContext context = applicationContext.getBeansOfType(SpringCamelContext.class).values().iterator().next(); + List<Route> list = context.getRoutes(); + assertEquals(1, list.size(), "Number routes created" + list); + for (Route route : list) { + DefaultRoute consumerRoute = assertIsInstanceOf(DefaultRoute.class, route); + Channel channel = unwrapChannel(consumerRoute.getProcessor()); + + DeadLetterChannel deadLetterChannel = assertIsInstanceOf(DeadLetterChannel.class, channel.getErrorHandler()); + RedeliveryPolicy redeliveryPolicy = deadLetterChannel.getRedeliveryPolicy(); + + assertEquals(1, redeliveryPolicy.getMaximumRedeliveries(), "getMaximumRedeliveries()"); + assertEquals(true, redeliveryPolicy.isUseExponentialBackOff(), "isUseExponentialBackOff()"); + } + } + +} diff --git a/components/camel-spring-xml/src/test/resources/org/apache/camel/spring/config/errorHandlerRoute.xml b/components/camel-spring-xml/src/test/resources/org/apache/camel/spring/config/errorHandlerRoute.xml new file mode 100644 index 00000000000..16954274ca4 --- /dev/null +++ b/components/camel-spring-xml/src/test/resources/org/apache/camel/spring/config/errorHandlerRoute.xml @@ -0,0 +1,41 @@ +<?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"> + <jmxAgent id="agent" disabled="true"/> + <route> + <errorHandler> + <deadLetterChannel deadLetterUri="mock:exceptionProcessor"> + <redeliveryPolicy maximumRedeliveries="1" redeliveryDelay="30000" useExponentialBackOff="true"/> + </deadLetterChannel> + </errorHandler> + <from uri="seda:a"/> + <to uri="seda:b"/> + </route> + </camelContext> + +</beans> 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 3c6e890502e..9a3383055c5 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 @@ -255,7 +255,7 @@ public class DefaultModel implements Model { r.setErrorHandlerRef(toBeInlined.getErrorHandlerRef()); r.setPrecondition(toBeInlined.getPrecondition()); if (toBeInlined.isErrorHandlerFactorySet()) { - r.setErrorHandlerFactory(toBeInlined.getErrorHandlerFactory()); + r.setErrorHandler(toBeInlined.getErrorHandler()); } } } diff --git a/core/camel-core-model/src/generated/resources/META-INF/org/apache/camel/model/route.json b/core/camel-core-model/src/generated/resources/META-INF/org/apache/camel/model/route.json index 8c9a21bbb1c..0451e8ceeb8 100644 --- a/core/camel-core-model/src/generated/resources/META-INF/org/apache/camel/model/route.json +++ b/core/camel-core-model/src/generated/resources/META-INF/org/apache/camel/model/route.json @@ -29,9 +29,10 @@ "shutdownRoute": { "index": 14, "kind": "attribute", "displayName": "Shutdown Route", "label": "advanced", "required": false, "type": "enum", "javaType": "org.apache.camel.ShutdownRoute", "enum": [ "Default", "Defer" ], "deprecated": false, "autowired": false, "secret": false, "description": "To control how to shutdown the route." }, "shutdownRunningTask": { "index": 15, "kind": "attribute", "displayName": "Shutdown Running Task", "label": "advanced", "required": false, "type": "enum", "javaType": "org.apache.camel.ShutdownRunningTask", "enum": [ "CompleteCurrentTaskOnly", "CompleteAllTasks" ], "deprecated": false, "autowired": false, "secret": false, "description": "To control how to shut down the route." }, "precondition": { "index": 16, "kind": "attribute", "displayName": "Precondition", "label": "advanced", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "The predicate of the precondition in simple language to evaluate in order to determine if this route should be included or not." }, - "inputType": { "index": 17, "kind": "element", "displayName": "Input Type", "label": "advanced", "required": false, "type": "object", "javaType": "org.apache.camel.model.InputTypeDefinition", "deprecated": false, "autowired": false, "secret": false, "description": "Declare the expected data type of the input message. If the actual message type is different at runtime, camel look for a required org.apache.camel.spi.Transformer and apply if exists. The type name consists of two parts, [...] - "outputType": { "index": 18, "kind": "element", "displayName": "Output Type", "label": "advanced", "required": false, "type": "object", "javaType": "org.apache.camel.model.OutputTypeDefinition", "deprecated": false, "autowired": false, "secret": false, "description": "Declare the expected data type of the output message. If the actual message type is different at runtime, camel look for a required org.apache.camel.spi.Transformer and apply if exists. The type name consists of two par [...] - "input": { "index": 19, "kind": "element", "displayName": "Input", "required": true, "type": "object", "javaType": "org.apache.camel.model.FromDefinition", "oneOf": [ "from" ], "deprecated": false, "autowired": false, "secret": false, "description": "Input to the route." }, - "outputs": { "index": 20, "kind": "element", "displayName": "Outputs", "required": true, "type": "array", "javaType": "java.util.List<org.apache.camel.model.ProcessorDefinition<?>>", "oneOf": [ "aggregate", "bean", "choice", "circuitBreaker", "claimCheck", "convertBodyTo", "convertHeaderTo", "convertVariableTo", "delay", "doCatch", "doFinally", "doTry", "dynamicRouter", "enrich", "filter", "idempotentConsumer", "intercept", "interceptFrom", "interceptSendToEndpoint", "kamelet", "load [...] + "errorHandler": { "index": 17, "kind": "element", "displayName": "Error Handler", "label": "error", "required": false, "type": "object", "javaType": "org.apache.camel.model.ErrorHandlerDefinition", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the error handler to use for this route" }, + "inputType": { "index": 18, "kind": "element", "displayName": "Input Type", "label": "advanced", "required": false, "type": "object", "javaType": "org.apache.camel.model.InputTypeDefinition", "deprecated": false, "autowired": false, "secret": false, "description": "Declare the expected data type of the input message. If the actual message type is different at runtime, camel look for a required org.apache.camel.spi.Transformer and apply if exists. The type name consists of two parts, [...] + "outputType": { "index": 19, "kind": "element", "displayName": "Output Type", "label": "advanced", "required": false, "type": "object", "javaType": "org.apache.camel.model.OutputTypeDefinition", "deprecated": false, "autowired": false, "secret": false, "description": "Declare the expected data type of the output message. If the actual message type is different at runtime, camel look for a required org.apache.camel.spi.Transformer and apply if exists. The type name consists of two par [...] + "input": { "index": 20, "kind": "element", "displayName": "Input", "required": true, "type": "object", "javaType": "org.apache.camel.model.FromDefinition", "oneOf": [ "from" ], "deprecated": false, "autowired": false, "secret": false, "description": "Input to the route." }, + "outputs": { "index": 21, "kind": "element", "displayName": "Outputs", "required": true, "type": "array", "javaType": "java.util.List<org.apache.camel.model.ProcessorDefinition<?>>", "oneOf": [ "aggregate", "bean", "choice", "circuitBreaker", "claimCheck", "convertBodyTo", "convertHeaderTo", "convertVariableTo", "delay", "doCatch", "doFinally", "doTry", "dynamicRouter", "enrich", "filter", "idempotentConsumer", "intercept", "interceptFrom", "interceptSendToEndpoint", "kamelet", "load [...] } } 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 fea85633ba5..bd1079609e7 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 @@ -56,7 +56,7 @@ import org.apache.camel.spi.RoutePolicy; */ @Metadata(label = "configuration") @XmlRootElement(name = "route") -@XmlType(propOrder = { "routeProperties", "input", "inputType", "outputType", "outputs" }) +@XmlType(propOrder = { "routeProperties", "errorHandler", "input", "inputType", "outputType", "outputs" }) @XmlAccessorType(XmlAccessType.PROPERTY) // must use XmlAccessType.PROPERTY as there is some custom logic needed to be executed in the setter methods public class RouteDefinition extends OutputDefinition<RouteDefinition> @@ -80,6 +80,7 @@ public class RouteDefinition extends OutputDefinition<RouteDefinition> private String shutdownRunningTask; private String errorHandlerRef; private ErrorHandlerFactory errorHandlerFactory; + private ErrorHandlerDefinition errorHandler; // keep state whether the error handler is context scoped or not // (will by default be context scoped of no explicit error handler // configured) @@ -327,6 +328,7 @@ public class RouteDefinition extends OutputDefinition<RouteDefinition> * * @return the builder */ + @Deprecated public RouteDefinition noStreamCaching() { setStreamCache("false"); return this; @@ -337,6 +339,7 @@ public class RouteDefinition extends OutputDefinition<RouteDefinition> * * @return the builder */ + @Deprecated public RouteDefinition streamCaching() { setStreamCache("true"); return this; @@ -345,10 +348,23 @@ public class RouteDefinition extends OutputDefinition<RouteDefinition> /** * Enable stream caching for this route. * + * @param streamCache whether to use stream caching (true or false), the value can be a property placeholder + * @return the builder + * @deprecated use {@link #streamCache(String)} + */ + @Deprecated + public RouteDefinition streamCaching(String streamCache) { + setStreamCache(streamCache); + return this; + } + + /** + * Enable or disables stream caching for this route. + * * @param streamCache whether to use stream caching (true or false), the value can be a property placeholder * @return the builder */ - public RouteDefinition streamCaching(String streamCache) { + public RouteDefinition streamCache(String streamCache) { setStreamCache(streamCache); return this; } @@ -358,6 +374,7 @@ public class RouteDefinition extends OutputDefinition<RouteDefinition> * * @return the builder */ + @Deprecated public RouteDefinition noTracing() { setTrace("false"); return this; @@ -368,6 +385,7 @@ public class RouteDefinition extends OutputDefinition<RouteDefinition> * * @return the builder */ + @Deprecated public RouteDefinition tracing() { setTrace("true"); return this; @@ -379,11 +397,34 @@ public class RouteDefinition extends OutputDefinition<RouteDefinition> * @param tracing whether to use tracing (true or false), the value can be a property placeholder * @return the builder */ + @Deprecated public RouteDefinition tracing(String tracing) { setTrace(tracing); return this; } + /** + * Enables or disables tracing for this route. + * + * @param trace whether to use tracing (true or false) + * @return the builder + */ + public RouteDefinition trace(boolean trace) { + setTrace(Boolean.toString(trace)); + return this; + } + + /** + * Enables or disables tracing for this route. + * + * @param trace whether to use tracing (true or false), the value can be a property placeholder + * @return the builder + */ + public RouteDefinition trace(String trace) { + setTrace(trace); + return this; + } + /** * Enable message history for this route. * @@ -394,6 +435,17 @@ public class RouteDefinition extends OutputDefinition<RouteDefinition> return this; } + /** + * Enable message history for this route. + * + * @param messageHistory whether to use message history (true or false) + * @return the builder + */ + public RouteDefinition messageHistory(boolean messageHistory) { + setMessageHistory(Boolean.toString(messageHistory)); + return this; + } + /** * Enable message history for this route. * @@ -432,6 +484,7 @@ public class RouteDefinition extends OutputDefinition<RouteDefinition> * * @return the builder */ + @Deprecated public RouteDefinition noMessageHistory() { setMessageHistory("false"); return this; @@ -442,6 +495,7 @@ public class RouteDefinition extends OutputDefinition<RouteDefinition> * * @return the builder */ + @Deprecated public RouteDefinition noDelayer() { setDelayer("0"); return this; @@ -489,6 +543,7 @@ public class RouteDefinition extends OutputDefinition<RouteDefinition> * * @return the builder */ + @Deprecated public RouteDefinition noAutoStartup() { setAutoStartup("false"); return this; @@ -1067,6 +1122,21 @@ public class RouteDefinition extends OutputDefinition<RouteDefinition> return errorHandlerRef; } + public ErrorHandlerDefinition getErrorHandler() { + return errorHandler; + } + + /** + * Sets the error handler to use for this route + */ + @XmlElement + public void setErrorHandler(ErrorHandlerDefinition errorHandler) { + this.errorHandler = errorHandler; + if (errorHandler != null) { + this.errorHandlerFactory = errorHandler.getErrorHandlerType(); + } + } + /** * Sets the error handler if one is not already set */ diff --git a/core/camel-core-model/src/main/java/org/apache/camel/model/RouteTemplateDefinition.java b/core/camel-core-model/src/main/java/org/apache/camel/model/RouteTemplateDefinition.java index baeecddbff1..8cff7141914 100644 --- a/core/camel-core-model/src/main/java/org/apache/camel/model/RouteTemplateDefinition.java +++ b/core/camel-core-model/src/main/java/org/apache/camel/model/RouteTemplateDefinition.java @@ -403,6 +403,7 @@ public class RouteTemplateDefinition extends OptionalIdentifiedDefinition<RouteT // only set factory if not already set copy.setErrorHandlerFactory(route.getErrorHandlerFactory()); } + copy.setErrorHandler(route.getErrorHandler()); // and then copy over the rest // (do not copy id as it is used for route template id) 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 d8807a60ffa..8b16a1acddd 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 @@ -1087,6 +1087,7 @@ public class ModelParser extends BaseParser { case "from": def.setInput(doParseFromDefinition()); break; case "inputType": def.setInputType(doParseInputTypeDefinition()); break; case "outputType": def.setOutputType(doParseOutputTypeDefinition()); break; + case "errorHandler": def.setErrorHandler(doParseErrorHandlerDefinition()); break; case "kamelet": def.setKamelet(Boolean.valueOf(doParseText())); break; case "rest": def.setRest(Boolean.valueOf(doParseText())); break; case "routeProperty": doAdd(doParsePropertyDefinition(), def.getRouteProperties(), def::setRouteProperties); break; diff --git a/core/camel-xml-io/src/generated/java/org/apache/camel/xml/out/ModelWriter.java b/core/camel-xml-io/src/generated/java/org/apache/camel/xml/out/ModelWriter.java index eb9433c08bb..944d33689e7 100644 --- a/core/camel-xml-io/src/generated/java/org/apache/camel/xml/out/ModelWriter.java +++ b/core/camel-xml-io/src/generated/java/org/apache/camel/xml/out/ModelWriter.java @@ -2115,6 +2115,7 @@ public class ModelWriter extends BaseWriter { doWriteAttribute("group", def.getGroup()); doWriteAttribute("errorHandlerRef", def.getErrorHandlerRef()); doWriteList(null, "routeProperty", def.getRouteProperties(), this::doWritePropertyDefinition); + doWriteElement("errorHandler", def.getErrorHandler(), this::doWriteErrorHandlerDefinition); doWriteElement(null, def.getInput(), this::doWriteFromDefinitionRef); doWriteElement(null, def.getInputType(), this::doWriteInputTypeDefinitionRef); doWriteElement(null, def.getOutputType(), this::doWriteOutputTypeDefinitionRef); diff --git a/core/camel-xml-io/src/test/resources/routeInlinedErrorHandler.xml b/core/camel-xml-io/src/test/resources/routeInlinedErrorHandler.xml new file mode 100644 index 00000000000..75bb0c65682 --- /dev/null +++ b/core/camel-xml-io/src/test/resources/routeInlinedErrorHandler.xml @@ -0,0 +1,32 @@ +<?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. + +--> +<routes xmlns="http://camel.apache.org/schema/spring"> + + <route> + <errorHandler> + <deadLetterChannel deadLetterUri="mock:dead"> + <redeliveryPolicy maximumRedeliveries="2" redeliveryDelay="123" + logStackTrace="false"/> + </deadLetterChannel> + </errorHandler> + <from uri="seda:a"/> + <to uri="seda:b"/> + </route> +</routes> diff --git a/core/camel-yaml-io/src/generated/java/org/apache/camel/yaml/out/ModelWriter.java b/core/camel-yaml-io/src/generated/java/org/apache/camel/yaml/out/ModelWriter.java index f4d114a2d51..77d425c592b 100644 --- a/core/camel-yaml-io/src/generated/java/org/apache/camel/yaml/out/ModelWriter.java +++ b/core/camel-yaml-io/src/generated/java/org/apache/camel/yaml/out/ModelWriter.java @@ -2115,6 +2115,7 @@ public class ModelWriter extends BaseWriter { doWriteAttribute("group", def.getGroup()); doWriteAttribute("errorHandlerRef", def.getErrorHandlerRef()); doWriteList(null, "routeProperty", def.getRouteProperties(), this::doWritePropertyDefinition); + doWriteElement("errorHandler", def.getErrorHandler(), this::doWriteErrorHandlerDefinition); doWriteElement(null, def.getInput(), this::doWriteFromDefinitionRef); doWriteElement(null, def.getInputType(), this::doWriteInputTypeDefinitionRef); doWriteElement(null, def.getOutputType(), this::doWriteOutputTypeDefinitionRef); diff --git a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_6.adoc b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_6.adoc index 258d52658e5..43f80e2c33d 100644 --- a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_6.adoc +++ b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_6.adoc @@ -65,4 +65,32 @@ instead of `org.apache.camel.Consumer`. === camel-kafka -The Kafka component now supports custom subscription adapters for applications with very complex subscription logic. \ No newline at end of file +The Kafka component now supports custom subscription adapters for applications with very complex subscription logic. + +=== camel-yaml-dsl + +Renamed `streamCaching` to `streamCache` on the `route` + +Before: + +[source,yaml] +---- +route: + streamCaching: false + from: + uri: "direct:foo" + steps: + - to: "mock:bar" +---- + +After: + +[source,yaml] +---- +route: + streamCache: false + from: + uri: "direct:foo" + steps: + - to: "mock:bar" +---- \ No newline at end of file diff --git a/docs/user-manual/modules/ROOT/pages/error-handler.adoc b/docs/user-manual/modules/ROOT/pages/error-handler.adoc index 4812073019e..37920f7630e 100644 --- a/docs/user-manual/modules/ROOT/pages/error-handler.adoc +++ b/docs/user-manual/modules/ROOT/pages/error-handler.adoc @@ -246,7 +246,6 @@ the `errorHandlerRef` attribute on the `route` tag. [source,xml] ---- <camelContext xmlns="http://camel.apache.org/schema/spring"> - <template id="myTemplate"/> <!-- set the errorHandlerRef to our DeadLetterChannel, this applies for this route only --> <route errorHandlerRef="myDeadLetterErrorHandler"> <from uri="direct:in"/> @@ -282,6 +281,25 @@ etc. </bean> ---- +In *Camel 4.6* you can now inline `<errorHandler>` directly in the routes. The example above can be done as follows: + +[source,xml] +---- + <camelContext xmlns="http://camel.apache.org/schema/spring"> + <route> + <errorHandler> + <deadLetterChannel deadLetterUri="mock:dead"> + <redeliveryPolicy maximumRedeliveries="3" redeliveryDelay="250"/> + </deadLetterChannel> + </errorHandler> + <from uri="direct:in"/> + <process ref="myFailureProcessor"/> + <to uri="mock:result"/> + </route> + </camelContext> +---- + + == Using the transactional error handler The transactional error handler is based on spring transaction. This 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 413065acf39..e87622c7732 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 @@ -28,6 +28,8 @@ import org.apache.camel.model.RouteDefinition; import org.apache.camel.spi.annotations.YamlIn; import org.apache.camel.spi.annotations.YamlProperty; import org.apache.camel.spi.annotations.YamlType; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.snakeyaml.engine.v2.nodes.MappingNode; import org.snakeyaml.engine.v2.nodes.Node; import org.snakeyaml.engine.v2.nodes.NodeTuple; @@ -47,7 +49,7 @@ import org.snakeyaml.engine.v2.nodes.NodeTuple; @YamlProperty(name = "autoStartup", type = "boolean"), @YamlProperty(name = "routePolicy", type = "string"), @YamlProperty(name = "startupOrder", type = "number"), - @YamlProperty(name = "streamCaching", type = "boolean"), + @YamlProperty(name = "streamCache", type = "boolean"), @YamlProperty(name = "messageHistory", type = "boolean"), @YamlProperty(name = "logMask", type = "boolean"), @YamlProperty(name = "trace", type = "boolean"), @@ -65,6 +67,8 @@ import org.snakeyaml.engine.v2.nodes.NodeTuple; }) public class RouteDefinitionDeserializer extends YamlDeserializerBase<RouteDefinition> { + private static final Logger LOG = LoggerFactory.getLogger(RouteDefinitionDeserializer.class); + public RouteDefinitionDeserializer() { super(RouteDefinition.class); } @@ -114,6 +118,11 @@ public class RouteDefinitionDeserializer extends YamlDeserializerBase<RouteDefin target.setStartupOrder(asInt(val)); break; case "streamCaching": + // backwards compatible + LOG.warn("Old option name detected! Option streamCaching should be renamed to streamCache"); + target.setStreamCache(asText(val)); + break; + case "streamCache": target.setStreamCache(asText(val)); break; case "logMask": diff --git a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/schema/camelYamlDsl.json b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/schema/camelYamlDsl.json index ab523aadfc5..158aa6eac22 100644 --- a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/schema/camelYamlDsl.json +++ b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/schema/camelYamlDsl.json @@ -5243,7 +5243,7 @@ "startupOrder" : { "type" : "number" }, - "streamCaching" : { + "streamCache" : { "type" : "boolean" }, "trace" : { diff --git a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/PipeLoaderTest.groovy b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/PipeLoaderTest.groovy index 858b8df4f72..767f788885c 100644 --- a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/PipeLoaderTest.groovy +++ b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/PipeLoaderTest.groovy @@ -705,7 +705,7 @@ class PipeLoaderTest extends YamlTestSupport { with (context.routeDefinitions[1]) { template == true - // stream-caching is disabled in the kamelet + // stream-cache is disabled in the kamelet streamCache == "false" messageHistory == "true" } diff --git a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/RouteTemplateTest.groovy b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/RouteTemplateTest.groovy index 4efb3fcef9c..907d2ae049b 100644 --- a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/RouteTemplateTest.groovy +++ b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/RouteTemplateTest.groovy @@ -416,7 +416,7 @@ class RouteTemplateTest extends YamlTestSupport { - name: "foo" - name: "bar" route: - streamCaching: false + streamCache: false messageHistory: true logMask: true from: diff --git a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/RoutesTest.groovy b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/RoutesTest.groovy index ee19ea61da6..f3970c28742 100644 --- a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/RoutesTest.groovy +++ b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/RoutesTest.groovy @@ -283,7 +283,7 @@ class RoutesTest extends YamlTestSupport { loadRoutes ''' - route: id: demo-route - streamCaching: true + streamCache: true autoStartup: false startupOrder: 123 routePolicy: "myPolicy" @@ -427,12 +427,12 @@ class RoutesTest extends YamlTestSupport { Assertions.assertEquals(2, context.getRoute("bar").filter("bbb*").size()); } - def "Error: kebab-case: stream-cacing"() { + def "Error: kebab-case: stream-cache"() { when: var route = ''' - route: id: demo-route - stream-caching: true + stream-cache: true auto-startup: false startup-order: 123 route-policy: "myPolicy" diff --git a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/resources/kamelets/route-timer-source.kamelet.yaml b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/resources/kamelets/route-timer-source.kamelet.yaml index 0608d771e6d..6fc6fd0cd3d 100644 --- a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/resources/kamelets/route-timer-source.kamelet.yaml +++ b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/resources/kamelets/route-timer-source.kamelet.yaml @@ -57,7 +57,7 @@ spec: - "camel:kamelet" template: route: - stream-caching: false + stream-cache: false message-history: true from: uri: timer:tick diff --git a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/SchemaGeneratorMojo.java b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/SchemaGeneratorMojo.java index 334a352cf9e..b435fdeb40c 100644 --- a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/SchemaGeneratorMojo.java +++ b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/SchemaGeneratorMojo.java @@ -857,6 +857,14 @@ public class SchemaGeneratorMojo extends AbstractGeneratorMojo { null, false, null, null, false, false); eipOptions.add(ep); + // error handler + docComment = findJavaDoc(null, "errorHandler", null, classElement, true); + ep = createOption("errorHandler", "Error Handler", "element", "org.apache.camel.model.ErrorHandlerDefinition", false, + "", + "error", docComment, false, + null, false, null, null, false, false); + eipOptions.add(ep); + // input type docComment = findJavaDoc(null, "inputType", null, classElement, true); ep = createOption("inputType", "Input Type", "element", "org.apache.camel.model.InputTypeDefinition", false, "",