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 3dcc4cfcaa57 CAMEL-25064: camel-management - EIP and service MBeans:
fix bugs found in a deep review (#26958)
3dcc4cfcaa57 is described below
commit 3dcc4cfcaa571ba7e5370e360621a19f9d36a7ca
Author: Claus Ibsen <[email protected]>
AuthorDate: Mon Sep 28 09:23:54 2026 +0200
CAMEL-25064: camel-management - EIP and service MBeans: fix bugs found in a
deep review (#26958)
- tabular data keyed by a non-unique value failed with
KeyAlreadyExistsException: choice and doTry
extendedInformation, listTasks (new index item), exchange factory
listStatistics (url and routeId),
endpoint utilization and listEndpoints for endpoints that only differ in
a (masked) secret
- listEndpoints reports static/dynamic by the real uri (not the masked)
- choice extendedInformation pairs the right predicate when a when is
disabled
- ForceCompletionOnStop of the aggregate MBean returns the right option
- the endpoint utilization tabular data of 8 EIP MBeans is built by one
helper
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Signed-off-by: Claus Ibsen <[email protected]>
---
.../processor/aggregate/AggregateProcessor.java | 4 +
.../api/management/mbean/CamelOpenMBeanTypes.java | 33 ++--
.../mbean/EndpointUtilizationHelper.java | 63 +++++++
.../mbean/ManagedAggregateProcessor.java | 2 +-
.../camel/management/mbean/ManagedChoice.java | 19 +-
.../camel/management/mbean/ManagedDoTry.java | 4 +-
.../management/mbean/ManagedDynamicRouter.java | 31 +---
.../management/mbean/ManagedEndpointRegistry.java | 13 +-
.../camel/management/mbean/ManagedEnricher.java | 31 +---
.../apache/camel/management/mbean/ManagedPoll.java | 31 +---
.../management/mbean/ManagedPollEnricher.java | 31 +---
.../management/mbean/ManagedRecipientList.java | 31 +---
.../camel/management/mbean/ManagedRoutingSlip.java | 31 +---
.../mbean/ManagedSendDynamicProcessor.java | 31 +---
.../mbean/ManagedTaskManagerRegistry.java | 8 +-
.../management/mbean/ManagedWireTapProcessor.java | 31 +---
.../ManagedTabularDataEdgeCasesTest.java | 201 +++++++++++++++++++++
.../ROOT/pages/camel-4x-upgrade-guide-4_23.adoc | 7 +
18 files changed, 331 insertions(+), 271 deletions(-)
diff --git
a/core/camel-core-processor/src/main/java/org/apache/camel/processor/aggregate/AggregateProcessor.java
b/core/camel-core-processor/src/main/java/org/apache/camel/processor/aggregate/AggregateProcessor.java
index aa569e1a4a5a..be77dbbfb0b3 100644
---
a/core/camel-core-processor/src/main/java/org/apache/camel/processor/aggregate/AggregateProcessor.java
+++
b/core/camel-core-processor/src/main/java/org/apache/camel/processor/aggregate/AggregateProcessor.java
@@ -1202,6 +1202,10 @@ public class AggregateProcessor extends
BaseProcessorSupport
this.discardOnAggregationFailure = discardOnAggregationFailure;
}
+ public boolean isForceCompletionOnStop() {
+ return forceCompletionOnStop;
+ }
+
public void setForceCompletionOnStop(boolean forceCompletionOnStop) {
this.forceCompletionOnStop = forceCompletionOnStop;
}
diff --git
a/core/camel-management-api/src/main/java/org/apache/camel/api/management/mbean/CamelOpenMBeanTypes.java
b/core/camel-management-api/src/main/java/org/apache/camel/api/management/mbean/CamelOpenMBeanTypes.java
index 5f5fc6a486be..9c1b3eb77d63 100644
---
a/core/camel-management-api/src/main/java/org/apache/camel/api/management/mbean/CamelOpenMBeanTypes.java
+++
b/core/camel-management-api/src/main/java/org/apache/camel/api/management/mbean/CamelOpenMBeanTypes.java
@@ -85,7 +85,8 @@ public final class CamelOpenMBeanTypes {
public static TabularType listExchangeFactoryTabularType() throws
OpenDataException {
CompositeType ct = listExchangeFactoryCompositeType();
- return new TabularType("listExchangeFactory", "Lists all the exchange
factories", ct, new String[] { "url" });
+ return new TabularType(
+ "listExchangeFactory", "Lists all the exchange factories", ct,
new String[] { "url", "routeId" });
}
public static CompositeType listExchangeFactoryCompositeType() throws
OpenDataException {
@@ -193,28 +194,29 @@ public final class CamelOpenMBeanTypes {
public static TabularType choiceTabularType() throws OpenDataException {
CompositeType ct = choiceCompositeType();
- return new TabularType("choice", "Choice statistics", ct, new String[]
{ "predicate" });
+ return new TabularType("choice", "Choice statistics", ct, new String[]
{ "index" });
}
public static CompositeType choiceCompositeType() throws OpenDataException
{
return new CompositeType(
"predicates", "Predicates",
- new String[] { "predicate", "language", "matches" },
- new String[] { "Predicate", "Language", "Matches" },
- new OpenType[] { SimpleType.STRING, SimpleType.STRING,
SimpleType.LONG });
+ new String[] { "index", "predicate", "language", "matches" },
+ new String[] { "Index", "Predicate", "Language", "Matches" },
+ new OpenType[] { SimpleType.INTEGER, SimpleType.STRING,
SimpleType.STRING, SimpleType.LONG });
}
public static TabularType doTryTabularType() throws OpenDataException {
CompositeType ct = doTryCompositeType();
- return new TabularType("doTry", "doTry statistics", ct, new String[] {
"exception" });
+ return new TabularType("doTry", "doTry statistics", ct, new String[] {
"index" });
}
public static CompositeType doTryCompositeType() throws OpenDataException {
return new CompositeType(
"exceptions", "Exception types",
- new String[] { "exception", "predicate", "language", "matches"
},
- new String[] { "Exception", "Predicate", "Language", "Matches"
},
- new OpenType[] { SimpleType.STRING, SimpleType.STRING,
SimpleType.STRING, SimpleType.LONG });
+ new String[] { "index", "exception", "predicate", "language",
"matches" },
+ new String[] { "Index", "Exception", "Predicate", "Language",
"Matches" },
+ new OpenType[] {
+ SimpleType.INTEGER, SimpleType.STRING,
SimpleType.STRING, SimpleType.STRING, SimpleType.LONG });
}
public static TabularType loadbalancerExceptionsTabularType() throws
OpenDataException {
@@ -362,20 +364,21 @@ public final class CamelOpenMBeanTypes {
CompositeType ct = listInternalTaskCompositeType();
return new TabularType(
"listTask", "Lists all the internal tasks", ct,
- new String[] { "name" });
+ new String[] { "index" });
}
public static CompositeType listInternalTaskCompositeType() throws
OpenDataException {
return new CompositeType(
"tasks", "Tasks",
new String[] {
- "name", "kind", "status", "attempts", "delay",
"elapsed", "firstTime", "lastTime", "nextTime",
- "failure" },
+ "index", "name", "kind", "status", "attempts",
"delay", "elapsed", "firstTime", "lastTime",
+ "nextTime", "failure" },
new String[] {
- "Name", "Kind", "Status", "Attempts", "Delay",
"Elapsed", "FirstTime", "LastTime", "NextTime",
- "Failure" },
+ "Index", "Name", "Kind", "Status", "Attempts",
"Delay", "Elapsed", "FirstTime", "LastTime",
+ "NextTime", "Failure" },
new OpenType[] {
- SimpleType.STRING, SimpleType.STRING,
SimpleType.STRING, SimpleType.LONG, SimpleType.LONG,
+ SimpleType.INTEGER, SimpleType.STRING,
SimpleType.STRING, SimpleType.STRING, SimpleType.LONG,
+ SimpleType.LONG,
SimpleType.LONG, SimpleType.LONG, SimpleType.LONG,
SimpleType.LONG, SimpleType.STRING });
}
diff --git
a/core/camel-management/src/main/java/org/apache/camel/management/mbean/EndpointUtilizationHelper.java
b/core/camel-management/src/main/java/org/apache/camel/management/mbean/EndpointUtilizationHelper.java
new file mode 100644
index 000000000000..5e18c626f766
--- /dev/null
+++
b/core/camel-management/src/main/java/org/apache/camel/management/mbean/EndpointUtilizationHelper.java
@@ -0,0 +1,63 @@
+/*
+ * 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.mbean;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import javax.management.openmbean.CompositeData;
+import javax.management.openmbean.CompositeDataSupport;
+import javax.management.openmbean.CompositeType;
+import javax.management.openmbean.OpenDataException;
+import javax.management.openmbean.TabularData;
+import javax.management.openmbean.TabularDataSupport;
+
+import org.apache.camel.api.management.mbean.CamelOpenMBeanTypes;
+import org.apache.camel.spi.EndpointUtilizationStatistics;
+import org.apache.camel.util.URISupport;
+
+/**
+ * The endpoint utilization statistics of an EIP (such as toD) as tabular data.
+ */
+final class EndpointUtilizationHelper {
+
+ private EndpointUtilizationHelper() {
+ }
+
+ static TabularData toTabularData(EndpointUtilizationStatistics stats,
boolean sanitize) throws OpenDataException {
+ TabularData answer = new
TabularDataSupport(CamelOpenMBeanTypes.endpointsUtilizationTabularType());
+ if (stats != null) {
+ // endpoints that only differ in a secret are the same url when
sanitized, so their hits are merged
+ Map<String, Long> hitsPerUrl = new LinkedHashMap<>();
+ for (Map.Entry<String, Long> entry :
stats.getStatistics().entrySet()) {
+ String url = entry.getKey();
+ if (sanitize) {
+ url = URISupport.sanitizeUri(url);
+ }
+ long hits = entry.getValue() != null ? entry.getValue() : 0L;
+ hitsPerUrl.merge(url, hits, Long::sum);
+ }
+ CompositeType ct =
CamelOpenMBeanTypes.endpointsUtilizationCompositeType();
+ for (Map.Entry<String, Long> entry : hitsPerUrl.entrySet()) {
+ CompositeData data = new CompositeDataSupport(
+ ct, new String[] { "url", "hits" }, new Object[] {
entry.getKey(), entry.getValue() });
+ answer.put(data);
+ }
+ }
+ return answer;
+ }
+}
diff --git
a/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedAggregateProcessor.java
b/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedAggregateProcessor.java
index 5b196dad0429..dddf5d16c079 100644
---
a/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedAggregateProcessor.java
+++
b/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedAggregateProcessor.java
@@ -175,7 +175,7 @@ public class ManagedAggregateProcessor extends
ManagedProcessor implements Manag
@Override
public boolean isForceCompletionOnStop() {
- return getProcessor().isCompletionFromBatchConsumer();
+ return getProcessor().isForceCompletionOnStop();
}
@Override
diff --git
a/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedChoice.java
b/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedChoice.java
index 29d93aa73f0e..f5f50529b89c 100644
---
a/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedChoice.java
+++
b/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedChoice.java
@@ -34,6 +34,7 @@ import org.apache.camel.model.ProcessorDefinition;
import org.apache.camel.model.WhenDefinition;
import org.apache.camel.processor.ChoiceProcessor;
import org.apache.camel.processor.FilterProcessor;
+import org.apache.camel.reifier.ProcessorReifier;
@ManagedResource(description = "Managed Choice")
public class ManagedChoice extends ManagedProcessor implements
ManagedChoiceMBean {
@@ -68,10 +69,13 @@ public class ManagedChoice extends ManagedProcessor
implements ManagedChoiceMBea
try {
TabularData answer = new
TabularDataSupport(CamelOpenMBeanTypes.choiceTabularType());
- List<WhenDefinition> whens = getDefinition().getWhenClauses();
+ // there is a filter for each when that is not disabled
+ List<WhenDefinition> whens =
getDefinition().getWhenClauses().stream()
+ .filter(w -> !ProcessorReifier.isDisabled(getContext(), w))
+ .toList();
List<FilterProcessor> filters = getProcessor().getFilters();
- for (int i = 0; i < filters.size(); i++) {
+ for (int i = 0; i < filters.size() && i < whens.size(); i++) {
WhenDefinition when = whens.get(i);
FilterProcessor filter = filters.get(i);
@@ -82,11 +86,12 @@ public class ManagedChoice extends ManagedProcessor
implements ManagedChoiceMBea
CompositeData data = new CompositeDataSupport(
ct,
- new String[] { "predicate", "language", "matches" },
- new Object[] { predicate, language, matches });
+ new String[] { "index", "predicate", "language",
"matches" },
+ new Object[] { answer.size(), predicate, language,
matches });
answer.put(data);
}
- if (getDefinition().getOtherwise() != null) {
+ if (getDefinition().getOtherwise() != null
+ && !ProcessorReifier.isDisabled(getContext(),
getDefinition().getOtherwise())) {
CompositeType ct = CamelOpenMBeanTypes.choiceCompositeType();
String predicate = "otherwise";
String language = "";
@@ -94,8 +99,8 @@ public class ManagedChoice extends ManagedProcessor
implements ManagedChoiceMBea
CompositeData data = new CompositeDataSupport(
ct,
- new String[] { "predicate", "language", "matches" },
- new Object[] { predicate, language, matches });
+ new String[] { "index", "predicate", "language",
"matches" },
+ new Object[] { answer.size(), predicate, language,
matches });
answer.put(data);
}
diff --git
a/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedDoTry.java
b/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedDoTry.java
index 22289a667b5b..dcfcfedc1c0b 100644
---
a/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedDoTry.java
+++
b/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedDoTry.java
@@ -84,8 +84,8 @@ public class ManagedDoTry extends ManagedProcessor implements
ManagedDoTryMBean
CompositeData data = new CompositeDataSupport(
ct,
- new String[] { "exception", "predicate",
"language", "matches" },
- new Object[] { fqn, predicate, language,
matches });
+ new String[] { "index", "exception",
"predicate", "language", "matches" },
+ new Object[] { answer.size(), fqn, predicate,
language, matches });
answer.put(data);
}
}
diff --git
a/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedDynamicRouter.java
b/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedDynamicRouter.java
index dadb79d8f63c..814691ef59d4 100644
---
a/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedDynamicRouter.java
+++
b/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedDynamicRouter.java
@@ -16,22 +16,14 @@
*/
package org.apache.camel.management.mbean;
-import java.util.Map;
-
-import javax.management.openmbean.CompositeData;
-import javax.management.openmbean.CompositeDataSupport;
-import javax.management.openmbean.CompositeType;
import javax.management.openmbean.TabularData;
-import javax.management.openmbean.TabularDataSupport;
import org.apache.camel.CamelContext;
import org.apache.camel.RuntimeCamelException;
import org.apache.camel.api.management.ManagedResource;
-import org.apache.camel.api.management.mbean.CamelOpenMBeanTypes;
import org.apache.camel.api.management.mbean.ManagedDynamicRouterMBean;
import org.apache.camel.model.DynamicRouterDefinition;
import org.apache.camel.processor.DynamicRouter;
-import org.apache.camel.spi.EndpointUtilizationStatistics;
import org.apache.camel.spi.ManagementStrategy;
import org.apache.camel.util.URISupport;
@@ -111,28 +103,7 @@ public class ManagedDynamicRouter extends ManagedProcessor
implements ManagedDyn
@Override
public TabularData extendedInformation() {
try {
- TabularData answer = new
TabularDataSupport(CamelOpenMBeanTypes.endpointsUtilizationTabularType());
-
- EndpointUtilizationStatistics stats =
getProcessor().getEndpointUtilizationStatistics();
- if (stats != null) {
- for (Map.Entry<String, Long> entry :
stats.getStatistics().entrySet()) {
- CompositeType ct =
CamelOpenMBeanTypes.endpointsUtilizationCompositeType();
- String url = entry.getKey();
- if (sanitize) {
- url = URISupport.sanitizeUri(url);
- }
-
- Long hits = entry.getValue();
- if (hits == null) {
- hits = 0L;
- }
-
- CompositeData data
- = new CompositeDataSupport(ct, new String[] {
"url", "hits" }, new Object[] { url, hits });
- answer.put(data);
- }
- }
- return answer;
+ return
EndpointUtilizationHelper.toTabularData(getProcessor().getEndpointUtilizationStatistics(),
sanitize);
} catch (Exception e) {
throw RuntimeCamelException.wrapRuntimeCamelException(e);
}
diff --git
a/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedEndpointRegistry.java
b/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedEndpointRegistry.java
index 7f93b0d1db83..1ed7bd26e49b 100644
---
a/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedEndpointRegistry.java
+++
b/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedEndpointRegistry.java
@@ -17,6 +17,8 @@
package org.apache.camel.management.mbean;
import java.util.Collection;
+import java.util.HashSet;
+import java.util.Set;
import javax.management.openmbean.CompositeData;
import javax.management.openmbean.CompositeDataSupport;
@@ -89,15 +91,20 @@ public class ManagedEndpointRegistry extends ManagedService
implements ManagedEn
try {
TabularData answer = new
TabularDataSupport(CamelOpenMBeanTypes.listEndpointsTabularType());
Collection<Endpoint> endpoints = endpointRegistry.values();
+ Set<String> urls = new HashSet<>();
for (Endpoint endpoint : endpoints) {
CompositeType ct =
CamelOpenMBeanTypes.listEndpointsCompositeType();
String url = endpoint.getEndpointUri();
+ // look up by the real uri (and not the sanitized)
+ boolean fromStatic = endpointRegistry.isStatic(url);
+ boolean fromDynamic = endpointRegistry.isDynamic(url);
if (sanitize) {
url = URISupport.sanitizeUri(url);
}
-
- boolean fromStatic = endpointRegistry.isStatic(url);
- boolean fromDynamic = endpointRegistry.isDynamic(url);
+ if (!urls.add(url)) {
+ // endpoints that only differ in a secret are the same url
when sanitized
+ continue;
+ }
CompositeData data = new CompositeDataSupport(
ct, new String[] { "url", "static", "dynamic" }, new
Object[] { url, fromStatic, fromDynamic });
diff --git
a/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedEnricher.java
b/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedEnricher.java
index dff6cdc211a6..cf1b9a8a5dc9 100644
---
a/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedEnricher.java
+++
b/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedEnricher.java
@@ -16,22 +16,14 @@
*/
package org.apache.camel.management.mbean;
-import java.util.Map;
-
-import javax.management.openmbean.CompositeData;
-import javax.management.openmbean.CompositeDataSupport;
-import javax.management.openmbean.CompositeType;
import javax.management.openmbean.TabularData;
-import javax.management.openmbean.TabularDataSupport;
import org.apache.camel.CamelContext;
import org.apache.camel.RuntimeCamelException;
import org.apache.camel.api.management.ManagedResource;
-import org.apache.camel.api.management.mbean.CamelOpenMBeanTypes;
import org.apache.camel.api.management.mbean.ManagedEnricherMBean;
import org.apache.camel.model.EnrichDefinition;
import org.apache.camel.processor.Enricher;
-import org.apache.camel.spi.EndpointUtilizationStatistics;
import org.apache.camel.spi.ManagementStrategy;
import org.apache.camel.util.URISupport;
@@ -126,28 +118,7 @@ public class ManagedEnricher extends ManagedProcessor
implements ManagedEnricher
@Override
public TabularData extendedInformation() {
try {
- TabularData answer = new
TabularDataSupport(CamelOpenMBeanTypes.endpointsUtilizationTabularType());
-
- EndpointUtilizationStatistics stats =
getProcessor().getEndpointUtilizationStatistics();
- if (stats != null) {
- for (Map.Entry<String, Long> entry :
stats.getStatistics().entrySet()) {
- CompositeType ct =
CamelOpenMBeanTypes.endpointsUtilizationCompositeType();
- String url = entry.getKey();
- if (sanitize) {
- url = URISupport.sanitizeUri(url);
- }
-
- Long hits = entry.getValue();
- if (hits == null) {
- hits = 0L;
- }
-
- CompositeData data
- = new CompositeDataSupport(ct, new String[] {
"url", "hits" }, new Object[] { url, hits });
- answer.put(data);
- }
- }
- return answer;
+ return
EndpointUtilizationHelper.toTabularData(getProcessor().getEndpointUtilizationStatistics(),
sanitize);
} catch (Exception e) {
throw RuntimeCamelException.wrapRuntimeCamelException(e);
}
diff --git
a/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedPoll.java
b/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedPoll.java
index fc11ccaa8262..1206d36fa3a9 100644
---
a/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedPoll.java
+++
b/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedPoll.java
@@ -16,22 +16,14 @@
*/
package org.apache.camel.management.mbean;
-import java.util.Map;
-
-import javax.management.openmbean.CompositeData;
-import javax.management.openmbean.CompositeDataSupport;
-import javax.management.openmbean.CompositeType;
import javax.management.openmbean.TabularData;
-import javax.management.openmbean.TabularDataSupport;
import org.apache.camel.CamelContext;
import org.apache.camel.RuntimeCamelException;
import org.apache.camel.api.management.ManagedResource;
-import org.apache.camel.api.management.mbean.CamelOpenMBeanTypes;
import org.apache.camel.api.management.mbean.ManagedPollMBean;
import org.apache.camel.model.PollDefinition;
import org.apache.camel.processor.PollProcessor;
-import org.apache.camel.spi.EndpointUtilizationStatistics;
import org.apache.camel.spi.ManagementStrategy;
import org.apache.camel.util.URISupport;
@@ -96,28 +88,7 @@ public class ManagedPoll extends ManagedProcessor implements
ManagedPollMBean {
@Override
public TabularData extendedInformation() {
try {
- TabularData answer = new
TabularDataSupport(CamelOpenMBeanTypes.endpointsUtilizationTabularType());
-
- EndpointUtilizationStatistics stats =
getProcessor().getEndpointUtilizationStatistics();
- if (stats != null) {
- for (Map.Entry<String, Long> entry :
stats.getStatistics().entrySet()) {
- CompositeType ct =
CamelOpenMBeanTypes.endpointsUtilizationCompositeType();
- String url = entry.getKey();
- if (sanitize) {
- url = URISupport.sanitizeUri(url);
- }
-
- Long hits = entry.getValue();
- if (hits == null) {
- hits = 0L;
- }
-
- CompositeData data
- = new CompositeDataSupport(ct, new String[] {
"url", "hits" }, new Object[] { url, hits });
- answer.put(data);
- }
- }
- return answer;
+ return
EndpointUtilizationHelper.toTabularData(getProcessor().getEndpointUtilizationStatistics(),
sanitize);
} catch (Exception e) {
throw RuntimeCamelException.wrapRuntimeCamelException(e);
}
diff --git
a/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedPollEnricher.java
b/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedPollEnricher.java
index 0f9a9c89d6d4..d167159e9f70 100644
---
a/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedPollEnricher.java
+++
b/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedPollEnricher.java
@@ -16,22 +16,14 @@
*/
package org.apache.camel.management.mbean;
-import java.util.Map;
-
-import javax.management.openmbean.CompositeData;
-import javax.management.openmbean.CompositeDataSupport;
-import javax.management.openmbean.CompositeType;
import javax.management.openmbean.TabularData;
-import javax.management.openmbean.TabularDataSupport;
import org.apache.camel.CamelContext;
import org.apache.camel.RuntimeCamelException;
import org.apache.camel.api.management.ManagedResource;
-import org.apache.camel.api.management.mbean.CamelOpenMBeanTypes;
import org.apache.camel.api.management.mbean.ManagedPollEnricherMBean;
import org.apache.camel.model.PollEnrichDefinition;
import org.apache.camel.processor.PollEnricher;
-import org.apache.camel.spi.EndpointUtilizationStatistics;
import org.apache.camel.spi.ManagementStrategy;
import org.apache.camel.util.URISupport;
@@ -131,28 +123,7 @@ public class ManagedPollEnricher extends ManagedProcessor
implements ManagedPoll
@Override
public TabularData extendedInformation() {
try {
- TabularData answer = new
TabularDataSupport(CamelOpenMBeanTypes.endpointsUtilizationTabularType());
-
- EndpointUtilizationStatistics stats =
getProcessor().getEndpointUtilizationStatistics();
- if (stats != null) {
- for (Map.Entry<String, Long> entry :
stats.getStatistics().entrySet()) {
- CompositeType ct =
CamelOpenMBeanTypes.endpointsUtilizationCompositeType();
- String url = entry.getKey();
- if (sanitize) {
- url = URISupport.sanitizeUri(url);
- }
-
- Long hits = entry.getValue();
- if (hits == null) {
- hits = 0L;
- }
-
- CompositeData data
- = new CompositeDataSupport(ct, new String[] {
"url", "hits" }, new Object[] { url, hits });
- answer.put(data);
- }
- }
- return answer;
+ return
EndpointUtilizationHelper.toTabularData(getProcessor().getEndpointUtilizationStatistics(),
sanitize);
} catch (Exception e) {
throw RuntimeCamelException.wrapRuntimeCamelException(e);
}
diff --git
a/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedRecipientList.java
b/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedRecipientList.java
index a3f434834869..7bb272ac7642 100644
---
a/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedRecipientList.java
+++
b/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedRecipientList.java
@@ -16,22 +16,14 @@
*/
package org.apache.camel.management.mbean;
-import java.util.Map;
-
-import javax.management.openmbean.CompositeData;
-import javax.management.openmbean.CompositeDataSupport;
-import javax.management.openmbean.CompositeType;
import javax.management.openmbean.TabularData;
-import javax.management.openmbean.TabularDataSupport;
import org.apache.camel.CamelContext;
import org.apache.camel.RuntimeCamelException;
import org.apache.camel.api.management.ManagedResource;
-import org.apache.camel.api.management.mbean.CamelOpenMBeanTypes;
import org.apache.camel.api.management.mbean.ManagedRecipientListMBean;
import org.apache.camel.model.RecipientListDefinition;
import org.apache.camel.processor.RecipientList;
-import org.apache.camel.spi.EndpointUtilizationStatistics;
import org.apache.camel.spi.ManagementStrategy;
import org.apache.camel.util.URISupport;
@@ -131,28 +123,7 @@ public class ManagedRecipientList extends ManagedProcessor
implements ManagedRec
@Override
public TabularData extendedInformation() {
try {
- TabularData answer = new
TabularDataSupport(CamelOpenMBeanTypes.endpointsUtilizationTabularType());
-
- EndpointUtilizationStatistics stats =
getProcessor().getEndpointUtilizationStatistics();
- if (stats != null) {
- for (Map.Entry<String, Long> entry :
stats.getStatistics().entrySet()) {
- CompositeType ct =
CamelOpenMBeanTypes.endpointsUtilizationCompositeType();
- String url = entry.getKey();
- if (sanitize) {
- url = URISupport.sanitizeUri(url);
- }
-
- Long hits = entry.getValue();
- if (hits == null) {
- hits = 0L;
- }
-
- CompositeData data
- = new CompositeDataSupport(ct, new String[] {
"url", "hits" }, new Object[] { url, hits });
- answer.put(data);
- }
- }
- return answer;
+ return
EndpointUtilizationHelper.toTabularData(getProcessor().getEndpointUtilizationStatistics(),
sanitize);
} catch (Exception e) {
throw RuntimeCamelException.wrapRuntimeCamelException(e);
}
diff --git
a/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedRoutingSlip.java
b/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedRoutingSlip.java
index d62a5f1acfbf..ed8fc0bccb20 100644
---
a/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedRoutingSlip.java
+++
b/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedRoutingSlip.java
@@ -16,22 +16,14 @@
*/
package org.apache.camel.management.mbean;
-import java.util.Map;
-
-import javax.management.openmbean.CompositeData;
-import javax.management.openmbean.CompositeDataSupport;
-import javax.management.openmbean.CompositeType;
import javax.management.openmbean.TabularData;
-import javax.management.openmbean.TabularDataSupport;
import org.apache.camel.CamelContext;
import org.apache.camel.RuntimeCamelException;
import org.apache.camel.api.management.ManagedResource;
-import org.apache.camel.api.management.mbean.CamelOpenMBeanTypes;
import org.apache.camel.api.management.mbean.ManagedRoutingSlipMBean;
import org.apache.camel.model.RoutingSlipDefinition;
import org.apache.camel.processor.RoutingSlip;
-import org.apache.camel.spi.EndpointUtilizationStatistics;
import org.apache.camel.spi.ManagementStrategy;
import org.apache.camel.util.URISupport;
@@ -106,28 +98,7 @@ public class ManagedRoutingSlip extends ManagedProcessor
implements ManagedRouti
@Override
public TabularData extendedInformation() {
try {
- TabularData answer = new
TabularDataSupport(CamelOpenMBeanTypes.endpointsUtilizationTabularType());
-
- EndpointUtilizationStatistics stats =
getProcessor().getEndpointUtilizationStatistics();
- if (stats != null) {
- for (Map.Entry<String, Long> entry :
stats.getStatistics().entrySet()) {
- CompositeType ct =
CamelOpenMBeanTypes.endpointsUtilizationCompositeType();
- String url = entry.getKey();
- if (sanitize) {
- url = URISupport.sanitizeUri(url);
- }
-
- Long hits = entry.getValue();
- if (hits == null) {
- hits = 0L;
- }
-
- CompositeData data
- = new CompositeDataSupport(ct, new String[] {
"url", "hits" }, new Object[] { url, hits });
- answer.put(data);
- }
- }
- return answer;
+ return
EndpointUtilizationHelper.toTabularData(getProcessor().getEndpointUtilizationStatistics(),
sanitize);
} catch (Exception e) {
throw RuntimeCamelException.wrapRuntimeCamelException(e);
}
diff --git
a/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedSendDynamicProcessor.java
b/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedSendDynamicProcessor.java
index 4c8b51a4072c..8d7ecbcb9f94 100644
---
a/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedSendDynamicProcessor.java
+++
b/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedSendDynamicProcessor.java
@@ -16,22 +16,14 @@
*/
package org.apache.camel.management.mbean;
-import java.util.Map;
-
-import javax.management.openmbean.CompositeData;
-import javax.management.openmbean.CompositeDataSupport;
-import javax.management.openmbean.CompositeType;
import javax.management.openmbean.TabularData;
-import javax.management.openmbean.TabularDataSupport;
import org.apache.camel.CamelContext;
import org.apache.camel.RuntimeCamelException;
import org.apache.camel.api.management.ManagedResource;
-import org.apache.camel.api.management.mbean.CamelOpenMBeanTypes;
import org.apache.camel.api.management.mbean.ManagedSendDynamicProcessorMBean;
import org.apache.camel.model.ProcessorDefinition;
import org.apache.camel.processor.SendDynamicProcessor;
-import org.apache.camel.spi.EndpointUtilizationStatistics;
import org.apache.camel.spi.ManagementStrategy;
import org.apache.camel.util.URISupport;
@@ -126,28 +118,7 @@ public class ManagedSendDynamicProcessor extends
ManagedProcessor implements Man
@Override
public TabularData extendedInformation() {
try {
- TabularData answer = new
TabularDataSupport(CamelOpenMBeanTypes.endpointsUtilizationTabularType());
-
- EndpointUtilizationStatistics stats =
getProcessor().getEndpointUtilizationStatistics();
- if (stats != null) {
- for (Map.Entry<String, Long> entry :
stats.getStatistics().entrySet()) {
- CompositeType ct =
CamelOpenMBeanTypes.endpointsUtilizationCompositeType();
- String url = entry.getKey();
- if (sanitize) {
- url = URISupport.sanitizeUri(url);
- }
-
- Long hits = entry.getValue();
- if (hits == null) {
- hits = 0L;
- }
-
- CompositeData data
- = new CompositeDataSupport(ct, new String[] {
"url", "hits" }, new Object[] { url, hits });
- answer.put(data);
- }
- }
- return answer;
+ return
EndpointUtilizationHelper.toTabularData(getProcessor().getEndpointUtilizationStatistics(),
sanitize);
} catch (Exception e) {
throw RuntimeCamelException.wrapRuntimeCamelException(e);
}
diff --git
a/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedTaskManagerRegistry.java
b/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedTaskManagerRegistry.java
index 96d529312f04..e9da27164927 100644
---
a/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedTaskManagerRegistry.java
+++
b/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedTaskManagerRegistry.java
@@ -65,9 +65,11 @@ public class ManagedTaskManagerRegistry extends
ManagedService implements Manage
CompositeData data = new CompositeDataSupport(
ct,
new String[] {
- "name", "kind", "status", "attempts", "delay",
"elapsed", "firstTime", "lastTime", "nextTime",
- "failure" },
- new Object[] { name, kind, status, attempts, delay,
elapsed, firstTime, lastTime, nextTime, failure });
+ "index", "name", "kind", "status", "attempts",
"delay", "elapsed", "firstTime", "lastTime",
+ "nextTime", "failure" },
+ new Object[] {
+ answer.size(), name, kind, status, attempts,
delay, elapsed, firstTime, lastTime, nextTime,
+ failure });
answer.put(data);
}
return answer;
diff --git
a/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedWireTapProcessor.java
b/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedWireTapProcessor.java
index 2dcf55c7fa31..4281c29176f5 100644
---
a/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedWireTapProcessor.java
+++
b/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedWireTapProcessor.java
@@ -16,22 +16,14 @@
*/
package org.apache.camel.management.mbean;
-import java.util.Map;
-
-import javax.management.openmbean.CompositeData;
-import javax.management.openmbean.CompositeDataSupport;
-import javax.management.openmbean.CompositeType;
import javax.management.openmbean.TabularData;
-import javax.management.openmbean.TabularDataSupport;
import org.apache.camel.CamelContext;
import org.apache.camel.RuntimeCamelException;
import org.apache.camel.api.management.ManagedResource;
-import org.apache.camel.api.management.mbean.CamelOpenMBeanTypes;
import org.apache.camel.api.management.mbean.ManagedWireTapMBean;
import org.apache.camel.model.ProcessorDefinition;
import org.apache.camel.processor.WireTapProcessor;
-import org.apache.camel.spi.EndpointUtilizationStatistics;
import org.apache.camel.spi.ManagementStrategy;
import org.apache.camel.util.URISupport;
@@ -112,28 +104,7 @@ public class ManagedWireTapProcessor extends
ManagedProcessor implements Managed
@Override
public TabularData extendedInformation() {
try {
- TabularData answer = new
TabularDataSupport(CamelOpenMBeanTypes.endpointsUtilizationTabularType());
-
- EndpointUtilizationStatistics stats =
getProcessor().getEndpointUtilizationStatistics();
- if (stats != null) {
- for (Map.Entry<String, Long> entry :
stats.getStatistics().entrySet()) {
- CompositeType ct =
CamelOpenMBeanTypes.endpointsUtilizationCompositeType();
- String url = entry.getKey();
- if (sanitize) {
- url = URISupport.sanitizeUri(url);
- }
-
- Long hits = entry.getValue();
- if (hits == null) {
- hits = 0L;
- }
-
- CompositeData data
- = new CompositeDataSupport(ct, new String[] {
"url", "hits" }, new Object[] { url, hits });
- answer.put(data);
- }
- }
- return answer;
+ return
EndpointUtilizationHelper.toTabularData(getProcessor().getEndpointUtilizationStatistics(),
sanitize);
} catch (Exception e) {
throw RuntimeCamelException.wrapRuntimeCamelException(e);
}
diff --git
a/core/camel-management/src/test/java/org/apache/camel/management/ManagedTabularDataEdgeCasesTest.java
b/core/camel-management/src/test/java/org/apache/camel/management/ManagedTabularDataEdgeCasesTest.java
new file mode 100644
index 000000000000..41835d5118c0
--- /dev/null
+++
b/core/camel-management/src/test/java/org/apache/camel/management/ManagedTabularDataEdgeCasesTest.java
@@ -0,0 +1,201 @@
+/*
+ * 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.io.IOException;
+import java.time.Duration;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+import javax.management.openmbean.CompositeData;
+import javax.management.openmbean.TabularData;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.ManagementStatisticsLevel;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.model.ChoiceDefinition;
+import org.apache.camel.processor.aggregate.UseLatestAggregationStrategy;
+import org.apache.camel.support.task.BackgroundTask;
+import org.apache.camel.support.task.Tasks;
+import org.apache.camel.support.task.budget.Budgets;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.condition.DisabledOnOs;
+import org.junit.jupiter.api.condition.OS;
+
+import static
org.apache.camel.management.DefaultManagementObjectNameStrategy.TYPE_PROCESSOR;
+import static org.awaitility.Awaitility.await;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+@DisabledOnOs(OS.AIX)
+public class ManagedTabularDataEdgeCasesTest extends ManagementTestSupport {
+
+ @Override
+ protected CamelContext createCamelContext() throws Exception {
+ CamelContext context = super.createCamelContext();
+
context.getManagementStrategy().getManagementAgent().setStatisticsLevel(ManagementStatisticsLevel.Extended);
+ return context;
+ }
+
+ private ObjectName service(String name) throws Exception {
+ return getMBeanServer().queryNames(new
ObjectName("*:type=services,*"), null).stream()
+ .filter(n ->
n.getCanonicalName().contains(name)).findFirst().orElseThrow();
+ }
+
+ private static CompositeData row(TabularData data, String item, Object
value) {
+ return data.values().stream().map(CompositeData.class::cast)
+ .filter(cd ->
value.equals(cd.get(item))).findFirst().orElseThrow();
+ }
+
+ @Test
+ public void testChoiceWithSamePredicateTwice() throws Exception {
+ template.sendBodyAndHeader("direct:choice", "Hello", "type", "b");
+
+ TabularData data = (TabularData)
getMBeanServer().invoke(getCamelObjectName(TYPE_PROCESSOR, "myChoice"),
+ "extendedInformation", null, null);
+ // two whens with the same predicate (such as with different outputs
for the same condition) and otherwise
+ assertEquals(3, data.size());
+ }
+
+ @Test
+ public void testChoiceWithDisabledWhen() throws Exception {
+ template.sendBodyAndHeader("direct:disabled", "Hello", "b", "true");
+
+ TabularData data = (TabularData)
getMBeanServer().invoke(getCamelObjectName(TYPE_PROCESSOR, "disabledChoice"),
+ "extendedInformation", null, null);
+ CompositeData b = row(data, "predicate", "${header.b}");
+ assertEquals(1L, b.get("matches"));
+ }
+
+ @Test
+ public void testDoTryWithSameExceptionTwice() throws Exception {
+ // caught by the first doCatch (onWhen), and by the second
+ template.sendBodyAndHeader("direct:try", "Hello", "a", "x");
+ template.sendBodyAndHeader("direct:try", "Hello", "a", "y");
+
+ TabularData data = (TabularData)
getMBeanServer().invoke(getCamelObjectName(TYPE_PROCESSOR, "myTry"),
+ "extendedInformation", null, null);
+ assertEquals(2, data.size());
+ }
+
+ @Test
+ public void testEndpointUtilizationWithSecrets() throws Exception {
+ template.sendBodyAndHeader("direct:dynamic", "Hello", "pw", "a");
+ template.sendBodyAndHeader("direct:dynamic", "Hello", "pw", "b");
+
+ TabularData data = (TabularData)
getMBeanServer().invoke(getCamelObjectName(TYPE_PROCESSOR, "myToD"),
+ "extendedInformation", null, null);
+ // the two endpoints only differ in the password, which is masked
+ assertEquals(1, data.size());
+ assertEquals(2L, ((CompositeData)
data.values().iterator().next()).get("hits"));
+ }
+
+ @Test
+ public void testExchangeFactoryOfSameUri() throws Exception {
+ TabularData data = (TabularData)
getMBeanServer().invoke(service("DefaultExchangeFactoryManager"),
+ "listStatistics", null, null);
+ assertTrue(data.size() >= 2);
+ }
+
+ @Test
+ public void testListEndpointsWithSecrets() throws Exception {
+ context.getEndpoint("mock:secret?password=a");
+ context.getEndpoint("mock:secret?password=b");
+
+ TabularData data = (TabularData)
getMBeanServer().invoke(service("DefaultEndpointRegistry"),
+ "listEndpoints", null, null);
+ CompositeData row = row(data, "url", "mock://result?password=xxxxxx");
+ assertEquals(true, row.get("static"));
+ }
+
+ @Test
+ public void testListTasksWithSameName() throws Exception {
+ ScheduledExecutorService executor =
Executors.newScheduledThreadPool(2);
+ try {
+ for (int i = 0; i < 2; i++) {
+ BackgroundTask.BackgroundTaskBuilder builder =
Tasks.backgroundTask();
+ builder.withName("same");
+ builder.withScheduledExecutor(executor)
+
.withBudget(Budgets.timeBudget().withInterval(Duration.ofMillis(100))
+
.withMaxDuration(Duration.ofSeconds(5)).build())
+ .build()
+ .schedule(context, () -> false);
+ }
+ MBeanServer mbeanServer = getMBeanServer();
+ ObjectName on = service("DefaultTaskManagerRegistry");
+ await().atMost(3, TimeUnit.SECONDS).untilAsserted(() -> {
+ TabularData data = (TabularData) mbeanServer.invoke(on,
"listTasks", null, null);
+ assertEquals(2, data.size());
+ });
+ } finally {
+ executor.shutdownNow();
+ }
+ }
+
+ @Test
+ public void testAggregateForceCompletionOnStop() throws Exception {
+ MBeanServer mbeanServer = getMBeanServer();
+ ObjectName on = getCamelObjectName(TYPE_PROCESSOR, "myAggregate");
+ assertEquals(Boolean.TRUE, mbeanServer.getAttribute(on,
"ForceCompletionOnStop"));
+ assertEquals(Boolean.FALSE, mbeanServer.getAttribute(on,
"CompletionFromBatchConsumer"));
+ }
+
+ @Override
+ protected RouteBuilder createRouteBuilder() {
+ return new RouteBuilder() {
+ @Override
+ public void configure() {
+ from("direct:choice")
+ .choice().id("myChoice")
+ .when(simple("${header.type} == 'a'")).to("mock:a")
+ .when(simple("${header.type} == 'a'")).to("mock:b")
+ .otherwise().to("mock:c")
+ .end();
+
+ ChoiceDefinition choice =
from("direct:disabled").choice().id("disabledChoice");
+ choice.when(simple("${header.a}")).to("mock:a")
+ .when(simple("${header.b}")).to("mock:b")
+ .end();
+ choice.getWhenClauses().get(0).setDisabled("true");
+
+ from("direct:try")
+ .doTry().id("myTry")
+ .throwException(new IOException("Forced"))
+
.doCatch(IOException.class).onWhen(header("a").isEqualTo("x"))
+ .to("mock:io1")
+ .doCatch(IOException.class)
+ .to("mock:io2")
+ .end();
+
+
from("direct:dynamic").toD("mock:secret?password=${header.pw}").id("myToD");
+
+
from("seda:foo?multipleConsumers=true").routeId("foo1").to("mock:foo1");
+
from("seda:foo?multipleConsumers=true").routeId("foo2").to("mock:foo2");
+
+ from("direct:result").to("mock:result?password=secret");
+
+ from("direct:aggregate")
+ .aggregate(header("id"), new
UseLatestAggregationStrategy()).completionSize(5)
+ .forceCompletionOnStop().id("myAggregate")
+ .to("mock:aggregated");
+ }
+ };
+ }
+}
diff --git
a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_23.adoc
b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_23.adoc
index 863807b29d5e..ec73dfa2e638 100644
--- a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_23.adoc
+++ b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_23.adoc
@@ -401,6 +401,13 @@ The `dynamic-router` endpoint gained an `allowedSchemes`
option, an optional com
allow-list of component schemes that a subscription destination may resolve
to. It is unset by
default, which allows any scheme, matching the previous behaviour.
+=== camel-management - JMX tabular data
+
+Some tabular data returned by the JMX MBeans had a key that was not unique, so
the operation failed with
+`KeyAlreadyExistsException`. The tabular data of the Choice EIP and doTry EIP
`extendedInformation` and of
+`listTasks` of the task manager registry now have an `index` item as their
key, the exchange factories of `listStatistics`
+are keyed by `url` and `routeId`, and endpoints that only differ in a secret
(which is masked) are shown once.
+
=== camel-exec
`allowControlHeaders` is now annotated `security = "insecure:dev"`.