You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jmeter.apache.org by pm...@apache.org on 2017/11/18 20:15:21 UTC

svn commit: r1815692 - in /jmeter/trunk: src/protocol/jms/org/apache/jmeter/protocol/jms/control/gui/JMSSamplerGui.java src/protocol/jms/org/apache/jmeter/protocol/jms/sampler/JMSSampler.java xdocs/changes.xml xdocs/usermanual/component_reference.xml

Author: pmouawad
Date: Sat Nov 18 20:15:20 2017
New Revision: 1815692

URL: http://svn.apache.org/viewvc?rev=1815692&view=rev
Log:
Bug 61544 - JMS Point-to-Point Sampler: Enhance communication styles with read, browse, clear
Bugzilla Id: 61544

Modified:
    jmeter/trunk/src/protocol/jms/org/apache/jmeter/protocol/jms/control/gui/JMSSamplerGui.java
    jmeter/trunk/src/protocol/jms/org/apache/jmeter/protocol/jms/sampler/JMSSampler.java
    jmeter/trunk/xdocs/changes.xml
    jmeter/trunk/xdocs/usermanual/component_reference.xml

Modified: jmeter/trunk/src/protocol/jms/org/apache/jmeter/protocol/jms/control/gui/JMSSamplerGui.java
URL: http://svn.apache.org/viewvc/jmeter/trunk/src/protocol/jms/org/apache/jmeter/protocol/jms/control/gui/JMSSamplerGui.java?rev=1815692&r1=1815691&r2=1815692&view=diff
==============================================================================
--- jmeter/trunk/src/protocol/jms/org/apache/jmeter/protocol/jms/control/gui/JMSSamplerGui.java (original)
+++ jmeter/trunk/src/protocol/jms/org/apache/jmeter/protocol/jms/control/gui/JMSSamplerGui.java Sat Nov 18 20:15:20 2017
@@ -23,7 +23,6 @@ import java.awt.BorderLayout;
 import javax.swing.BorderFactory;
 import javax.swing.Box;
 import javax.swing.JCheckBox;
-import javax.swing.JComboBox;
 import javax.swing.JLabel;
 import javax.swing.JPanel;
 
@@ -36,6 +35,9 @@ import org.apache.jmeter.protocol.jms.sa
 import org.apache.jmeter.protocol.jms.sampler.JMSSampler;
 import org.apache.jmeter.samplers.gui.AbstractSamplerGui;
 import org.apache.jmeter.testelement.TestElement;
+import org.apache.jmeter.testelement.property.BooleanProperty;
+import org.apache.jmeter.testelement.property.JMeterProperty;
+import org.apache.jmeter.testelement.property.NullProperty;
 import org.apache.jmeter.util.JMeterUtils;
 import org.apache.jorphan.gui.JLabeledChoice;
 import org.apache.jorphan.gui.JLabeledTextField;
@@ -56,25 +58,34 @@ public class JMSSamplerGui extends Abstr
 
     private JLabeledTextField receiveQueue = new JLabeledTextField(JMeterUtils.getResString("jms_receive_queue")); //$NON-NLS-1$
 
-    private JLabeledTextField timeout = new JLabeledTextField(JMeterUtils.getResString("jms_timeout"),10); //$NON-NLS-1$
+    private JLabeledTextField timeout = new JLabeledTextField(JMeterUtils.getResString("jms_timeout"), 10); //$NON-NLS-1$
 
-    private JLabeledTextField expiration = new JLabeledTextField(JMeterUtils.getResString("jms_expiration"),10); //$NON-NLS-1$
+    private JLabeledTextField expiration = new JLabeledTextField(JMeterUtils.getResString("jms_expiration"), 10); //$NON-NLS-1$
 
-    private JLabeledTextField priority = new JLabeledTextField(JMeterUtils.getResString("jms_priority"),1); //$NON-NLS-1$
+    private JLabeledTextField priority = new JLabeledTextField(JMeterUtils.getResString("jms_priority"), 1); //$NON-NLS-1$
 
     private JLabeledTextField jmsSelector = new JLabeledTextField(JMeterUtils.getResString("jms_selector")); //$NON-NLS-1$
 
-    private JSyntaxTextArea messageContent = JSyntaxTextArea.getInstance(10, 50); //$NON-NLS-1$
+    private JLabeledTextField numberOfSamplesToAggregate = new JLabeledTextField("Number of samples to aggregate"); //$NON-NLS-1$
+
+    private JSyntaxTextArea messageContent = JSyntaxTextArea.getInstance(10, 50); // $NON-NLS-1$
 
     private JLabeledTextField initialContextFactory = new JLabeledTextField(
             JMeterUtils.getResString("jms_initial_context_factory")); //$NON-NLS-1$
 
     private JLabeledTextField providerUrl = new JLabeledTextField(JMeterUtils.getResString("jms_provider_url")); //$NON-NLS-1$
 
-    private String[] labels = new String[] { JMeterUtils.getResString("jms_request"), //$NON-NLS-1$
-            JMeterUtils.getResString("jms_requestreply") }; //$NON-NLS-1$
-
-    private JLabeledChoice oneWay = new JLabeledChoice(JMeterUtils.getResString("jms_communication_style"), labels); //$NON-NLS-1$
+    private static final String[] JMS_COMMUNICATION_STYLE_LABELS = new String[] { 
+            "request_only", // $NON-NLS-1$
+            "request_reply", // $NON-NLS-1$
+            "read", // $NON-NLS-1$
+            "browse", // $NON-NLS-1$
+            "clear" // $NON-NLS-1$
+    };
+
+    private JLabeledChoice jmsCommunicationStyle = new JLabeledChoice(
+            JMeterUtils.getResString("jms_communication_style"), // $NON-NLS-1$
+            JMS_COMMUNICATION_STYLE_LABELS);
 
     private JMSPropertiesPanel jmsPropertiesPanel;
 
@@ -99,11 +110,12 @@ public class JMSSamplerGui extends Abstr
         queueConnectionFactory.setText(""); // $NON-NLS-1$
         sendQueue.setText(""); // $NON-NLS-1$
         receiveQueue.setText(""); // $NON-NLS-1$
-        ((JComboBox<?>) oneWay.getComponentList().get(1)).setSelectedItem(JMeterUtils.getResString("jms_request")); //$NON-NLS-1$
-        timeout.setText("");  // $NON-NLS-1$
-        expiration.setText("");  // $NON-NLS-1$
-        priority.setText("");  // $NON-NLS-1$
+        jmsCommunicationStyle.setSelectedIndex(0);
+        timeout.setText(""); // $NON-NLS-1$
+        expiration.setText(""); // $NON-NLS-1$
+        priority.setText(""); // $NON-NLS-1$
         jmsSelector.setText(""); // $NON-NLS-1$
+        numberOfSamplesToAggregate.setText(""); // $NON-NLS-1$
         messageContent.setInitialText(""); // $NON-NLS-1$
         initialContextFactory.setText(""); // $NON-NLS-1$
         providerUrl.setText(""); // $NON-NLS-1$
@@ -124,8 +136,7 @@ public class JMSSamplerGui extends Abstr
         element.setSendQueue(sendQueue.getText());
         element.setReceiveQueue(receiveQueue.getText());
 
-        boolean isOneway = oneWay.getText().equals(JMeterUtils.getResString("jms_request")); //$NON-NLS-1$
-        element.setIsOneway(isOneway);
+        element.setProperty(JMSSampler.JMS_COMMUNICATION_STYLE, jmsCommunicationStyle.getSelectedIndex());
 
         element.setNonPersistent(useNonPersistentDelivery.isSelected());
         element.setUseReqMsgIdAsCorrelId(useReqMsgIdAsCorrelId.isSelected());
@@ -134,6 +145,7 @@ public class JMSSamplerGui extends Abstr
         element.setExpiration(expiration.getText());
         element.setPriority(priority.getText());
         element.setJMSSelector(jmsSelector.getText());
+        element.setNumberOfSamplesToAggregate(numberOfSamplesToAggregate.getText());
         element.setContent(messageContent.getText());
 
         element.setInitialContextFactory(initialContextFactory.getText());
@@ -148,12 +160,15 @@ public class JMSSamplerGui extends Abstr
 
     /**
      *
-     * @param element the test element being created
+     * @param element
+     *            the test element being created
      */
     @Override
     public void modifyTestElement(TestElement element) {
         super.configureTestElement(element);
-        if (!(element instanceof JMSSampler)) { return; }
+        if (!(element instanceof JMSSampler)) {
+            return;
+        }
         JMSSampler sampler = (JMSSampler) element;
         transfer(sampler);
     }
@@ -161,20 +176,22 @@ public class JMSSamplerGui extends Abstr
     @Override
     public void configure(TestElement el) {
         super.configure(el);
-        if (!(el instanceof JMSSampler)) { return; }
+        if (!(el instanceof JMSSampler)) {
+            return;
+        }
         JMSSampler sampler = (JMSSampler) el;
         queueConnectionFactory.setText(sampler.getQueueConnectionFactory());
         sendQueue.setText(sampler.getSendQueue());
         receiveQueue.setText(sampler.getReceiveQueue());
-
-        JComboBox<?> box = (JComboBox<?>) oneWay.getComponentList().get(1);
-        String selected = null;
-        if (sampler.isOneway()) {
-            selected = JMeterUtils.getResString("jms_request"); //$NON-NLS-1$
+        JMeterProperty oneWay = el.getProperty(JMSSampler.IS_ONE_WAY); // NOSONAR
+        if(oneWay instanceof NullProperty) {
+            jmsCommunicationStyle.setSelectedIndex(el.getPropertyAsInt(JMSSampler.JMS_COMMUNICATION_STYLE));
         } else {
-            selected = JMeterUtils.getResString("jms_requestreply"); //$NON-NLS-1$
+            jmsCommunicationStyle.setSelectedIndex(
+                    ((BooleanProperty)oneWay).getBooleanValue() ? 
+                            JMSSampler.COMMUNICATION_STYLE.ONE_WAY.getValue() 
+                            : JMSSampler.COMMUNICATION_STYLE.REQUEST_REPLY.getValue());
         }
-        box.setSelectedItem(selected);
 
         useNonPersistentDelivery.setSelected(sampler.isNonPersistent());
         useReqMsgIdAsCorrelId.setSelected(sampler.isUseReqMsgIdAsCorrelId());
@@ -184,6 +201,7 @@ public class JMSSamplerGui extends Abstr
         expiration.setText(sampler.getExpiration());
         priority.setText(sampler.getPriority());
         jmsSelector.setText(sampler.getJMSSelector());
+        numberOfSamplesToAggregate.setText(sampler.getNumberOfSamplesToAggregate());
         messageContent.setInitialText(sampler.getContent());
         initialContextFactory.setText(sampler.getInitialContextFactory());
         providerUrl.setText(sampler.getContextProvider());
@@ -196,7 +214,8 @@ public class JMSSamplerGui extends Abstr
      * Initializes the configuration screen.
      *
      */
-    private void init() { // WARNING: called from ctor so must not be overridden (i.e. must be private or final)
+    private void init() { // WARNING: called from ctor so must not be overridden
+                          // (i.e. must be private or final)
         setLayout(new BorderLayout());
         setBorder(makeBorder());
         add(makeTitlePanel(), BorderLayout.NORTH);
@@ -214,8 +233,9 @@ public class JMSSamplerGui extends Abstr
         jmsQueueingPanel.add(sendQueuePanel, BorderLayout.CENTER);
 
         JPanel receiveQueuePanel = new JPanel(new BorderLayout(5, 0));
-        receiveQueuePanel.add(jmsSelector,BorderLayout.SOUTH);
-        receiveQueuePanel.add(receiveQueue,BorderLayout.NORTH);
+        receiveQueuePanel.add(jmsSelector, BorderLayout.SOUTH);
+        receiveQueuePanel.add(numberOfSamplesToAggregate, BorderLayout.CENTER);
+        receiveQueuePanel.add(receiveQueue, BorderLayout.NORTH);
         jmsQueueingPanel.add(receiveQueuePanel, BorderLayout.SOUTH);
 
         JPanel messagePanel = new JPanel(new BorderLayout());
@@ -226,20 +246,20 @@ public class JMSSamplerGui extends Abstr
         correlationPanel.setBorder(BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder(),
                 JMeterUtils.getResString("jms_correlation_title"))); //$NON-NLS-1$
 
-        useReqMsgIdAsCorrelId = new JCheckBox(JMeterUtils.getResString("jms_use_req_msgid_as_correlid"),false); //$NON-NLS-1$
+        useReqMsgIdAsCorrelId = new JCheckBox(JMeterUtils.getResString("jms_use_req_msgid_as_correlid"), false); //$NON-NLS-1$
 
-        useResMsgIdAsCorrelId = new JCheckBox(JMeterUtils.getResString("jms_use_res_msgid_as_correlid"),false); //$NON-NLS-1$
+        useResMsgIdAsCorrelId = new JCheckBox(JMeterUtils.getResString("jms_use_res_msgid_as_correlid"), false); //$NON-NLS-1$
 
         correlationPanel.add(useReqMsgIdAsCorrelId);
         correlationPanel.add(useResMsgIdAsCorrelId);
 
         JPanel messageNorthPanel = new JPanel(new BorderLayout());
         JPanel onewayPanel = new HorizontalPanel();
-        onewayPanel.add(oneWay);
+        onewayPanel.add(jmsCommunicationStyle);
         onewayPanel.add(correlationPanel);
         messageNorthPanel.add(onewayPanel, BorderLayout.NORTH);
 
-        useNonPersistentDelivery = new JCheckBox(JMeterUtils.getResString("jms_use_non_persistent_delivery"),false); //$NON-NLS-1$
+        useNonPersistentDelivery = new JCheckBox(JMeterUtils.getResString("jms_use_non_persistent_delivery"), false); //$NON-NLS-1$
 
         JPanel timeoutPanel = new HorizontalPanel();
         timeoutPanel.add(timeout);
@@ -255,7 +275,7 @@ public class JMSSamplerGui extends Abstr
         messageContentPanel.add(JTextScrollPane.getInstance(messageContent), BorderLayout.CENTER);
         messagePanel.add(messageContentPanel, BorderLayout.CENTER);
 
-        jmsPropertiesPanel = new JMSPropertiesPanel(); //$NON-NLS-1$
+        jmsPropertiesPanel = new JMSPropertiesPanel(); // $NON-NLS-1$
         messagePanel.add(jmsPropertiesPanel, BorderLayout.SOUTH);
 
         Box mainPanel = Box.createVerticalBox();
@@ -292,7 +312,7 @@ public class JMSSamplerGui extends Abstr
 
     @Override
     public String getLabelResource() {
-        return "jms_point_to_point"; //$NON-NLS-1$ // TODO - probably wrong
+        return "jms_point_to_point"; //$NON-NLS-1$ 
     }
 
 }

Modified: jmeter/trunk/src/protocol/jms/org/apache/jmeter/protocol/jms/sampler/JMSSampler.java
URL: http://svn.apache.org/viewvc/jmeter/trunk/src/protocol/jms/org/apache/jmeter/protocol/jms/sampler/JMSSampler.java?rev=1815692&r1=1815691&r2=1815692&view=diff
==============================================================================
--- jmeter/trunk/src/protocol/jms/org/apache/jmeter/protocol/jms/sampler/JMSSampler.java (original)
+++ jmeter/trunk/src/protocol/jms/org/apache/jmeter/protocol/jms/sampler/JMSSampler.java Sat Nov 18 20:15:20 2017
@@ -19,15 +19,21 @@
 package org.apache.jmeter.protocol.jms.sampler;
 
 import java.util.Date;
+import java.util.Enumeration;
 import java.util.Hashtable;
 import java.util.Map;
 
+import javax.jms.BytesMessage;
 import javax.jms.DeliveryMode;
 import javax.jms.JMSException;
+import javax.jms.MapMessage;
 import javax.jms.Message;
+import javax.jms.ObjectMessage;
 import javax.jms.Queue;
+import javax.jms.QueueBrowser;
 import javax.jms.QueueConnection;
 import javax.jms.QueueConnectionFactory;
+import javax.jms.QueueReceiver;
 import javax.jms.QueueSender;
 import javax.jms.QueueSession;
 import javax.jms.Session;
@@ -41,9 +47,14 @@ import org.apache.jmeter.protocol.jms.Ut
 import org.apache.jmeter.samplers.AbstractSampler;
 import org.apache.jmeter.samplers.Entry;
 import org.apache.jmeter.samplers.SampleResult;
+import org.apache.jmeter.samplers.Sampler;
 import org.apache.jmeter.testelement.ThreadListener;
 import org.apache.jmeter.testelement.property.BooleanProperty;
+import org.apache.jmeter.testelement.property.IntegerProperty;
+import org.apache.jmeter.testelement.property.JMeterProperty;
 import org.apache.jmeter.testelement.property.TestElementProperty;
+import org.apache.jmeter.threads.JMeterContext;
+import org.apache.jmeter.threads.JMeterContextService;
 import org.apache.jmeter.util.JMeterUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -61,7 +72,7 @@ public class JMSSampler extends Abstract
     private static final int DEFAULT_TIMEOUT = 2000;
     private static final String DEFAULT_TIMEOUT_STRING = Integer.toString(DEFAULT_TIMEOUT);
 
-    //++ These are JMX names, and must not be changed
+    // ++ These are JMX names, and must not be changed
     private static final String JNDI_INITIAL_CONTEXT_FACTORY = "JMSSampler.initialContextFactory"; // $NON-NLS-1$
 
     private static final String JNDI_CONTEXT_PROVIDER_URL = "JMSSampler.contextProviderUrl"; // $NON-NLS-1$
@@ -78,7 +89,17 @@ public class JMSSampler extends Abstract
 
     private static final String JMS_SELECTOR_DEFAULT = ""; // $NON-NLS-1$
 
-    private static final String IS_ONE_WAY = "JMSSampler.isFireAndForget"; // $NON-NLS-1$
+    /**
+     * @deprecated since 4.0 replaced by JMS_COMMUNICATION_STYLE
+     */
+    @Deprecated
+    public static final String IS_ONE_WAY = "JMSSampler.isFireAndForget"; // $NON-NLS-1$
+    
+    private static final String JMS_NUMBEROFSAMPLES = "JMSSampler.jmsNumberOfSamplesToAggregate"; // $NON-NLS-1$
+
+    private static final String JMS_NUMBEROFSAMPLES_DEFAULT = "1"; // $NON-NLS-1$
+
+    public static final String JMS_COMMUNICATION_STYLE = "JMSSampler.communicationStyle"; // $NON-NLS-1$
 
     private static final String JMS_PROPERTIES = "arguments"; // $NON-NLS-1$
 
@@ -96,14 +117,34 @@ public class JMSSampler extends Abstract
 
     private static final String USE_RES_MSGID_AS_CORRELID = "JMSSampler.useResMsgIdAsCorrelId"; // $NON-NLS-1$
 
-    private static final boolean USE_RES_MSGID_AS_CORRELID_DEFAULT = false; // Default to be applied
-
-
-    //--
+    private static final boolean USE_RES_MSGID_AS_CORRELID_DEFAULT = false; // Default
+                                                                            // to
+                                                                            // be
+                                                                            // applied
+
+    public enum COMMUNICATION_STYLE {
+        ONE_WAY(0), 
+        REQUEST_REPLY(1), 
+        READ(2), 
+        BROWSE(3), 
+        CLEAR(4);
+
+        private final int value;
+        COMMUNICATION_STYLE(int value) {
+            this.value = value;
+        }
+        
+        public int getValue() { 
+            return value; 
+        }
+    }
 
-    // Should we use java.naming.security.[principal|credentials] to create the QueueConnection?
-    private static final boolean USE_SECURITY_PROPERTIES =
-        JMeterUtils.getPropDefault("JMSSampler.useSecurity.properties", true); // $NON-NLS-1$
+    // --
+
+    // Should we use java.naming.security.[principal|credentials] to create the
+    // QueueConnection?
+    private static final boolean USE_SECURITY_PROPERTIES = JMeterUtils
+            .getPropDefault("JMSSampler.useSecurity.properties", true); // $NON-NLS-1$
 
     //
     // Member variables
@@ -111,6 +152,9 @@ public class JMSSampler extends Abstract
     /** Queue for receiving messages (if applicable). */
     private transient Queue receiveQueue;
 
+    /** Queue for sending messages. */
+    private transient Queue sendQueue;
+
     /** The session with the queueing system. */
     private transient QueueSession session;
 
@@ -134,6 +178,8 @@ public class JMSSampler extends Abstract
      */
     @Override
     public SampleResult sample(Entry entry) {
+        JMeterContext context = JMeterContextService.getContext();
+
         SampleResult res = new SampleResult();
         res.setSampleLabel(getName());
         res.setSamplerData(getContent());
@@ -142,41 +188,23 @@ public class JMSSampler extends Abstract
         res.sampleStart();
 
         try {
-            TextMessage msg = createMessage();
-            if (isOneway()) {
-                int deliveryMode = isNonPersistent() ? 
-                        DeliveryMode.NON_PERSISTENT:DeliveryMode.PERSISTENT;
-                producer.send(msg, deliveryMode, Integer.parseInt(getPriority()), 
-                        Long.parseLong(getExpiration()));
-                res.setRequestHeaders(Utils.messageProperties(msg));
-                res.setResponseOK();
-                res.setResponseData("Oneway request has no response data", null);
+            LOGGER.debug("Point-to-point mode: " + getCommunicationstyle());
+            if (isBrowse()) {
+                handleBrowse(res);
+            } else if (isClearQueue()) {
+                handleClearQueue(res);
+            } else if (isOneway()) {
+                handleOneWay(res);
+            } else if (isRead()) {
+                handleRead(context, res);
             } else {
-                if (!useTemporyQueue()) {
-                    msg.setJMSReplyTo(receiveQueue);
-                }
-                Message replyMsg = executor.sendAndReceive(msg,
-                        isNonPersistent() ? DeliveryMode.NON_PERSISTENT : DeliveryMode.PERSISTENT, 
-                        Integer.parseInt(getPriority()), 
-                        Long.parseLong(getExpiration()));
-                res.setRequestHeaders(Utils.messageProperties(msg));
-                if (replyMsg == null) {
-                    res.setResponseMessage("No reply message received");
-                } else {
-                    if (replyMsg instanceof TextMessage) {
-                        res.setResponseData(((TextMessage) replyMsg).getText(), null);
-                    } else {
-                        res.setResponseData(replyMsg.toString(), null);
-                    }
-                    res.setResponseHeaders(Utils.messageProperties(replyMsg));
-                    res.setResponseOK();
-                }
+                handleRequestResponse(res);
             }
         } catch (Exception e) {
             LOGGER.warn(e.getLocalizedMessage(), e);
-            if (thrown != null){
+            if (thrown != null) {
                 res.setResponseMessage(thrown.toString());
-            } else {                
+            } else {
                 res.setResponseMessage(e.getLocalizedMessage());
             }
         }
@@ -184,6 +212,226 @@ public class JMSSampler extends Abstract
         return res;
     }
 
+    private void handleBrowse(SampleResult res) throws JMSException {
+        LOGGER.debug("isBrowseOnly");
+        StringBuilder sb = new StringBuilder("");
+        res.setSuccessful(true);
+        sb.append("\n \n  Browse message on Send Queue " + sendQueue.getQueueName());
+        sb.append(browseQueueDetails(sendQueue, res));
+        res.setResponseData(sb.toString().getBytes());
+    }
+
+    private void handleClearQueue(SampleResult res) throws JMSException {
+        LOGGER.debug("isClearQueue");
+        StringBuilder sb = new StringBuilder("");
+        res.setSuccessful(true);
+        sb.append("\n \n  Clear messages on Send Queue " + sendQueue.getQueueName());
+        sb.append(clearQueue(sendQueue, res));
+        res.setResponseData(sb.toString().getBytes());
+    }
+
+    private void handleOneWay(SampleResult res) throws JMSException {
+        LOGGER.debug("isOneWay");
+        TextMessage msg = createMessage();
+        int deliveryMode = isNonPersistent() ? DeliveryMode.NON_PERSISTENT : DeliveryMode.PERSISTENT;
+        producer.send(msg, deliveryMode, Integer.parseInt(getPriority()), Long.parseLong(getExpiration()));
+        res.setRequestHeaders(Utils.messageProperties(msg));
+        res.setResponseOK();
+        res.setResponseData("Oneway request has no response data", null);
+    }
+
+    private void handleRead(JMeterContext context, SampleResult res) {
+        LOGGER.debug("isRead");
+        StringBuilder sb = new StringBuilder("");
+        res.setSuccessful(true);
+        Sampler sampler = context.getPreviousSampler();
+        SampleResult sr = context.getPreviousResult();
+        String jmsSelector = getJMSSelector();
+        if (jmsSelector.equals("_PREV_SAMPLER_")
+                && (sampler instanceof JMSSampler)) {
+            jmsSelector = sr.getResponseMessage();
+        }
+        int sampleCounter = 0;
+        int sampleTries = 0;
+        String result = null;
+
+        StringBuilder buffer = new StringBuilder();
+        StringBuilder propBuffer = new StringBuilder();
+
+        do {
+            result = browseQueueForConsumption(sendQueue, jmsSelector, res, buffer, propBuffer);
+            if (result != null) {
+                sb.append(result);
+                sb.append('\n');
+                sampleCounter++;
+            }
+            sampleTries++;
+        } while ((result != null) && (sampleTries < getNumberOfSamplesToAggregateAsInt()));
+
+        res.setResponseMessage(sampleCounter + " samples messages received");
+        res.setResponseData(buffer.toString().getBytes()); // TODO - charset?
+        res.setResponseHeaders(propBuffer.toString());
+        if (sampleCounter == 0) {
+            res.setResponseCode("404");
+            res.setSuccessful(false);
+        } else {
+            res.setResponseCodeOK();
+            res.setSuccessful(true);
+        }
+        res.setResponseMessage(sampleCounter + " message(s) received successfully");
+        res.setSamplerData(getNumberOfSamplesToAggregateAsInt() + " messages expected");
+        res.setSampleCount(sampleCounter);
+    }
+
+    private void handleRequestResponse(SampleResult res) throws JMSException {
+        TextMessage msg = createMessage();
+        if (!useTemporyQueue()) {
+            LOGGER.debug("NO TEMP QUEUE");
+            msg.setJMSReplyTo(receiveQueue);
+        }
+        LOGGER.debug("Create temp message");
+        Message replyMsg = executor.sendAndReceive(msg,
+                isNonPersistent() ? DeliveryMode.NON_PERSISTENT : DeliveryMode.PERSISTENT,
+                Integer.parseInt(getPriority()), Long.parseLong(getExpiration()));
+        res.setRequestHeaders(Utils.messageProperties(msg));
+        if (replyMsg == null) {
+            res.setResponseMessage("No reply message received");
+        } else {
+            if (replyMsg instanceof TextMessage) {
+                res.setResponseData(((TextMessage) replyMsg).getText(), null);
+            } else {
+                res.setResponseData(replyMsg.toString(), null);
+            }
+            res.setResponseHeaders(Utils.messageProperties(replyMsg));
+            res.setResponseOK();
+        }
+    }
+
+    private String browseQueueForConsumption(Queue queue, 
+            String jmsSelector, 
+            SampleResult res, 
+            StringBuilder buffer,
+            StringBuilder propBuffer) {
+        String retVal = null;
+        QueueReceiver consumer = null;
+        Message reply = null;
+        try {
+            consumer = session.createReceiver(queue, jmsSelector);
+            reply = consumer.receive(Long.valueOf(getTimeout()));
+            LOGGER.debug("Message: {}", reply);
+            if (reply != null) {
+                res.setResponseMessage("1 message(s) received successfully");
+                res.setResponseHeaders(reply.toString());
+                TextMessage msg = (TextMessage) reply;
+                retVal = msg.getText();
+                extractContent(buffer, propBuffer, msg);
+            } else {
+                res.setResponseMessage("No message received");
+            }
+        } catch (Exception ex) {
+            LOGGER.error("Error browsing queue with selector {}", jmsSelector, ex.getMessage());
+        } finally {
+            Utils.close(consumer, LOGGER);
+        }
+        return retVal;
+    }
+
+    private void extractContent(StringBuilder buffer, StringBuilder propBuffer, Message msg) {
+        if (msg != null) {
+            try {
+                if (msg instanceof TextMessage) {
+                    buffer.append(((TextMessage) msg).getText());
+                } else if (msg instanceof ObjectMessage) {
+                    ObjectMessage objectMessage = (ObjectMessage) msg;
+                    if (objectMessage.getObject() != null) {
+                        buffer.append(objectMessage.getObject().getClass());
+                    } else {
+                        buffer.append("object is null");
+                    }
+                } else if (msg instanceof BytesMessage) {
+                    BytesMessage bytesMessage = (BytesMessage) msg;
+                    buffer.append(bytesMessage.getBodyLength() + " bytes received in BytesMessage");
+                } else if (msg instanceof MapMessage) {
+                    MapMessage mapm = (MapMessage) msg;
+                    @SuppressWarnings("unchecked") // MapNames are Strings
+                    Enumeration<String> enumb = mapm.getMapNames();
+                    while (enumb.hasMoreElements()) {
+                        String name = enumb.nextElement();
+                        Object obj = mapm.getObject(name);
+                        buffer.append(name);
+                        buffer.append(",");
+                        buffer.append(obj.getClass().getCanonicalName());
+                        buffer.append(",");
+                        buffer.append(obj);
+                        buffer.append("\n");
+                    }
+                }
+                Utils.messageProperties(propBuffer, msg);
+            } catch (JMSException e) {
+                LOGGER.error(e.getMessage());
+            }
+        }
+    }
+
+    private String browseQueueDetails(Queue queue, SampleResult res) {
+        try {
+            String messageBodies = "\n==== Browsing Messages === \n";
+            // get some queue details
+            QueueBrowser qBrowser = session.createBrowser(queue);
+            // browse the messages
+            Enumeration<?> e = qBrowser.getEnumeration();
+            int numMsgs = 0;
+            // count number of messages
+            String corrID = "";
+            while (e.hasMoreElements()) {
+                TextMessage message = (TextMessage) e.nextElement();
+                corrID = message.getJMSCorrelationID();
+                if (corrID == null) {
+                    corrID = message.getJMSMessageID();
+                    messageBodies = messageBodies + numMsgs + " - MessageID: " + corrID + ": " + message.getText()
+                            + "\n";
+                } else {
+                    messageBodies = messageBodies + numMsgs + " - CorrelationID: " + corrID + ": " + message.getText()
+                            + "\n";
+                }
+                numMsgs++;
+            }
+            res.setResponseMessage(numMsgs + " messages available on the queue");
+            res.setResponseHeaders(qBrowser.toString());
+            return (messageBodies + queue.getQueueName() + " has " + numMsgs + " messages");
+        } catch (Exception e) {
+            res.setResponseMessage("Error counting message on the queue");
+            LOGGER.error("Error browsing messages on the queue, message {}", e.getMessage());
+            return "Error browsing messages on the queue, message "+ e.getMessage();
+        }
+    }
+
+    private String clearQueue(Queue queue, SampleResult res) {
+        String retVal = null;
+        QueueReceiver consumer = null;
+        try {
+            consumer = session.createReceiver(queue);
+            Message deletedMsg = null;
+            long deletedMsgCount = 0;
+            do {
+                deletedMsg = consumer.receive(getTimeoutAsInt());
+                if (deletedMsg != null) {
+                    deletedMsgCount++;
+                    deletedMsg.acknowledge();
+                }
+            } while (deletedMsg != null);
+            retVal = deletedMsgCount + " message(s) removed";
+            res.setResponseMessage(retVal);
+        } catch (Exception ex) {
+            res.setResponseMessage("Error clearing queue");
+            LOGGER.error("Error clearing queue, message {}", ex.getMessage());
+            return "Error clearing queue, message" + ex.getMessage();
+        } finally {
+            Utils.close(consumer, LOGGER);
+        }
+        return retVal;
+    }
+
     private TextMessage createMessage() throws JMSException {
         if (session == null) {
             throw new IllegalStateException("Session may not be null while creating message");
@@ -198,27 +446,28 @@ public class JMSSampler extends Abstract
         Utils.addJMSProperties(msg, getJMSProperties().getJmsPropertysAsMap());
     }
 
-    /** 
+    /**
      * @return {@link JMSProperties} JMS Properties
      */
     public JMSProperties getJMSProperties() {
         Object o = getProperty(JMS_PROPERTIES).getObjectValue();
         JMSProperties jmsProperties = null;
         // Backward compatibility with versions <= 2.10
-        if(o instanceof Arguments) {
-            jmsProperties = Utils.convertArgumentsToJmsProperties((Arguments)o);
+        if (o instanceof Arguments) {
+            jmsProperties = Utils.convertArgumentsToJmsProperties((Arguments) o);
         } else {
             jmsProperties = (JMSProperties) o;
         }
-        if(jmsProperties == null) {
+        if (jmsProperties == null) {
             jmsProperties = new JMSProperties();
             setJMSProperties(jmsProperties);
         }
         return jmsProperties;
     }
-    
+
     /**
-     * @param jmsProperties JMS Properties
+     * @param jmsProperties
+     *            JMS Properties
      */
     public void setJMSProperties(JMSProperties jmsProperties) {
         setProperty(new TestElementProperty(JMS_PROPERTIES, jmsProperties));
@@ -265,7 +514,19 @@ public class JMSSampler extends Abstract
     }
 
     public boolean isOneway() {
-        return getPropertyAsBoolean(IS_ONE_WAY);
+        return COMMUNICATION_STYLE.ONE_WAY.value == getPropertyAsInt(JMS_COMMUNICATION_STYLE);
+    }
+
+    public boolean isRead() {
+        return COMMUNICATION_STYLE.READ.value == getPropertyAsInt(JMS_COMMUNICATION_STYLE);
+    }
+
+    public boolean isBrowse() {
+        return COMMUNICATION_STYLE.BROWSE.value == getPropertyAsInt(JMS_COMMUNICATION_STYLE);
+    }
+
+    public boolean isClearQueue() {
+        return COMMUNICATION_STYLE.CLEAR.value == getPropertyAsInt(JMS_COMMUNICATION_STYLE);
     }
 
     public boolean isNonPersistent() {
@@ -275,7 +536,8 @@ public class JMSSampler extends Abstract
     /**
      * Which request field to use for correlation?
      * 
-     * @return true if correlation should use the request JMSMessageID rather than JMSCorrelationID
+     * @return true if correlation should use the request JMSMessageID rather
+     *         than JMSCorrelationID
      */
     public boolean isUseReqMsgIdAsCorrelId() {
         return getPropertyAsBoolean(USE_REQ_MSGID_AS_CORRELID);
@@ -284,7 +546,8 @@ public class JMSSampler extends Abstract
     /**
      * Which response field to use for correlation?
      * 
-     * @return true if correlation should use the response JMSMessageID rather than JMSCorrelationID
+     * @return true if correlation should use the response JMSMessageID rather
+     *         than JMSCorrelationID
      */
     public boolean isUseResMsgIdAsCorrelId() {
         return getPropertyAsBoolean(USE_RES_MSGID_AS_CORRELID, USE_RES_MSGID_AS_CORRELID_DEFAULT);
@@ -298,8 +561,24 @@ public class JMSSampler extends Abstract
         return getPropertyAsString(JMSSampler.JNDI_CONTEXT_PROVIDER_URL);
     }
 
+    public int getCommunicationstyle() {
+        JMeterProperty prop = getProperty(JMS_COMMUNICATION_STYLE);
+        return Integer.parseInt(prop.getStringValue());
+    }
+
+    public String getCommunicationstyleString() {
+        return getPropertyAsString(JMS_COMMUNICATION_STYLE);
+    }
+
+    public void setCommunicationstyle(int communicationStyle) {
+        setProperty(new IntegerProperty(JMS_COMMUNICATION_STYLE, communicationStyle));
+    }
+    
     public void setIsOneway(boolean isOneway) {
-        setProperty(new BooleanProperty(IS_ONE_WAY, isOneway));
+        setProperty(new IntegerProperty(JMS_COMMUNICATION_STYLE, 
+                isOneway ? 
+                        COMMUNICATION_STYLE.ONE_WAY.value : 
+                            COMMUNICATION_STYLE.REQUEST_REPLY.value));
     }
 
     public void setNonPersistent(boolean value) {
@@ -329,23 +608,24 @@ public class JMSSampler extends Abstract
             Object obj = context.lookup(getQueueConnectionFactory());
             if (!(obj instanceof QueueConnectionFactory)) {
                 String msg = "QueueConnectionFactory expected, but got "
-                    + (obj != null ? obj.getClass().getName() : "null");
+                        + (obj != null ? obj.getClass().getName() : "null");
                 LOGGER.error(msg);
                 throw new IllegalStateException(msg);
             }
             QueueConnectionFactory factory = (QueueConnectionFactory) obj;
-            Queue sendQueue = (Queue) context.lookup(getSendQueue());
+            sendQueue = (Queue) context.lookup(getSendQueue());
 
             if (!useTemporyQueue()) {
                 receiveQueue = (Queue) context.lookup(getReceiveQueue());
-                receiverThread = Receiver.createReceiver(factory, receiveQueue, Utils.getFromEnvironment(context, Context.SECURITY_PRINCIPAL), 
-                        Utils.getFromEnvironment(context, Context.SECURITY_CREDENTIALS)
-                        , isUseResMsgIdAsCorrelId(), getJMSSelector());
+                receiverThread = Receiver.createReceiver(factory, receiveQueue,
+                        Utils.getFromEnvironment(context, Context.SECURITY_PRINCIPAL),
+                        Utils.getFromEnvironment(context, Context.SECURITY_CREDENTIALS), isUseResMsgIdAsCorrelId(),
+                        getJMSSelector());
             }
 
             String principal = null;
             String credentials = null;
-            if (USE_SECURITY_PROPERTIES){
+            if (USE_SECURITY_PROPERTIES) {
                 principal = Utils.getFromEnvironment(context, Context.SECURITY_PRINCIPAL);
                 credentials = Utils.getFromEnvironment(context, Context.SECURITY_CREDENTIALS);
             }
@@ -359,7 +639,9 @@ public class JMSSampler extends Abstract
 
             LOGGER.debug("Session created");
 
-            if (isOneway()) {
+            if (isBrowse() || isRead() || isClearQueue()) {
+                // Do nothing!
+            } else if (isOneway()) {
                 producer = session.createSender(sendQueue);
                 if (isNonPersistent()) {
                     producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
@@ -367,7 +649,6 @@ public class JMSSampler extends Abstract
                 producer.setPriority(Integer.parseInt(getPriority()));
                 producer.setTimeToLive(Long.parseLong(getExpiration()));
             } else {
-
                 if (useTemporyQueue()) {
                     executor = new TemporaryQueueExecutor(session, sendQueue);
                 } else {
@@ -418,14 +699,15 @@ public class JMSSampler extends Abstract
 
     private void printEnvironment(Context context) throws NamingException {
         try {
-            Hashtable<?,?> env = context.getEnvironment();
-            if(env != null) {
+            Hashtable<?, ?> env = context.getEnvironment();
+            if (env != null) {
                 LOGGER.debug("Initial Context Properties");
                 for (Map.Entry<?, ?> entry : env.entrySet()) {
                     LOGGER.debug("{}={}", entry.getKey(), entry.getValue());
                 }
             } else {
-                LOGGER.warn("context.getEnvironment() returned null (should not happen according to javadoc but non compliant implementation can return this)");
+                LOGGER.warn(
+                        "context.getEnvironment() returned null (should not happen according to javadoc but non compliant implementation can return this)");
             }
         } catch (javax.naming.OperationNotSupportedException ex) {
             // Some JNDI implementation can return this
@@ -454,7 +736,7 @@ public class JMSSampler extends Abstract
     public String getTimeout() {
         return getPropertyAsString(TIMEOUT, DEFAULT_TIMEOUT_STRING);
     }
-    
+
     public String getExpiration() {
         String expiration = getPropertyAsString(JMS_EXPIRATION);
         if (expiration.length() == 0) {
@@ -472,7 +754,7 @@ public class JMSSampler extends Abstract
             return priority;
         }
     }
-    
+
     /**
      * {@inheritDoc}
      */
@@ -510,11 +792,11 @@ public class JMSSampler extends Abstract
     public void setTimeout(String s) {
         setProperty(JMSSampler.TIMEOUT, s);
     }
-    
+
     public void setPriority(String s) {
         setProperty(JMSSampler.JMS_PRIORITY, s, Utils.DEFAULT_PRIORITY_4);
     }
-    
+
     public void setExpiration(String s) {
         setProperty(JMSSampler.JMS_EXPIRATION, s, Utils.DEFAULT_NO_EXPIRY);
     }
@@ -527,25 +809,47 @@ public class JMSSampler extends Abstract
     }
 
     /**
-     * @param selector String selector
+     * @param selector
+     *            String selector
      */
     public void setJMSSelector(String selector) {
         setProperty(JMSSampler.JMS_SELECTOR, selector, JMS_SELECTOR_DEFAULT);
     }
-    
+
+    public String getNumberOfSamplesToAggregate() {
+        return getPropertyAsString(JMSSampler.JMS_NUMBEROFSAMPLES, JMS_NUMBEROFSAMPLES_DEFAULT);
+    }
+
+    public void setNumberOfSamplesToAggregate(String selector) {
+        setProperty(JMSSampler.JMS_NUMBEROFSAMPLES, selector, JMS_NUMBEROFSAMPLES_DEFAULT);
+    }
+
+    private int getNumberOfSamplesToAggregateAsInt() {
+        int val = 1;
+        try {
+            val = getPropertyAsInt(JMS_NUMBEROFSAMPLES);
+        } catch (Exception e) {
+            val = 1;
+        }
+        if (val < 1) {
+            val = 1;
+        }
+        return val;
+    }
+
     /**
-     * @param string name of the initial context factory to use
+     * @param string
+     *            name of the initial context factory to use
      */
     public void setInitialContextFactory(String string) {
         setProperty(JNDI_INITIAL_CONTEXT_FACTORY, string);
-
     }
 
     /**
-     * @param string url of the provider
+     * @param string
+     *            url of the provider
      */
     public void setContextProvider(String string) {
         setProperty(JNDI_CONTEXT_PROVIDER_URL, string);
-
     }
 }

Modified: jmeter/trunk/xdocs/changes.xml
URL: http://svn.apache.org/viewvc/jmeter/trunk/xdocs/changes.xml?rev=1815692&r1=1815691&r2=1815692&view=diff
==============================================================================
--- jmeter/trunk/xdocs/changes.xml [utf-8] (original)
+++ jmeter/trunk/xdocs/changes.xml [utf-8] Sat Nov 18 20:15:20 2017
@@ -102,6 +102,7 @@ Summary
 <ul>
     <li><bug>61739</bug>Java Request / JavaSamplerClient : Improve <code>org.apache.jmeter.protocol.java.sampler.JavaSamplerContext</code></li>
     <li><bug>61762</bug>Start Next Thread Loop should be used everywhere</li>
+    <li><bug>61544</bug>JMS Point-to-Point Sampler: Enhance communication styles with read, browse, clear. Based on a contribution by Benny van Wijngaarden (benny at smaragd-it.nl)</li>
 </ul>
 
 <h3>Controllers</h3>
@@ -253,6 +254,7 @@ Summary
     <li>orimarko at gmail.com</li>
     <li>Artem Fedorov (artem at blazemeter.com)</li>
     <li><a href="https://www.blazemeter.com">BlazeMeter Ltd</a></li>
+    <li>Benny van Wijngaarden (benny at smaragd-it.nl)</li>
 </ul>
 <p>We also thank bug reporters who helped us improve JMeter. <br/>
 For this release we want to give special thanks to the following reporters for the clear reports and tests made after our fixes:</p>

Modified: jmeter/trunk/xdocs/usermanual/component_reference.xml
URL: http://svn.apache.org/viewvc/jmeter/trunk/xdocs/usermanual/component_reference.xml?rev=1815692&r1=1815691&r2=1815692&view=diff
==============================================================================
--- jmeter/trunk/xdocs/usermanual/component_reference.xml (original)
+++ jmeter/trunk/xdocs/usermanual/component_reference.xml Sat Nov 18 20:15:20 2017
@@ -1571,8 +1571,11 @@ The following table shows some values wh
         It is different from pub/sub messages and is generally used for handling transactions.
         </p>
         <p>
-        <code>Request Only</code> will typically be used to put load on a JMS System.<br></br>
-        <code>Request Response</code> will be used when you want to test response time of a JMS service that processes messages sent to the Request Queue as this mode will wait for the response on the Reply queue sent by this service.<br></br>
+        <code>request_only</code> will typically be used to put load on a JMS System.<br></br>
+        <code>request_reply</code> will be used when you want to test response time of a JMS service that processes messages sent to the Request Queue as this mode will wait for the response on the Reply queue sent by this service.<br></br>
+        <code>browse</code> returns the current queue depth, i.e. the number of messages on the queue.<br></br>
+        <code>read</code> reads a message from the queue (if any).<br></br>
+        <code>clear</code> clears the queue, i.e. remove all messages from the queue.<br></br>
         </p>
         <p>
         JMeter use the properties <code>java.naming.security.[principal|credentials]</code> - if present -
@@ -1594,12 +1597,14 @@ The following table shows some values wh
     The JNDI name of the receiving queue. If a value is provided here and the communication style is <code>Request Response</code>
     this queue will be monitored for responses to the requests sent.
   </property>
+  <property name="Number of samples to aggregate" required="Yes">Number of samples to aggregate. Only applicable for Communication style Read.</property>
   <property name="JMS Selector" required="No">
     Message Selector as defined by JMS specification to extract only 
     messages that respect the Selector condition. Syntax uses subpart of SQL 92.
   </property>
   <property name="Communication style" required="Yes">
-    The Communication style can be <code>Request Only</code> (also known as Fire and Forget) or <code>Request Response</code>:
+    The Communication style can be <code>Request Only</code> (also known as Fire and Forget), <code>Request Response</code>,
+    <code>Read</code>, <code>Browse</code>, <code>Clear</code>:
     <dl>
     <dt><code>Request Only</code></dt><dd> will only send messages and will not monitor replies. As such it can be used to put load on a system.</dd>
     <dt><code>Request Response</code></dt><dd> will send messages and monitor the replies it receives. Behaviour depends on the value of the JNDI Name Reply Queue.
@@ -1609,6 +1614,11 @@ The following table shows some values wh
     This is very different from the fixed reply queue. With temporary queues the sending thread will block until the reply message has been received.
     With <code>Request Response</code> mode, you need to have a Server that listens to messages sent to Request Queue and sends replies to 
     queue referenced by <code>message.getJMSReplyTo()</code>.</dd>
+    <dt><code>Read</code></dt><dd> will read a message from an outgoing queue which has no listeners attached. This can be convenient for testing purposes.
+     This method can be used if you need to handle queues without a binding file (in case the jmeter-jms-skip-jndi library is used),
+     which only works with the JMS Point-to-Point sampler. In case binding files are used, one can also use the JMS Subscriber Sampler for reading from a queue.</dd>
+    <dt><code>Browse</code></dt><dd> will determine the current queue depth without removing messages from the queue, returning the number of messages on the queue.</dd>
+    <dt><code>Clear</code></dt><dd> will clear the queue, i.e. remove all messages from the queue.</dd>
     </dl>
   </property>
   <property name="Use alternate fields for message correlation" required="Yes">