This is an automated email from the ASF dual-hosted git repository. davsclaus pushed a commit to branch CAMEL-16757b in repository https://gitbox.apache.org/repos/asf/camel.git
commit 33beec2734a530d044f6ce4f15592824ab10e90a Author: Claus Ibsen <claus.ib...@gmail.com> AuthorDate: Tue Aug 3 11:03:12 2021 +0200 CAMEL-16757: route configuration added to classic spring xml (also for cdi xml) --- .../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 +++++++++++++++ .../java/org/apache/camel/impl/DefaultModel.java | 9 +++ ...ainer.java => RouteConfigurationContainer.java} | 16 ++--- .../camel/model/RouteConfigurationsDefinition.java | 2 +- .../org/apache/camel/model/RouteContainer.java | 2 +- .../apache/camel/model/RouteTemplateContainer.java | 2 +- .../core/xml/AbstractCamelContextFactoryBean.java | 45 +++++++++++-- .../RoutesConfigurationBuilderIdOrPatternTest.java | 21 ++++++ 15 files changed, 342 insertions(+), 15 deletions(-) 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/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 475a975..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 @@ -123,6 +123,15 @@ public class DefaultModel implements Model { // 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); } } 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/RouteConfigurationContainer.java similarity index 69% copy from core/camel-core-model/src/main/java/org/apache/camel/model/RouteContainer.java copy to core/camel-core-model/src/main/java/org/apache/camel/model/RouteConfigurationContainer.java index 5e4ba8e..c46aabe 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/RouteConfigurationContainer.java @@ -21,22 +21,22 @@ import java.util.List; import javax.xml.bind.annotation.XmlElementRef; /** - * Container to hold {@link org.apache.camel.model.RouteDefinition Route}. + * Container to hold {@link RouteConfigurationDefinition route configurations}. */ -public interface RouteContainer { +public interface RouteConfigurationContainer { /** - * Returns the routes + * Returns the route configurations * - * @return the routes + * @return the route configurations */ @XmlElementRef - List<RouteDefinition> getRoutes(); + List<RouteConfigurationDefinition> getRouteConfigurations(); /** - * Sets the routes to use + * Sets the route configurations to use * - * @param routes the routes + * @param routes the route configurations */ - void setRoutes(List<RouteDefinition> routes); + void setRouteConfigurations(List<RouteConfigurationDefinition> routes); } diff --git a/core/camel-core-model/src/main/java/org/apache/camel/model/RouteConfigurationsDefinition.java b/core/camel-core-model/src/main/java/org/apache/camel/model/RouteConfigurationsDefinition.java index c56874b..92ec02c 100644 --- a/core/camel-core-model/src/main/java/org/apache/camel/model/RouteConfigurationsDefinition.java +++ b/core/camel-core-model/src/main/java/org/apache/camel/model/RouteConfigurationsDefinition.java @@ -34,7 +34,7 @@ import org.apache.camel.spi.Metadata; @Metadata(label = "configuration") @XmlRootElement(name = "routeConfigurations") @XmlAccessorType(XmlAccessType.FIELD) -public class RouteConfigurationsDefinition { +public class RouteConfigurationsDefinition implements RouteConfigurationContainer { @XmlElementRef private List<RouteConfigurationDefinition> routeConfigurations = new ArrayList<>(); 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/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-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/model/RoutesConfigurationBuilderIdOrPatternTest.java b/core/camel-core/src/test/java/org/apache/camel/model/RoutesConfigurationBuilderIdOrPatternTest.java index ebefa1b..d79b4d0 100644 --- 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 @@ -16,6 +16,7 @@ */ package org.apache.camel.model; +import java.io.FileNotFoundException; import java.io.IOException; import java.util.ArrayList; import java.util.List; @@ -28,6 +29,7 @@ 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 { @@ -219,4 +221,23 @@ public class RoutesConfigurationBuilderIdOrPatternTest extends ContextTestSuppor 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()); + } + } + }