jbonofre commented on code in PR #1966:
URL: https://github.com/apache/activemq/pull/1966#discussion_r3658457946


##########
activemq-console/src/test/java/org/apache/activemq/console/QueuesCommandTest.java:
##########
@@ -0,0 +1,277 @@
+/**
+ * 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.activemq.console;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.io.ByteArrayOutputStream;
+import java.util.LinkedList;
+
+import jakarta.jms.Connection;
+import jakarta.jms.MessageProducer;
+import jakarta.jms.Session;
+import jakarta.jms.TextMessage;
+import javax.management.ObjectName;
+
+import org.apache.activemq.ActiveMQConnectionFactory;
+import org.apache.activemq.broker.BrokerService;
+import org.apache.activemq.broker.TransportConnector;
+import org.apache.activemq.broker.jmx.QueueViewMBean;
+import org.apache.activemq.command.ActiveMQDestination;
+import org.apache.activemq.command.ActiveMQQueue;
+import org.apache.activemq.console.command.QueuesCommand;
+import org.apache.activemq.console.formatter.CommandShellOutputFormatter;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TestName;
+
+public class QueuesCommandTest {
+
+    @Rule
+    public TestName name = new TestName();
+
+    private BrokerService brokerService;
+    private ActiveMQConnectionFactory connectionFactory;
+
+    @Before
+    public void createBroker() throws Exception {
+        brokerService = new BrokerService();
+        brokerService.getManagementContext().setCreateConnector(false);
+        brokerService.setPersistent(false);
+        brokerService.setDestinations(new ActiveMQDestination[]{
+                new ActiveMQQueue("Q1"),
+                new ActiveMQQueue("Q2")
+        });
+        TransportConnector connector = 
brokerService.addConnector("tcp://0.0.0.0:0");
+        brokerService.start();
+        brokerService.waitUntilStarted();
+        connectionFactory = new 
ActiveMQConnectionFactory(connector.getPublishableConnectString());
+    }
+
+    @After
+    public void stopBroker() throws Exception {
+        if (brokerService != null) {
+            brokerService.stop();
+        }
+    }
+
+    // --- list ---
+
+    @Test(timeout = 30000)
+    public void testListShowsAllQueues() throws Exception {
+        String result = execute("list");
+        assertTrue("Q1 in output", result.contains("Q1"));
+        assertTrue("Q2 in output", result.contains("Q2"));
+        assertTrue("column header present", result.contains("Messages"));
+        assertTrue("column header present", result.contains("Consumers"));
+    }
+
+    // --- create ---
+
+    @Test(timeout = 30000)
+    public void testCreateQueue() throws Exception {
+        String result = execute("create", "NEW.QUEUE");
+        assertTrue("confirmation message", result.contains("Queue created: 
NEW.QUEUE"));
+
+        // Verify via JMX proxy that the queue now exists
+        QueueViewMBean proxy = getQueueProxy("NEW.QUEUE");
+        assertEquals(0, proxy.getQueueSize());
+    }
+
+    // --- delete ---
+
+    @Test(timeout = 30000)
+    public void testDeleteQueue() throws Exception {
+        // Q1 was created at startup; delete it
+        String result = execute("delete", "Q1");
+        assertTrue("confirmation message", result.contains("Queue deleted: 
Q1"));
+
+        // Verify Q1 no longer appears in list
+        String listResult = execute("list");
+        assertFalse("Q1 gone from list", listResult.contains("Q1"));
+        assertTrue("Q2 still present", listResult.contains("Q2"));
+    }
+
+    // --- purge ---
+
+    @Test(timeout = 30000)
+    public void testPurgeQueue() throws Exception {
+        sendMessages("Q1", 5);
+
+        QueueViewMBean proxy = getQueueProxy("Q1");
+        assertEquals("5 messages before purge", 5, proxy.getQueueSize());
+
+        String result = execute("purge", "Q1");
+        assertTrue("confirmation message", result.contains("Queue purged: 
Q1"));
+        assertEquals("0 messages after purge", 0, proxy.getQueueSize());
+    }
+
+    // --- info ---
+
+    @Test(timeout = 30000)
+    public void testInfoQueue() throws Exception {
+        sendMessages("Q1", 3);
+        String result = execute("info", "Q1");
+
+        assertTrue("name field", result.contains("Q1"));
+        assertTrue("Messages field", result.contains("Messages"));
+        assertTrue("Consumers field", result.contains("Consumers"));
+        assertTrue("Producers field", result.contains("Producers"));
+        assertTrue("Memory usage field", result.contains("Memory usage"));
+        assertTrue("Paused field", result.contains("Paused"));
+    }
+
+    @Test(timeout = 30000)
+    public void testInfoQueueNotFound() throws Exception {
+        String result = execute("info", "DOES.NOT.EXIST");
+        assertTrue("not found message", result.contains("not found"));
+    }
+
+    // --- browse ---
+
+    @Test(timeout = 30000)
+    public void testBrowseQueue() throws Exception {
+        sendTextMessages("Q1", "hello-browse-msg", 2);
+
+        String result = execute("browse", "Q1");
+        assertTrue("browse header present", result.contains("Browsing queue"));
+        assertTrue("message count in header", result.contains("2 message(s)"));
+        assertTrue("JMSMessageID field present", 
result.contains("JMSMessageID"));
+        assertTrue("message body present", 
result.contains("hello-browse-msg"));
+    }
+
+    @Test(timeout = 30000)
+    public void testBrowseEmptyQueue() throws Exception {
+        String result = execute("browse", "Q1");
+        assertTrue("empty queue message", result.contains("No messages in 
queue"));
+    }
+
+    // --- produce ---
+
+    @Test(timeout = 30000)
+    public void testProduceMessage() throws Exception {
+        QueueViewMBean proxy = getQueueProxy("Q1");
+        assertEquals("queue empty before produce", 0, proxy.getQueueSize());
+
+        String result = execute("produce", "Q1", "test-message-body");
+        assertTrue("confirmation with message ID", result.contains("Message 
sent to Q1"));
+        assertTrue("message ID in output", result.contains("ID:"));
+
+        assertEquals("queue has 1 message after produce", 1, 
proxy.getQueueSize());
+    }
+
+    @Test(timeout = 30000)
+    public void testProduceMissingBody() throws Exception {

Review Comment:
   Same silent-pass problem here: the `try/catch` around `execute("produce", 
"Q1")` has no `fail()`, so the test passes whether or not the exception is 
thrown. Please use `assertThrows(IllegalArgumentException.class, ...)` or add a 
`fail(...)`.



##########
activemq-console/src/test/java/org/apache/activemq/console/NetworkConnectorsCommandTest.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.activemq.console;
+
+import static org.junit.Assert.assertTrue;
+
+import java.io.ByteArrayOutputStream;
+import java.util.LinkedList;
+
+import org.apache.activemq.broker.BrokerService;
+import org.apache.activemq.network.DiscoveryNetworkConnector;
+import org.apache.activemq.console.command.NetworkConnectorsCommand;
+import org.apache.activemq.console.formatter.CommandShellOutputFormatter;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+public class NetworkConnectorsCommandTest {
+
+    private static final String NC_NAME = "test-nc";
+
+    private BrokerService brokerService;
+
+    @Before
+    public void createBroker() throws Exception {
+        brokerService = new BrokerService();
+        brokerService.getManagementContext().setCreateConnector(false);
+        brokerService.setPersistent(false);
+        brokerService.start();
+        brokerService.waitUntilStarted();
+    }
+
+    @After
+    public void stopBroker() throws Exception {
+        if (brokerService != null) {
+            brokerService.stop();
+        }
+    }
+
+    // --- list ---
+
+    @Test(timeout = 30000)
+    public void testListWithNoNetworkConnectors() throws Exception {
+        String result = execute("list");
+        assertTrue("empty message shown", result.contains("No network 
connectors configured."));
+    }
+
+    @Test(timeout = 30000)
+    public void testListShowsConfiguredConnector() throws Exception {
+        // Add a network connector directly to the broker before testing
+        DiscoveryNetworkConnector nc = new DiscoveryNetworkConnector();
+        nc.setName(NC_NAME);
+        // Use a discovery URI that won't fail immediately even without a 
remote broker
+        nc.setUri(new java.net.URI("static:(failover:(tcp://localhost:0))"));
+        brokerService.addNetworkConnector(nc);
+        brokerService.registerNetworkConnectorMBean(nc);
+
+        String result = execute("list");
+        assertTrue("connector name in output", result.contains(NC_NAME));
+        assertTrue("Auto-Start column present", result.contains("Auto-Start"));
+        assertTrue("Duplex column present", result.contains("Duplex"));
+    }
+
+    // --- error handling ---
+
+    @Test(timeout = 30000)
+    public void testUnknownActionShowsHelp() throws Exception {
+        String result = execute("badaction");
+        assertTrue("unknown action message", result.contains("Unknown 
action"));
+    }
+
+    @Test(timeout = 30000)
+    public void testNoActionShowsHelp() throws Exception {
+        String result = execute();
+        assertTrue("help content shown", result.contains("Actions:"));
+    }
+
+    @Test(timeout = 30000)
+    public void testAddMissingUriThrows() throws Exception {
+        try {
+            execute("add");
+        } catch (IllegalArgumentException e) {
+            assertTrue(e.getMessage().contains("URI required"));
+        }
+    }
+
+    @Test(timeout = 30000)
+    public void testRemoveMissingNameThrows() throws Exception {

Review Comment:
   Same issue as `testAddMissingUriThrows`: no `fail()` after 
`execute("remove")`, so this passes even if no exception is thrown. Use 
`assertThrows(...)` or add a `fail(...)` after the call.



##########
activemq-console/src/test/java/org/apache/activemq/console/BrokerCommandTest.java:
##########
@@ -0,0 +1,156 @@
+/**
+ * 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.activemq.console;
+
+import static org.junit.Assert.assertFalse;

Review Comment:
   `assertFalse` is imported but never used in this test — please remove the 
unused import.



##########
activemq-console/src/test/java/org/apache/activemq/console/NetworkConnectorsCommandTest.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.activemq.console;
+
+import static org.junit.Assert.assertTrue;
+
+import java.io.ByteArrayOutputStream;
+import java.util.LinkedList;
+
+import org.apache.activemq.broker.BrokerService;
+import org.apache.activemq.network.DiscoveryNetworkConnector;
+import org.apache.activemq.console.command.NetworkConnectorsCommand;
+import org.apache.activemq.console.formatter.CommandShellOutputFormatter;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+public class NetworkConnectorsCommandTest {
+
+    private static final String NC_NAME = "test-nc";
+
+    private BrokerService brokerService;
+
+    @Before
+    public void createBroker() throws Exception {
+        brokerService = new BrokerService();
+        brokerService.getManagementContext().setCreateConnector(false);
+        brokerService.setPersistent(false);
+        brokerService.start();
+        brokerService.waitUntilStarted();
+    }
+
+    @After
+    public void stopBroker() throws Exception {
+        if (brokerService != null) {
+            brokerService.stop();
+        }
+    }
+
+    // --- list ---
+
+    @Test(timeout = 30000)
+    public void testListWithNoNetworkConnectors() throws Exception {
+        String result = execute("list");
+        assertTrue("empty message shown", result.contains("No network 
connectors configured."));
+    }
+
+    @Test(timeout = 30000)
+    public void testListShowsConfiguredConnector() throws Exception {
+        // Add a network connector directly to the broker before testing
+        DiscoveryNetworkConnector nc = new DiscoveryNetworkConnector();
+        nc.setName(NC_NAME);
+        // Use a discovery URI that won't fail immediately even without a 
remote broker
+        nc.setUri(new java.net.URI("static:(failover:(tcp://localhost:0))"));
+        brokerService.addNetworkConnector(nc);
+        brokerService.registerNetworkConnectorMBean(nc);
+
+        String result = execute("list");
+        assertTrue("connector name in output", result.contains(NC_NAME));
+        assertTrue("Auto-Start column present", result.contains("Auto-Start"));
+        assertTrue("Duplex column present", result.contains("Duplex"));
+    }
+
+    // --- error handling ---
+
+    @Test(timeout = 30000)
+    public void testUnknownActionShowsHelp() throws Exception {
+        String result = execute("badaction");
+        assertTrue("unknown action message", result.contains("Unknown 
action"));
+    }
+
+    @Test(timeout = 30000)
+    public void testNoActionShowsHelp() throws Exception {
+        String result = execute();
+        assertTrue("help content shown", result.contains("Actions:"));
+    }
+
+    @Test(timeout = 30000)
+    public void testAddMissingUriThrows() throws Exception {

Review Comment:
   This test can pass silently: the `try/catch` has no `fail()` after 
`execute("add")`, so if the `IllegalArgumentException` is never thrown the 
assertion in the catch block simply doesn't run and the test still passes. It 
would keep passing even if the validation were removed. Please add a 
`fail("expected IllegalArgumentException")` after the `execute(...)` call, or 
switch to `assertThrows(IllegalArgumentException.class, () -> execute("add"))`.



##########
activemq-console/src/test/java/org/apache/activemq/console/TopicsCommandTest.java:
##########
@@ -0,0 +1,162 @@
+/**
+ * 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.activemq.console;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.io.ByteArrayOutputStream;
+import java.util.LinkedList;
+
+import javax.management.ObjectName;
+
+import org.apache.activemq.broker.BrokerService;
+import org.apache.activemq.broker.jmx.TopicViewMBean;
+import org.apache.activemq.command.ActiveMQDestination;
+import org.apache.activemq.command.ActiveMQTopic;
+import org.apache.activemq.console.command.TopicsCommand;
+import org.apache.activemq.console.formatter.CommandShellOutputFormatter;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+public class TopicsCommandTest {
+
+    private BrokerService brokerService;
+
+    @Before
+    public void createBroker() throws Exception {
+        brokerService = new BrokerService();
+        brokerService.getManagementContext().setCreateConnector(false);
+        brokerService.setPersistent(false);
+        brokerService.setDestinations(new ActiveMQDestination[]{
+                new ActiveMQTopic("T1"),
+                new ActiveMQTopic("T2")
+        });
+        brokerService.start();
+        brokerService.waitUntilStarted();
+    }
+
+    @After
+    public void stopBroker() throws Exception {
+        if (brokerService != null) {
+            brokerService.stop();
+        }
+    }
+
+    // --- list ---
+
+    @Test(timeout = 30000)
+    public void testListShowsAllTopics() throws Exception {
+        String result = execute("list");
+        assertTrue("T1 in output", result.contains("T1"));
+        assertTrue("T2 in output", result.contains("T2"));
+        assertTrue("column header present", result.contains("Messages"));
+        assertTrue("column header present", result.contains("Consumers"));
+    }
+
+    @Test(timeout = 30000)
+    public void testListDoesNotShowQueues() throws Exception {
+        String result = execute("list");
+        // Queues should never appear in topic list output
+        assertFalse("queue header not shown", result.contains("Queue Size"));
+    }
+
+    // --- create ---
+
+    @Test(timeout = 30000)
+    public void testCreateTopic() throws Exception {
+        String result = execute("create", "NEW.TOPIC");
+        assertTrue("confirmation message", result.contains("Topic created: 
NEW.TOPIC"));
+
+        // Verify it now appears in list
+        String listResult = execute("list");
+        assertTrue("new topic in list", listResult.contains("NEW.TOPIC"));
+    }
+
+    // --- delete ---
+
+    @Test(timeout = 30000)
+    public void testDeleteTopic() throws Exception {
+        String result = execute("delete", "T1");
+        assertTrue("confirmation message", result.contains("Topic deleted: 
T1"));
+
+        // T1 should no longer appear in list
+        String listResult = execute("list");
+        assertFalse("T1 gone from list", listResult.contains("T1"));
+        assertTrue("T2 still present", listResult.contains("T2"));
+    }
+
+    // --- info ---
+
+    @Test(timeout = 30000)
+    public void testInfoTopic() throws Exception {
+        String result = execute("info", "T1");
+        assertTrue("name field", result.contains("T1"));
+        assertTrue("Messages field", result.contains("Messages"));
+        assertTrue("Consumers field", result.contains("Consumers"));
+        assertTrue("Producers field", result.contains("Producers"));
+        assertTrue("Memory usage field", result.contains("Memory usage"));
+    }
+
+    @Test(timeout = 30000)
+    public void testInfoTopicNotFound() throws Exception {
+        String result = execute("info", "DOES.NOT.EXIST");
+        assertTrue("not found message", result.contains("not found"));
+    }
+
+    // --- error handling ---
+
+    @Test(timeout = 30000)
+    public void testUnknownActionShowsHelp() throws Exception {
+        String result = execute("badaction");
+        assertTrue("unknown action message", result.contains("Unknown 
action"));
+    }
+
+    @Test(timeout = 30000)
+    public void testNoActionShowsHelp() throws Exception {
+        String result = execute();
+        assertTrue("help content shown", result.contains("Actions:"));
+    }
+
+    // --- helpers ---
+
+    private String execute(String... args) throws Exception {
+        ByteArrayOutputStream out = new ByteArrayOutputStream(1024);
+        CommandContext context = new CommandContext();
+        context.setFormatter(new CommandShellOutputFormatter(out));
+
+        TopicsCommand cmd = new TopicsCommand();
+        cmd.setJmxUseLocal(true);
+        cmd.setCommandContext(context);
+
+        LinkedList<String> tokens = new LinkedList<>();
+        for (String arg : args) {
+            tokens.add(arg);
+        }
+        cmd.execute(tokens);
+        return out.toString();
+    }
+
+    private TopicViewMBean getTopicProxy(String topicName) throws Exception {

Review Comment:
   `getTopicProxy(...)` is never called anywhere in this test class (unlike 
`getQueueProxy` in `QueuesCommandTest`, which is used). Please remove this dead 
helper.



##########
activemq-console/src/main/java/org/apache/activemq/console/command/QueuesCommand.java:
##########
@@ -0,0 +1,321 @@
+/**
+ * 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.activemq.console.command;
+
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Locale;
+
+import javax.management.MBeanServerInvocationHandler;
+import javax.management.ObjectInstance;
+import javax.management.ObjectName;
+import javax.management.openmbean.CompositeData;
+
+import org.apache.activemq.broker.jmx.BrokerViewMBean;
+import org.apache.activemq.broker.jmx.QueueViewMBean;
+import org.apache.activemq.console.util.JmxMBeansUtil;
+
+public class QueuesCommand extends AbstractJmxCommand {
+
+    protected String[] helpFile = new String[] {
+        "Task Usage: activemq queues <action> [options] [queue-name] [args]",
+        "Description: List, create, delete, purge, browse, produce, pause, 
resume, or inspect queues.",
+        "",
+        "Actions:",
+        "    list                           List all queues with their key 
statistics.",
+        "    create <queue-name>            Create a new queue.",
+        "    delete <queue-name>            Delete an existing queue.",
+        "    purge  <queue-name>            Purge all messages from a queue.",
+        "    info   <queue-name>            Show detailed statistics for a 
queue.",
+        "    browse <queue-name>            Browse messages in a queue 
(non-destructive).",
+        "    produce <queue-name> <body>    Send a text message to a queue.",
+        "    pause  <queue-name>            Pause dispatch on a queue.",
+        "    resume <queue-name>            Resume dispatch on a paused 
queue.",
+        "",
+        "Options:",
+        "    --jmxurl <url>               Set the JMX URL to connect to.",
+        "    --pid <pid>                  Set the pid to connect to (only on 
Sun JVM).",
+        "    --jmxuser <user>             Set the JMX user used for 
authenticating.",
+        "    --jmxpassword <password>     Set the JMX password used for 
authenticating.",
+        "    --jmxlocal                   Use the local JMX server instead of 
a remote one.",
+        "    --version                    Display the version information.",
+        "    -h,-?,--help                 Display this help information.",
+        "",
+        "Examples:",
+        "    activemq queues list",
+        "        - List all queues with their statistics.",
+        "    activemq queues create FOO.BAR",
+        "        - Create a new queue named FOO.BAR.",
+        "    activemq queues delete FOO.BAR",
+        "        - Delete the queue named FOO.BAR.",
+        "    activemq queues purge FOO.BAR",
+        "        - Purge all messages from queue FOO.BAR.",
+        "    activemq queues info FOO.BAR",
+        "        - Show detailed statistics for queue FOO.BAR.",
+        "    activemq queues browse FOO.BAR",
+        "        - Browse all messages in queue FOO.BAR without consuming 
them.",
+        "    activemq queues produce FOO.BAR \"Hello World\"",
+        "        - Send a text message with body 'Hello World' to queue 
FOO.BAR.",
+        "    activemq queues pause FOO.BAR",
+        "        - Pause message dispatch on queue FOO.BAR.",
+        "    activemq queues resume FOO.BAR",
+        "        - Resume message dispatch on queue FOO.BAR.",
+        ""
+    };
+
+    @Override
+    public String getName() {
+        return "queues";
+    }
+
+    @Override
+    public String getOneLineDescription() {
+        return "List, create, delete, purge, browse, produce, pause, or resume 
queues";
+    }
+
+    @Override
+    protected void runTask(List<String> tokens) throws Exception {
+        if (tokens.isEmpty()) {
+            printHelp();
+            return;
+        }
+
+        String action = tokens.remove(0);
+        if (action.equals("list")) {
+            listQueues();
+        } else if (action.equals("create")) {
+            requireQueueName(tokens, "create");
+            createQueue(tokens.get(0));
+        } else if (action.equals("delete")) {
+            requireQueueName(tokens, "delete");
+            deleteQueue(tokens.get(0));
+        } else if (action.equals("purge")) {
+            requireQueueName(tokens, "purge");
+            purgeQueue(tokens.get(0));
+        } else if (action.equals("info")) {
+            requireQueueName(tokens, "info");
+            infoQueue(tokens.get(0));
+        } else if (action.equals("browse")) {
+            requireQueueName(tokens, "browse");
+            browseQueue(tokens.get(0));
+        } else if (action.equals("produce")) {
+            requireQueueName(tokens, "produce");
+            if (tokens.size() < 2) {
+                throw new IllegalArgumentException("Message body required: 
activemq queues produce <queue-name> <body>");
+            }
+            produceMessage(tokens.get(0), tokens.get(1));
+        } else if (action.equals("pause")) {
+            requireQueueName(tokens, "pause");
+            pauseQueue(tokens.get(0));
+        } else if (action.equals("resume")) {
+            requireQueueName(tokens, "resume");
+            resumeQueue(tokens.get(0));
+        } else {
+            context.printInfo("Unknown action '" + action + "'. See 'activemq 
queues --help'.");
+            printHelp();
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    private void listQueues() throws Exception {
+        List<ObjectInstance> queueList = 
JmxMBeansUtil.queryMBeans(createJmxConnection(),
+                
"type=Broker,brokerName=*,destinationType=Queue,destinationName=*");
+
+        Collections.sort(queueList, new Comparator<ObjectInstance>() {
+            @Override
+            public int compare(ObjectInstance o1, ObjectInstance o2) {
+                return o1.getObjectName().compareTo(o2.getObjectName());
+            }
+        });
+
+        final String fmt = "%-50s  %10s  %10s  %10s  %10s  %10s";
+        context.print(String.format(Locale.US, fmt, "Name", "Messages", 
"Consumers", "Producers", "Enqueued", "Dequeued"));
+        context.print(String.format(Locale.US, fmt,
+                dashes(50), dashes(10), dashes(10), dashes(10), dashes(10), 
dashes(10)));
+
+        for (ObjectInstance obj : queueList) {
+            ObjectName name = obj.getObjectName();
+            QueueViewMBean q = MBeanServerInvocationHandler.newProxyInstance(
+                    createJmxConnection(), name, QueueViewMBean.class, true);
+            context.print(String.format(Locale.US, "%-50s  %10d  %10d  %10d  
%10d  %10d",
+                    q.getName(),
+                    q.getQueueSize(),
+                    q.getConsumerCount(),
+                    q.getProducerCount(),
+                    q.getEnqueueCount(),
+                    q.getDequeueCount()));
+        }
+
+        if (queueList.isEmpty()) {
+            context.print("No queues found.");
+        }
+    }
+
+    private void createQueue(String queueName) throws Exception {
+        getBrokerMBean().addQueue(queueName);
+        context.print("Queue created: " + queueName);
+    }
+
+    private void deleteQueue(String queueName) throws Exception {
+        getBrokerMBean().removeQueue(queueName);
+        context.print("Queue deleted: " + queueName);
+    }
+
+    @SuppressWarnings("unchecked")
+    private void purgeQueue(String queueName) throws Exception {
+        List<ObjectInstance> results = 
JmxMBeansUtil.queryMBeans(createJmxConnection(),
+                
"type=Broker,brokerName=*,destinationType=Queue,destinationName=" + queueName);
+        if (results.isEmpty()) {
+            context.printInfo("Queue not found: " + queueName);
+            return;
+        }
+        ObjectName name = results.get(0).getObjectName();
+        QueueViewMBean q = MBeanServerInvocationHandler.newProxyInstance(
+                createJmxConnection(), name, QueueViewMBean.class, true);
+        q.purge();
+        context.print("Queue purged: " + queueName);
+    }
+
+    @SuppressWarnings("unchecked")
+    private void infoQueue(String queueName) throws Exception {
+        List<ObjectInstance> results = 
JmxMBeansUtil.queryMBeans(createJmxConnection(),
+                
"type=Broker,brokerName=*,destinationType=Queue,destinationName=" + queueName);
+        if (results.isEmpty()) {
+            context.printInfo("Queue not found: " + queueName);
+            return;
+        }
+        ObjectName name = results.get(0).getObjectName();
+        QueueViewMBean q = MBeanServerInvocationHandler.newProxyInstance(
+                createJmxConnection(), name, QueueViewMBean.class, true);
+
+        context.print("Name          : " + q.getName());
+        context.print("Messages      : " + q.getQueueSize());
+        context.print("Consumers     : " + q.getConsumerCount());
+        context.print("Producers     : " + q.getProducerCount());
+        context.print("Enqueued      : " + q.getEnqueueCount());
+        context.print("Dequeued      : " + q.getDequeueCount());
+        context.print("In-flight     : " + q.getInFlightCount());
+        context.print("Memory usage  : " + q.getMemoryPercentUsage() + "%");
+        context.print("Paused        : " + q.isPaused());
+    }
+
+    @SuppressWarnings("unchecked")
+    private void browseQueue(String queueName) throws Exception {
+        List<ObjectInstance> results = 
JmxMBeansUtil.queryMBeans(createJmxConnection(),
+                
"type=Broker,brokerName=*,destinationType=Queue,destinationName=" + queueName);
+        if (results.isEmpty()) {
+            context.printInfo("Queue not found: " + queueName);
+            return;
+        }
+        ObjectName name = results.get(0).getObjectName();
+        QueueViewMBean q = MBeanServerInvocationHandler.newProxyInstance(
+                createJmxConnection(), name, QueueViewMBean.class, true);
+        CompositeData[] messages = q.browse();
+        if (messages == null || messages.length == 0) {
+            context.print("No messages in queue: " + queueName);
+            return;
+        }
+        context.print("Browsing queue: " + queueName + " (" + messages.length 
+ " message(s))");
+        for (int i = 0; i < messages.length; i++) {
+            CompositeData msg = messages[i];
+            context.print("");
+            context.print("--- Message " + (i + 1) + " ---");
+            for (String key : msg.getCompositeType().keySet()) {
+                Object value = msg.get(key);
+                if (value != null && !value.toString().isEmpty()) {
+                    context.print(String.format("  %-24s: %s", key, value));
+                }
+            }
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    private void produceMessage(String queueName, String body) throws 
Exception {
+        List<ObjectInstance> results = 
JmxMBeansUtil.queryMBeans(createJmxConnection(),
+                
"type=Broker,brokerName=*,destinationType=Queue,destinationName=" + queueName);
+        if (results.isEmpty()) {
+            context.printInfo("Queue not found: " + queueName);
+            return;
+        }
+        ObjectName name = results.get(0).getObjectName();
+        QueueViewMBean q = MBeanServerInvocationHandler.newProxyInstance(
+                createJmxConnection(), name, QueueViewMBean.class, true);
+        String messageId = q.sendTextMessage(body);
+        context.print("Message sent to " + queueName + ". ID: " + messageId);
+    }
+
+    @SuppressWarnings("unchecked")
+    private void pauseQueue(String queueName) throws Exception {
+        List<ObjectInstance> results = 
JmxMBeansUtil.queryMBeans(createJmxConnection(),
+                
"type=Broker,brokerName=*,destinationType=Queue,destinationName=" + queueName);
+        if (results.isEmpty()) {
+            context.printInfo("Queue not found: " + queueName);
+            return;
+        }
+        ObjectName name = results.get(0).getObjectName();
+        QueueViewMBean q = MBeanServerInvocationHandler.newProxyInstance(
+                createJmxConnection(), name, QueueViewMBean.class, true);
+        q.pause();
+        context.print("Queue paused: " + queueName);
+    }
+
+    @SuppressWarnings("unchecked")
+    private void resumeQueue(String queueName) throws Exception {
+        List<ObjectInstance> results = 
JmxMBeansUtil.queryMBeans(createJmxConnection(),
+                
"type=Broker,brokerName=*,destinationType=Queue,destinationName=" + queueName);
+        if (results.isEmpty()) {
+            context.printInfo("Queue not found: " + queueName);
+            return;
+        }
+        ObjectName name = results.get(0).getObjectName();
+        QueueViewMBean q = MBeanServerInvocationHandler.newProxyInstance(
+                createJmxConnection(), name, QueueViewMBean.class, true);
+        q.resume();
+        context.print("Queue resumed: " + queueName);
+    }
+
+    @SuppressWarnings("unchecked")
+    private BrokerViewMBean getBrokerMBean() throws Exception {

Review Comment:
   `getBrokerMBean()` and `dashes()` are duplicated verbatim across all four 
new command classes (`QueuesCommand`, `TopicsCommand`, `BrokerCommand`, 
`NetworkConnectorsCommand`). Consider lifting a shared helper (e.g. 
`getBrokerViewMBean()`) into `AbstractJmxCommand` so all commands reuse it. 
Non-blocking, but it would avoid the copy-paste drift.



##########
activemq-console/src/main/java/org/apache/activemq/console/command/QueuesCommand.java:
##########
@@ -0,0 +1,321 @@
+/**
+ * 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.activemq.console.command;
+
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Locale;
+
+import javax.management.MBeanServerInvocationHandler;
+import javax.management.ObjectInstance;
+import javax.management.ObjectName;
+import javax.management.openmbean.CompositeData;
+
+import org.apache.activemq.broker.jmx.BrokerViewMBean;
+import org.apache.activemq.broker.jmx.QueueViewMBean;
+import org.apache.activemq.console.util.JmxMBeansUtil;
+
+public class QueuesCommand extends AbstractJmxCommand {
+
+    protected String[] helpFile = new String[] {
+        "Task Usage: activemq queues <action> [options] [queue-name] [args]",
+        "Description: List, create, delete, purge, browse, produce, pause, 
resume, or inspect queues.",
+        "",
+        "Actions:",
+        "    list                           List all queues with their key 
statistics.",
+        "    create <queue-name>            Create a new queue.",
+        "    delete <queue-name>            Delete an existing queue.",
+        "    purge  <queue-name>            Purge all messages from a queue.",
+        "    info   <queue-name>            Show detailed statistics for a 
queue.",
+        "    browse <queue-name>            Browse messages in a queue 
(non-destructive).",
+        "    produce <queue-name> <body>    Send a text message to a queue.",
+        "    pause  <queue-name>            Pause dispatch on a queue.",
+        "    resume <queue-name>            Resume dispatch on a paused 
queue.",
+        "",
+        "Options:",
+        "    --jmxurl <url>               Set the JMX URL to connect to.",
+        "    --pid <pid>                  Set the pid to connect to (only on 
Sun JVM).",
+        "    --jmxuser <user>             Set the JMX user used for 
authenticating.",
+        "    --jmxpassword <password>     Set the JMX password used for 
authenticating.",
+        "    --jmxlocal                   Use the local JMX server instead of 
a remote one.",
+        "    --version                    Display the version information.",
+        "    -h,-?,--help                 Display this help information.",
+        "",
+        "Examples:",
+        "    activemq queues list",
+        "        - List all queues with their statistics.",
+        "    activemq queues create FOO.BAR",
+        "        - Create a new queue named FOO.BAR.",
+        "    activemq queues delete FOO.BAR",
+        "        - Delete the queue named FOO.BAR.",
+        "    activemq queues purge FOO.BAR",
+        "        - Purge all messages from queue FOO.BAR.",
+        "    activemq queues info FOO.BAR",
+        "        - Show detailed statistics for queue FOO.BAR.",
+        "    activemq queues browse FOO.BAR",
+        "        - Browse all messages in queue FOO.BAR without consuming 
them.",
+        "    activemq queues produce FOO.BAR \"Hello World\"",
+        "        - Send a text message with body 'Hello World' to queue 
FOO.BAR.",
+        "    activemq queues pause FOO.BAR",
+        "        - Pause message dispatch on queue FOO.BAR.",
+        "    activemq queues resume FOO.BAR",
+        "        - Resume message dispatch on queue FOO.BAR.",
+        ""
+    };
+
+    @Override
+    public String getName() {
+        return "queues";
+    }
+
+    @Override
+    public String getOneLineDescription() {
+        return "List, create, delete, purge, browse, produce, pause, or resume 
queues";
+    }
+
+    @Override
+    protected void runTask(List<String> tokens) throws Exception {
+        if (tokens.isEmpty()) {
+            printHelp();
+            return;
+        }
+
+        String action = tokens.remove(0);
+        if (action.equals("list")) {
+            listQueues();
+        } else if (action.equals("create")) {
+            requireQueueName(tokens, "create");
+            createQueue(tokens.get(0));
+        } else if (action.equals("delete")) {
+            requireQueueName(tokens, "delete");
+            deleteQueue(tokens.get(0));
+        } else if (action.equals("purge")) {
+            requireQueueName(tokens, "purge");
+            purgeQueue(tokens.get(0));
+        } else if (action.equals("info")) {
+            requireQueueName(tokens, "info");
+            infoQueue(tokens.get(0));
+        } else if (action.equals("browse")) {
+            requireQueueName(tokens, "browse");
+            browseQueue(tokens.get(0));
+        } else if (action.equals("produce")) {
+            requireQueueName(tokens, "produce");
+            if (tokens.size() < 2) {
+                throw new IllegalArgumentException("Message body required: 
activemq queues produce <queue-name> <body>");
+            }
+            produceMessage(tokens.get(0), tokens.get(1));
+        } else if (action.equals("pause")) {
+            requireQueueName(tokens, "pause");
+            pauseQueue(tokens.get(0));
+        } else if (action.equals("resume")) {
+            requireQueueName(tokens, "resume");
+            resumeQueue(tokens.get(0));
+        } else {
+            context.printInfo("Unknown action '" + action + "'. See 'activemq 
queues --help'.");
+            printHelp();
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    private void listQueues() throws Exception {
+        List<ObjectInstance> queueList = 
JmxMBeansUtil.queryMBeans(createJmxConnection(),
+                
"type=Broker,brokerName=*,destinationType=Queue,destinationName=*");
+
+        Collections.sort(queueList, new Comparator<ObjectInstance>() {
+            @Override
+            public int compare(ObjectInstance o1, ObjectInstance o2) {
+                return o1.getObjectName().compareTo(o2.getObjectName());
+            }
+        });
+
+        final String fmt = "%-50s  %10s  %10s  %10s  %10s  %10s";
+        context.print(String.format(Locale.US, fmt, "Name", "Messages", 
"Consumers", "Producers", "Enqueued", "Dequeued"));
+        context.print(String.format(Locale.US, fmt,
+                dashes(50), dashes(10), dashes(10), dashes(10), dashes(10), 
dashes(10)));
+
+        for (ObjectInstance obj : queueList) {
+            ObjectName name = obj.getObjectName();
+            QueueViewMBean q = MBeanServerInvocationHandler.newProxyInstance(
+                    createJmxConnection(), name, QueueViewMBean.class, true);
+            context.print(String.format(Locale.US, "%-50s  %10d  %10d  %10d  
%10d  %10d",
+                    q.getName(),
+                    q.getQueueSize(),
+                    q.getConsumerCount(),
+                    q.getProducerCount(),
+                    q.getEnqueueCount(),
+                    q.getDequeueCount()));
+        }
+
+        if (queueList.isEmpty()) {
+            context.print("No queues found.");
+        }
+    }
+
+    private void createQueue(String queueName) throws Exception {
+        getBrokerMBean().addQueue(queueName);
+        context.print("Queue created: " + queueName);
+    }
+
+    private void deleteQueue(String queueName) throws Exception {
+        getBrokerMBean().removeQueue(queueName);
+        context.print("Queue deleted: " + queueName);
+    }
+
+    @SuppressWarnings("unchecked")
+    private void purgeQueue(String queueName) throws Exception {

Review Comment:
   `purge`, `info`, `browse`, `produce`, `pause`, and `resume` all repeat the 
same ~6-line block: query by `destinationName`, bail with a not-found message 
if empty, otherwise build a `QueueViewMBean` proxy from the first result. 
Extracting a `private QueueViewMBean lookupQueue(String name)` helper 
(returning `null` and printing the not-found message on a miss) would remove 
most of the repetition and centralize the not-found behavior.



##########
activemq-console/src/main/java/org/apache/activemq/console/command/QueuesCommand.java:
##########
@@ -0,0 +1,321 @@
+/**
+ * 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.activemq.console.command;
+
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Locale;
+
+import javax.management.MBeanServerInvocationHandler;
+import javax.management.ObjectInstance;
+import javax.management.ObjectName;
+import javax.management.openmbean.CompositeData;
+
+import org.apache.activemq.broker.jmx.BrokerViewMBean;
+import org.apache.activemq.broker.jmx.QueueViewMBean;
+import org.apache.activemq.console.util.JmxMBeansUtil;
+
+public class QueuesCommand extends AbstractJmxCommand {
+
+    protected String[] helpFile = new String[] {
+        "Task Usage: activemq queues <action> [options] [queue-name] [args]",
+        "Description: List, create, delete, purge, browse, produce, pause, 
resume, or inspect queues.",
+        "",
+        "Actions:",
+        "    list                           List all queues with their key 
statistics.",
+        "    create <queue-name>            Create a new queue.",
+        "    delete <queue-name>            Delete an existing queue.",
+        "    purge  <queue-name>            Purge all messages from a queue.",
+        "    info   <queue-name>            Show detailed statistics for a 
queue.",
+        "    browse <queue-name>            Browse messages in a queue 
(non-destructive).",
+        "    produce <queue-name> <body>    Send a text message to a queue.",
+        "    pause  <queue-name>            Pause dispatch on a queue.",
+        "    resume <queue-name>            Resume dispatch on a paused 
queue.",
+        "",
+        "Options:",
+        "    --jmxurl <url>               Set the JMX URL to connect to.",
+        "    --pid <pid>                  Set the pid to connect to (only on 
Sun JVM).",
+        "    --jmxuser <user>             Set the JMX user used for 
authenticating.",
+        "    --jmxpassword <password>     Set the JMX password used for 
authenticating.",
+        "    --jmxlocal                   Use the local JMX server instead of 
a remote one.",
+        "    --version                    Display the version information.",
+        "    -h,-?,--help                 Display this help information.",
+        "",
+        "Examples:",
+        "    activemq queues list",
+        "        - List all queues with their statistics.",
+        "    activemq queues create FOO.BAR",
+        "        - Create a new queue named FOO.BAR.",
+        "    activemq queues delete FOO.BAR",
+        "        - Delete the queue named FOO.BAR.",
+        "    activemq queues purge FOO.BAR",
+        "        - Purge all messages from queue FOO.BAR.",
+        "    activemq queues info FOO.BAR",
+        "        - Show detailed statistics for queue FOO.BAR.",
+        "    activemq queues browse FOO.BAR",
+        "        - Browse all messages in queue FOO.BAR without consuming 
them.",
+        "    activemq queues produce FOO.BAR \"Hello World\"",
+        "        - Send a text message with body 'Hello World' to queue 
FOO.BAR.",
+        "    activemq queues pause FOO.BAR",
+        "        - Pause message dispatch on queue FOO.BAR.",
+        "    activemq queues resume FOO.BAR",
+        "        - Resume message dispatch on queue FOO.BAR.",
+        ""
+    };
+
+    @Override
+    public String getName() {
+        return "queues";
+    }
+
+    @Override
+    public String getOneLineDescription() {
+        return "List, create, delete, purge, browse, produce, pause, or resume 
queues";
+    }
+
+    @Override
+    protected void runTask(List<String> tokens) throws Exception {
+        if (tokens.isEmpty()) {
+            printHelp();
+            return;
+        }
+
+        String action = tokens.remove(0);
+        if (action.equals("list")) {
+            listQueues();
+        } else if (action.equals("create")) {
+            requireQueueName(tokens, "create");
+            createQueue(tokens.get(0));
+        } else if (action.equals("delete")) {
+            requireQueueName(tokens, "delete");
+            deleteQueue(tokens.get(0));
+        } else if (action.equals("purge")) {
+            requireQueueName(tokens, "purge");
+            purgeQueue(tokens.get(0));
+        } else if (action.equals("info")) {
+            requireQueueName(tokens, "info");
+            infoQueue(tokens.get(0));
+        } else if (action.equals("browse")) {
+            requireQueueName(tokens, "browse");
+            browseQueue(tokens.get(0));
+        } else if (action.equals("produce")) {
+            requireQueueName(tokens, "produce");
+            if (tokens.size() < 2) {
+                throw new IllegalArgumentException("Message body required: 
activemq queues produce <queue-name> <body>");
+            }
+            produceMessage(tokens.get(0), tokens.get(1));
+        } else if (action.equals("pause")) {
+            requireQueueName(tokens, "pause");
+            pauseQueue(tokens.get(0));
+        } else if (action.equals("resume")) {
+            requireQueueName(tokens, "resume");
+            resumeQueue(tokens.get(0));
+        } else {
+            context.printInfo("Unknown action '" + action + "'. See 'activemq 
queues --help'.");
+            printHelp();
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    private void listQueues() throws Exception {
+        List<ObjectInstance> queueList = 
JmxMBeansUtil.queryMBeans(createJmxConnection(),
+                
"type=Broker,brokerName=*,destinationType=Queue,destinationName=*");
+
+        Collections.sort(queueList, new Comparator<ObjectInstance>() {
+            @Override
+            public int compare(ObjectInstance o1, ObjectInstance o2) {
+                return o1.getObjectName().compareTo(o2.getObjectName());
+            }
+        });
+
+        final String fmt = "%-50s  %10s  %10s  %10s  %10s  %10s";
+        context.print(String.format(Locale.US, fmt, "Name", "Messages", 
"Consumers", "Producers", "Enqueued", "Dequeued"));
+        context.print(String.format(Locale.US, fmt,
+                dashes(50), dashes(10), dashes(10), dashes(10), dashes(10), 
dashes(10)));
+
+        for (ObjectInstance obj : queueList) {
+            ObjectName name = obj.getObjectName();
+            QueueViewMBean q = MBeanServerInvocationHandler.newProxyInstance(
+                    createJmxConnection(), name, QueueViewMBean.class, true);
+            context.print(String.format(Locale.US, "%-50s  %10d  %10d  %10d  
%10d  %10d",
+                    q.getName(),
+                    q.getQueueSize(),
+                    q.getConsumerCount(),
+                    q.getProducerCount(),
+                    q.getEnqueueCount(),
+                    q.getDequeueCount()));
+        }
+
+        if (queueList.isEmpty()) {
+            context.print("No queues found.");
+        }
+    }
+
+    private void createQueue(String queueName) throws Exception {
+        getBrokerMBean().addQueue(queueName);
+        context.print("Queue created: " + queueName);
+    }
+
+    private void deleteQueue(String queueName) throws Exception {
+        getBrokerMBean().removeQueue(queueName);
+        context.print("Queue deleted: " + queueName);
+    }
+
+    @SuppressWarnings("unchecked")
+    private void purgeQueue(String queueName) throws Exception {
+        List<ObjectInstance> results = 
JmxMBeansUtil.queryMBeans(createJmxConnection(),
+                
"type=Broker,brokerName=*,destinationType=Queue,destinationName=" + queueName);
+        if (results.isEmpty()) {
+            context.printInfo("Queue not found: " + queueName);
+            return;
+        }
+        ObjectName name = results.get(0).getObjectName();
+        QueueViewMBean q = MBeanServerInvocationHandler.newProxyInstance(
+                createJmxConnection(), name, QueueViewMBean.class, true);
+        q.purge();
+        context.print("Queue purged: " + queueName);
+    }
+
+    @SuppressWarnings("unchecked")
+    private void infoQueue(String queueName) throws Exception {
+        List<ObjectInstance> results = 
JmxMBeansUtil.queryMBeans(createJmxConnection(),
+                
"type=Broker,brokerName=*,destinationType=Queue,destinationName=" + queueName);
+        if (results.isEmpty()) {
+            context.printInfo("Queue not found: " + queueName);
+            return;
+        }
+        ObjectName name = results.get(0).getObjectName();
+        QueueViewMBean q = MBeanServerInvocationHandler.newProxyInstance(
+                createJmxConnection(), name, QueueViewMBean.class, true);
+
+        context.print("Name          : " + q.getName());
+        context.print("Messages      : " + q.getQueueSize());
+        context.print("Consumers     : " + q.getConsumerCount());
+        context.print("Producers     : " + q.getProducerCount());
+        context.print("Enqueued      : " + q.getEnqueueCount());
+        context.print("Dequeued      : " + q.getDequeueCount());
+        context.print("In-flight     : " + q.getInFlightCount());
+        context.print("Memory usage  : " + q.getMemoryPercentUsage() + "%");
+        context.print("Paused        : " + q.isPaused());
+    }
+
+    @SuppressWarnings("unchecked")
+    private void browseQueue(String queueName) throws Exception {
+        List<ObjectInstance> results = 
JmxMBeansUtil.queryMBeans(createJmxConnection(),
+                
"type=Broker,brokerName=*,destinationType=Queue,destinationName=" + queueName);
+        if (results.isEmpty()) {
+            context.printInfo("Queue not found: " + queueName);
+            return;
+        }
+        ObjectName name = results.get(0).getObjectName();
+        QueueViewMBean q = MBeanServerInvocationHandler.newProxyInstance(
+                createJmxConnection(), name, QueueViewMBean.class, true);
+        CompositeData[] messages = q.browse();
+        if (messages == null || messages.length == 0) {
+            context.print("No messages in queue: " + queueName);
+            return;
+        }
+        context.print("Browsing queue: " + queueName + " (" + messages.length 
+ " message(s))");
+        for (int i = 0; i < messages.length; i++) {
+            CompositeData msg = messages[i];
+            context.print("");
+            context.print("--- Message " + (i + 1) + " ---");
+            for (String key : msg.getCompositeType().keySet()) {
+                Object value = msg.get(key);
+                if (value != null && !value.toString().isEmpty()) {
+                    context.print(String.format("  %-24s: %s", key, value));
+                }
+            }
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    private void produceMessage(String queueName, String body) throws 
Exception {
+        List<ObjectInstance> results = 
JmxMBeansUtil.queryMBeans(createJmxConnection(),
+                
"type=Broker,brokerName=*,destinationType=Queue,destinationName=" + queueName);
+        if (results.isEmpty()) {
+            context.printInfo("Queue not found: " + queueName);
+            return;
+        }
+        ObjectName name = results.get(0).getObjectName();
+        QueueViewMBean q = MBeanServerInvocationHandler.newProxyInstance(
+                createJmxConnection(), name, QueueViewMBean.class, true);
+        String messageId = q.sendTextMessage(body);
+        context.print("Message sent to " + queueName + ". ID: " + messageId);
+    }
+
+    @SuppressWarnings("unchecked")
+    private void pauseQueue(String queueName) throws Exception {
+        List<ObjectInstance> results = 
JmxMBeansUtil.queryMBeans(createJmxConnection(),
+                
"type=Broker,brokerName=*,destinationType=Queue,destinationName=" + queueName);
+        if (results.isEmpty()) {
+            context.printInfo("Queue not found: " + queueName);
+            return;
+        }
+        ObjectName name = results.get(0).getObjectName();
+        QueueViewMBean q = MBeanServerInvocationHandler.newProxyInstance(
+                createJmxConnection(), name, QueueViewMBean.class, true);
+        q.pause();
+        context.print("Queue paused: " + queueName);
+    }
+
+    @SuppressWarnings("unchecked")
+    private void resumeQueue(String queueName) throws Exception {
+        List<ObjectInstance> results = 
JmxMBeansUtil.queryMBeans(createJmxConnection(),
+                
"type=Broker,brokerName=*,destinationType=Queue,destinationName=" + queueName);
+        if (results.isEmpty()) {
+            context.printInfo("Queue not found: " + queueName);
+            return;
+        }
+        ObjectName name = results.get(0).getObjectName();
+        QueueViewMBean q = MBeanServerInvocationHandler.newProxyInstance(
+                createJmxConnection(), name, QueueViewMBean.class, true);
+        q.resume();
+        context.print("Queue resumed: " + queueName);
+    }
+
+    @SuppressWarnings("unchecked")
+    private BrokerViewMBean getBrokerMBean() throws Exception {
+        List<ObjectInstance> brokers = 
JmxMBeansUtil.getAllBrokers(createJmxConnection());
+        if (brokers.isEmpty()) {
+            throw new Exception("No broker found in JMX context.");
+        }
+        ObjectName brokerName = brokers.get(0).getObjectName();
+        return MBeanServerInvocationHandler.newProxyInstance(
+                createJmxConnection(), brokerName, BrokerViewMBean.class, 
true);
+    }
+
+    private void requireQueueName(List<String> tokens, String action) throws 
Exception {
+        if (tokens.isEmpty()) {
+            throw new IllegalArgumentException("Queue name required for '" + 
action + "'.");
+        }
+    }
+
+    private static String dashes(int count) {

Review Comment:
   `dashes(int)` can just be `"-".repeat(count)` (Java 11+ is available here), 
which would also let this duplicated helper disappear once the shared base is 
in place.



-- 
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]


---------------------------------------------------------------------
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