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 90824ad1050077dca392489f49bc522ee47a2951 Author: Claus Ibsen <claus.ib...@gmail.com> AuthorDate: Mon Aug 2 07:36:50 2021 +0200 CAMEL-16757: routes configuration for intercept, on completion --- .../org/apache/camel/catalog/models.properties | 5 +- ...sConfiguration.json => routeConfiguration.json} | 8 +- .../camel/catalog/models/routeConfigurations.json | 16 ++ .../camel/catalog/models/routesConfigurations.json | 17 -- .../camel/catalog/models/templateBeanFactory.json | 17 -- .../apache/camel/catalog/schemas/camel-spring.xsd | 82 ++++---- .../camel/model/RouteConfigurationDefinition.java | 60 ++++++ .../model/RoutesConfigurationBuilderTest.java | 225 ++++++++++++++++++++- 8 files changed, 345 insertions(+), 85 deletions(-) diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models.properties b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models.properties index fd5fa5c..e0d7e06 100644 --- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models.properties +++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models.properties @@ -145,6 +145,8 @@ rollback roundRobin route routeBuilder +routeConfiguration +routeConfigurations routeContext routeContextRef routeTemplate @@ -152,8 +154,6 @@ routeTemplateContext routeTemplateContextRef routeTemplates routes -routesConfiguration -routesConfigurations routingSlip rss saga @@ -189,7 +189,6 @@ syslog tarfile template templateBean -templateBeanFactory templateParameter templateScript threadPool diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/routesConfiguration.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/routeConfiguration.json similarity index 76% rename from catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/routesConfiguration.json rename to catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/routeConfiguration.json index c4a5307..515c123 100644 --- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/routesConfiguration.json +++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/routeConfiguration.json @@ -1,12 +1,12 @@ { "model": { "kind": "model", - "name": "routesConfiguration", - "title": "Routes Configuration", - "description": "Global configuration for Camel routes", + "name": "routeConfiguration", + "title": "Route Configuration", + "description": "Reusable configuration for Camel route(s).", "deprecated": false, "label": "configuration", - "javaType": "org.apache.camel.model.RoutesConfigurationDefinition", + "javaType": "org.apache.camel.model.RouteConfigurationDefinition", "input": false, "output": false }, diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/routeConfigurations.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/routeConfigurations.json new file mode 100644 index 0000000..d9d128f --- /dev/null +++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/routeConfigurations.json @@ -0,0 +1,16 @@ +{ + "model": { + "kind": "model", + "name": "routeConfigurations", + "title": "Route Configurations", + "description": "A series of route configurations", + "deprecated": false, + "label": "configuration", + "javaType": "org.apache.camel.model.RouteConfigurationsDefinition", + "input": false, + "output": false + }, + "properties": { + + } +} diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/routesConfigurations.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/routesConfigurations.json deleted file mode 100644 index 8bd9060..0000000 --- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/routesConfigurations.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "model": { - "kind": "model", - "name": "routesConfigurations", - "title": "Routes Configurations", - "description": "A series of global configuration for Camel routes", - "deprecated": false, - "label": "configuration", - "javaType": "org.apache.camel.model.RoutesConfigurationsDefinition", - "input": false, - "output": false - }, - "properties": { - "id": { "kind": "attribute", "displayName": "Id", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the id of this node" }, - "description": { "kind": "element", "displayName": "Description", "required": false, "type": "object", "javaType": "org.apache.camel.model.DescriptionDefinition", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the description of this node" } - } -} diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/templateBeanFactory.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/templateBeanFactory.json deleted file mode 100644 index 538a54b..0000000 --- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/templateBeanFactory.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "model": { - "kind": "model", - "name": "templateBeanFactory", - "title": "Template Bean Factory", - "description": "A route template bean factory (local bean)", - "deprecated": false, - "label": "configuration", - "javaType": "org.apache.camel.model.RouteTemplateBeanFactoryDefinition", - "input": false, - "output": false - }, - "properties": { - "language": { "kind": "attribute", "displayName": "Language", "required": false, "type": "enum", "javaType": "java.lang.String", "enum": [ "bean", "groovy", "joor", "language", "mvel", "ognl" ], "deprecated": false, "autowired": false, "secret": false, "description": "The language to use for creating the bean (such as groovy, joor)" }, - "script": { "kind": "value", "displayName": "Script", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "The script to execute that creates the bean. If the script use the prefix resource: such as resource:classpath:com\/foo\/myscript.groovy, resource:file:\/var\/myscript.groovy, then its loaded from the external resource." } - } -} diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/schemas/camel-spring.xsd b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/schemas/camel-spring.xsd index 1000a99..a9e8def 100644 --- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/schemas/camel-spring.xsd +++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/schemas/camel-spring.xsd @@ -1265,6 +1265,22 @@ To refer to a Java org.apache.camel.builder.RouteBuilder instance to use. </xs:annotation> </xs:element> + <xs:element name="routeConfiguration" type="tns:routeConfigurationDefinition"> + <xs:annotation> + <xs:documentation xml:lang="en"><![CDATA[ +Reusable configuration for Camel route(s). + ]]></xs:documentation> + </xs:annotation> + </xs:element> + + <xs:element name="routeConfigurations" type="tns:routeConfigurationsDefinition"> + <xs:annotation> + <xs:documentation xml:lang="en"><![CDATA[ +A series of route configurations + ]]></xs:documentation> + </xs:annotation> + </xs:element> + <xs:element name="routeContext" type="tns:camelRouteContextFactoryBean"> <xs:annotation> <xs:documentation xml:lang="en"><![CDATA[ @@ -1329,22 +1345,6 @@ A series of Camel routes </xs:annotation> </xs:element> - <xs:element name="routesConfiguration" type="tns:routesConfigurationDefinition"> - <xs:annotation> - <xs:documentation xml:lang="en"><![CDATA[ -Global configuration for Camel routes - ]]></xs:documentation> - </xs:annotation> - </xs:element> - - <xs:element name="routesConfigurations" type="tns:routesConfigurationsDefinition"> - <xs:annotation> - <xs:documentation xml:lang="en"><![CDATA[ -A series of global configuration for Camel routes - ]]></xs:documentation> - </xs:annotation> - </xs:element> - <xs:element name="routingSlip" type="tns:routingSlipDefinition"> <xs:annotation> <xs:documentation xml:lang="en"><![CDATA[ @@ -10627,6 +10627,29 @@ Reference to the route builder instance. </xs:complexContent> </xs:complexType> + <xs:complexType name="routeConfigurationDefinition"> + <xs:complexContent> + <xs:extension base="tns:optionalIdentifiedDefinition"> + <xs:sequence> + <xs:element maxOccurs="unbounded" minOccurs="0" ref="tns:onException"/> + <xs:element maxOccurs="unbounded" minOccurs="0" ref="tns:onCompletion"/> + <xs:choice maxOccurs="unbounded" minOccurs="0"> + <xs:element ref="tns:intercept"/> + <xs:element ref="tns:interceptFrom"/> + </xs:choice> + <xs:element maxOccurs="unbounded" minOccurs="0" ref="tns:interceptFrom"/> + <xs:element maxOccurs="unbounded" minOccurs="0" ref="tns:interceptSendToEndpoint"/> + </xs:sequence> + </xs:extension> + </xs:complexContent> + </xs:complexType> + + <xs:complexType name="routeConfigurationsDefinition"> + <xs:sequence> + <xs:element maxOccurs="unbounded" minOccurs="0" ref="tns:routeConfiguration"/> + </xs:sequence> + </xs:complexType> + <xs:complexType name="routeContextRefDefinition"> <xs:sequence/> <xs:attribute name="ref" type="xs:string" use="required"> @@ -10922,33 +10945,6 @@ Description of the parameter. </xs:complexContent> </xs:complexType> - <xs:complexType name="routesConfigurationDefinition"> - <xs:complexContent> - <xs:extension base="tns:optionalIdentifiedDefinition"> - <xs:sequence> - <xs:element maxOccurs="unbounded" minOccurs="0" ref="tns:onException"/> - <xs:element maxOccurs="unbounded" minOccurs="0" ref="tns:onCompletion"/> - <xs:choice maxOccurs="unbounded" minOccurs="0"> - <xs:element ref="tns:intercept"/> - <xs:element ref="tns:interceptFrom"/> - </xs:choice> - <xs:element maxOccurs="unbounded" minOccurs="0" ref="tns:interceptFrom"/> - <xs:element maxOccurs="unbounded" minOccurs="0" ref="tns:interceptSendToEndpoint"/> - </xs:sequence> - </xs:extension> - </xs:complexContent> - </xs:complexType> - - <xs:complexType name="routesConfigurationsDefinition"> - <xs:complexContent> - <xs:extension base="tns:optionalIdentifiedDefinition"> - <xs:sequence> - <xs:element maxOccurs="unbounded" minOccurs="0" ref="tns:routesConfiguration"/> - </xs:sequence> - </xs:extension> - </xs:complexContent> - </xs:complexType> - <xs:complexType name="routesDefinition"> <xs:complexContent> <xs:extension base="tns:optionalIdentifiedDefinition"> 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 e4b4090..3ffb1f1 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 @@ -135,4 +135,64 @@ public class RouteConfigurationDefinition extends OptionalIdentifiedDefinition<R return answer; } + /** + * <a href="http://camel.apache.org/oncompletion.html">On completion</a> callback for doing custom routing when the + * {@link org.apache.camel.Exchange} is complete. + * + * @return the on completion builder to configure + */ + public OnCompletionDefinition onCompletion() { + OnCompletionDefinition answer = new OnCompletionDefinition(); + // is global scoped by default + answer.setRouteScoped(false); + onCompletions.add(answer); + return answer; + } + + /** + * Adds a route for an interceptor that intercepts every processing step. + * + * @return the builder + */ + public InterceptDefinition intercept() { + InterceptDefinition answer = new InterceptDefinition(); + intercepts.add(answer); + return answer; + } + + /** + * Adds a route for an interceptor that intercepts incoming messages on any inputs in this route + * + * @return the builder + */ + public InterceptFromDefinition interceptFrom() { + InterceptFromDefinition answer = new InterceptFromDefinition(); + interceptFroms.add(answer); + return answer; + } + + /** + * Adds a route for an interceptor that intercepts incoming messages on the given endpoint. + * + * @param uri endpoint uri + * @return the builder + */ + public InterceptFromDefinition interceptFrom(String uri) { + InterceptFromDefinition answer = new InterceptFromDefinition(uri); + interceptFroms.add(answer); + return answer; + } + + /** + * Applies a route for an interceptor if an exchange is send to the given endpoint + * + * @param uri endpoint uri + * @return the builder + */ + public InterceptSendToEndpointDefinition interceptSendToEndpoint(String uri) { + InterceptSendToEndpointDefinition answer = new InterceptSendToEndpointDefinition(uri); + interceptSendTos.add(answer); + return answer; + } + } diff --git a/core/camel-core/src/test/java/org/apache/camel/model/RoutesConfigurationBuilderTest.java b/core/camel-core/src/test/java/org/apache/camel/model/RoutesConfigurationBuilderTest.java index 38e31b0..5e70d18 100644 --- a/core/camel-core/src/test/java/org/apache/camel/model/RoutesConfigurationBuilderTest.java +++ b/core/camel-core/src/test/java/org/apache/camel/model/RoutesConfigurationBuilderTest.java @@ -35,7 +35,7 @@ public class RoutesConfigurationBuilderTest extends ContextTestSupport { } @Test - public void testRoutesConfiguration() throws Exception { + public void testRoutesConfigurationOnException() throws Exception { List<RoutesBuilder> routes = new ArrayList<>(); routes.add(new RouteBuilder() { @@ -84,4 +84,227 @@ public class RoutesConfigurationBuilderTest extends ContextTestSupport { assertMockEndpointsSatisfied(); } + @Test + public void testRoutesConfigurationOnCompletion() throws Exception { + List<RoutesBuilder> routes = new ArrayList<>(); + + routes.add(new RouteBuilder() { + @Override + public void configure() throws Exception { + from("direct:start") + .to("mock:result"); + } + }); + routes.add(new RouteBuilder() { + @Override + public void configure() throws Exception { + from("direct:start2") + // route scoped that overrides the global scoped + .onCompletion().to("mock:done2").end() + .to("mock:result"); + } + }); + routes.add(new RouteConfigurationBuilder() { + @Override + public void configuration() throws Exception { + // global routes configuration + routeConfiguration().onCompletion().to("mock:done"); + } + }); + context.start(); + + // sort routes according to ordered + routes.sort(OrderedComparator.get()); + + // first add the routes configurations as they are globally for all routes + for (RoutesBuilder builder : routes) { + if (builder instanceof RouteConfigurationsBuilder) { + RouteConfigurationsBuilder rcb = (RouteConfigurationsBuilder) builder; + context.addRoutesConfigurations(rcb); + } + } + // then add the routes + for (RoutesBuilder builder : routes) { + context.addRoutes(builder); + } + + getMockEndpoint("mock:result").expectedMessageCount(2); + getMockEndpoint("mock:done").expectedBodiesReceived("Hello World"); + getMockEndpoint("mock:done2").expectedBodiesReceived("Bye World"); + + template.sendBody("direct:start", "Hello World"); + template.sendBody("direct:start2", "Bye World"); + + assertMockEndpointsSatisfied(); + } + + @Test + public void testRoutesConfigurationIntercept() throws Exception { + List<RoutesBuilder> routes = new ArrayList<>(); + + routes.add(new RouteBuilder() { + @Override + public void configure() throws Exception { + from("direct:start") + .setBody(constant("A")) + .setBody(constant("B")) + .to("mock:result"); + } + }); + routes.add(new RouteBuilder() { + @Override + public void configure() throws Exception { + from("direct:start2") + .setBody(constant("C")) + .setBody(constant("D")) + .to("mock:result"); + } + }); + routes.add(new RouteConfigurationBuilder() { + @Override + public void configuration() throws Exception { + // global routes configuration + routeConfiguration().intercept().to("mock:step"); + } + }); + context.start(); + + // sort routes according to ordered + routes.sort(OrderedComparator.get()); + + // first add the routes configurations as they are globally for all routes + for (RoutesBuilder builder : routes) { + if (builder instanceof RouteConfigurationsBuilder) { + RouteConfigurationsBuilder rcb = (RouteConfigurationsBuilder) builder; + context.addRoutesConfigurations(rcb); + } + } + // then add the routes + for (RoutesBuilder builder : routes) { + context.addRoutes(builder); + } + + getMockEndpoint("mock:result").expectedMessageCount(2); + getMockEndpoint("mock:step").expectedBodiesReceived("Hello World", "A", "B", "Bye World", "C", "D"); + + template.sendBody("direct:start", "Hello World"); + template.sendBody("direct:start2", "Bye World"); + + assertMockEndpointsSatisfied(); + } + + @Test + public void testRoutesConfigurationInterceptFrom() throws Exception { + List<RoutesBuilder> routes = new ArrayList<>(); + + routes.add(new RouteBuilder() { + @Override + public void configure() throws Exception { + from("seda:start") + .setBody(constant("A")) + .setBody(constant("B")) + .to("mock:result"); + } + }); + routes.add(new RouteBuilder() { + @Override + public void configure() throws Exception { + from("direct:start2") + .setBody(constant("C")) + .setBody(constant("D")) + .to("mock:result"); + } + }); + routes.add(new RouteConfigurationBuilder() { + @Override + public void configuration() throws Exception { + // global routes configuration + routeConfiguration().interceptFrom("direct*").to("mock:step"); + } + }); + context.start(); + + // sort routes according to ordered + routes.sort(OrderedComparator.get()); + + // first add the routes configurations as they are globally for all routes + for (RoutesBuilder builder : routes) { + if (builder instanceof RouteConfigurationsBuilder) { + RouteConfigurationsBuilder rcb = (RouteConfigurationsBuilder) builder; + context.addRoutesConfigurations(rcb); + } + } + // then add the routes + for (RoutesBuilder builder : routes) { + context.addRoutes(builder); + } + + getMockEndpoint("mock:result").expectedMessageCount(2); + getMockEndpoint("mock:step").expectedBodiesReceived("Bye World"); + + template.sendBody("seda:start", "Hello World"); + template.sendBody("direct:start2", "Bye World"); + + assertMockEndpointsSatisfied(); + } + + @Test + public void testRoutesConfigurationInterceptSendTo() throws Exception { + List<RoutesBuilder> routes = new ArrayList<>(); + + routes.add(new RouteBuilder() { + @Override + public void configure() throws Exception { + from("direct:start") + .setBody(constant("A")) + .to("mock:foo") + .setBody(constant("B")) + .to("mock:bar") + .to("mock:result"); + } + }); + routes.add(new RouteBuilder() { + @Override + public void configure() throws Exception { + from("direct:start2") + .setBody(constant("C")) + .to("mock:foo") + .setBody(constant("D")) + .to("mock:bar") + .to("mock:result"); + } + }); + routes.add(new RouteConfigurationBuilder() { + @Override + public void configuration() throws Exception { + // global routes configuration + routeConfiguration().interceptSendToEndpoint("mock:foo").to("mock:step"); + } + }); + context.start(); + + // sort routes according to ordered + routes.sort(OrderedComparator.get()); + + // first add the routes configurations as they are globally for all routes + for (RoutesBuilder builder : routes) { + if (builder instanceof RouteConfigurationsBuilder) { + RouteConfigurationsBuilder rcb = (RouteConfigurationsBuilder) builder; + context.addRoutesConfigurations(rcb); + } + } + // then add the routes + for (RoutesBuilder builder : routes) { + context.addRoutes(builder); + } + + getMockEndpoint("mock:result").expectedMessageCount(2); + getMockEndpoint("mock:step").expectedBodiesReceived("A", "C"); + + template.sendBody("direct:start", "Hello World"); + template.sendBody("direct:start2", "Bye World"); + + assertMockEndpointsSatisfied(); + } + }