This is an automated email from the ASF dual-hosted git repository.

davsclaus pushed a commit to branch mg
in repository https://gitbox.apache.org/repos/asf/camel.git

commit 833b3680fb78cf575100cf6273718e953910348a
Author: Claus Ibsen <[email protected]>
AuthorDate: Wed Feb 25 21:35:21 2026 +0100

    CAMEL-23049: Add getLastError to ManagedRouteGroupMBean
---
 .../management/mbean/ManagedRouteGroupMBean.java   |  3 +
 .../camel/management/mbean/ManagedRouteGroup.java  | 56 ++++++++++++++
 .../management/ManagedRouteGroupLastErrorTest.java | 88 ++++++++++++++++++++++
 3 files changed, 147 insertions(+)

diff --git 
a/core/camel-management-api/src/main/java/org/apache/camel/api/management/mbean/ManagedRouteGroupMBean.java
 
b/core/camel-management-api/src/main/java/org/apache/camel/api/management/mbean/ManagedRouteGroupMBean.java
index 75a8ed8441bd..ff2b3f8486cf 100644
--- 
a/core/camel-management-api/src/main/java/org/apache/camel/api/management/mbean/ManagedRouteGroupMBean.java
+++ 
b/core/camel-management-api/src/main/java/org/apache/camel/api/management/mbean/ManagedRouteGroupMBean.java
@@ -75,6 +75,9 @@ public interface ManagedRouteGroupMBean extends 
ManagedPerformanceCounterMBean {
     @ManagedAttribute(description = "Throughput message/second")
     String getThroughput();
 
+    @ManagedAttribute(description = "Last error from the routes in this group")
+    RouteError getLastError();
+
     @ManagedOperation(description = "Start all routes")
     void start() throws Exception;
 
diff --git 
a/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedRouteGroup.java
 
b/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedRouteGroup.java
index b1db8651afbd..4c9a1f3e04e3 100644
--- 
a/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedRouteGroup.java
+++ 
b/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedRouteGroup.java
@@ -16,6 +16,7 @@
  */
 package org.apache.camel.management.mbean;
 
+import java.util.Date;
 import java.util.List;
 
 import org.apache.camel.CamelContext;
@@ -25,6 +26,7 @@ import org.apache.camel.ServiceStatus;
 import org.apache.camel.TimerListener;
 import org.apache.camel.api.management.ManagedResource;
 import org.apache.camel.api.management.mbean.ManagedRouteGroupMBean;
+import org.apache.camel.api.management.mbean.RouteError;
 import org.apache.camel.spi.ManagementStrategy;
 import org.apache.camel.util.TimeUtils;
 
@@ -161,6 +163,60 @@ public class ManagedRouteGroup extends 
ManagedPerformanceCounter implements Time
         }
     }
 
+    @Override
+    public RouteError getLastError() {
+        org.apache.camel.spi.RouteError last = null;
+        for (Route route : context.getRoutesByGroup(group)) {
+            var e = route.getLastError();
+            if (e != null) {
+                if (last == null) {
+                    last = e;
+                } else if (e.getDate().compareTo(last.getDate()) > 0) {
+                    last = e;
+                }
+            }
+        }
+        if (last == null) {
+            return null;
+        } else {
+            final org.apache.camel.spi.RouteError error = last;
+            return new RouteError() {
+                @Override
+                public Phase getPhase() {
+                    if (error.getPhase() != null) {
+                        switch (error.getPhase()) {
+                            case START:
+                                return Phase.START;
+                            case STOP:
+                                return Phase.STOP;
+                            case SUSPEND:
+                                return Phase.SUSPEND;
+                            case RESUME:
+                                return Phase.RESUME;
+                            case SHUTDOWN:
+                                return Phase.SHUTDOWN;
+                            case REMOVE:
+                                return Phase.REMOVE;
+                            default:
+                                throw new IllegalStateException();
+                        }
+                    }
+                    return null;
+                }
+
+                @Override
+                public Throwable getException() {
+                    return error.getException();
+                }
+
+                @Override
+                public Date getDate() {
+                    return error.getDate();
+                }
+            };
+        }
+    }
+
     @Override
     public void onTimer() {
         load.update(getInflightExchanges());
diff --git 
a/core/camel-management/src/test/java/org/apache/camel/management/ManagedRouteGroupLastErrorTest.java
 
b/core/camel-management/src/test/java/org/apache/camel/management/ManagedRouteGroupLastErrorTest.java
new file mode 100644
index 000000000000..d84d414ff789
--- /dev/null
+++ 
b/core/camel-management/src/test/java/org/apache/camel/management/ManagedRouteGroupLastErrorTest.java
@@ -0,0 +1,88 @@
+/*
+ * 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 java.util.Set;
+import java.util.concurrent.RejectedExecutionException;
+
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+
+import org.apache.camel.api.management.mbean.RouteError;
+import org.apache.camel.builder.RouteBuilder;
+import org.junit.jupiter.api.Assertions;
+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 ManagedRouteGroupLastErrorTest extends ManagementTestSupport {
+
+    @Test
+    public void testLastError() throws Exception {
+        // fire a message to get it running
+        getMockEndpoint("mock:result").expectedMessageCount(2);
+        template.sendBody("direct:first", "Hello World");
+        template.sendBody("direct:second", "Bye World");
+        assertMockEndpointsSatisfied();
+
+        MBeanServer mbeanServer = getMBeanServer();
+
+        Set<ObjectName> set = mbeanServer.queryNames(new 
ObjectName("*:type=routes,*"), null);
+        assertEquals(3, set.size());
+        var it = set.iterator();
+        ObjectName on = it.next();
+        boolean registered = mbeanServer.isRegistered(on);
+        assertTrue(registered, "Should be registered");
+
+        mbeanServer.invoke(on, "stopAndFail", null, null);
+        on = it.next();
+
+        mbeanServer.invoke(on, "stopAndFail", null, null);
+        // leave the 3rd route okay
+
+        set = mbeanServer.queryNames(new ObjectName("*:type=routegroups,*"), 
null);
+        on = set.iterator().next();
+        registered = mbeanServer.isRegistered(on);
+        assertTrue(registered, "Should be registered");
+
+        String group = (String) mbeanServer.getAttribute(on, "RouteGroup");
+        assertEquals("myGroup", group);
+
+        org.apache.camel.api.management.mbean.RouteError re = (RouteError) 
mbeanServer.getAttribute(on, "LastError");
+
+        Assertions.assertNotNull(re);
+        Assertions.assertInstanceOf(RejectedExecutionException.class, 
re.getException());
+        Assertions.assertEquals(RouteError.Phase.STOP, re.getPhase());
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() {
+        return new RouteBuilder() {
+            @Override
+            public void configure() {
+                
from("direct:first").routeId("first").group("myGroup").to("log:foo").to("mock:result");
+                
from("direct:second").routeId("second").group("myGroup").to("log:foo").to("mock:result");
+                
from("direct:third").routeId("third").group("myGroup").to("log:foo").to("mock:result");
+            }
+        };
+    }
+
+}

Reply via email to