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 f83ef00 CAMEL-16374: allow multiple onCompletion at route scope
(#5879)
f83ef00 is described below
commit f83ef00a1cd305839e22d588f764d4715692e728
Author: klease <[email protected]>
AuthorDate: Wed Jul 28 14:56:15 2021 +0200
CAMEL-16374: allow multiple onCompletion at route scope (#5879)
CAMEL-16374: allow multiple onCompletion for a route and not only one. The
restriction to a single onCompletion for a route has been removed so any number
may be added as for global onCompletion.
---
.../apache/camel/model/OnCompletionDefinition.java | 9 +++---
.../apache/camel/model/ProcessorDefinition.java | 10 +-----
.../apache/camel/model/RouteDefinitionHelper.java | 13 --------
.../OnCompletionCompleteAndFailureTest.java | 6 ++--
.../camel/processor/OnCompletionFailAndOkTest.java | 11 ++-----
.../OnCompletionMoreGlobalRouteCompletionTest.java | 36 ++++++++++++++++++++--
.../modules/ROOT/pages/oncompletion.adoc | 20 +++++++-----
7 files changed, 56 insertions(+), 49 deletions(-)
diff --git
a/core/camel-core-model/src/main/java/org/apache/camel/model/OnCompletionDefinition.java
b/core/camel-core-model/src/main/java/org/apache/camel/model/OnCompletionDefinition.java
index 3761be9..6d50f9f 100644
---
a/core/camel-core-model/src/main/java/org/apache/camel/model/OnCompletionDefinition.java
+++
b/core/camel-core-model/src/main/java/org/apache/camel/model/OnCompletionDefinition.java
@@ -111,15 +111,16 @@ public class OnCompletionDefinition extends
OutputDefinition<OnCompletionDefinit
}
/**
- * Removes all existing {@link
org.apache.camel.model.OnCompletionDefinition} from the definition.
+ * Removes all existing global {@link
org.apache.camel.model.OnCompletionDefinition} from the definition.
* <p/>
- * This is used to let route scoped <tt>onCompletion</tt> overrule any
global <tt>onCompletion</tt>. Hence we remove
- * all existing as they are global.
+ * This is used to let route scoped <tt>onCompletion</tt> overrule any
global <tt>onCompletion</tt>. Do not remove
+ * an existing route-scoped because it is now possible (CAMEL-16374) to
have several.
*
* @param definition the parent definition that is the route
*/
public void removeAllOnCompletionDefinition(ProcessorDefinition<?>
definition) {
- definition.getOutputs().removeIf(out -> out instanceof
OnCompletionDefinition);
+ definition.getOutputs().removeIf(out -> out instanceof
OnCompletionDefinition &&
+ !((OnCompletionDefinition) out).isRouteScoped());
}
@Override
diff --git
a/core/camel-core-model/src/main/java/org/apache/camel/model/ProcessorDefinition.java
b/core/camel-core-model/src/main/java/org/apache/camel/model/ProcessorDefinition.java
index 10f9145..6d2fe06 100644
---
a/core/camel-core-model/src/main/java/org/apache/camel/model/ProcessorDefinition.java
+++
b/core/camel-core-model/src/main/java/org/apache/camel/model/ProcessorDefinition.java
@@ -3574,15 +3574,7 @@ public abstract class ProcessorDefinition<Type extends
ProcessorDefinition<Type>
public OnCompletionDefinition onCompletion() {
OnCompletionDefinition answer = new OnCompletionDefinition();
- Collection<OnCompletionDefinition> col
- = ProcessorDefinitionHelper.filterTypeInOutputs(getOutputs(),
OnCompletionDefinition.class);
- // check if there is a clash
- for (OnCompletionDefinition ocd : col) {
- if (ocd.isRouteScoped()) {
- throw new IllegalArgumentException("Only 1 onCompletion is
allowed per route.");
- }
- }
- // remove all on completions as they would be global scoped and we add
a route scoped which
+ // remove all on completions if they are global scoped and we add a
route scoped which
// should override the global
answer.removeAllOnCompletionDefinition(this);
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 edc6de4..f765b68 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
@@ -637,19 +637,6 @@ public final class RouteDefinitionHelper {
List<OnCompletionDefinition> onCompletions) {
List<OnCompletionDefinition> completions = new ArrayList<>();
- // check if there is a clash
- Collection<OnCompletionDefinition> col
- = ProcessorDefinitionHelper.filterTypeInOutputs(abstracts,
OnCompletionDefinition.class);
- int count = 0;
- for (OnCompletionDefinition ocd : col) {
- if (ocd.isRouteScoped()) {
- count++;
- }
- }
- if (count > 1) {
- throw new IllegalArgumentException("Only 1 onCompletion is allowed
per route.");
- }
-
// find the route scoped onCompletions
for (ProcessorDefinition out : abstracts) {
if (out instanceof OnCompletionDefinition) {
diff --git
a/core/camel-core/src/test/java/org/apache/camel/processor/OnCompletionCompleteAndFailureTest.java
b/core/camel-core/src/test/java/org/apache/camel/processor/OnCompletionCompleteAndFailureTest.java
index 96072b5..3d6a4fd 100644
---
a/core/camel-core/src/test/java/org/apache/camel/processor/OnCompletionCompleteAndFailureTest.java
+++
b/core/camel-core/src/test/java/org/apache/camel/processor/OnCompletionCompleteAndFailureTest.java
@@ -21,7 +21,6 @@ import org.apache.camel.builder.RouteBuilder;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.fail;
public class OnCompletionCompleteAndFailureTest extends ContextTestSupport {
@@ -31,7 +30,7 @@ public class OnCompletionCompleteAndFailureTest extends
ContextTestSupport {
}
@Test
- public void testInvalid() throws Exception {
+ public void testMultipleRouteOnComplete() throws Exception {
try {
context.addRoutes(new RouteBuilder() {
@Override
@@ -39,10 +38,11 @@ public class OnCompletionCompleteAndFailureTest extends
ContextTestSupport {
from("direct:start")
.onCompletion().onCompleteOnly().to("mock:ok").end()
.onCompletion().onFailureOnly().to("mock:error").end()
+ .onCompletion().to("mock:all").end()
.to("mock:result");
}
});
- fail("Should throw exception");
+ //fail("Should throw exception"); Now allowed: CAMEL-16374
} catch (IllegalArgumentException e) {
assertEquals("Only 1 onCompletion is allowed per route.",
e.getMessage());
}
diff --git
a/core/camel-core/src/test/java/org/apache/camel/processor/OnCompletionFailAndOkTest.java
b/core/camel-core/src/test/java/org/apache/camel/processor/OnCompletionFailAndOkTest.java
index e92324b..2b8ba82 100644
---
a/core/camel-core/src/test/java/org/apache/camel/processor/OnCompletionFailAndOkTest.java
+++
b/core/camel-core/src/test/java/org/apache/camel/processor/OnCompletionFailAndOkTest.java
@@ -17,7 +17,6 @@
package org.apache.camel.processor;
import org.apache.camel.ContextTestSupport;
-import org.apache.camel.Exchange;
import org.apache.camel.builder.RouteBuilder;
import org.junit.jupiter.api.Test;
@@ -75,14 +74,8 @@ public class OnCompletionFailAndOkTest extends
ContextTestSupport {
@Override
public void configure() throws Exception {
from("direct:start")
- .onCompletion()
- .choice()
- .when(e ->
e.getProperty(Exchange.EXCEPTION_CAUGHT) != null)
- .to("log:fail").to("mock:fail")
- .otherwise()
- .to("log:ok").to("mock:ok")
- .end()
- .end()
+
.onCompletion().onCompleteOnly().to("log:ok").to("mock:ok").end()
+
.onCompletion().onFailureOnly().to("log:fail").to("mock:fail").end()
.process(new OnCompletionTest.MyProcessor())
.to("mock:result");
}
diff --git
a/core/camel-core/src/test/java/org/apache/camel/processor/OnCompletionMoreGlobalRouteCompletionTest.java
b/core/camel-core/src/test/java/org/apache/camel/processor/OnCompletionMoreGlobalRouteCompletionTest.java
index 47771bd..54084ca 100644
---
a/core/camel-core/src/test/java/org/apache/camel/processor/OnCompletionMoreGlobalRouteCompletionTest.java
+++
b/core/camel-core/src/test/java/org/apache/camel/processor/OnCompletionMoreGlobalRouteCompletionTest.java
@@ -72,7 +72,9 @@ public class OnCompletionMoreGlobalRouteCompletionTest
extends ContextTestSuppor
getMockEndpoint("mock:failure").expectedMessageCount(0);
getMockEndpoint("mock:two").expectedMessageCount(0);
getMockEndpoint("mock:sync").expectedMessageCount(0);
- getMockEndpoint("mock:route").expectedBodiesReceived("Bye World");
+ getMockEndpoint("mock:routeComplete").expectedBodiesReceived("Bye
World");
+ getMockEndpoint("mock:routeFailure").expectedMessageCount(0);
+ getMockEndpoint("mock:routeAll").expectedBodiesReceived("Bye World");
MockEndpoint mock = getMockEndpoint("mock:other");
mock.expectedBodiesReceived("Bye World");
@@ -82,6 +84,31 @@ public class OnCompletionMoreGlobalRouteCompletionTest
extends ContextTestSuppor
assertMockEndpointsSatisfied();
}
+ @Test
+ public void testSynchronizeOtherFailure() throws Exception {
+ // The global onComplete cases should not be invoked
+ getMockEndpoint("mock:complete").expectedMessageCount(0);
+ getMockEndpoint("mock:failure").expectedMessageCount(0);
+ getMockEndpoint("mock:two").expectedMessageCount(0);
+ getMockEndpoint("mock:sync").expectedMessageCount(0);
+ // The onComplete cases on the route for any outcome and for failure
should be invoked
+ getMockEndpoint("mock:routeComplete").expectedMessageCount(0);
+ getMockEndpoint("mock:routeFailure").expectedMessageCount(1);
+ getMockEndpoint("mock:routeAll").expectedMessageCount(1);
+
+ MockEndpoint mock = getMockEndpoint("mock:other");
+ mock.expectedMessageCount(0);
+
+ try {
+ template.sendBody("direct:other", "Kabom");
+ fail("Should throw exception");
+ } catch (CamelExecutionException e) {
+ assertEquals("Kabom", e.getCause().getMessage());
+ }
+
+ assertMockEndpointsSatisfied();
+ }
+
@Override
protected RouteBuilder createRouteBuilder() throws Exception {
return new RouteBuilder() {
@@ -99,8 +126,11 @@ public class OnCompletionMoreGlobalRouteCompletionTest
extends ContextTestSuppor
.process(new MyProcessor()).to("mock:result");
from("direct:other")
- // this route completion should override the global
- .onCompletion().to("mock:route").end().process(new
MyProcessor()).to("mock:other");
+ // these route completions should override the global
+
.onCompletion().onCompleteOnly().to("mock:routeComplete").end()
+
.onCompletion().onFailureOnly().to("mock:routeFailure").end()
+ .onCompletion().to("mock:routeAll").end()
+ .process(new MyProcessor()).to("mock:other");
}
};
}
diff --git a/docs/user-manual/modules/ROOT/pages/oncompletion.adoc
b/docs/user-manual/modules/ROOT/pages/oncompletion.adoc
index a7c733c..3eb8523 100644
--- a/docs/user-manual/modules/ROOT/pages/oncompletion.adoc
+++ b/docs/user-manual/modules/ROOT/pages/oncompletion.adoc
@@ -39,18 +39,18 @@ headers, or send to a log to log the response message, etc.
== onCompletion with route scope
The *onCompletion* DSL allows you to add custom routes/processors when
-the original Exchange is complete. Camel spin-off a
+the original Exchange is complete. Camel spins off a
copy of the Exchange and routes it in a separate
-thread, kinda like a Wire Tap. This allows the
+thread, similar to a Wire Tap. This allows the
original thread to continue while the *onCompletion* route is running
-concurrently. We decided for this model as we did not want the
+concurrently. We chose this model as we did not want the
*onCompletion* route to interfere with the original route.
-*Only 1 onCompletion supported by route scope*
+*Multiple onCompletions allowed at both route and global scope*
-You can only have 1 onCompletion in a route. Only at context scoped
-level you can have multiple. And notice that when you use a route scoped
-onCompletion then any context scoped are disabled for that given route.
+You may define multiple onCompletions at both context and route scope.
+When you define route scoped
+onCompletions then any context scoped are disabled for that given route.
[source,java]
-----------------------------------------------------------
@@ -79,8 +79,12 @@ from("direct:start")
// here we qualify onCompletion to only invoke when the exchange failed
(exception or FAULT body)
.onCompletion().onFailureOnly()
.to("log:sync")
- .to("mock:sync")
+ .to("mock:syncFail")
// must use end to denote the end of the onCompletion route
+ .end()
+ .onCompletion().onCompleteOnly()
+ .to("log:sync")
+ .to("mock:syncOK")
.end()
// here the original route continues
.process(new MyProcessor())