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

andytaylor pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/activemq-artemis-console.git

commit c1c9a225485c3a25c368db964425cca598ed9670
Author: Grzegorz Grzybek <[email protected]>
AuthorDate: Thu Dec 4 17:29:49 2025 +0100

    ARTEMIS-5788, ARTEMIS-5417: Reorganize org.apache.activemq.artemis JMX tree
---
 .../src/artemis-tree-processor.ts                  | 180 +++++++++++++++++++++
 .../src/brokers/BrokerDiagram.tsx                  |   2 +-
 .../packages/artemis-console-plugin/src/context.ts |   4 -
 .../packages/artemis-console-plugin/src/index.ts   |   5 +-
 4 files changed, 185 insertions(+), 6 deletions(-)

diff --git 
a/artemis-console-extension/artemis-extension/packages/artemis-console-plugin/src/artemis-tree-processor.ts
 
b/artemis-console-extension/artemis-extension/packages/artemis-console-plugin/src/artemis-tree-processor.ts
new file mode 100644
index 0000000..84b3865
--- /dev/null
+++ 
b/artemis-console-extension/artemis-extension/packages/artemis-console-plugin/src/artemis-tree-processor.ts
@@ -0,0 +1,180 @@
+/*
+ * 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.
+ */
+
+import { MBeanNode, type MBeanTree, TreeProcessor } from '@hawtio/react'
+import { configManager } from './config-manager'
+import { FolderIcon } from '@patternfly/react-icons/dist/esm/icons/folder-icon'
+import { FolderOpenIcon } from 
'@patternfly/react-icons/dist/esm/icons/folder-open-icon'
+import { NetworkWiredIcon } from 
'@patternfly/react-icons/dist/esm/icons/network-wired-icon'
+import { ServerIcon } from '@patternfly/react-icons/dist/esm/icons/server-icon'
+import { StreamIcon } from '@patternfly/react-icons/dist/esm/icons/stream-icon'
+import React from 'react'
+
+const icons = {
+  address: React.createElement(FolderIcon),
+  acceptor: React.createElement(NetworkWiredIcon),
+  addressOpened: React.createElement(FolderOpenIcon),
+  queue: React.createElement(StreamIcon),
+  server: React.createElement(ServerIcon)
+}
+
+const artemisTreeProcessor: TreeProcessor = async (tree: MBeanTree) => {
+  const config = await configManager.getArtemisconfig()
+  const artemisDomain = tree.get(config.jmx.domain)
+
+  if (!artemisDomain) {
+    return
+  }
+
+  const brokerNodes = artemisDomain.removeChildren()
+
+  const brokers = findBrokers(brokerNodes)
+  for (const broker of brokers) {
+    artemisDomain.adopt(broker)
+    broker.icon = icons.server
+    broker.expandedIcon = icons.server
+
+    const acceptors = broker.get('acceptors', true)
+    acceptors?.children?.forEach(acceptor => {
+      acceptor.icon = icons.acceptor
+      acceptor.expandedIcon = icons.acceptor
+    })
+
+    const addressesFolder = broker.get('addresses', true)
+    if (!addressesFolder) {
+      continue
+    }
+    // removed childrens are removed from the folder, returned and their 
parent is set to null
+    // but don't remove all children, as there may be "diverts" too
+    // const addressNodes = addressesFolder.removeChildren()
+    const addresses = findAddresses(addressesFolder.children)
+    for (const address of addresses) {
+      addressesFolder.findChildren(address.name).forEach(c => {
+        addressesFolder.removeChild(c)
+      })
+      addressesFolder.adopt(restructureAddress(address))
+    }
+  }
+}
+
+/**
+ * Translate an array of JMX tree nodes for brokers, where each broker has a 
folder and leaf node
+ * into an array of just folder nodes, but having a leaf functionality 
(operations, attributes, ...)
+ * @param children
+ */
+function findBrokers(children: MBeanNode[] | undefined): MBeanNode[] {
+  if (!children) {
+    return []
+  }
+  const oldBrokers = new Map<string, MBeanNode>()
+  for (const c of children) {
+    if (!c.id.endsWith('-folder')) {
+      if (c.mbean?.class === 
'org.apache.activemq.artemis.core.management.impl.ActiveMQServerControlImpl') {
+        oldBrokers.set(c.name, c)
+      }
+    }
+  }
+  const brokers: MBeanNode[] = []
+  for (const c of children) {
+    if (c.id.endsWith('-folder')) {
+      if (oldBrokers.has(c.name)) {
+        const newBrokerNode = oldBrokers.get(c.name)!.copyTo(`Broker 
${c.name}`)
+        newBrokerNode.children = c.children
+        newBrokerNode.icon = c.icon
+        newBrokerNode.expandedIcon = c.expandedIcon
+        brokers.push(newBrokerNode)
+      }
+    }
+  }
+
+  return brokers
+}
+
+/**
+ * Translate an array of JMX tree nodes for addresses, where each addresses 
has a folder and leaf node
+ * into an array of just folder nodes, but having a leaf functionality 
(operations, attributes, ...)
+ * @param children
+ */
+function findAddresses(children: MBeanNode[] | undefined): MBeanNode[] {
+  if (!children) {
+    return []
+  }
+  const oldAddresses = new Map<string, MBeanNode>()
+  const hadFolders = new Map<string, boolean>()
+  for (const c of children) {
+    if (!c.id.endsWith('-folder')) {
+      if (c.mbean?.class === 
'org.apache.activemq.artemis.core.management.impl.AddressControlImpl') {
+        // non folder child with this class is an address
+        oldAddresses.set(c.name, c)
+      }
+    } else {
+      hadFolders.set(c.name, true)
+    }
+  }
+  const addresses: MBeanNode[] = []
+  for (const c of children) {
+    if (oldAddresses.has(c.name)) {
+      const newAddressNode = oldAddresses.get(c.name)!
+      newAddressNode.children = c.children
+      addresses.push(newAddressNode)
+    }
+  }
+
+  return addresses
+}
+
+function restructureAddress(address: MBeanNode): MBeanNode {
+  address.icon = icons.address
+  address.expandedIcon = icons.addressOpened
+  const queuesFolder = address.get("queues", true)
+
+  if (!queuesFolder) {
+    return address
+  }
+
+  const anycastQueuesFolder = queuesFolder.get("anycast", true)
+  const multicastQueuesFolder = queuesFolder.get("multicast", true)
+
+  if (anycastQueuesFolder) {
+    queuesFolder?.removeChild(anycastQueuesFolder)
+  }
+  if (multicastQueuesFolder) {
+    queuesFolder?.removeChild(multicastQueuesFolder)
+  }
+  address.removeChild(queuesFolder)
+
+  if (anycastQueuesFolder && anycastQueuesFolder.children && 
anycastQueuesFolder.children.length > 0) {
+    let folder = address.create("Anycast Queues", true)
+    folder.children = anycastQueuesFolder.children
+    anycastQueuesFolder.children.forEach(q => {
+      // q.icon = icons.queue
+      q.parent = folder
+    })
+  }
+  if (multicastQueuesFolder && multicastQueuesFolder.children && 
multicastQueuesFolder.children.length > 0) {
+    let folder = address.create("Multicast Queues", true)
+    folder.children = multicastQueuesFolder.children
+    multicastQueuesFolder.children.forEach(q => {
+      // q.icon = icons.queue
+      q.parent = folder
+    })
+  }
+
+  return address
+}
+
+export { artemisTreeProcessor }
diff --git 
a/artemis-console-extension/artemis-extension/packages/artemis-console-plugin/src/brokers/BrokerDiagram.tsx
 
b/artemis-console-extension/artemis-extension/packages/artemis-console-plugin/src/brokers/BrokerDiagram.tsx
index 5e78e66..e086c89 100644
--- 
a/artemis-console-extension/artemis-extension/packages/artemis-console-plugin/src/brokers/BrokerDiagram.tsx
+++ 
b/artemis-console-extension/artemis-extension/packages/artemis-console-plugin/src/brokers/BrokerDiagram.tsx
@@ -381,7 +381,7 @@ export const BrokerDiagram: React.FunctionComponent = () => 
{
     if (!topologyLoaded) {
       artemisService.createBrokerTopology(maxAddresses, 
addressFilter).then(brokerTopology => {
         setTopologyLoaded(true);
-        setBrokerTopology(brokerTopology);
+        setBrokerTopology(brokerTopology!);
       });
       return
     }
diff --git 
a/artemis-console-extension/artemis-extension/packages/artemis-console-plugin/src/context.ts
 
b/artemis-console-extension/artemis-extension/packages/artemis-console-plugin/src/context.ts
index e8999b4..ae772a7 100644
--- 
a/artemis-console-extension/artemis-extension/packages/artemis-console-plugin/src/context.ts
+++ 
b/artemis-console-extension/artemis-extension/packages/artemis-console-plugin/src/context.ts
@@ -42,10 +42,6 @@ export function useArtemisTree() {
                 rootNode.children[0].addMetadata("type", "brokerType");
                 setBrokerNode(rootNode.children[0]);
             }
-            if (rootNode.children[1].objectName) {
-                rootNode.children[1].addMetadata("type", "brokerType");
-                setBrokerNode(rootNode.children[1]);
-            }
             // Expand the nodes to redisplay the path
             if (selectedNode) {
                 rootNode.forEach(selectedNode?.path(), (node: MBeanNode) => {
diff --git 
a/artemis-console-extension/artemis-extension/packages/artemis-console-plugin/src/index.ts
 
b/artemis-console-extension/artemis-extension/packages/artemis-console-plugin/src/index.ts
index 48aa98e..5a4795e 100644
--- 
a/artemis-console-extension/artemis-extension/packages/artemis-console-plugin/src/index.ts
+++ 
b/artemis-console-extension/artemis-extension/packages/artemis-console-plugin/src/index.ts
@@ -14,11 +14,12 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-import { type HawtioPlugin, hawtio, configManager as hawtioConfigMgr, 
helpRegistry, workspace, preferencesRegistry, type Plugin } from '@hawtio/react'
+import { type HawtioPlugin, hawtio, configManager as hawtioConfigMgr, 
helpRegistry, treeProcessorRegistry, workspace, preferencesRegistry, type 
Plugin } from '@hawtio/react'
 import { log, artemisPluginName, artemisPluginTitle, artemisPluginPath, 
artemisJMXPluginName, artemisJMXPluginPath, artemisJMXPluginTitle, 
artemisHeaderPluginName } from './globals'
 import help from './help.md'
 import { artemisService } from './artemis-service'
 import { configManager } from './config-manager'
+import { artemisTreeProcessor } from './artemis-tree-processor'
 
 /**
  * Main entry point to Artemis Console Extension called during application 
bootstrap (`bootstrap.tsx`) before
@@ -51,6 +52,8 @@ export const artemis: HawtioPlugin = () => {
     return import('./plugin-ui').then(m => {
       preferencesRegistry.add(artemisPluginName, artemisPluginTitle, 
m.ArtemisPreferences, 1)
 
+      treeProcessorRegistry.add('artemis', artemisTreeProcessor)
+
       const plugins: Plugin[] = []
       plugins.push({
         id: artemisPluginName,


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]
For further information, visit: https://activemq.apache.org/contact


Reply via email to