etzel-mes commented on code in PR #28272:
URL: https://github.com/apache/camel/pull/28272#discussion_r4346558366


##########
components/camel-milo/src/main/java/org/apache/camel/component/milo/client/MiloClientDevConsole.java:
##########
@@ -0,0 +1,128 @@
+/*
+ * 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.component.milo.client;
+
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.camel.Route;
+import 
org.apache.camel.component.milo.client.MiloClientConnection.MonitoringState;
+import org.apache.camel.component.milo.client.MiloClientConnection.RefusedNode;
+import org.apache.camel.spi.Metadata;
+import org.apache.camel.spi.annotations.DevConsole;
+import org.apache.camel.support.console.AbstractDevConsole;
+import org.apache.camel.util.URISupport;
+import org.apache.camel.util.json.JsonRecordSupport;
+import org.eclipse.milo.opcua.stack.core.StatusCodes;
+import org.eclipse.milo.opcua.stack.core.types.builtin.StatusCode;
+
+/**
+ * The connections of the OPC UA client consumers, with their refused 
monitored items. It reads the state of the
+ * connections without waiting for a service call in progress.
+ */
+@DevConsole(name = "milo-client", displayName = "OPC UA Client",
+            description = "OPC UA client connections and their refused 
monitored items")
+public class MiloClientDevConsole extends AbstractDevConsole {
+
+    public record RefusedNodeEntry(
+            @Metadata(description = "The node ID") String nodeId,
+            @Metadata(description = "The status of the latest attempt to 
create the monitored item of the node: the refusal, or the failure of the 
attempt") String status,
+            @Metadata(description = "Why the client refused the node without 
asking the server (only present when it did)") String reason) {
+    }
+
+    public record ConnectionEntry(
+            @Metadata(description = "The OPC UA server endpoint, with its 
password masked") String endpointUri,
+            @Metadata(description = "The ids of the routes whose consumers use 
the connection") List<String> routeIds,
+            @Metadata(description = "Whether the session with the server is 
active") boolean sessionActive,
+            @Metadata(description = "The number of nodes that have a monitored 
item on the server") int monitoredNodes,
+            @Metadata(description = "The nodes whose monitored item was 
refused, which are created again every reconnectTimeout milliseconds") 
List<RefusedNodeEntry> refusedNodes) {
+    }
+
+    public record Response(@Metadata(description = "The connections of the 
consumers") List<ConnectionEntry> connections) {
+    }
+
+    public MiloClientDevConsole() {
+        super("camel", "milo-client", "OPC UA Client",
+              "OPC UA client connections and their refused monitored items");
+    }
+
+    @Override
+    protected String doCallText(Map<String, Object> options) {
+        StringBuilder sb = new StringBuilder();
+        for (ConnectionEntry connection : connections()) {
+            sb.append(String.format("%n    Endpoint: %s", 
connection.endpointUri()));
+            sb.append(String.format("%n    Routes: %s", String.join(", ", 
connection.routeIds())));
+            sb.append(String.format("%n    Session Active: %b", 
connection.sessionActive()));
+            sb.append(String.format("%n    Monitored Nodes: %d", 
connection.monitoredNodes()));
+            sb.append(String.format("%n    Refused Nodes: %d", 
connection.refusedNodes().size()));
+            for (RefusedNodeEntry node : connection.refusedNodes()) {
+                sb.append(String.format("%n        %s: %s", node.nodeId(), 
node.status()));
+                if (node.reason() != null) {
+                    sb.append(String.format(" (%s)", node.reason()));
+                }
+            }
+            sb.append("\n");
+        }
+        return sb.toString();
+    }
+
+    @Override
+    protected Map<String, Object> doCallJson(Map<String, Object> options) {
+        Response response = new Response(connections());
+        return JsonRecordSupport.toJsonObject(response);
+    }
+
+    /**
+     * The connections of the started consumers, each with the routes that use 
it, in the order of the routes
+     */
+    private List<ConnectionEntry> connections() {
+        Map<MiloClientConnection, List<String>> routeIds = new 
LinkedHashMap<>();
+        for (Route route : getCamelContext().getRoutes()) {
+            if (route.getConsumer() instanceof MiloClientConsumer consumer && 
consumer.isStarted()) {
+                routeIds.computeIfAbsent(consumer.getConnection(), connection 
-> new ArrayList<>())
+                        .add(route.getRouteId());
+            }
+        }
+
+        List<ConnectionEntry> connections = new ArrayList<>();
+        for (Map.Entry<MiloClientConnection, List<String>> entry : 
routeIds.entrySet()) {
+            MonitoringState state = entry.getKey().getMonitoringState();
+            if (state == null) {
+                // closed while the consumers stop
+                continue;
+            }
+            List<RefusedNodeEntry> refusedNodes = new ArrayList<>();
+            for (RefusedNode node : state.refusedNodes()) {
+                refusedNodes.add(new RefusedNodeEntry(node.nodeId(), 
statusName(node.status()), node.reason()));
+            }
+            connections.add(new ConnectionEntry(
+                    
URISupport.sanitizeUri(entry.getKey().getConfiguration().getEndpointUri()), 
entry.getValue(),

Review Comment:
   Thanks Claus. Added in 8347735c332: `ConnectionEntry` has a `clientId`, 
present only when one is set, and the text output shows it below the endpoint 
(`Client Id: timeout`). `clientIdTellsTheConnectionsOfAServerApart` starts two 
consumers on the same server, one of them with `clientId=timeout`, and checks 
both outputs. The requested publishing interval and the trust settings also 
give a connection of its own, but they are not a name for the connection, so 
the route ids still tell such connections apart.
   
   _Claude Code on behalf of etzel-mes_
   



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to