diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/dev-consoles-openapi.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/dev-consoles-openapi.json index 14a36d69d974a..2c3ca58c2b861 100644 --- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/dev-consoles-openapi.json +++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/dev-consoles-openapi.json @@ -5134,7 +5134,7 @@ "properties": { "id": { "type": "string", - "description": "The processor ID" + "description": "The processor ID (the id of the from for the route input, as in the trace and message history)" }, "type": { "type": "string", @@ -5175,7 +5175,7 @@ "properties": { "id": { "type": "string", - "description": "The processor ID" + "description": "The processor ID (the id of the from for the route input, as in the trace and message history)" }, "type": { "type": "string", diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/dev-consoles/processor-detail.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/dev-consoles/processor-detail.json index e280d7a3314c4..097481df5898f 100644 --- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/dev-consoles/processor-detail.json +++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/dev-consoles/processor-detail.json @@ -42,7 +42,7 @@ "properties": { "id": { "type": "string", - "description": "The processor ID" + "description": "The processor ID (the id of the from for the route input, as in the trace and message history)" }, "type": { "type": "string", @@ -83,7 +83,7 @@ "properties": { "id": { "type": "string", - "description": "The processor ID" + "description": "The processor ID (the id of the from for the route input, as in the trace and message history)" }, "type": { "type": "string", diff --git a/core/camel-console/src/generated/resources/META-INF/org/apache/camel/dev-console/processor-detail.json b/core/camel-console/src/generated/resources/META-INF/org/apache/camel/dev-console/processor-detail.json index e280d7a3314c4..097481df5898f 100644 --- a/core/camel-console/src/generated/resources/META-INF/org/apache/camel/dev-console/processor-detail.json +++ b/core/camel-console/src/generated/resources/META-INF/org/apache/camel/dev-console/processor-detail.json @@ -42,7 +42,7 @@ "properties": { "id": { "type": "string", - "description": "The processor ID" + "description": "The processor ID (the id of the from for the route input, as in the trace and message history)" }, "type": { "type": "string", @@ -83,7 +83,7 @@ "properties": { "id": { "type": "string", - "description": "The processor ID" + "description": "The processor ID (the id of the from for the route input, as in the trace and message history)" }, "type": { "type": "string", diff --git a/core/camel-console/src/main/java/org/apache/camel/impl/console/ProcessorDetailDevConsole.java b/core/camel-console/src/main/java/org/apache/camel/impl/console/ProcessorDetailDevConsole.java index 4577ed631f8d1..858f41feebff1 100644 --- a/core/camel-console/src/main/java/org/apache/camel/impl/console/ProcessorDetailDevConsole.java +++ b/core/camel-console/src/main/java/org/apache/camel/impl/console/ProcessorDetailDevConsole.java @@ -52,7 +52,7 @@ public class ProcessorDetailDevConsole extends AbstractDevConsole { public static final String ROUTE_ID = "routeId"; public record ProcessorEntry( - @Metadata(description = "The processor ID") String id, + @Metadata(description = "The processor ID (the id of the from for the route input, as in the trace and message history)") String id, @Metadata(description = "The processor type (the XML element name, or 'from' for the route input)") String type, @Metadata(description = "The endpoint URI (only present for the route input entry)") String endpointUri, @Metadata(description = "The source line number (only present when known)") Integer line, @@ -160,6 +160,8 @@ private static RouteDetail buildRouteDetail(ManagedRouteMBean mr) { List processors = new ArrayList<>(); Integer fromLine = null; + // the from has a node id of its own (from1), which the trace and message history name it by + String fromId = routeId; try { String xml = mr.dumpRouteAsXml(false, true, true); @@ -175,7 +177,11 @@ private static RouteDetail buildRouteDetail(ManagedRouteMBean mr) { // extract source line number for the from entry from the child element NodeList fromNodes = routeElement.getElementsByTagName("from"); if (fromNodes.getLength() > 0) { - fromLine = extractSourceLineNumber((Element) fromNodes.item(0)); + Element from = (Element) fromNodes.item(0); + fromLine = extractSourceLineNumber(from); + if (!from.getAttribute("id").isEmpty()) { + fromId = from.getAttribute("id"); + } } collectProcessors(routeElement, processors); @@ -184,7 +190,7 @@ private static RouteDetail buildRouteDetail(ManagedRouteMBean mr) { // ignore } - ProcessorEntry fromEntry = new ProcessorEntry(routeId, "from", mr.getEndpointUri(), fromLine, new LinkedHashMap<>()); + ProcessorEntry fromEntry = new ProcessorEntry(fromId, "from", mr.getEndpointUri(), fromLine, new LinkedHashMap<>()); processors.add(0, fromEntry); return new RouteDetail(routeId, processors); diff --git a/core/camel-console/src/test/java/org/apache/camel/impl/console/ProcessorDetailFromIdTest.java b/core/camel-console/src/test/java/org/apache/camel/impl/console/ProcessorDetailFromIdTest.java new file mode 100644 index 0000000000000..8d3af1e0a4b4f --- /dev/null +++ b/core/camel-console/src/test/java/org/apache/camel/impl/console/ProcessorDetailFromIdTest.java @@ -0,0 +1,66 @@ +/* + * 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.impl.console; + +import java.util.Map; + +import org.apache.camel.ContextTestSupport; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.console.DevConsole; +import org.apache.camel.model.ModelCamelContext; +import org.apache.camel.support.PluginHelper; +import org.apache.camel.util.json.JsonArray; +import org.apache.camel.util.json.JsonObject; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +/** + * The route input is named by the id of its from (from1), as the trace and the message history name it, not by the id + * of the route (CAMEL-26864). + */ +class ProcessorDetailFromIdTest extends ContextTestSupport { + + @Override + protected boolean useJmx() { + // the processor-detail console reads the routes from JMX + return true; + } + + @Override + protected RouteBuilder createRouteBuilder() { + return new RouteBuilder() { + @Override + public void configure() { + from("direct:start").routeId("myRoute").to("mock:result"); + } + }; + } + + @Test + void theFromIsNamedByItsNodeId() { + DevConsole con = PluginHelper.getDevConsoleResolver(context).resolveDevConsole("processor-detail"); + JsonObject out = (JsonObject) con.call(DevConsole.MediaType.JSON, Map.of("routeId", "myRoute")); + + JsonObject from = (JsonObject) ((JsonArray) out.get("processors")).get(0); + String fromId = ((ModelCamelContext) context).getRouteDefinition("myRoute").getInput().getId(); + Assertions.assertEquals("from", from.getString("type")); + Assertions.assertNotNull(fromId); + Assertions.assertEquals(fromId, from.getString("id")); + Assertions.assertNotEquals("myRoute", from.getString("id")); + Assertions.assertEquals("myRoute", out.getString("routeId")); + } +} diff --git a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_24.adoc b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_24.adoc index 70478e671681d..2f252178a3e11 100644 --- a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_24.adoc +++ b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_24.adoc @@ -278,6 +278,12 @@ new `reply` component; its seven-argument constructor is kept and creates an edg A `wireTap` or a `toD` to an endpoint the route names, rather than one it computes with an expression, is now an edge too (a wire tap never waits for the answer), and an external endpoint when no route consumes from it. +=== camel-console - the processor-detail console names the route input by the id of its from + +The first entry of the `processor-detail` developer console, the route input (`type` is `from`), now has the id of the +`from` of the route as `id` (such as `from1`, or the id given to the `from`), which the tracer, the message history and +the backlog debugger name it by. It had the route id before, which is still the `routeId` of the response. + === camel-management - LastExchangeCompletedExchangeId is updated at most once per millisecond The JMX attribute `LastExchangeCompletedExchangeId`, of the `CamelContext`, route and processor MBeans, is now updated diff --git a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/DiagramDetailSupport.java b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/DiagramDetailSupport.java index 2fe5127a1e1a8..b0302ea6ef6a8 100644 --- a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/DiagramDetailSupport.java +++ b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/DiagramDetailSupport.java @@ -38,6 +38,7 @@ import org.apache.camel.diagram.RouteDiagramLayoutEngine; import org.apache.camel.dsl.jbang.core.commands.tui.diagram.DiagramColors; import org.apache.camel.util.TimeUtils; +import org.apache.camel.util.json.JsonArray; import org.apache.camel.util.json.JsonObject; import static org.apache.camel.dsl.jbang.core.commands.tui.EipDocSupport.*; @@ -133,6 +134,10 @@ private JsonObject requestRouteProcessorDetail(String routeId) { } } + void setRouteDetailForTesting(JsonObject routeDetail) { + cachedRouteDetail = routeDetail; + } + JsonObject findProcessorEntry(String nodeId) { if (cachedRouteDetail == null || nodeId == null) { return null; @@ -142,6 +147,16 @@ JsonObject findProcessorEntry(String nodeId) { return p; } } + // the diagram names the input of a route by the route id, the app by the id of its from (from1) + JsonArray routes = (JsonArray) cachedRouteDetail.get("routes"); + for (Object r : routes != null ? routes : List.of()) { + JsonObject route = (JsonObject) r; + JsonArray procs = (JsonArray) route.get("processors"); + if (nodeId.equals(route.getString("routeId")) && procs != null && !procs.isEmpty() + && "from".equals(((JsonObject) procs.get(0)).getString("type"))) { + return (JsonObject) procs.get(0); + } + } return null; } diff --git a/dsl/camel-jbang/camel-jbang-plugin-tui/src/test/java/org/apache/camel/dsl/jbang/core/commands/tui/DiagramDetailFromIdTest.java b/dsl/camel-jbang/camel-jbang-plugin-tui/src/test/java/org/apache/camel/dsl/jbang/core/commands/tui/DiagramDetailFromIdTest.java new file mode 100644 index 0000000000000..7e661e19cf8b2 --- /dev/null +++ b/dsl/camel-jbang/camel-jbang-plugin-tui/src/test/java/org/apache/camel/dsl/jbang/core/commands/tui/DiagramDetailFromIdTest.java @@ -0,0 +1,55 @@ +/* + * 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.dsl.jbang.core.commands.tui; + +import java.util.List; +import java.util.concurrent.atomic.AtomicReference; + +import org.apache.camel.util.json.JsonObject; +import org.apache.camel.util.json.Jsoner; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * CAMEL-26864: the app names the input of a route by the id of its from (from1), as the trace does; the diagram names + * it by the route id. The detail panel finds it by either, and by the route id with an app that still says so. + */ +class DiagramDetailFromIdTest { + + @Test + void theFromIsFoundByItsIdAndByTheRouteId() throws Exception { + MonitorContext ctx = new MonitorContext(new AtomicReference<>(List.of()), new AtomicReference<>(List.of())); + DiagramDetailSupport detail = new DiagramDetailSupport(ctx, new DiagramSupport()); + detail.setRouteDetailForTesting((JsonObject) Jsoner.deserialize(""" + {"routes": [ + {"routeId": "hello", "processors": [ + {"id": "from1", "type": "from", "endpointUri": "timer://tick"}, + {"id": "setBody1", "type": "setBody"}]}, + {"routeId": "seven", "processors": [ + {"id": "seven", "type": "from", "endpointUri": "direct://seven"}]}]} + """)); + + assertThat(detail.findProcessorEntry("from1").getString("endpointUri")).isEqualTo("timer://tick"); + assertThat(detail.findProcessorEntry("hello").getString("endpointUri")).as("the diagram's from node") + .isEqualTo("timer://tick"); + assertThat(detail.findProcessorEntry("setBody1").getString("type")).isEqualTo("setBody"); + assertThat(detail.findProcessorEntry("seven").getString("endpointUri")).as("an app before CAMEL-26864") + .isEqualTo("direct://seven"); + assertThat(detail.findProcessorEntry("nope")).isNull(); + } +}