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 52764e6e0b9 CAMEL-18557: camel-core - Total counter on ContextMBean is 
too high
52764e6e0b9 is described below

commit 52764e6e0b91ccbd740cc905429e9f35b0b65567
Author: Claus Ibsen <claus.ib...@gmail.com>
AuthorDate: Mon Sep 26 19:07:33 2022 +0200

    CAMEL-18557: camel-core - Total counter on ContextMBean is too high
---
 .../main/java/org/apache/camel/spi/UnitOfWork.java | 13 ++++
 .../camel/impl/engine/DefaultUnitOfWork.java       |  5 ++
 .../management/mbean/ManagedCamelContext.java      | 53 ++++++++++++++
 .../ManagedCamelContextTotalCounterTest.java       | 85 ++++++++++++++++++++++
 .../ROOT/pages/camel-3x-upgrade-guide-3_19.adoc    |  8 ++
 5 files changed, 164 insertions(+)

diff --git a/core/camel-api/src/main/java/org/apache/camel/spi/UnitOfWork.java 
b/core/camel-api/src/main/java/org/apache/camel/spi/UnitOfWork.java
index e2f25fa1533..b9d28cb530e 100644
--- a/core/camel-api/src/main/java/org/apache/camel/spi/UnitOfWork.java
+++ b/core/camel-api/src/main/java/org/apache/camel/spi/UnitOfWork.java
@@ -190,6 +190,19 @@ public interface UnitOfWork {
      */
     Route popRoute();
 
+    /**
+     * Gets the {@link Route} level-of-depth that this {@link UnitOfWork} 
currently is being routed through.
+     * <p/>
+     * Notice that an {@link Exchange} can be routed through multiple routes 
and thus the level of depth can change over
+     * time.
+     *
+     * If level is 1 then the current route is at the first route (original 
route). Maybe be <tt>0</tt> if not routed
+     * through a route currently.
+     *
+     * @return the route level-of-depth
+     */
+    int routeStackLevel();
+
     /**
      * Whether the unit of work should call the before/after process methods 
or not.
      */
diff --git 
a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultUnitOfWork.java
 
b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultUnitOfWork.java
index 09110b55a89..ea1640933a6 100644
--- 
a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultUnitOfWork.java
+++ 
b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultUnitOfWork.java
@@ -348,6 +348,11 @@ public class DefaultUnitOfWork implements UnitOfWork {
         return routes.poll();
     }
 
+    @Override
+    public int routeStackLevel() {
+        return routes.size();
+    }
+
     @Override
     public boolean isBeforeAfterProcess() {
         return false;
diff --git 
a/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedCamelContext.java
 
b/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedCamelContext.java
index 511fa3fbb72..2d9e1848aa8 100644
--- 
a/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedCamelContext.java
+++ 
b/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedCamelContext.java
@@ -32,6 +32,7 @@ import org.w3c.dom.Document;
 
 import org.apache.camel.CamelContext;
 import org.apache.camel.Endpoint;
+import org.apache.camel.Exchange;
 import org.apache.camel.ExtendedCamelContext;
 import org.apache.camel.ManagementStatisticsLevel;
 import org.apache.camel.Producer;
@@ -52,6 +53,7 @@ import org.apache.camel.model.RoutesDefinition;
 import org.apache.camel.model.rest.RestDefinition;
 import org.apache.camel.model.rest.RestsDefinition;
 import org.apache.camel.spi.ManagementStrategy;
+import org.apache.camel.spi.UnitOfWork;
 
 @ManagedResource(description = "Managed CamelContext")
 public class ManagedCamelContext extends ManagedPerformanceCounter implements 
TimerListener, ManagedCamelContextMBean {
@@ -74,6 +76,57 @@ public class ManagedCamelContext extends 
ManagedPerformanceCounter implements Ti
         setStatisticsEnabled(enabled);
     }
 
+    @Override
+    public void completedExchange(Exchange exchange, long time) {
+        // the camel-context mbean is triggered for every route mbean
+        // so we must only trigger on the root level, otherwise the context 
mbean
+        // total counter will be incorrect. For example if an exchange is 
routed via 3 routes
+        // we should only count this as 1 instead of 3.
+        UnitOfWork uow = exchange.getUnitOfWork();
+        if (uow != null) {
+            int level = uow.routeStackLevel();
+            if (level <= 1) {
+                super.completedExchange(exchange, time);
+            }
+        } else {
+            super.completedExchange(exchange, time);
+        }
+    }
+
+    @Override
+    public void failedExchange(Exchange exchange) {
+        // the camel-context mbean is triggered for every route mbean
+        // so we must only trigger on the root level, otherwise the context 
mbean
+        // total counter will be incorrect. For example if an exchange is 
routed via 3 routes
+        // we should only count this as 1 instead of 3.
+        UnitOfWork uow = exchange.getUnitOfWork();
+        if (uow != null) {
+            int level = uow.routeStackLevel();
+            if (level <= 1) {
+                super.failedExchange(exchange);
+            }
+        } else {
+            super.failedExchange(exchange);
+        }
+    }
+
+    @Override
+    public void processExchange(Exchange exchange, String type) {
+        // the camel-context mbean is triggered for every route mbean
+        // so we must only trigger on the root level, otherwise the context 
mbean
+        // total counter will be incorrect. For example if an exchange is 
routed via 3 routes
+        // we should only count this as 1 instead of 3.
+        UnitOfWork uow = exchange.getUnitOfWork();
+        if (uow != null) {
+            int level = uow.routeStackLevel();
+            if (level <= 1) {
+                super.processExchange(exchange, type);
+            }
+        } else {
+            super.processExchange(exchange, type);
+        }
+    }
+
     public CamelContext getContext() {
         return context;
     }
diff --git 
a/core/camel-management/src/test/java/org/apache/camel/management/ManagedCamelContextTotalCounterTest.java
 
b/core/camel-management/src/test/java/org/apache/camel/management/ManagedCamelContextTotalCounterTest.java
new file mode 100644
index 00000000000..5fb6b28cd25
--- /dev/null
+++ 
b/core/camel-management/src/test/java/org/apache/camel/management/ManagedCamelContextTotalCounterTest.java
@@ -0,0 +1,85 @@
+/*
+ * 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.management;
+
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.impl.engine.ExplicitCamelContextNameStrategy;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.condition.DisabledOnOs;
+import org.junit.jupiter.api.condition.OS;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+@DisabledOnOs(OS.AIX)
+public class ManagedCamelContextTotalCounterTest extends ManagementTestSupport 
{
+
+    @Override
+    protected CamelContext createCamelContext() throws Exception {
+        CamelContext context = super.createCamelContext();
+        // to force a different management name than the camel id
+        context.getManagementNameStrategy().setNamePattern("20-#name#");
+        context.setNameStrategy(new 
ExplicitCamelContextNameStrategy("my-camel-context"));
+        return context;
+    }
+
+    @Test
+    public void testContextTotalCounter() throws Exception {
+        template.sendBody("direct:a", "Hello World");
+
+        MBeanServer mbeanServer = getMBeanServer();
+        ObjectName on = getContextObjectName();
+
+        assertTrue(mbeanServer.isRegistered(on), "Should be registered");
+        String name = (String) mbeanServer.getAttribute(on, "CamelId");
+        assertEquals("my-camel-context", name);
+
+        String managementName = (String) mbeanServer.getAttribute(on, 
"ManagementName");
+        assertEquals("20-my-camel-context", managementName);
+
+        Integer total = (Integer) mbeanServer.getAttribute(on, "TotalRoutes");
+        assertEquals(3, total.intValue());
+
+        // 3 routes but only 1 exchange completed
+        Long ec = (Long) mbeanServer.getAttribute(on, "ExchangesCompleted");
+        assertEquals(1, ec.intValue());
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                from("direct:a")
+                        .to("log:a")
+                        .to("direct:b");
+
+                from("direct:b")
+                        .to("log:b")
+                        .to("direct:c");
+
+                from("direct:c")
+                        .to("log:c");
+            }
+        };
+    }
+
+}
diff --git 
a/docs/user-manual/modules/ROOT/pages/camel-3x-upgrade-guide-3_19.adoc 
b/docs/user-manual/modules/ROOT/pages/camel-3x-upgrade-guide-3_19.adoc
index 90a14b93ca3..6ccb2fe316a 100644
--- a/docs/user-manual/modules/ROOT/pages/camel-3x-upgrade-guide-3_19.adoc
+++ b/docs/user-manual/modules/ROOT/pages/camel-3x-upgrade-guide-3_19.adoc
@@ -12,6 +12,14 @@ Added `addClassLoader` method to 
`org.apache.camel.spi.ClassResolver`.
 
 The default TLS protocol is changed from `TLSv1.2` to `TLSv1.3` in Camel JSSE 
support.
 
+=== camel-management
+
+The context MBean (`ManagedCamelContextMBean`) total counter is changed to 
count only once
+while an _exchange_ is being routed through multiple routes. Previously the 
counter was
+a total aggregation of all the routes the _exchange_ was processed. For 
example if an _exchange_
+is routed via A, B and C; then previously the total counter was +3 (+1 for 
route A, +1 for route B, +1 for route C).
+This is now corrected so the total is +1 on the context MBean.
+
 === camel-main
 
 The option `camel.main.eager-classloading` has been removed.

Reply via email to