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"); + } + }; + } + +}
