From 7c6322700389c013be50139ae5c087f3e7da9510 Mon Sep 17 00:00:00 2001 From: Alexej Timonin Date: Sat, 4 Sep 2021 22:31:22 +0200 Subject: [PATCH] Allow custom delimiter when sending TextMessages via MBean This enables possibility to send messages containing commas in the body with tools such as jconsole. Example simple text as body: body=Hello, world! Example json as body: body={"a":"b","c":"d"} --- .../activemq/broker/jmx/DestinationView.java | 19 ++++++++- .../broker/jmx/DestinationViewMBean.java | 25 +++++++++-- .../apache/activemq/broker/jmx/MBeanTest.java | 42 ++++++++++++++++++- 3 files changed, 78 insertions(+), 8 deletions(-) diff --git a/activemq-broker/src/main/java/org/apache/activemq/broker/jmx/DestinationView.java b/activemq-broker/src/main/java/org/apache/activemq/broker/jmx/DestinationView.java index d795c4d5e9..3126a525b5 100644 --- a/activemq-broker/src/main/java/org/apache/activemq/broker/jmx/DestinationView.java +++ b/activemq-broker/src/main/java/org/apache/activemq/broker/jmx/DestinationView.java @@ -336,7 +336,22 @@ public class DestinationView implements DestinationViewMBean { @Override public String sendTextMessageWithProperties(String properties) throws Exception { - String[] kvs = properties.split(","); + Map props = parseProps(properties, ","); + return sendTextMessage(props, props.remove("body"), props.remove("username"), props.remove("password")); + } + + @Override + public String sendTextMessageWithProperties(String properties, String delimiter) throws Exception { + if (delimiter == null || delimiter.isEmpty()) { + return sendTextMessageWithProperties(properties); + } else { + Map props = parseProps(properties, delimiter); + return sendTextMessage(props, props.remove("body"), props.remove("username"), props.remove("password")); + } + } + + private Map parseProps(String properties, String delimiter) { + String[] kvs = properties.split(delimiter); Map props = new HashMap(); for (String kv : kvs) { String[] it = kv.split("="); @@ -344,7 +359,7 @@ public class DestinationView implements DestinationViewMBean { props.put(it[0],it[1]); } } - return sendTextMessage(props, props.remove("body"), props.remove("username"), props.remove("password")); + return props; } @Override diff --git a/activemq-broker/src/main/java/org/apache/activemq/broker/jmx/DestinationViewMBean.java b/activemq-broker/src/main/java/org/apache/activemq/broker/jmx/DestinationViewMBean.java index ad0ae32e4c..84179d59f6 100644 --- a/activemq-broker/src/main/java/org/apache/activemq/broker/jmx/DestinationViewMBean.java +++ b/activemq-broker/src/main/java/org/apache/activemq/broker/jmx/DestinationViewMBean.java @@ -168,13 +168,30 @@ public interface DestinationViewMBean { /** * Sends a TextMessage to the destination. * - * @param properties the message properties to set as a comma sep name=value list. Can only - * contain Strings maped to primitive types or JMS properties. eg: body=hi,JMSReplyTo=Queue2 + * @param properties the message properties to set as name=value list separated + * by a comma. Can only contain Strings mapped to primitive + * types or JMS properties. eg: body=hi,JMSReplyTo=Queue2 * @return the message id of the message sent. * @throws Exception */ - @MBeanInfo("Sends a TextMessage to the destination.") - public String sendTextMessageWithProperties(String properties) throws Exception; + @MBeanInfo("Sends a TextMessage to the destination using comma separeted properties list. Example properties: body=value,header=value") + public String sendTextMessageWithProperties(@MBeanInfo("properties") String properties) throws Exception; + + /** + * Sends a TextMessage to the destination. + * + * @param properties the message properties to set as name=value list separated + * by a custom delimiter. Can only contain Strings mapped to + * primitive types or JMS properties. eg: + * body=hi,JMSReplyTo=Queue2 + * @param delimiter The delimiter that separates each property. Defaults to + * comma if none is provided. + * @return the message id of the message sent. + * @throws Exception + */ + @MBeanInfo("Sends a TextMessage to the destination using properties separeted by arbetrary delimiter. Example properties: body=value;header=value") + public String sendTextMessageWithProperties(@MBeanInfo("properties") String properties, + @MBeanInfo("delimiter") String delimiter) throws Exception; /** * Sends a TextMesage to the destination. diff --git a/activemq-unit-tests/src/test/java/org/apache/activemq/broker/jmx/MBeanTest.java b/activemq-unit-tests/src/test/java/org/apache/activemq/broker/jmx/MBeanTest.java index 8ecfee3c32..b059f44a76 100644 --- a/activemq-unit-tests/src/test/java/org/apache/activemq/broker/jmx/MBeanTest.java +++ b/activemq-unit-tests/src/test/java/org/apache/activemq/broker/jmx/MBeanTest.java @@ -46,8 +46,6 @@ import javax.management.ObjectName; import javax.management.openmbean.CompositeData; import javax.management.openmbean.TabularData; -import junit.textui.TestRunner; - import org.apache.activemq.ActiveMQConnection; import org.apache.activemq.ActiveMQConnectionFactory; import org.apache.activemq.ActiveMQPrefetchPolicy; @@ -69,6 +67,9 @@ import org.apache.activemq.util.Wait; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import junit.textui.TestRunner; + + /** * A test case of the various MBeans in ActiveMQ. If you want to look at the * various MBeans after the test has been run then run this test case as a @@ -117,6 +118,7 @@ public class MBeanTest extends EmbeddedBrokerTestSupport { // messages on a queue assertSendViaMBean(); assertSendCsnvViaMBean(); + assertSendTextMessageWithCustomDelimitedPropsViaMBean(); assertQueueBrowseWorks(); assertCreateAndDestroyDurableSubscriptions(); assertConsumerCounts(); @@ -728,6 +730,42 @@ public class MBeanTest extends EmbeddedBrokerTestSupport { browseAndVerifyTypes(proxy, true); } + protected void assertSendTextMessageWithCustomDelimitedPropsViaMBean() throws Exception { + String queueName = getDestinationString() + ".SendMBBean"; + + ObjectName brokerName = assertRegisteredObjectName(domain + ":type=Broker,brokerName=localhost"); + echo("Create QueueView MBean..."); + BrokerViewMBean broker = MBeanServerInvocationHandler.newProxyInstance(mbeanServer, brokerName, BrokerViewMBean.class, true); + broker.addQueue(queueName); + + ObjectName queueViewMBeanName = assertRegisteredObjectName(domain + ":type=Broker,brokerName=localhost,destinationType=Queue,destinationName=" + queueName); + + echo("Create QueueView MBean..."); + QueueViewMBean proxy = MBeanServerInvocationHandler.newProxyInstance(mbeanServer, queueViewMBeanName, QueueViewMBean.class, true); + + proxy.purge(); + + int count = 5; + + String delimiter = ";"; + for (int i = 0; i < count; i++) { + String props = String.join(delimiter, + "body=message:" + i, + "JMSCorrelationID=MyCorrId", + "JMSDeliveryMode=1", + "JMSXGroupID=MyGroupID", + "JMSXGroupSeq=1234", + "JMSPriority=" + (i + 1), + "JMSType=MyType", + "MyHeader=" + i, + "MyStringHeader=StringHeader" + i); + + proxy.sendTextMessageWithProperties(props, delimiter); + } + + browseAndVerifyTypes(proxy, true); + } + protected void assertComplexData(int messageIndex, CompositeData cdata, String name, Object expected) { Object value = cdata.get(name); assertEquals("Message " + messageIndex + " CData field: " + name, expected, value);