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
