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())

Reply via email to