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/01/14 20:47:19 UTC

svn commit: r1778825 - in /jmeter/trunk: src/core/org/apache/jmeter/resources/ src/protocol/jms/org/apache/jmeter/protocol/jms/client/ src/protocol/jms/org/apache/jmeter/protocol/jms/control/gui/ src/protocol/jms/org/apache/jmeter/protocol/jms/sampler/...

Author: pmouawad
Date: Sat Jan 14 20:47:19 2017
New Revision: 1778825

URL: http://svn.apache.org/viewvc?rev=1778825&view=rev
Log:
Bug 60585 - JMS Publisher and JMS Subscriber : Allow reconnection on error and pause between errors
Based on PR 240  from by Logan Mauzaize (logan.mauzaize at gmail.com) and Maxime Chassagneux (maxime.chassagneux at gmail.com).

This closes #240 
Bugzilla Id: 60585

Modified:
    jmeter/trunk/src/core/org/apache/jmeter/resources/messages.properties
    jmeter/trunk/src/core/org/apache/jmeter/resources/messages_fr.properties
    jmeter/trunk/src/protocol/jms/org/apache/jmeter/protocol/jms/client/ClientPool.java
    jmeter/trunk/src/protocol/jms/org/apache/jmeter/protocol/jms/control/gui/JMSPublisherGui.java
    jmeter/trunk/src/protocol/jms/org/apache/jmeter/protocol/jms/control/gui/JMSSubscriberGui.java
    jmeter/trunk/src/protocol/jms/org/apache/jmeter/protocol/jms/sampler/BaseJMSSampler.java
    jmeter/trunk/src/protocol/jms/org/apache/jmeter/protocol/jms/sampler/PublisherSampler.java
    jmeter/trunk/src/protocol/jms/org/apache/jmeter/protocol/jms/sampler/SubscriberSampler.java
    jmeter/trunk/xdocs/changes.xml
    jmeter/trunk/xdocs/usermanual/component_reference.xml

Modified: jmeter/trunk/src/core/org/apache/jmeter/resources/messages.properties
URL: http://svn.apache.org/viewvc/jmeter/trunk/src/core/org/apache/jmeter/resources/messages.properties?rev=1778825&r1=1778824&r2=1778825&view=diff
==============================================================================
--- jmeter/trunk/src/core/org/apache/jmeter/resources/messages.properties (original)
+++ jmeter/trunk/src/core/org/apache/jmeter/resources/messages.properties Sat Jan 14 20:47:19 2017
@@ -458,6 +458,8 @@ jms_dest_setup=Setup
 jms_dest_setup_dynamic=Each sample
 jms_dest_setup_static=At startup
 jms_durable_subscription_id=Durable Subscription ID
+jms_error_reconnect_on_codes=Reconnect on error codes (regex)
+jms_error_pause_between=Pause between errors (ms)
 jms_expiration=Expiration (ms)
 jms_file=File
 jms_initial_context_factory=Initial Context Factory

Modified: jmeter/trunk/src/core/org/apache/jmeter/resources/messages_fr.properties
URL: http://svn.apache.org/viewvc/jmeter/trunk/src/core/org/apache/jmeter/resources/messages_fr.properties?rev=1778825&r1=1778824&r2=1778825&view=diff
==============================================================================
--- jmeter/trunk/src/core/org/apache/jmeter/resources/messages_fr.properties (original)
+++ jmeter/trunk/src/core/org/apache/jmeter/resources/messages_fr.properties Sat Jan 14 20:47:19 2017
@@ -451,6 +451,8 @@ jms_dest_setup=Evaluer
 jms_dest_setup_dynamic=A chaque \u00E9chantillon
 jms_dest_setup_static=Au d\u00E9marrage
 jms_durable_subscription_id=ID d'abonnement durable
+jms_error_reconnect_on_codes=Se reconnecter pour les codes d'erreurs (regex)
+jms_error_pause_between=Temporisation entre erreurs (ms)
 jms_expiration=Expiration (ms)
 jms_file=Fichier
 jms_initial_context_factory=Fabrique de connexion initiale

Modified: jmeter/trunk/src/protocol/jms/org/apache/jmeter/protocol/jms/client/ClientPool.java
URL: http://svn.apache.org/viewvc/jmeter/trunk/src/protocol/jms/org/apache/jmeter/protocol/jms/client/ClientPool.java?rev=1778825&r1=1778824&r2=1778825&view=diff
==============================================================================
--- jmeter/trunk/src/protocol/jms/org/apache/jmeter/protocol/jms/client/ClientPool.java (original)
+++ jmeter/trunk/src/protocol/jms/org/apache/jmeter/protocol/jms/client/ClientPool.java Sat Jan 14 20:47:19 2017
@@ -80,4 +80,12 @@ public class ClientPool {
     public static Object get(Object key) {
         return client_map.get(key);
     }
+
+    /**
+     * Remove publisher from clients
+     * @param publisher {@link Publisher}
+     */
+    public static synchronized void removeClient(Publisher publisher) {
+        clients.remove(publisher);
+    }
 }

Modified: jmeter/trunk/src/protocol/jms/org/apache/jmeter/protocol/jms/control/gui/JMSPublisherGui.java
URL: http://svn.apache.org/viewvc/jmeter/trunk/src/protocol/jms/org/apache/jmeter/protocol/jms/control/gui/JMSPublisherGui.java?rev=1778825&r1=1778824&r2=1778825&view=diff
==============================================================================
--- jmeter/trunk/src/protocol/jms/org/apache/jmeter/protocol/jms/control/gui/JMSPublisherGui.java (original)
+++ jmeter/trunk/src/protocol/jms/org/apache/jmeter/protocol/jms/control/gui/JMSPublisherGui.java Sat Jan 14 20:47:19 2017
@@ -90,6 +90,9 @@ public class JMSPublisherGui extends Abs
 
     private final JLabeledTextField expiration = new JLabeledTextField(JMeterUtils.getResString("jms_expiration"),10); //$NON-NLS-1$
 
+    private final JLabeledTextField jmsErrorReconnectOnCodes =
+            new JLabeledTextField(JMeterUtils.getResString("jms_error_reconnect_on_codes")); // $NON-NLS-1$
+
     private final JLabeledTextField priority = new JLabeledTextField(JMeterUtils.getResString("jms_priority"),1); //$NON-NLS-1$
 
     private final JCheckBox useAuth = new JCheckBox(JMeterUtils.getResString("jms_use_auth"), false); //$NON-NLS-1$
@@ -169,6 +172,7 @@ public class JMSPublisherGui extends Abs
       sampler.setConnectionFactory(jndiConnFac.getText());
       sampler.setDestination(jmsDestination.getText());
       sampler.setExpiration(expiration.getText());
+      sampler.setReconnectionErrorCodes(jmsErrorReconnectOnCodes.getText());
       sampler.setPriority(priority.getText());
       sampler.setUsername(jmsUser.getText());
       sampler.setPassword(jmsPwd.getText());
@@ -204,6 +208,7 @@ public class JMSPublisherGui extends Abs
         mainPanel.add(createDestinationPane());
         mainPanel.add(createAuthPane());
         mainPanel.add(createPriorityAndExpiration());
+        mainPanel.add(jmsErrorReconnectOnCodes);
         mainPanel.add(iterations);
 
         jmsPropertiesPanel = new JMSPropertiesPanel(); //$NON-NLS-1$
@@ -236,6 +241,7 @@ public class JMSPublisherGui extends Abs
         jndiConnFac.setText(""); // $NON-NLS-1$
         jmsDestination.setText(""); // $NON-NLS-1$
         expiration.setText(""); // $NON-NLS-1$
+        jmsErrorReconnectOnCodes.setText("");
         priority.setText(""); // $NON-NLS-1$
         jmsUser.setText(""); // $NON-NLS-1$
         jmsPwd.setText(""); // $NON-NLS-1$
@@ -277,6 +283,7 @@ public class JMSPublisherGui extends Abs
         msgChoice.setText(sampler.getMessageChoice());
         iterations.setText(sampler.getIterations());
         expiration.setText(sampler.getExpiration());
+        jmsErrorReconnectOnCodes.setText(sampler.getReconnectionErrorCodes());
         priority.setText(sampler.getPriority());
         useAuth.setSelected(sampler.isUseAuth());
         jmsUser.setEnabled(useAuth.isSelected());

Modified: jmeter/trunk/src/protocol/jms/org/apache/jmeter/protocol/jms/control/gui/JMSSubscriberGui.java
URL: http://svn.apache.org/viewvc/jmeter/trunk/src/protocol/jms/org/apache/jmeter/protocol/jms/control/gui/JMSSubscriberGui.java?rev=1778825&r1=1778824&r2=1778825&view=diff
==============================================================================
--- jmeter/trunk/src/protocol/jms/org/apache/jmeter/protocol/jms/control/gui/JMSSubscriberGui.java (original)
+++ jmeter/trunk/src/protocol/jms/org/apache/jmeter/protocol/jms/control/gui/JMSSubscriberGui.java Sat Jan 14 20:47:19 2017
@@ -87,6 +87,12 @@ public class JMSSubscriberGui extends Ab
     private final JLabeledTextField timeout = 
         new JLabeledTextField(JMeterUtils.getResString("jms_timeout")); //$NON-NLS-1$
 
+    private final JLabeledTextField jmsErrorPauseBetween =
+        new JLabeledTextField(JMeterUtils.getResString("jms_error_pause_between")); // $NON-NLS-1$
+
+    private final JLabeledTextField jmsErrorReconnectOnCodes =
+        new JLabeledTextField(JMeterUtils.getResString("jms_error_reconnect_on_codes")); // $NON-NLS-1$
+
     private final JLabeledTextField separator = 
         new JLabeledTextField(JMeterUtils.getResString("jms_separator")); //$NON-NLS-1$
 
@@ -159,6 +165,8 @@ public class JMSSubscriberGui extends Ab
         sampler.setClientChoice(clientChoice.getText());
         sampler.setStopBetweenSamples(stopBetweenSamples.isSelected());
         sampler.setTimeout(timeout.getText());
+        sampler.setReconnectionErrorCodes(jmsErrorReconnectOnCodes.getText());
+        sampler.setPauseBetweenErrors(jmsErrorPauseBetween.getText());
         sampler.setDestinationStatic(destSetup.getText().equals(DEST_SETUP_STATIC));
         sampler.setSeparator(separator.getText());
     }
@@ -201,6 +209,9 @@ public class JMSSubscriberGui extends Ab
         mainPanel.add(choice);
         mainPanel.add(separator);
         
+        mainPanel.add(jmsErrorReconnectOnCodes);
+        mainPanel.add(jmsErrorPauseBetween);
+
         useProperties.addChangeListener(this);
         useAuth.addChangeListener(this);
     }
@@ -232,6 +243,8 @@ public class JMSSubscriberGui extends Ab
         timeout.setText(sampler.getTimeout());
         separator.setText(sampler.getSeparator());
         destSetup.setText(sampler.isDestinationStatic() ? DEST_SETUP_STATIC : DEST_SETUP_DYNAMIC);
+        jmsErrorReconnectOnCodes.setText(sampler.getReconnectionErrorCodes());
+        jmsErrorPauseBetween.setText(sampler.getPauseBetweenErrors());
     }
 
     @Override
@@ -257,6 +270,8 @@ public class JMSSubscriberGui extends Ab
         clientChoice.setText(RECEIVE_RSC);
         stopBetweenSamples.setSelected(false);
         destSetup.setText(DEST_SETUP_STATIC);
+        jmsErrorReconnectOnCodes.setText("");
+        jmsErrorPauseBetween.setText("");
     }
 
     /**

Modified: jmeter/trunk/src/protocol/jms/org/apache/jmeter/protocol/jms/sampler/BaseJMSSampler.java
URL: http://svn.apache.org/viewvc/jmeter/trunk/src/protocol/jms/org/apache/jmeter/protocol/jms/sampler/BaseJMSSampler.java?rev=1778825&r1=1778824&r2=1778825&view=diff
==============================================================================
--- jmeter/trunk/src/protocol/jms/org/apache/jmeter/protocol/jms/sampler/BaseJMSSampler.java (original)
+++ jmeter/trunk/src/protocol/jms/org/apache/jmeter/protocol/jms/sampler/BaseJMSSampler.java Sat Jan 14 20:47:19 2017
@@ -18,12 +18,15 @@
 package org.apache.jmeter.protocol.jms.sampler;
 
 import java.util.Date;
+import java.util.function.Predicate;
+import java.util.regex.Pattern;
 
 import javax.jms.DeliveryMode;
 import javax.jms.Destination;
 import javax.jms.JMSException;
 import javax.jms.Message;
 
+import org.apache.commons.lang3.StringUtils;
 import org.apache.jmeter.samplers.AbstractSampler;
 import org.apache.jmeter.samplers.Entry;
 import org.apache.jmeter.samplers.SampleResult;
@@ -75,6 +78,10 @@ public abstract class BaseJMSSampler ext
     private static final String DESTINATION_STATIC = "jms.destination_static"; // $NON-NLS-1$
     private static final boolean DESTINATION_STATIC_DEFAULT = true; // default to maintain compatibility
 
+    /** Property name for regex of error codes which force reconnection **/
+    private static final String ERROR_RECONNECT_ON_CODES = "jms_error_reconnect_on_codes"; // $NON-NLS-1$
+    private transient Predicate<String> isReconnectErrorCode = e -> false;
+
     //-- End of JMX file attribute names
 
     // See BUG 45460. We need to keep the resource in order to interpret existing files
@@ -381,4 +388,28 @@ public abstract class BaseJMSSampler ext
 
         return response.toString();
     }
+
+    public String getReconnectionErrorCodes() {
+        return getPropertyAsString(ERROR_RECONNECT_ON_CODES);
+    }
+
+    public void setReconnectionErrorCodes(String reconnectionErrorCodes) {
+        setProperty(ERROR_RECONNECT_ON_CODES, reconnectionErrorCodes);
+    }
+
+    public Predicate<String> getIsReconnectErrorCode() {
+        return isReconnectErrorCode;
+    }
+
+    /**
+     * 
+     */
+    protected void configureIsReconnectErrorCode() {
+        String regex = StringUtils.trimToEmpty(getReconnectionErrorCodes());
+        if (regex.isEmpty()) {
+            isReconnectErrorCode = e -> false;
+        } else {
+            isReconnectErrorCode = Pattern.compile(regex).asPredicate();
+        }
+    }
 }

Modified: jmeter/trunk/src/protocol/jms/org/apache/jmeter/protocol/jms/sampler/PublisherSampler.java
URL: http://svn.apache.org/viewvc/jmeter/trunk/src/protocol/jms/org/apache/jmeter/protocol/jms/sampler/PublisherSampler.java?rev=1778825&r1=1778824&r2=1778825&view=diff
==============================================================================
--- jmeter/trunk/src/protocol/jms/org/apache/jmeter/protocol/jms/sampler/PublisherSampler.java (original)
+++ jmeter/trunk/src/protocol/jms/org/apache/jmeter/protocol/jms/sampler/PublisherSampler.java Sat Jan 14 20:47:19 2017
@@ -21,12 +21,15 @@ import java.io.BufferedInputStream;
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.InputStream;
+import java.io.PrintWriter;
 import java.io.Serializable;
+import java.io.StringWriter;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.Objects;
+import java.util.Optional;
 
 import javax.jms.DeliveryMode;
 import javax.jms.JMSException;
@@ -139,6 +142,7 @@ public class PublisherSampler extends Ba
      *
      */
     private void initClient() throws JMSException, NamingException {
+        configureIsReconnectErrorCode();
         publisher = new Publisher(getUseJNDIPropertiesAsBoolean(), getJNDIInitialContextFactory(), 
                 getProviderUrl(), getConnectionFactory(), getDestination(), isUseAuth(), getUsername(),
                 getPassword(), isDestinationStatic());
@@ -161,11 +165,8 @@ public class PublisherSampler extends Ba
         if (publisher == null) {
             try {
                 initClient();
-            } catch (JMSException e) {
-                result.setResponseMessage(e.toString());
-                return result;
-            } catch (NamingException e) {
-                result.setResponseMessage(e.toString());
+            } catch (JMSException | NamingException e) {
+                handleError(result, e, false);
                 return result;
             }
         }
@@ -209,14 +210,46 @@ public class PublisherSampler extends Ba
             result.setSamplerData(buffer.toString());
             result.setSampleCount(loop);
             result.setRequestHeaders(propBuffer.toString());
+        } catch (JMSException e) {
+            handleError(result, e, true);
         } catch (Exception e) {
-            result.setResponseMessage(e.toString());
+            handleError(result, e, false);
         } finally {
             result.sampleEnd();            
         }
         return result;
     }
 
+    /**
+     * Fills in result and decide wether to reconnect or not depending on checkForReconnect 
+     * and underlying {@link JMSException#getErrorCode()}
+     * @param result {@link SampleResult}
+     * @param e {@link Exception}
+     * @param checkForReconnect if true and exception is a {@link JMSException}
+     */
+    private void handleError(SampleResult result, Exception e, boolean checkForReconnect) {
+        result.setSuccessful(false);
+        result.setResponseMessage(e.toString());
+
+        if (e instanceof JMSException) {
+            JMSException jms = (JMSException)e;
+
+            String errorCode = Optional.ofNullable(jms.getErrorCode()).orElse("");
+            if (checkForReconnect && publisher != null 
+                    && getIsReconnectErrorCode().test(errorCode)) {
+                ClientPool.removeClient(publisher);
+                IOUtils.closeQuietly(publisher);
+                publisher = null;
+            }
+
+            result.setResponseCode(errorCode);
+        }
+
+        StringWriter writer = new StringWriter();
+        e.printStackTrace(new PrintWriter(writer)); // NOSONAR We're getting it to put it in ResponseData 
+        result.setResponseData(writer.toString(), "UTF-8");
+    }
+
     private Map<String, Object> getMapContent() throws ClassNotFoundException, SecurityException, NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException {
         Map<String,Object> m = new HashMap<>();
         String text = getMessageContent();

Modified: jmeter/trunk/src/protocol/jms/org/apache/jmeter/protocol/jms/sampler/SubscriberSampler.java
URL: http://svn.apache.org/viewvc/jmeter/trunk/src/protocol/jms/org/apache/jmeter/protocol/jms/sampler/SubscriberSampler.java?rev=1778825&r1=1778824&r2=1778825&view=diff
==============================================================================
--- jmeter/trunk/src/protocol/jms/org/apache/jmeter/protocol/jms/sampler/SubscriberSampler.java (original)
+++ jmeter/trunk/src/protocol/jms/org/apache/jmeter/protocol/jms/sampler/SubscriberSampler.java Sat Jan 14 20:47:19 2017
@@ -18,6 +18,7 @@
 package org.apache.jmeter.protocol.jms.sampler;
 
 import java.util.Enumeration;
+import java.util.Optional;
 
 import javax.jms.BytesMessage;
 import javax.jms.JMSException;
@@ -27,6 +28,7 @@ import javax.jms.ObjectMessage;
 import javax.jms.TextMessage;
 import javax.naming.NamingException;
 
+import org.apache.commons.io.IOUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.jmeter.protocol.jms.Utils;
 import org.apache.jmeter.protocol.jms.client.InitialContextFactory;
@@ -92,6 +94,8 @@ public class SubscriberSampler extends B
     private static final String STOP_BETWEEN = "jms.stop_between_samples"; // $NON-NLS-1$
     private static final String SEPARATOR = "jms.separator"; // $NON-NLS-1$
     private static final String SEPARATOR_DEFAULT = ""; // $NON-NLS-1$
+    private static final String ERROR_PAUSE_BETWEEN = "jms_error_pause_between"; // $NON-NLS-1$
+    private static final String ERROR_PAUSE_BETWEEN_DEFAULT = ""; // $NON-NLS-1$
 
     
     private transient boolean START_ON_SAMPLE = false;
@@ -113,7 +117,6 @@ public class SubscriberSampler extends B
         SUBSCRIBER = new ReceiveSubscriber(0, getUseJNDIPropertiesAsBoolean(), getJNDIInitialContextFactory(),
                     getProviderUrl(), getConnectionFactory(), getDestination(), getDurableSubscriptionId(),
                     getClientId(), getJmsSelector(), isUseAuth(), getUsername(), getPassword());
-        setupSeparator();
         log.debug("SubscriberSampler.initListenerClient called");
     }
 
@@ -126,7 +129,6 @@ public class SubscriberSampler extends B
         SUBSCRIBER = new ReceiveSubscriber(getUseJNDIPropertiesAsBoolean(),
                 getJNDIInitialContextFactory(), getProviderUrl(), getConnectionFactory(), getDestination(),
                 getDurableSubscriptionId(), getClientId(), getJmsSelector(), isUseAuth(), getUsername(), getPassword());
-        setupSeparator();
         log.debug("SubscriberSampler.initReceiveClient called");
     }
 
@@ -152,6 +154,7 @@ public class SubscriberSampler extends B
             result.setSuccessful(false);
             result.setResponseCode("000");
             result.setResponseMessage(exceptionDuringInit.toString());
+            handleErrorAndAddTemporize(true);
             return result; 
         }
         if (stopBetweenSamples){ // If so, we need to start collection here
@@ -183,7 +186,10 @@ public class SubscriberSampler extends B
                     extractContent(buffer, propBuffer, msg, read == loop);
                 }
             } catch (JMSException e) {
-                log.warn("Error "+e.toString());
+                String errorCode = Optional.ofNullable(e.getErrorCode()).orElse("");
+                log.warn(String.format("Error [%s] %s", errorCode, e.toString()), e);
+
+                handleErrorAndAddTemporize(getIsReconnectErrorCode().test(errorCode));
             }
             now = System.currentTimeMillis();
         }
@@ -223,6 +229,37 @@ public class SubscriberSampler extends B
     }
 
     /**
+     * Try to reconnect if configured to or temporize if not or an exception occured
+     * @param reconnect
+     */
+    private void handleErrorAndAddTemporize(boolean reconnect) {
+        if (reconnect) {
+            cleanup();
+            initClient();
+        }
+
+        if (!reconnect || exceptionDuringInit != null) {
+            try {
+                long pause = getPauseBetweenErrorsAsLong();
+                if(pause > 0) {
+                    Thread.sleep(pause);
+                }
+            } catch (InterruptedException ie) {
+                log.warn(String.format("Interrupted %s", ie.toString()), ie);
+                Thread.currentThread().interrupt();
+                interrupted = true;
+            }
+        }
+    }
+
+    /**
+     * 
+     */
+    private void cleanup() {
+        IOUtils.closeQuietly(SUBSCRIBER);
+    }
+
+    /**
      * Calculate the wait time, will never be more than DEFAULT_WAIT.
      * 
      * @param until target end time or 0 if timeouts not active
@@ -286,6 +323,8 @@ public class SubscriberSampler extends B
      */
     @Override
     public void threadStarted() {
+        configureIsReconnectErrorCode();
+
         // Disabled thread start if listen on sample choice
         if (isDestinationStatic() || START_ON_SAMPLE) {
             timeout = getTimeoutAsLong();
@@ -293,31 +332,32 @@ public class SubscriberSampler extends B
             exceptionDuringInit = null;
             useReceive = getClientChoice().equals(JMSSubscriberGui.RECEIVE_RSC);
             stopBetweenSamples = isStopBetweenSamples();
-            if (useReceive) {
-                try {
-                    initReceiveClient();
-                    if (!stopBetweenSamples){ // Don't start yet if stop between samples
-                        SUBSCRIBER.start();
-                    }
-                } catch (NamingException | JMSException e) {
-                    exceptionDuringInit = e;
-                }
+            setupSeparator();
+            initClient();
+        }
+    }
+
+    private void initClient() {
+        exceptionDuringInit = null;
+        try {
+            if(useReceive) {
+                initReceiveClient();
             } else {
-                try {
-                    initListenerClient();
-                    if (!stopBetweenSamples){ // Don't start yet if stop between samples
-                        SUBSCRIBER.start();
-                    }
-                } catch (JMSException | NamingException e) {
-                    exceptionDuringInit = e;
-                }
+                initListenerClient();
             }
-            if (exceptionDuringInit != null){
-                log.error("Could not initialise client",exceptionDuringInit);
+            if (!stopBetweenSamples) { // Don't start yet if stop between
+                                       // samples
+                SUBSCRIBER.start();
             }
+        } catch (NamingException | JMSException e) {
+            exceptionDuringInit = e;
+        }
+        
+        if (exceptionDuringInit != null) {
+            log.error("Could not initialise client", exceptionDuringInit);
         }
     }
-    
+
     public void threadStarted(boolean wts) {
         if (wts) {
             START_ON_SAMPLE = true; // listen on sample 
@@ -333,7 +373,7 @@ public class SubscriberSampler extends B
     @Override
     public void threadFinished() {
         if (SUBSCRIBER != null){ // Can be null if init fails
-            SUBSCRIBER.close();
+            cleanup();
         }
     }
     
@@ -462,6 +502,18 @@ public class SubscriberSampler extends B
         setProperty(STOP_BETWEEN, selected, false);                
     }
 
+    public void setPauseBetweenErrors(String pause) {
+        setProperty(ERROR_PAUSE_BETWEEN, pause, ERROR_PAUSE_BETWEEN_DEFAULT);
+    }
+
+    public String getPauseBetweenErrors() {
+        return getPropertyAsString(ERROR_PAUSE_BETWEEN, ERROR_PAUSE_BETWEEN_DEFAULT);
+    }
+
+    public long getPauseBetweenErrorsAsLong() {
+        return getPropertyAsLong(ERROR_PAUSE_BETWEEN, DEFAULT_WAIT);
+    }
+
     /**
      * {@inheritDoc}
      */

Modified: jmeter/trunk/xdocs/changes.xml
URL: http://svn.apache.org/viewvc/jmeter/trunk/xdocs/changes.xml?rev=1778825&r1=1778824&r2=1778825&view=diff
==============================================================================
--- jmeter/trunk/xdocs/changes.xml [utf-8] (original)
+++ jmeter/trunk/xdocs/changes.xml [utf-8] Sat Jan 14 20:47:19 2017
@@ -114,6 +114,7 @@ Fill in some detail.
 
 <h3>Other samplers</h3>
 <ul>
+    <li><bug>60585</bug>JMS Publisher and JMS Subscriber : Allow reconnection on error and pause between errors. Based on <pr>240</pr> from by Logan Mauzaize (logan.mauzaize at gmail.com) and Maxime Chassagneux (maxime.chassagneux at gmail.com).</li>
 </ul>
 
 <h3>Controllers</h3>
@@ -124,7 +125,7 @@ Fill in some detail.
 <ul>
     <li><bug>60144</bug>View Results Tree : Add a more up to date Browser Renderer to replace old Render</li>
     <li><bug>60542</bug>View Results Tree : Allow Upper Panel to be collapsed. Contributed by Ubik Load Pack (support at ubikloadpack.com)</li>
-    <li><bug>52962</bug>Allow sorting by columns for View Results in Table, Summary Report, Aggregate Report and Aggregate Graph. Based on a contribution by Logan Mauzaize (logan.mauzaize at gmail.com) and Maxime Chassagneux (maxime.chassagneux@gmail.com).</li>
+    <li><bug>52962</bug>Allow sorting by columns for View Results in Table, Summary Report, Aggregate Report and Aggregate Graph. Based on a <pr>245</pr> by Logan Mauzaize (logan.mauzaize at gmail.com) and Maxime Chassagneux (maxime.chassagneux at gmail.com).</li>
 </ul>
 
 <h3>Timers, Assertions, Config, Pre- &amp; Post-Processors</h3>
@@ -148,7 +149,7 @@ Fill in some detail.
 <h3>General</h3>
 <ul>
     <li><bug>54525</bug>Search Feature : Enhance it with ability to replace</li>
-    <li><bug>60530</bug>Add API to create JMeter threads while test is running. Based on a contribution by Logan Mauzaize (logan.mauzaize at gmail.com) and Maxime Chassagneux (maxime.chassagneux@gmail.com).</li>
+    <li><bug>60530</bug>Add API to create JMeter threads while test is running. Based on a contribution by Logan Mauzaize (logan.mauzaize at gmail.com) and Maxime Chassagneux (maxime.chassagneux at gmail.com).</li>
 </ul>
 
 <ch_section>Non-functional changes</ch_section>
@@ -218,7 +219,7 @@ Fill in some detail.
 <li>Thomas Schapitz (ts-nospam12 at online.de)</li>
 <li>Murdecai777 (https://github.com/Murdecai777)</li>
 <li>Logan Mauzaize (logan.mauzaize at gmail.com)</li>
-<li>Maxime Chassagneux (maxime.chassagneux@gmail.com)</li>
+<li>Maxime Chassagneux (maxime.chassagneux at gmail.com)</li>
 <li>\u5ffb\u9686 (298015902 at qq.com)</li>
 <li><a href="http://ubikloadpack.com">Ubik Load Pack</a></li>
 </ul>

Modified: jmeter/trunk/xdocs/usermanual/component_reference.xml
URL: http://svn.apache.org/viewvc/jmeter/trunk/xdocs/usermanual/component_reference.xml?rev=1778825&r1=1778824&r2=1778825&view=diff
==============================================================================
--- jmeter/trunk/xdocs/usermanual/component_reference.xml (original)
+++ jmeter/trunk/xdocs/usermanual/component_reference.xml Sat Jan 14 20:47:19 2017
@@ -1461,6 +1461,7 @@ Currently the only way to changes these
       The priority level of the message. There are ten priority levels from <code>0</code> (lowest) to <code>9</code> (highest). 
       If you do not specify a priority level, the default level is <code>4</code>. 
   </property>
+  <property name="Reconnect on error codes (regex)" required="No">Regular expression for JMSException error codes which force reconnection. If empty no reconnection will be done</property>
   <property name="Number of samples to aggregate" required="Yes">Number of samples to aggregate</property>
   <property name="Message source" required="Yes">Where to obtain the message:
   <dl>
@@ -1584,6 +1585,8 @@ The following table shows some values wh
   Separator used to separate messages when there is more than one (related to setting Number of samples to aggregate).
   Note that <code>\n</code>, <code>\r</code>, <code>\t</code> are accepted.
   </property>
+  <property name="Reconnect on error codes (regex)" required="No">Regular expression for JMSException error codes which force reconnection. If empty no reconnection will be done</property>
+  <property name="Pause between errors (ms)" required="No">Pause in milliseconds that Subscriber will make when an error occurs</property>
 </properties>
 </component>