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 2014/11/22 16:36:38 UTC

svn commit: r1641081 - in /jmeter/trunk: ./ bin/ res/maven/ src/components/org/apache/jmeter/visualizers/backend/ src/core/org/apache/jmeter/resources/ src/core/org/apache/jmeter/samplers/ src/core/org/apache/jmeter/save/ xdocs/ xdocs/usermanual/

Author: pmouawad
Date: Sat Nov 22 15:36:37 2014
New Revision: 1641081

URL: http://svn.apache.org/r1641081
Log:
Bug 55932 - Create a Async BackendListener to allow easy plug of new listener (Graphite, JDBC, Console,...) 
Bugzilla Id: 55932

Added:
    jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/
    jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/AbstractBackendListenerClient.java   (with props)
    jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/BackendListener.java   (with props)
    jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/BackendListenerClient.java   (with props)
    jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/BackendListenerContext.java   (with props)
    jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/BackendListenerGui.java   (with props)
    jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/SamplerMetric.java   (with props)
Modified:
    jmeter/trunk/bin/saveservice.properties
    jmeter/trunk/build.properties
    jmeter/trunk/build.xml
    jmeter/trunk/eclipse.classpath
    jmeter/trunk/res/maven/ApacheJMeter_parent.pom
    jmeter/trunk/src/core/org/apache/jmeter/resources/messages.properties
    jmeter/trunk/src/core/org/apache/jmeter/resources/messages_fr.properties
    jmeter/trunk/src/core/org/apache/jmeter/samplers/SampleResult.java
    jmeter/trunk/src/core/org/apache/jmeter/save/SaveService.java
    jmeter/trunk/xdocs/changes.xml
    jmeter/trunk/xdocs/usermanual/component_reference.xml

Modified: jmeter/trunk/bin/saveservice.properties
URL: http://svn.apache.org/viewvc/jmeter/trunk/bin/saveservice.properties?rev=1641081&r1=1641080&r2=1641081&view=diff
==============================================================================
--- jmeter/trunk/bin/saveservice.properties (original)
+++ jmeter/trunk/bin/saveservice.properties Sat Nov 22 15:36:37 2014
@@ -53,7 +53,8 @@ _file_version=$Revision$
 # 2.5 = 2.10
 # 2.6 = 2.11
 # 2.7 = 2.12
-_version=2.7
+# 2.8 = 2.13
+_version=2.8
 #
 #
 # Character set encoding used to read and write JMeter XML files and CSV results
@@ -78,6 +79,8 @@ AssertionVisualizer=org.apache.jmeter.vi
 AuthManager=org.apache.jmeter.protocol.http.control.AuthManager
 Authorization=org.apache.jmeter.protocol.http.control.Authorization
 AuthPanel=org.apache.jmeter.protocol.http.gui.AuthPanel
+BackendListener=org.apache.jmeter.visualizers.backend.BackendListener
+BackendListenerGui=org.apache.jmeter.visualizers.backend.BackendListenerGui
 BarChart=org.apache.jmeter.testelement.BarChart
 BarChartGui=org.apache.jmeter.report.gui.BarChartGui
 BeanShellAssertion=org.apache.jmeter.assertions.BeanShellAssertion

Modified: jmeter/trunk/build.properties
URL: http://svn.apache.org/viewvc/jmeter/trunk/build.properties?rev=1641081&r1=1641080&r2=1641081&view=diff
==============================================================================
--- jmeter/trunk/build.properties (original)
+++ jmeter/trunk/build.properties Sat Nov 22 15:36:37 2014
@@ -118,11 +118,21 @@ commons-logging.loc         = ${maven2.r
 #commons-logging.md5         = E2C390FE739B2550A218262B28F290CE
 commons-logging.md5         = 040b4b4d8eac886f6b4a2a3bd2f31b00
 
+commons-math3.version         = 3.3
+commons-math3.jar             = commons-math3-${commons-math3.version}.jar
+commons-math3.loc             = ${maven2.repo}/org/apache/commons/commons-math3/${commons-math3.version}
+commons-math3.md5             = 87346cf2772dc2becf106c45e0f63863
+
 commons-net.version         = 3.3
 commons-net.jar             = commons-net-${commons-net.version}.jar
 commons-net.loc             = ${maven2.repo}/commons-net/commons-net/${commons-net.version}
 commons-net.md5             = c077ca61598e9c21f43f8b6488fbbee9
 
+commons-pool2.version         = 2.2
+commons-pool2.jar             = commons-pool2-${commons-pool2.version}.jar
+commons-pool2.loc             = ${maven2.repo}/org/apache/commons/commons-pool2/${commons-pool2.version}
+commons-pool2.md5             = 51b56c92883812c56fbeb339866ce2df
+
 # dnsjava for DNSCacheManager
 dnsjava.version             = 2.1.6
 dnsjava.jar                 = dnsjava-${dnsjava.version}.jar

Modified: jmeter/trunk/build.xml
URL: http://svn.apache.org/viewvc/jmeter/trunk/build.xml?rev=1641081&r1=1641080&r2=1641081&view=diff
==============================================================================
--- jmeter/trunk/build.xml (original)
+++ jmeter/trunk/build.xml Sat Nov 22 15:36:37 2014
@@ -365,7 +365,9 @@
     <include name="${lib.dir}/${commons-jexl2.jar}"/>
     <include name="${lib.dir}/${commons-lang3.jar}"/>
     <include name="${lib.dir}/${commons-logging.jar}"/>
+    <include name="${lib.dir}/${commons-math3}"/>
     <include name="${lib.dir}/${commons-net.jar}"/>
+    <include name="${lib.dir}/${commons-pool2.jar}"/>
     <include name="${lib.dir}/${dnsjava.jar}"/>
     <include name="${lib.dir}/${excalibur-datasource.jar}"/>
     <include name="${lib.dir}/${excalibur-instrument.jar}"/>
@@ -438,8 +440,10 @@
     <pathelement location="${lib.dir}/${commons-jexl2.jar}"/>
     <pathelement location="${lib.dir}/${commons-lang3.jar}"/>
     <pathelement location="${lib.dir}/${commons-logging.jar}"/>
+    <pathelement location="${lib.dir}/${commons-math3.jar}"/>
     <pathelement location="${lib.dir}/${commons-net.jar}"/>
-    <pathelement location="${lib.dir}/${dnsjava.jar}"/>
+  	<pathelement location="${lib.dir}/${commons-pool2.jar}"/>
+  	<pathelement location="${lib.dir}/${dnsjava.jar}"/>
     <pathelement location="${lib.dir}/${excalibur-datasource.jar}"/>
     <pathelement location="${lib.dir}/${excalibur-instrument.jar}"/>
     <pathelement location="${lib.dir}/${excalibur-logger.jar}"/>
@@ -2909,7 +2913,9 @@ run JMeter unless all the JMeter jars ar
         <process_jarfile jarname="commons-jexl2"/>
         <process_jarfile jarname="commons-lang3"/>
         <process_jarfile jarname="commons-logging"/>
+        <process_jarfile jarname="commons-math3"/>
         <process_jarfile jarname="commons-net"/>
+    	<process_jarfile jarname="commons-pool2"/>
         <process_jarfile jarname="dnsjava"/>
         <process_jarfile jarname="excalibur-datasource"/>
         <process_jarfile jarname="excalibur-instrument"/>

Modified: jmeter/trunk/eclipse.classpath
URL: http://svn.apache.org/viewvc/jmeter/trunk/eclipse.classpath?rev=1641081&r1=1641080&r2=1641081&view=diff
==============================================================================
--- jmeter/trunk/eclipse.classpath (original)
+++ jmeter/trunk/eclipse.classpath Sat Nov 22 15:36:37 2014
@@ -55,7 +55,9 @@
 	<classpathentry kind="lib" path="lib/commons-jexl-2.1.1.jar"/>
 	<classpathentry kind="lib" path="lib/commons-lang3-3.3.2.jar"/>
 	<classpathentry kind="lib" path="lib/commons-logging-1.2.jar"/>
+    <classpathentry kind="lib" path="lib/commons-math3-3.3.jar"/>
 	<classpathentry kind="lib" path="lib/commons-net-3.3.jar"/>
+    <classpathentry kind="lib" path="lib/commons-pool2-2.2.jar"/>
 	<classpathentry kind="lib" path="lib/dnsjava-2.1.6.jar"/>
 	<classpathentry kind="lib" path="lib/excalibur-datasource-2.1.jar"/>
 	<classpathentry kind="lib" path="lib/excalibur-instrument-1.0.jar"/>

Modified: jmeter/trunk/res/maven/ApacheJMeter_parent.pom
URL: http://svn.apache.org/viewvc/jmeter/trunk/res/maven/ApacheJMeter_parent.pom?rev=1641081&r1=1641080&r2=1641081&view=diff
==============================================================================
--- jmeter/trunk/res/maven/ApacheJMeter_parent.pom (original)
+++ jmeter/trunk/res/maven/ApacheJMeter_parent.pom Sat Nov 22 15:36:37 2014
@@ -66,7 +66,9 @@ under the License.
       <commons-jexl2.version>2.1.1</commons-jexl2.version>
       <commons-lang3.version>3.3.2</commons-lang3.version>
       <commons-logging.version>1.2</commons-logging.version>
+      <commons-math3.version>3.3</commons-math3.version>
       <commons-net.version>3.3</commons-net.version>
+      <commons-pool2.version>2.2</commons-pool2.version>
       <dnsjava.version>2.1.6</dnsjava.version>
       <excalibur-datasource.version>2.1</excalibur-datasource.version>
       <excalibur-instrument.version>1.0</excalibur-instrument.version>
@@ -181,11 +183,21 @@ under the License.
         <version>${commons-logging.version}</version>
       </dependency>
       <dependency>
+        <groupId>commons-math3</groupId>
+        <artifactId>commons-math3</artifactId>
+        <version>${commons-math3.version}</version>
+      </dependency>
+      <dependency>
         <groupId>commons-net</groupId>
         <artifactId>commons-net</artifactId>
         <version>${commons-net.version}</version>
       </dependency>
       <dependency>
+        <groupId>commons-pool2</groupId>
+        <artifactId>commons-pool2</artifactId>
+        <version>${commons-pool2.version}</version>
+      </dependency>
+      <dependency>
 	    <groupId>dnsjava</groupId>
 	    <artifactId>dnsjava</artifactId>
 	    <version>${dnsjava.version}</version>

Added: jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/AbstractBackendListenerClient.java
URL: http://svn.apache.org/viewvc/jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/AbstractBackendListenerClient.java?rev=1641081&view=auto
==============================================================================
--- jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/AbstractBackendListenerClient.java (added)
+++ jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/AbstractBackendListenerClient.java Sat Nov 22 15:36:37 2014
@@ -0,0 +1,121 @@
+/*
+ * 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.jmeter.visualizers.backend;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.apache.jmeter.config.Arguments;
+import org.apache.jmeter.samplers.SampleResult;
+import org.apache.jorphan.logging.LoggingManager;
+import org.apache.log.Logger;
+
+/**
+ * An abstract implementation of the BackendListenerClient interface. This
+ * implementation provides default implementations of most of the methods in the
+ * interface, as well as some convenience methods, in order to simplify
+ * development of BackendListenerClient implementations.
+ * 
+ * While it may be necessary to make changes to the BackendListenerClient interface
+ * from time to time (therefore requiring changes to any implementations of this
+ * interface), we intend to make this abstract class provide reasonable
+ * implementations of any new methods so that subclasses do not necessarily need
+ * to be updated for new versions. Therefore, when creating a new
+ * BackendListenerClient implementation, developers are encouraged to subclass this
+ * abstract class rather than implementing the BackendListenerClient interface
+ * directly. Implementing BackendListenerClient directly will continue to be
+ * supported for cases where extending this class is not possible (for example,
+ * when the client class is already a subclass of some other class).
+ * <p>
+ * The handleSampleResult() method of BackendListenerClient does not have a default
+ * implementation here, so subclasses must define at least this method. It may
+ * be useful to override other methods as well.
+ *
+ * @see BackendListener#sampleOccurred(org.apache.jmeter.samplers.SampleEvent)
+ * @since 2.13
+ */
+public abstract class AbstractBackendListenerClient implements BackendListenerClient {
+
+    private static final Logger log = LoggingManager.getLoggerForClass();
+    
+    private ConcurrentHashMap<String, SamplerMetric> metricsPerSampler = new ConcurrentHashMap<String, SamplerMetric>();
+
+    /* Implements BackendListenerClient.setupTest(JavaSamplerContext) */
+    @Override
+    public void setupTest(BackendListenerContext context) throws Exception {
+        log.debug(getClass().getName() + ": setupTest");
+    }
+
+    /* Implements BackendListenerClient.teardownTest(JavaSamplerContext) */
+    @Override
+    public void teardownTest(BackendListenerContext context) throws Exception {
+        log.debug(getClass().getName() + ": teardownTest");
+        metricsPerSampler.clear();
+    }
+
+    /* Implements BackendListenerClient.getDefaultParameters() */
+    @Override
+    public Arguments getDefaultParameters() {
+        return null;
+    }
+
+    /**
+     * Get a Logger instance which can be used by subclasses to log information.
+     *
+     * @return a Logger instance which can be used for logging
+     */
+    protected Logger getLogger() {
+        return log;
+    }
+
+    /* (non-Javadoc)
+     * @see org.apache.jmeter.visualizers.backend.BackendListenerClient#createSampleResult(org.apache.jmeter.samplers.SampleResult)
+     */
+    @Override
+    public SampleResult createSampleResult(BackendListenerContext context, SampleResult result) {
+        SampleResult sampleResult = (SampleResult) result.clone();
+        return sampleResult;
+    }
+
+    /**
+     * 
+     * @param sampleLabel
+     * @return SamplerMetric
+     */
+    protected SamplerMetric getSamplerMetric(String sampleLabel) {
+        SamplerMetric samplerMetric = metricsPerSampler.get(sampleLabel);
+        if(samplerMetric == null) {
+            samplerMetric = new SamplerMetric();
+            SamplerMetric oldValue = metricsPerSampler.putIfAbsent(sampleLabel, samplerMetric);
+            if(oldValue != null ){
+                samplerMetric = oldValue;
+            }
+        }
+        return samplerMetric;
+    }
+    
+    /**
+     * 
+     * @return Map<String, SamplerMetric>
+     */
+    protected Map<String, SamplerMetric> getMetricsPerSampler() {
+        return metricsPerSampler;
+    }
+
+}

Propchange: jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/AbstractBackendListenerClient.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/BackendListener.java
URL: http://svn.apache.org/viewvc/jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/BackendListener.java?rev=1641081&view=auto
==============================================================================
--- jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/BackendListener.java (added)
+++ jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/BackendListener.java Sat Nov 22 15:36:37 2014
@@ -0,0 +1,448 @@
+/*
+ * 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.jmeter.visualizers.backend;
+
+import java.io.Serializable;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.locks.LockSupport;
+
+import org.apache.jmeter.config.Arguments;
+import org.apache.jmeter.engine.util.NoThreadClone;
+import org.apache.jmeter.protocol.java.sampler.JavaSamplerContext;
+import org.apache.jmeter.samplers.Remoteable;
+import org.apache.jmeter.samplers.SampleEvent;
+import org.apache.jmeter.samplers.SampleListener;
+import org.apache.jmeter.samplers.SampleResult;
+import org.apache.jmeter.testelement.AbstractTestElement;
+import org.apache.jmeter.testelement.TestElement;
+import org.apache.jmeter.testelement.TestStateListener;
+import org.apache.jmeter.testelement.property.TestElementProperty;
+import org.apache.jorphan.logging.LoggingManager;
+import org.apache.log.Logger;
+
+/**
+ * Async Listener that delegates SampleResult handling to implementations of {@link BackendListenerClient}
+ * @since 2.13
+ */
+public class BackendListener extends AbstractTestElement
+    implements Serializable, SampleListener, TestStateListener, NoThreadClone, Remoteable  {
+
+    /**
+     * 
+     */
+    private static final long serialVersionUID = 8184103677832024335L;
+
+    private static final Logger log = LoggingManager.getLoggerForClass();
+
+    /**
+     * Set used to register instances which implement teardownTest.
+     * This is used so that the BackendListenerClient can be notified when the test ends.
+     */
+    private static final Set<BackendListener> TEAR_DOWN_SET = new HashSet<BackendListener>();
+
+    /**
+     * Property key representing the classname of the BackendListenerClient to user.
+     */
+    public static final String CLASSNAME = "classname";
+
+    /**
+     * Queue size
+     */
+    public static final String QUEUE_SIZE = "QUEUE_SIZE";
+    
+    /**
+     * Property key representing the arguments for the BackendListenerClient.
+     */
+    public static final String ARGUMENTS = "arguments";
+
+    /**
+     * The BackendListenerClient class used by this sampler.
+     * Created by testStarted; copied to cloned instances.
+     */
+    private Class<?> javaClass;
+
+    /**
+     * If true, the BackendListenerClient class implements teardownTest.
+     * Created by testStarted; copied to cloned instances.
+     */
+    private boolean isToBeRegistered;
+
+    /**
+     * The BackendListenerClient instance 
+     */
+    private transient BackendListenerClient backendListenerClient = null;
+
+    /**
+     * The JavaSamplerContext instance used by this sampler to hold information
+     * related to the test run, such as the parameters specified for the sampler
+     * client.
+     */
+    private transient BackendListenerContext context = null;
+
+    private static final int DEFAULT_QUEUE_SIZE = 5000;
+    
+    private transient BlockingQueue<SampleResult> queue; // created by server in readResolve method
+    
+    private transient long queueWaits; // how many times we had to wait to queue a sample
+    
+    private transient long queueWaitTime; // how long we had to wait (nanoSeconds)
+
+    // Create unique object as marker for end of queue
+    private transient static final SampleResult FINAL_EVENT = new SampleResult();
+
+    /**
+     * Create a BackendListener.
+     */
+    public BackendListener() {
+        setArguments(new Arguments());    
+    }
+
+    /*
+     * Ensure that the required class variables are cloned,
+     * as this is not currently done by the super-implementation.
+     */
+    @Override
+    public Object clone() {
+        BackendListener clone = (BackendListener) super.clone();
+        clone.javaClass = this.javaClass;
+        clone.isToBeRegistered = this.isToBeRegistered;
+        return clone;
+    }
+
+    private void initClass() {
+        String name = getClassname().trim();
+        try {
+            javaClass = Class.forName(name, false, Thread.currentThread().getContextClassLoader());
+            Method method = javaClass.getMethod("teardownTest", new Class[]{BackendListenerContext.class});
+            isToBeRegistered = !method.getDeclaringClass().equals(AbstractBackendListenerClient.class);
+            log.info("Created class: " + name + ". Uses teardownTest: " + isToBeRegistered);
+        } catch (Exception e) {
+            log.error(whoAmI() + "\tException initialising: " + name, e);
+        }   
+    }
+
+    /**
+     * Retrieves reference to BackendListenerClient.
+     *
+     * Convience method used to check for null reference without actually
+     * creating a BackendListenerClient
+     *
+     * @return reference to BackendListenerClient NOTUSED private BackendListenerClient
+     *         retrieveJavaClient() { return javaClient; }
+     */
+
+    /**
+     * Generate a String identifier of this instance for debugging purposes.
+     *
+     * @return a String identifier for this sampler instance
+     */
+    private String whoAmI() {
+        StringBuilder sb = new StringBuilder();
+        sb.append(Thread.currentThread().getName());
+        sb.append("@");
+        sb.append(Integer.toHexString(hashCode()));
+        sb.append("-");
+        sb.append(getName());
+        return sb.toString();
+    }
+
+    // TestStateListener implementation
+    /* Implements TestStateListener.testStarted() */
+    @Override
+    public void testStarted() {
+        testStarted("");
+    }
+
+    /* Implements TestStateListener.testStarted(String) */
+    @Override
+    public void testStarted(String host) {
+        log.debug(whoAmI() + "\ttestStarted(" + host + ")");
+        queue = new ArrayBlockingQueue<SampleResult>(getQueueSize()); 
+        initClass();
+        queueWaits=0L;
+        queueWaitTime=0L;
+        log.info(getName()+":Starting worker with class:"+javaClass +" and queue capacity:"+getQueueSize());
+
+        backendListenerClient = createBackendListenerClientImpl(javaClass);
+        context = new BackendListenerContext((Arguments)getArguments().clone());
+        if(isToBeRegistered) {
+            TEAR_DOWN_SET.add(this);
+        }
+        try {
+            backendListenerClient.setupTest(context);
+        } catch (Exception e) {
+            throw new java.lang.IllegalStateException("Failed calling setupTest", e);
+        }
+
+        Worker worker = new Worker(javaClass, backendListenerClient, (Arguments) getArguments().clone(), queue);
+        worker.setDaemon(true);
+        worker.start();
+        log.info(getName()+":Started  worker with class:"+javaClass);
+        
+    }
+
+    /* (non-Javadoc)
+     * @see org.apache.jmeter.samplers.SampleListener#sampleOccurred(org.apache.jmeter.samplers.SampleEvent)
+     */
+    @Override
+    public void sampleOccurred(SampleEvent e) {
+        Arguments args = getArguments();
+        context = new BackendListenerContext(args);
+
+        SampleResult sr = backendListenerClient.createSampleResult(context, e.getResult());
+        try {
+            if (!queue.offer(sr)){ // we failed to add the element first time
+                queueWaits++;
+                long t1 = System.nanoTime();
+                queue.put(sr);
+                long t2 = System.nanoTime();
+                queueWaitTime += t2-t1;
+            }
+        } catch (Exception err) {
+            log.error("sampleOccurred, failed to queue the sample", err);
+        }
+    }
+    
+    private static final class Worker extends Thread {
+        
+        private final BlockingQueue<SampleResult> queue;
+        private final BackendListenerContext context;
+        private final BackendListenerClient backendListenerClient;
+        private Worker(Class<?> javaClass, BackendListenerClient backendListenerClient, Arguments arguments, BlockingQueue<SampleResult> q){
+            queue = q;
+            // Allow BackendListenerClient implementations to get access to test element name
+            arguments.addArgument(TestElement.NAME, getName()); 
+            context = new BackendListenerContext(arguments);
+            this.backendListenerClient = backendListenerClient;
+        }
+
+        
+        @Override
+        public void run() {
+            boolean isDebugEnabled = log.isDebugEnabled();
+            List<SampleResult> l = new ArrayList<SampleResult>(queue.size());
+            try {
+                boolean eof = false;
+                while (!eof) {
+                    if(isDebugEnabled) {
+                        log.debug("Thread:"+Thread.currentThread().getName()+" taking SampleResult from queue:"+queue.size());
+                    }
+                    SampleResult e = queue.take();
+                    if(isDebugEnabled) {
+                        log.debug("Thread:"+Thread.currentThread().getName()+" took SampleResult:"+e+", isFinal:" + (e==FINAL_EVENT));
+                    }
+                    while (!(eof = (e == FINAL_EVENT)) && e != null ) { // try to process as many as possible
+                        l.add(e);
+                        if(isDebugEnabled) {
+                            log.debug("Thread:"+Thread.currentThread().getName()+" polling from queue:"+queue.size());
+                        }
+                        e = queue.poll(); // returns null if nothing on queue currently
+                        if(isDebugEnabled) {
+                            log.debug("Thread:"+Thread.currentThread().getName()+" took from queue:"+e+", isFinal:" + (e==FINAL_EVENT));
+                        }
+                    }
+                    if(isDebugEnabled) {
+                        log.debug("Thread:"+Thread.currentThread().getName()+
+                                " exiting with FINAL EVENT:"+(e == FINAL_EVENT)
+                                +", null:" + (e==null));
+                    }
+                    int size = l.size();
+                    if (size > 0) {
+                        backendListenerClient.handleSampleResults(l, context);
+                        l.clear();
+                    }
+                    if(!eof) {
+                        LockSupport.parkNanos(100);
+                    }
+                }
+            } catch (InterruptedException e) {
+                // NOOP
+            }
+            // We may have been interrupted
+            int size = l.size();
+            if (size > 0) {
+                backendListenerClient.handleSampleResults(l, context);
+                l.clear();
+            }
+            log.info("Worker ended");
+        }
+    }
+    
+
+    /**
+     * Returns reference to <code>BackendListenerClient</code>.
+     *
+     *
+     * @return BackendListenerClient reference.
+     */
+    static BackendListenerClient createBackendListenerClientImpl(Class<?> javaClass) {
+        if (javaClass == null) { // failed to initialise the class
+            return new ErrorBackendListenerClient();
+        }
+        BackendListenerClient client;
+        try {
+            client = (BackendListenerClient) javaClass.newInstance();
+        } catch (Exception e) {
+            log.error("Exception creating: " + javaClass, e);
+            client = new ErrorBackendListenerClient();
+        }
+        return client;
+    }
+
+    /**
+     * Method called at the end of the test. This is called only on one instance
+     * of BackendListener. This method will loop through all of the other
+     * BackendListenerClients which have been registered (automatically in the
+     * constructor) and notify them that the test has ended, allowing the
+     * BackendListenerClients to cleanup.
+     */
+    @Override
+    public void testEnded() {
+        try {
+            queue.put(FINAL_EVENT);
+        } catch (Exception ex) {
+            log.warn("testEnded() with exception:"+ex.getMessage(), ex);
+        }
+        if (queueWaits > 0) {
+            log.warn("QueueWaits: "+queueWaits+"; QueueWaitTime: "+queueWaitTime+" (nanoseconds), you may need to increase queue capacity, see property 'backend_queue_capacity'");            
+        }
+        synchronized (TEAR_DOWN_SET) {
+            for (BackendListener backendListener : TEAR_DOWN_SET) {
+                BackendListenerClient client = backendListener.backendListenerClient;
+                if (client != null) {
+                    try {
+                        client.teardownTest(backendListener.context);
+                    } catch (Exception e) {
+                        throw new java.lang.IllegalStateException("Failed calling teardownTest", e);
+                    }
+                }
+            }
+            TEAR_DOWN_SET.clear();
+        }
+    }
+
+    /* Implements TestStateListener.testEnded(String) */
+    @Override
+    public void testEnded(String host) {
+        testEnded();
+    }
+
+    /**
+     * A {@link BackendListenerClient} implementation used for error handling. If an
+     * error occurs while creating the real BackendListenerClient object, it is
+     * replaced with an instance of this class. Each time a sample occurs with
+     * this class, the result is marked as a failure so the user can see that
+     * the test failed.
+     */
+    static class ErrorBackendListenerClient extends AbstractBackendListenerClient {
+        /**
+         * Return SampleResult with data on error.
+         *
+         * @see BackendListenerClient#runTest(JavaSamplerContext)
+         */
+        @Override
+        public void handleSampleResults(List<SampleResult> sampleResults, BackendListenerContext context) {
+            log.warn("ErrorBackendListenerClient#handleSampleResult called, noop");
+            Thread.yield();
+        }
+    }
+    
+    /* (non-Javadoc)
+     * @see org.apache.jmeter.samplers.SampleListener#sampleStarted(org.apache.jmeter.samplers.SampleEvent)
+     */
+    @Override
+    public void sampleStarted(SampleEvent e) {
+        // NOOP
+        
+    }
+
+    /* (non-Javadoc)
+     * @see org.apache.jmeter.samplers.SampleListener#sampleStopped(org.apache.jmeter.samplers.SampleEvent)
+     */
+    @Override
+    public void sampleStopped(SampleEvent e) {
+        // NOOP
+        
+    }
+
+    /**
+     * Set the arguments (parameters) for the BackendListenerClient to be executed
+     * with.
+     *
+     * @param args
+     *            the new arguments. These replace any existing arguments.
+     */
+    public void setArguments(Arguments args) {
+        setProperty(new TestElementProperty(ARGUMENTS, args));
+    }
+
+    /**
+     * Get the arguments (parameters) for the BackendListenerClient to be executed
+     * with.
+     *
+     * @return the arguments
+     */
+    public Arguments getArguments() {
+        return (Arguments) getProperty(ARGUMENTS).getObjectValue();
+    }
+
+    /**
+     * Sets the Classname of the BackendListenerClient object
+     *
+     * @param classname
+     *            the new Classname value
+     */
+    public void setClassname(String classname) {
+        setProperty(CLASSNAME, classname);
+    }
+
+    /**
+     * Gets the Classname of the BackendListenerClient object
+     *
+     * @return the Classname value
+     */
+    public String getClassname() {
+        return getPropertyAsString(CLASSNAME);
+    }
+    
+    /**
+     * Sets the queue size
+     *
+     * @param queueSize
+     *            
+     */
+    public void setQueueSize(int queueSize) {
+        setProperty(QUEUE_SIZE, queueSize, DEFAULT_QUEUE_SIZE);
+    }
+
+    /**
+     * Gets the queue size
+     *
+     * @return int queueSize
+     */
+    public int getQueueSize() {
+        return getPropertyAsInt(QUEUE_SIZE, DEFAULT_QUEUE_SIZE);
+    }
+}

Propchange: jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/BackendListener.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/BackendListenerClient.java
URL: http://svn.apache.org/viewvc/jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/BackendListenerClient.java?rev=1641081&view=auto
==============================================================================
--- jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/BackendListenerClient.java (added)
+++ jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/BackendListenerClient.java Sat Nov 22 15:36:37 2014
@@ -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.jmeter.visualizers.backend;
+
+import java.util.List;
+
+import org.apache.jmeter.config.Arguments;
+import org.apache.jmeter.samplers.SampleResult;
+
+/**
+ * This interface defines the interactions between the BackendListener and external
+ * Java programs which can be executed by JMeter. Any Java class which wants to
+ * be executed as a JMeter test must implement this interface (either directly
+ * or indirectly through AbstractBackendListenerClient).
+ * <p>
+ * JMeter will create one instance of a BackendListenerClient implementation for
+ * each user/thread in the test. Additional instances may be created for
+ * internal use by JMeter (for example, to find out what parameters are
+ * supported by the client).
+ * <p>
+ * When the test is started, setupTest() will be called on each thread's
+ * BackendListenerClient instance to initialize the client. Then handleSampleResult() will be
+ * called for each SampleResult notification. Finally, teardownTest() will be called
+ * to allow the client to do any necessary clean-up.
+ * <p>
+ * The JMeter BackendListener GUI allows a list of parameters to be defined for the
+ * test. These are passed to the various test methods through the
+ * {@link BackendListenerContext}. A list of default parameters can be defined
+ * through the getDefaultParameters() method. These parameters and any default
+ * values associated with them will be shown in the GUI. Users can add other
+ * parameters as well.
+ * <p>
+ * When possible, Listeners should extend {@link AbstractBackendListenerClient
+ * AbstractBackendListenerClient} rather than implementing BackendListenerClient
+ * directly. This should protect your tests from future changes to the
+ * interface. While it may be necessary to make changes to the BackendListenerClient
+ * interface from time to time (therefore requiring changes to any
+ * implementations of this interface), we intend to make this abstract class
+ * provide reasonable default implementations of any new methods so that
+ * subclasses do not necessarily need to be updated for new versions.
+ * Implementing BackendListenerClient directly will continue to be supported for
+ * cases where extending this class is not possible (for example, when the
+ * client class is already a subclass of some other class).
+ *
+ * @since 2.13
+ */
+public interface BackendListenerClient {
+    /**
+     * Do any initialization required by this client. It is generally
+     * recommended to do any initialization such as getting parameter values in
+     * the setupTest method rather than the runTest method in order to add as
+     * little overhead as possible to the test.
+     *
+     * @param context
+     *            the context to run with. This provides access to
+     *            initialization parameters.
+     */
+    void setupTest(BackendListenerContext context) throws Exception;
+
+    /**
+     * Perform a single sample for each iteration. This method returns a
+     * <code>SampleResult</code> object. <code>SampleResult</code> has many
+     * fields which can be used. At a minimum, the test should use
+     * <code>SampleResult.sampleStart</code> and
+     * <code>SampleResult.sampleEnd</code>to set the time that the test
+     * required to execute. It is also a good idea to set the sampleLabel and
+     * the successful flag.
+     *
+     * @see org.apache.jmeter.samplers.SampleResult#sampleStart()
+     * @see org.apache.jmeter.samplers.SampleResult#sampleEnd()
+     * @see org.apache.jmeter.samplers.SampleResult#setSuccessful(boolean)
+     * @see org.apache.jmeter.samplers.SampleResult#setSampleLabel(String)
+     *
+     * @param context
+     *            the context to run with. This provides access to
+     *            initialization parameters.
+     *
+     */
+    void handleSampleResults(List<SampleResult> sampleResults, BackendListenerContext context);
+
+    /**
+     * Do any clean-up required by this test at the end of a test run.
+     *
+     * @param context
+     *            the context to run with. This provides access to
+     *            initialization parameters.
+     */
+    void teardownTest(BackendListenerContext context) throws Exception;
+
+    /**
+     * Provide a list of parameters which this test supports. Any parameter
+     * names and associated values returned by this method will appear in the
+     * GUI by default so the user doesn't have to remember the exact names. The
+     * user can add other parameters which are not listed here. If this method
+     * returns null then no parameters will be listed. If the value for some
+     * parameter is null then that parameter will be listed in the GUI with an
+     * empty value.
+     *
+     * @return a specification of the parameters used by this test which should
+     *         be listed in the GUI, or null if no parameters should be listed.
+     */
+    Arguments getDefaultParameters();
+
+    /**
+     * 
+     * @param context
+     * @param result
+     * @return
+     */
+    SampleResult createSampleResult(
+            BackendListenerContext context, SampleResult result);
+}

Propchange: jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/BackendListenerClient.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/BackendListenerContext.java
URL: http://svn.apache.org/viewvc/jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/BackendListenerContext.java?rev=1641081&view=auto
==============================================================================
--- jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/BackendListenerContext.java (added)
+++ jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/BackendListenerContext.java Sat Nov 22 15:36:37 2014
@@ -0,0 +1,237 @@
+/*
+
+ * 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.jmeter.visualizers.backend;
+
+import java.util.Iterator;
+import java.util.Map;
+
+import org.apache.jmeter.config.Arguments;
+import org.apache.jorphan.logging.LoggingManager;
+import org.apache.log.Logger;
+
+/**
+ * BackendListenerContext is used to provide context information to a
+ * BackendListenerClient implementation. This currently consists of the
+ * initialization parameters which were specified in the GUI. 
+ * @since 2.13
+ */
+public class BackendListenerContext {
+    /*
+     * Implementation notes:
+     *
+     * All of the methods in this class are currently read-only. If update
+     * methods are included in the future, they should be defined so that a
+     * single instance of BackendListenerContext can be associated with each thread.
+     * Therefore, no synchronization should be needed. The same instance should
+     * be used for the call to setupTest, all calls to runTest, and the call to
+     * teardownTest.
+     */
+
+    /** Logging */
+    private static final Logger log = LoggingManager.getLoggerForClass();
+
+    /**
+     * Map containing the initialization parameters for the BackendListenerClient.
+     */
+    private final Map<String, String> params;
+
+    /**
+     *
+     * @param args
+     *            the initialization parameters.
+     */
+    public BackendListenerContext(Arguments args) {
+        this.params = args.getArgumentsAsMap();
+    }
+
+    /**
+     * Determine whether or not a value has been specified for the parameter
+     * with this name.
+     *
+     * @param name
+     *            the name of the parameter to test
+     * @return true if the parameter value has been specified, false otherwise.
+     */
+    public boolean containsParameter(String name) {
+        return params.containsKey(name);
+    }
+
+    /**
+     * Get an iterator of the parameter names. Each entry in the Iterator is a
+     * String.
+     *
+     * @return an Iterator of Strings listing the names of the parameters which
+     *         have been specified for this test.
+     */
+    public Iterator<String> getParameterNamesIterator() {
+        return params.keySet().iterator();
+    }
+
+    /**
+     * Get the value of a specific parameter as a String, or null if the value
+     * was not specified.
+     *
+     * @param name
+     *            the name of the parameter whose value should be retrieved
+     * @return the value of the parameter, or null if the value was not
+     *         specified
+     */
+    public String getParameter(String name) {
+        return getParameter(name, null);
+    }
+
+    /**
+     * Get the value of a specified parameter as a String, or return the
+     * specified default value if the value was not specified.
+     *
+     * @param name
+     *            the name of the parameter whose value should be retrieved
+     * @param defaultValue
+     *            the default value to return if the value of this parameter was
+     *            not specified
+     * @return the value of the parameter, or the default value if the parameter
+     *         was not specified
+     */
+    public String getParameter(String name, String defaultValue) {
+        if (params == null || !params.containsKey(name)) {
+            return defaultValue;
+        }
+        return params.get(name);
+    }
+
+    /**
+     * Get the value of a specified parameter as an integer. An exception will
+     * be thrown if the parameter is not specified or if it is not an integer.
+     * The value may be specified in decimal, hexadecimal, or octal, as defined
+     * by Integer.decode().
+     *
+     * @param name
+     *            the name of the parameter whose value should be retrieved
+     * @return the value of the parameter
+     *
+     * @throws NumberFormatException
+     *             if the parameter is not specified or is not an integer
+     *
+     * @see java.lang.Integer#decode(java.lang.String)
+     */
+    public int getIntParameter(String name) throws NumberFormatException {
+        if (params == null || !params.containsKey(name)) {
+            throw new NumberFormatException("No value for parameter named '" + name + "'.");
+        }
+
+        return Integer.decode(params.get(name)).intValue();
+    }
+
+    /**
+     * Get the value of a specified parameter as an integer, or return the
+     * specified default value if the value was not specified or is not an
+     * integer. A warning will be logged if the value is not an integer. The
+     * value may be specified in decimal, hexadecimal, or octal, as defined by
+     * Integer.decode().
+     *
+     * @param name
+     *            the name of the parameter whose value should be retrieved
+     * @param defaultValue
+     *            the default value to return if the value of this parameter was
+     *            not specified
+     * @return the value of the parameter, or the default value if the parameter
+     *         was not specified
+     *
+     * @see java.lang.Integer#decode(java.lang.String)
+     */
+    public int getIntParameter(String name, int defaultValue) {
+        if (params == null || !params.containsKey(name)) {
+            return defaultValue;
+        }
+
+        try {
+            return Integer.decode(params.get(name)).intValue();
+        } catch (NumberFormatException e) {
+            log.warn("Value for parameter '" + name + "' not an integer: '" + params.get(name) + "'.  Using default: '"
+                    + defaultValue + "'.", e);
+            return defaultValue;
+        }
+    }
+
+    /**
+     * Get the value of a specified parameter as a long. An exception will be
+     * thrown if the parameter is not specified or if it is not a long. The
+     * value may be specified in decimal, hexadecimal, or octal, as defined by
+     * Long.decode().
+     *
+     * @param name
+     *            the name of the parameter whose value should be retrieved
+     * @return the value of the parameter
+     *
+     * @throws NumberFormatException
+     *             if the parameter is not specified or is not a long
+     *
+     * @see Long#decode(String)
+     */
+    public long getLongParameter(String name) throws NumberFormatException {
+        if (params == null || !params.containsKey(name)) {
+            throw new NumberFormatException("No value for parameter named '" + name + "'.");
+        }
+
+        return Long.decode(params.get(name)).longValue();
+    }
+
+    /**
+     * Get the value of a specified parameter as along, or return the specified
+     * default value if the value was not specified or is not a long. A warning
+     * will be logged if the value is not a long. The value may be specified in
+     * decimal, hexadecimal, or octal, as defined by Long.decode().
+     *
+     * @param name
+     *            the name of the parameter whose value should be retrieved
+     * @param defaultValue
+     *            the default value to return if the value of this parameter was
+     *            not specified
+     * @return the value of the parameter, or the default value if the parameter
+     *         was not specified
+     *
+     * @see Long#decode(String)
+     */
+    public long getLongParameter(String name, long defaultValue) {
+        if (params == null || !params.containsKey(name)) {
+            return defaultValue;
+        }
+        try {
+            return Long.decode(params.get(name)).longValue();
+        } catch (NumberFormatException e) {
+            log.warn("Value for parameter '" + name + "' not a long: '" + params.get(name) + "'.  Using default: '"
+                    + defaultValue + "'.", e);
+            return defaultValue;
+        }
+    }
+
+    /**
+     * 
+     * @param name
+     * @param defaultValue
+     * @return
+     */
+    public boolean getBooleanParameter(String name, boolean defaultValue) {
+        if (params == null || !params.containsKey(name)) {
+            return defaultValue;
+        }
+        return Boolean.valueOf(params.get(name));
+    }
+}

Propchange: jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/BackendListenerContext.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/BackendListenerGui.java
URL: http://svn.apache.org/viewvc/jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/BackendListenerGui.java?rev=1641081&view=auto
==============================================================================
--- jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/BackendListenerGui.java (added)
+++ jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/BackendListenerGui.java Sat Nov 22 15:36:37 2014
@@ -0,0 +1,282 @@
+/*
+ * 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.jmeter.visualizers.backend;
+
+import java.awt.BorderLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.swing.ComboBoxModel;
+import javax.swing.JComboBox;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JTextField;
+
+import org.apache.jmeter.config.Argument;
+import org.apache.jmeter.config.Arguments;
+import org.apache.jmeter.config.gui.ArgumentsPanel;
+import org.apache.jmeter.gui.util.HorizontalPanel;
+import org.apache.jmeter.testelement.TestElement;
+import org.apache.jmeter.testelement.property.PropertyIterator;
+import org.apache.jmeter.util.JMeterUtils;
+import org.apache.jmeter.visualizers.gui.AbstractListenerGui;
+import org.apache.jorphan.logging.LoggingManager;
+import org.apache.jorphan.reflect.ClassFinder;
+import org.apache.log.Logger;
+
+/**
+ * The <code>BackendListenerGui</code> class provides the user interface for the
+ * {@link BackendListener} object.
+ * @since 2.13
+ */
+public class BackendListenerGui extends AbstractListenerGui implements ActionListener {
+
+    /**
+     * 
+     */
+    private static final long serialVersionUID = 4331668988576438604L;
+
+    /** Logging */
+    private static final Logger log = LoggingManager.getLoggerForClass();
+
+    /** A combo box allowing the user to choose a backend class. */
+    private JComboBox classnameCombo;
+    
+    /**
+     * A field allowing the user to specify the size of Queue
+     */
+    private JTextField queueSize;
+
+    /** A panel allowing the user to set arguments for this test. */
+    private ArgumentsPanel argsPanel;
+
+    /**
+     * Create a new BackendListenerGui as a standalone component.
+     */
+    public BackendListenerGui() {
+        super();
+        init();
+    }
+
+
+    /** {@inheritDoc} */
+    @Override
+    public String getLabelResource() {
+        return "backend_listener"; // $NON-NLS-1$
+    }
+
+    /**
+     * Initialize the GUI components and layout.
+     */
+    private void init() {// called from ctor, so must not be overridable
+        setLayout(new BorderLayout(0, 5));
+
+        setBorder(makeBorder());
+        add(makeTitlePanel(), BorderLayout.NORTH);
+
+        JPanel classnameRequestPanel = new JPanel(new BorderLayout(0, 5));
+        classnameRequestPanel.add(createClassnamePanel(), BorderLayout.NORTH);
+        classnameRequestPanel.add(createParameterPanel(), BorderLayout.CENTER);
+
+        add(classnameRequestPanel, BorderLayout.CENTER);
+    }
+
+    /**
+     * Create a panel with GUI components allowing the user to select a test
+     * class.
+     *
+     * @return a panel containing the relevant components
+     */
+    private JPanel createClassnamePanel() {
+        List<String> possibleClasses = new ArrayList<String>();
+
+        try {
+            // Find all the classes which implement the BackendListenerClient
+            // interface.
+            possibleClasses = ClassFinder.findClassesThatExtend(JMeterUtils.getSearchPaths(),
+                    new Class[] { BackendListenerClient.class });
+
+            // Remove the BackendListener class from the list since it only
+            // implements the interface for error conditions.
+
+            possibleClasses.remove(BackendListener.class.getName() + "$ErrorBackendListenerClient");
+        } catch (Exception e) {
+            log.debug("Exception getting interfaces.", e);
+        }
+
+        JLabel label = new JLabel(JMeterUtils.getResString("backend_listener_classname")); // $NON-NLS-1$
+
+        classnameCombo = new JComboBox(possibleClasses.toArray());
+        classnameCombo.addActionListener(this);
+        classnameCombo.setEditable(false);
+        label.setLabelFor(classnameCombo);
+
+        HorizontalPanel classNamePanel = new HorizontalPanel();
+        classNamePanel.add(label);
+        classNamePanel.add(classnameCombo);
+
+        queueSize = new JTextField("", 5);
+        queueSize.setName("Queue Size"); //$NON-NLS-1$
+        JLabel queueSizeLabel = new JLabel(JMeterUtils.getResString("backend_listener_queue_size")); // $NON-NLS-1$
+        queueSizeLabel.setLabelFor(queueSize);
+        HorizontalPanel queueSizePanel = new HorizontalPanel();
+        queueSizePanel.add(queueSizeLabel, BorderLayout.WEST);
+        queueSizePanel.add(queueSize);
+
+        JPanel panel = new JPanel(new BorderLayout(0, 5));
+        panel.add(classNamePanel, BorderLayout.NORTH);
+        panel.add(queueSizePanel, BorderLayout.CENTER);
+        return panel;
+    }
+
+    /**
+     * Handle action events for this component. This method currently handles
+     * events for the classname combo box.
+     *
+     * @param evt
+     *            the ActionEvent to be handled
+     */
+    @Override
+    public void actionPerformed(ActionEvent evt) {
+        if (evt.getSource() == classnameCombo) {
+            String className = ((String) classnameCombo.getSelectedItem()).trim();
+            try {
+                BackendListenerClient client = (BackendListenerClient) Class.forName(className, true,
+                        Thread.currentThread().getContextClassLoader()).newInstance();
+
+                Arguments currArgs = new Arguments();
+                argsPanel.modifyTestElement(currArgs);
+                Map<String, String> currArgsMap = currArgs.getArgumentsAsMap();
+
+                Arguments newArgs = new Arguments();
+                Arguments testParams = null;
+                try {
+                    testParams = client.getDefaultParameters();
+                } catch (AbstractMethodError e) {
+                    log.warn("BackendListenerClient doesn't implement "
+                            + "getDefaultParameters.  Default parameters won't "
+                            + "be shown.  Please update your client class: " + className);
+                }
+
+                if (testParams != null) {
+                    PropertyIterator i = testParams.getArguments().iterator();
+                    while (i.hasNext()) {
+                        Argument arg = (Argument) i.next().getObjectValue();
+                        String name = arg.getName();
+                        String value = arg.getValue();
+
+                        // If a user has set parameters in one test, and then
+                        // selects a different test which supports the same
+                        // parameters, those parameters should have the same
+                        // values that they did in the original test.
+                        if (currArgsMap.containsKey(name)) {
+                            String newVal = currArgsMap.get(name);
+                            if (newVal != null && newVal.length() > 0) {
+                                value = newVal;
+                            }
+                        }
+                        newArgs.addArgument(name, value);
+                    }
+                }
+
+                argsPanel.configure(newArgs);
+            } catch (Exception e) {
+                log.error("Error getting argument list for " + className, e);
+            }
+        }
+    }
+
+    /**
+     * Create a panel containing components allowing the user to provide
+     * arguments to be passed to the test class instance.
+     *
+     * @return a panel containing the relevant components
+     */
+    private JPanel createParameterPanel() {
+        argsPanel = new ArgumentsPanel(JMeterUtils.getResString("backend_listener_paramtable")); // $NON-NLS-1$
+        return argsPanel;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void configure(TestElement config) {
+        super.configure(config);
+
+        argsPanel.configure((Arguments) config.getProperty(BackendListener.ARGUMENTS).getObjectValue());
+
+        String className = config.getPropertyAsString(BackendListener.CLASSNAME);
+        if(checkContainsClassName(classnameCombo.getModel(), className)) {
+            classnameCombo.setSelectedItem(className);
+        } else {
+            log.error("Error setting class:'"+className+"' in BackendListener: "+getName()+
+                    ", check for a missing jar in your jmeter 'search_paths' and 'plugin_dependency_paths' properties");
+        }
+        queueSize.setText(Integer.toString(((BackendListener)config).getQueueSize()));
+    }
+
+    /**
+     * Check combo contains className
+     * @param model ComboBoxModel
+     * @param className String class name
+     * @return boolean
+     */
+    private static final boolean checkContainsClassName(ComboBoxModel model, String className) {
+        int size = model.getSize();
+        Set<String> set = new HashSet<String>(size);
+        for (int i = 0; i < size; i++) {
+            set.add((String)model.getElementAt(i));
+        }
+        return set.contains(className);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public TestElement createTestElement() {
+        BackendListener config = new BackendListener();
+        modifyTestElement(config);
+        return config;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void modifyTestElement(TestElement config) {
+        configureTestElement(config);
+        BackendListener backendListener = (BackendListener) config;
+        backendListener.setArguments((Arguments) argsPanel.createTestElement());
+        backendListener.setClassname(String.valueOf(classnameCombo.getSelectedItem()));
+        backendListener.setQueueSize(Integer.parseInt(queueSize.getText()));
+        
+    }
+
+    /* (non-Javadoc)
+     * @see org.apache.jmeter.gui.AbstractJMeterGuiComponent#clearGui()
+     */
+    @Override
+    public void clearGui() {
+        super.clearGui();
+        argsPanel.clearGui();
+        classnameCombo.setSelectedIndex(0);
+        queueSize.setText("");
+    }
+}

Propchange: jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/BackendListenerGui.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/SamplerMetric.java
URL: http://svn.apache.org/viewvc/jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/SamplerMetric.java?rev=1641081&view=auto
==============================================================================
--- jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/SamplerMetric.java (added)
+++ jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/SamplerMetric.java Sat Nov 22 15:36:37 2014
@@ -0,0 +1,138 @@
+/*
+ * 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.jmeter.visualizers.backend;
+
+import org.apache.commons.math3.stat.descriptive.DescriptiveStatistics;
+import org.apache.jmeter.samplers.SampleResult;
+
+/**
+ * Sampler metric
+ * @since 2.13
+ */
+public class SamplerMetric {
+    // Limit to sliding window of 100 values 
+    private DescriptiveStatistics stats = new DescriptiveStatistics(100);
+    private int success;
+    private int failure;
+    private long maxTime=0L;
+    private long minTime=Long.MAX_VALUE;
+    private int maxActiveThreads = 0;
+    private int minActiveThreads = Integer.MAX_VALUE;
+    /**
+     * 
+     */
+    public SamplerMetric() {
+    }
+
+    /**
+     * 
+     * @param result SampleResult
+     */
+    public synchronized void add(SampleResult result) {
+        if(result.isSuccessful()) {
+            success++;
+        } else {
+            failure++;
+        }
+        long time = result.getTime();
+        int activeThreads = result.getAllThreads();
+        maxTime = Math.max(time, maxTime);
+        minTime = Math.min(time, minTime); 
+        maxActiveThreads = Math.max(maxActiveThreads, activeThreads);
+        minActiveThreads = Math.min(minActiveThreads, activeThreads);
+        if(result.isSuccessful()) {
+            // Should we also compute KO , all response time ?
+            // only take successful requests for time computing
+            stats.addValue(time);
+        }
+    }
+    
+    /**
+     * Reset metric except for percentile related datas
+     */
+    public synchronized void resetForTimeInterval() {
+        // We don't clear stats as it will slide as per my understanding of 
+        // http://commons.apache.org/proper/commons-math/userguide/stat.html
+        success = 0;
+        failure = 0;
+        maxTime=0L;
+        minTime=Long.MAX_VALUE;
+        maxActiveThreads = 0;
+        minActiveThreads = Integer.MAX_VALUE;
+    }
+
+    /**
+     * @return mean
+     */
+    public double getMean() {
+        return stats.getMean();
+    }
+    
+    /**
+     * @param percentile
+     * @return
+     */
+    public double getPercentile(double percentile) {
+        return stats.getPercentile(percentile);
+    }
+
+    /**
+     * 
+     * @return total request
+     */
+    public int getTotal() {
+        return success+failure;
+    }
+    
+    /**
+     * @return the success
+     */
+    public int getSuccess() {
+        return success;
+    }
+
+    /**
+     * @return the failure
+     */
+    public int getFailure() {
+        return failure;
+    }
+
+    /**
+     * @return the maxTime
+     */
+    public long getMaxTime() {
+        return maxTime;
+    }
+
+    /**
+     * @return the minTime
+     */
+    public long getMinTime() {
+        return minTime;
+    }
+
+    public int getMaxActiveThreads() {
+        return maxActiveThreads;
+    }
+
+    public int getMinActiveThreads() {
+        return minActiveThreads;
+    }
+}

Propchange: jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/SamplerMetric.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

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=1641081&r1=1641080&r2=1641081&view=diff
==============================================================================
--- jmeter/trunk/src/core/org/apache/jmeter/resources/messages.properties (original)
+++ jmeter/trunk/src/core/org/apache/jmeter/resources/messages.properties Sat Nov 22 15:36:37 2014
@@ -129,6 +129,10 @@ auth_manager_title=HTTP Authorization Ma
 auths_stored=Authorizations Stored in the Authorization Manager
 average=Average
 average_bytes=Avg. Bytes
+backend_listener=Backend Listener
+backend_listener_classname=Backend Listener implementation
+backend_listener_paramtable=Parameters
+backend_listener_queue_size=Async Queue size
 bind=Thread Bind
 bouncy_castle_unavailable_message=The jars for bouncy castle are unavailable, please add them to your classpath.
 browse=Browse...

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=1641081&r1=1641080&r2=1641081&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 Nov 22 15:36:37 2014
@@ -123,6 +123,10 @@ auth_manager_title=Gestionnaire d'autori
 auths_stored=Autorisations stock\u00E9es
 average=Moyenne
 average_bytes=Moy. octets
+backend_listener=R\u00E9cepteur asynchrone
+backend_listener_classname=Implémentation du r\u00E9cepteur asynchrone
+backend_listener_paramtable=Param\u00E8tres
+backend_listener_queue_size=Taille de la queue
 bind=Connexion de l'unit\u00E9
 bouncy_castle_unavailable_message=Les jars de bouncycastle sont indisponibles, ajoutez les au classpath.
 browse=Parcourir...

Modified: jmeter/trunk/src/core/org/apache/jmeter/samplers/SampleResult.java
URL: http://svn.apache.org/viewvc/jmeter/trunk/src/core/org/apache/jmeter/samplers/SampleResult.java?rev=1641081&r1=1641080&r2=1641081&view=diff
==============================================================================
--- jmeter/trunk/src/core/org/apache/jmeter/samplers/SampleResult.java (original)
+++ jmeter/trunk/src/core/org/apache/jmeter/samplers/SampleResult.java Sat Nov 22 15:36:37 2014
@@ -42,7 +42,7 @@ import org.apache.log.Logger;
  * sample of an entry.
  *
  */
-public class SampleResult implements Serializable {
+public class SampleResult implements Serializable, Cloneable {
 
     private static final long serialVersionUID = 241L;
 
@@ -1349,4 +1349,13 @@ public class SampleResult implements Ser
     public void cleanAfterSample() {
         this.responseDataAsString = null;
     }
+
+    @Override
+    public Object clone() {
+        try {
+            return super.clone();
+        } catch (CloneNotSupportedException e) {
+            throw new IllegalStateException("This should not happen");
+        }
+    }
 }

Modified: jmeter/trunk/src/core/org/apache/jmeter/save/SaveService.java
URL: http://svn.apache.org/viewvc/jmeter/trunk/src/core/org/apache/jmeter/save/SaveService.java?rev=1641081&r1=1641080&r2=1641081&view=diff
==============================================================================
--- jmeter/trunk/src/core/org/apache/jmeter/save/SaveService.java (original)
+++ jmeter/trunk/src/core/org/apache/jmeter/save/SaveService.java Sat Nov 22 15:36:37 2014
@@ -176,7 +176,7 @@ public class SaveService {
     
     // Must match _version property value in saveservice.properties
     // used to ensure saveservice.properties and SaveService are updated simultaneously
-    private static final String PROPVERSION = "2.7";// Expected version $NON-NLS-1$
+    private static final String PROPVERSION = "2.8";// Expected version $NON-NLS-1$
 
     // Internal information only
     private static String fileVersion = ""; // read from saveservice.properties file// $NON-NLS-1$

Modified: jmeter/trunk/xdocs/changes.xml
URL: http://svn.apache.org/viewvc/jmeter/trunk/xdocs/changes.xml?rev=1641081&r1=1641080&r2=1641081&view=diff
==============================================================================
--- jmeter/trunk/xdocs/changes.xml (original)
+++ jmeter/trunk/xdocs/changes.xml Sat Nov 22 15:36:37 2014
@@ -188,6 +188,7 @@ See  <bugzilla>56357</bugzilla> for deta
 
 <h3>Listeners</h3>
 <ul>
+<li><bugzilla>55932</bugzilla> - Create a Async BackendListener to allow easy plug of new listener (Graphite, JDBC, Console,...)</li>
 </ul>
 
 <h3>Timers, Assertions, Config, Pre- &amp; Post-Processors</h3>

Modified: jmeter/trunk/xdocs/usermanual/component_reference.xml
URL: http://svn.apache.org/viewvc/jmeter/trunk/xdocs/usermanual/component_reference.xml?rev=1641081&r1=1641080&r2=1641081&view=diff
==============================================================================
--- jmeter/trunk/xdocs/usermanual/component_reference.xml (original)
+++ jmeter/trunk/xdocs/usermanual/component_reference.xml Sat Nov 22 15:36:37 2014
@@ -3380,6 +3380,19 @@ The Comparison Assertion Visualizer show
  </properties>
 </component>
 
+<component name="Backend Listener" index="&sect-num;.3.21"  width="777" height="266" screenshot="backend_listener.png">
+<description>
+The backend listener is an Asynchronous listener that enables you to plug custom implementations of <a href="../api/org/apache/jmeter/visualizers/backend/BackendListenerClient.html">BackendListenerClient</a>.
+By default, a Graphite implementation is provided.
+</description>
+ <properties>
+ <property name="Name" required="Yes">Descriptive name for this element that is shown in the tree.</property>
+ <property name="Backend Listener implementation" required="Yes">Class of the BackendListenerClient implementation.</property>
+ <property name="Async Queue size" required="Yes">Size of the queue that holds the SampleResults while they are processed asynchronously.</property>
+ <property name="Parameters" required="Yes">Parameters of the BackendListenerClient implementation.</property>
+ </properties>
+</component>
+
 <a href="#">^</a>
 
 </section>



Re: svn commit: r1641081 - in /jmeter/trunk: ./ bin/ res/maven/ src/components/org/apache/jmeter/visualizers/backend/ src/core/org/apache/jmeter/resources/ src/core/org/apache/jmeter/samplers/ src/core/org/apache/jmeter/save/ xdocs/ xdocs/usermanual/

Posted by Philippe Mouawad <ph...@gmail.com>.
On Sunday, November 23, 2014, Felix Schumacher <
felix.schumacher@internetallee.de> wrote:

> Hi Phillipe,
> Am 22.11.2014 um 19:29 schrieb Philippe Mouawad:
>
>> Hi Felix,
>> As I said in thread, I commited code and will improve, feel free to fix
>> javadocs issues on your side.
>> I will review your comment.
>>
>> I have spent many hours if not days on this code and I am aware it is not
>> yet fully completed (although tests are promising) but my aim when
>> commiting it was to have feedback and help to finish it.
>>
> I did not mean to offend you. I can clearly see, that you put a lot of
> effort
> in this listener and I will surely try to integrate jmeter into our
> collectd server.
>
>  Great.
I will add documentation on Influxdb/grafana setup.
I suppose you will be doing the same for collectd.

I think we also need to make resistance tests( few hours of run),
aggressive tests and check that obtained graphs matchs existing graphs.
My first tests look ok for now.

> Regards
>  Felix
>
>>
>> Regards
>> Philippe
>>
>> On Sat, Nov 22, 2014 at 7:21 PM, Felix Schumacher <
>> felix.schumacher@internetallee.de> wrote:
>>
>>  Hello Philippe,
>>>
>>> I have hidden a few comments inside the cited code.
>>> They are mostly around javadoc and naming things.
>>>
>>> Am 22.11.2014 um 16:36 schrieb pmouawad@apache.org:
>>>
>>>  Author: pmouawad
>>>> Date: Sat Nov 22 15:36:37 2014
>>>> New Revision: 1641081
>>>>
>>>> URL: http://svn.apache.org/r1641081
>>>> Log:
>>>> Bug 55932 - Create a Async BackendListener to allow easy plug of new
>>>> listener (Graphite, JDBC, Console,...)
>>>> Bugzilla Id: 55932
>>>>
>>>> Added:
>>>>       jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>>>> backend/
>>>>       jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>>>> backend/
>>>> AbstractBackendListenerClient.java   (with props)
>>>>       jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>>>> backend/BackendListener.java
>>>>   (with props)
>>>>       jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>>>> backend/BackendListenerClient.java   (with props)
>>>>       jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>>>> backend/BackendListenerContext.java
>>>>   (with props)
>>>>       jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>>>> backend/BackendListenerGui.java   (with props)
>>>>       jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>>>> backend/SamplerMetric.java
>>>>   (with props)
>>>> Modified:
>>>>       jmeter/trunk/bin/saveservice.properties
>>>>       jmeter/trunk/build.properties
>>>>       jmeter/trunk/build.xml
>>>>       jmeter/trunk/eclipse.classpath
>>>>       jmeter/trunk/res/maven/ApacheJMeter_parent.pom
>>>>       jmeter/trunk/src/core/org/apache/jmeter/resources/
>>>> messages.properties
>>>>       jmeter/trunk/src/core/org/apache/jmeter/resources/
>>>> messages_fr.properties
>>>>       jmeter/trunk/src/core/org/apache/jmeter/samplers/
>>>> SampleResult.java
>>>>       jmeter/trunk/src/core/org/apache/jmeter/save/SaveService.java
>>>>       jmeter/trunk/xdocs/changes.xml
>>>>       jmeter/trunk/xdocs/usermanual/component_reference.xml
>>>>
>>>> Modified: jmeter/trunk/bin/saveservice.properties
>>>> URL: http://svn.apache.org/viewvc/jmeter/trunk/bin/saveservice.
>>>> properties?rev=1641081&r1=1641080&r2=1641081&view=diff
>>>> ============================================================
>>>> ==================
>>>> --- jmeter/trunk/bin/saveservice.properties (original)
>>>> +++ jmeter/trunk/bin/saveservice.properties Sat Nov 22 15:36:37 2014
>>>> @@ -53,7 +53,8 @@ _file_version=$Revision$
>>>>    # 2.5 = 2.10
>>>>    # 2.6 = 2.11
>>>>    # 2.7 = 2.12
>>>> -_version=2.7
>>>> +# 2.8 = 2.13
>>>> +_version=2.8
>>>>    #
>>>>    #
>>>>    # Character set encoding used to read and write JMeter XML files and
>>>> CSV results
>>>> @@ -78,6 +79,8 @@ AssertionVisualizer=org.apache.jmeter.vi
>>>>    AuthManager=org.apache.jmeter.protocol.http.control.AuthManager
>>>>    Authorization=org.apache.jmeter.protocol.http.control.Authorization
>>>>    AuthPanel=org.apache.jmeter.protocol.http.gui.AuthPanel
>>>> +BackendListener=org.apache.jmeter.visualizers.backend.BackendListener
>>>> +BackendListenerGui=org.apache.jmeter.visualizers.
>>>> backend.BackendListenerGui
>>>>    BarChart=org.apache.jmeter.testelement.BarChart
>>>>    BarChartGui=org.apache.jmeter.report.gui.BarChartGui
>>>>    BeanShellAssertion=org.apache.jmeter.assertions.BeanShellAssertion
>>>>
>>>> Modified: jmeter/trunk/build.properties
>>>> URL: http://svn.apache.org/viewvc/jmeter/trunk/build.properties?
>>>> rev=1641081&r1=1641080&r2=1641081&view=diff
>>>> ============================================================
>>>> ==================
>>>> --- jmeter/trunk/build.properties (original)
>>>> +++ jmeter/trunk/build.properties Sat Nov 22 15:36:37 2014
>>>> @@ -118,11 +118,21 @@ commons-logging.loc         = ${maven2.r
>>>>    #commons-logging.md5         = E2C390FE739B2550A218262B28F290CE
>>>>    commons-logging.md5         = 040b4b4d8eac886f6b4a2a3bd2f31b00
>>>>    +commons-math3.version         = 3.3
>>>> +commons-math3.jar             = commons-math3-${commons-math3.
>>>> version}.jar
>>>> +commons-math3.loc             = ${maven2.repo}/org/apache/
>>>> commons/commons-math3/${commons-math3.version}
>>>> +commons-math3.md5             = 87346cf2772dc2becf106c45e0f63863
>>>> +
>>>>    commons-net.version         = 3.3
>>>>    commons-net.jar             = commons-net-${commons-net.version}.jar
>>>>    commons-net.loc             = ${maven2.repo}/commons-net/
>>>> commons-net/${commons-net.version}
>>>>    commons-net.md5             = c077ca61598e9c21f43f8b6488fbbee9
>>>>    +commons-pool2.version         = 2.2
>>>> +commons-pool2.jar             = commons-pool2-${commons-pool2.
>>>> version}.jar
>>>> +commons-pool2.loc             = ${maven2.repo}/org/apache/
>>>> commons/commons-pool2/${commons-pool2.version}
>>>> +commons-pool2.md5             = 51b56c92883812c56fbeb339866ce2df
>>>> +
>>>>    # dnsjava for DNSCacheManager
>>>>    dnsjava.version             = 2.1.6
>>>>    dnsjava.jar                 = dnsjava-${dnsjava.version}.jar
>>>>
>>>> Modified: jmeter/trunk/build.xml
>>>> URL: http://svn.apache.org/viewvc/jmeter/trunk/build.xml?rev=
>>>> 1641081&r1=1641080&r2=1641081&view=diff
>>>> ============================================================
>>>> ==================
>>>> --- jmeter/trunk/build.xml (original)
>>>> +++ jmeter/trunk/build.xml Sat Nov 22 15:36:37 2014
>>>> @@ -365,7 +365,9 @@
>>>>        <include name="${lib.dir}/${commons-jexl2.jar}"/>
>>>>        <include name="${lib.dir}/${commons-lang3.jar}"/>
>>>>        <include name="${lib.dir}/${commons-logging.jar}"/>
>>>> +    <include name="${lib.dir}/${commons-math3}"/>
>>>>        <include name="${lib.dir}/${commons-net.jar}"/>
>>>> +    <include name="${lib.dir}/${commons-pool2.jar}"/>
>>>>        <include name="${lib.dir}/${dnsjava.jar}"/>
>>>>        <include name="${lib.dir}/${excalibur-datasource.jar}"/>
>>>>        <include name="${lib.dir}/${excalibur-instrument.jar}"/>
>>>> @@ -438,8 +440,10 @@
>>>>        <pathelement location="${lib.dir}/${commons-jexl2.jar}"/>
>>>>        <pathelement location="${lib.dir}/${commons-lang3.jar}"/>
>>>>        <pathelement location="${lib.dir}/${commons-logging.jar}"/>
>>>> +    <pathelement location="${lib.dir}/${commons-math3.jar}"/>
>>>>        <pathelement location="${lib.dir}/${commons-net.jar}"/>
>>>> -    <pathelement location="${lib.dir}/${dnsjava.jar}"/>
>>>> +       <pathelement location="${lib.dir}/${commons-pool2.jar}"/>
>>>> +       <pathelement location="${lib.dir}/${dnsjava.jar}"/>
>>>>        <pathelement location="${lib.dir}/${excalibur-datasource.jar}"/>
>>>>        <pathelement location="${lib.dir}/${excalibur-instrument.jar}"/>
>>>>        <pathelement location="${lib.dir}/${excalibur-logger.jar}"/>
>>>> @@ -2909,7 +2913,9 @@ run JMeter unless all the JMeter jars ar
>>>>            <process_jarfile jarname="commons-jexl2"/>
>>>>            <process_jarfile jarname="commons-lang3"/>
>>>>            <process_jarfile jarname="commons-logging"/>
>>>> +        <process_jarfile jarname="commons-math3"/>
>>>>            <process_jarfile jarname="commons-net"/>
>>>> +       <process_jarfile jarname="commons-pool2"/>
>>>>            <process_jarfile jarname="dnsjava"/>
>>>>            <process_jarfile jarname="excalibur-datasource"/>
>>>>            <process_jarfile jarname="excalibur-instrument"/>
>>>>
>>>> Modified: jmeter/trunk/eclipse.classpath
>>>> URL: http://svn.apache.org/viewvc/jmeter/trunk/eclipse.
>>>> classpath?rev=1641081&r1=1641080&r2=1641081&view=diff
>>>> ============================================================
>>>> ==================
>>>> --- jmeter/trunk/eclipse.classpath (original)
>>>> +++ jmeter/trunk/eclipse.classpath Sat Nov 22 15:36:37 2014
>>>> @@ -55,7 +55,9 @@
>>>>          <classpathentry kind="lib" path="lib/commons-jexl-2.1.1.jar"/>
>>>>          <classpathentry kind="lib" path="lib/commons-lang3-3.3.2.
>>>> jar"/>
>>>>          <classpathentry kind="lib" path="lib/commons-logging-1.2.
>>>> jar"/>
>>>> +    <classpathentry kind="lib" path="lib/commons-math3-3.3.jar"/>
>>>>          <classpathentry kind="lib" path="lib/commons-net-3.3.jar"/>
>>>> +    <classpathentry kind="lib" path="lib/commons-pool2-2.2.jar"/>
>>>>          <classpathentry kind="lib" path="lib/dnsjava-2.1.6.jar"/>
>>>>          <classpathentry kind="lib" path="lib/excalibur-
>>>> datasource-2.1.jar"/>
>>>>          <classpathentry kind="lib" path="lib/excalibur-
>>>> instrument-1.0.jar"/>
>>>>
>>>> Modified: jmeter/trunk/res/maven/ApacheJMeter_parent.pom
>>>> URL: http://svn.apache.org/viewvc/jmeter/trunk/res/maven/
>>>> ApacheJMeter_parent.pom?rev=1641081&r1=1641080&r2=1641081&view=diff
>>>> ============================================================
>>>> ==================
>>>> --- jmeter/trunk/res/maven/ApacheJMeter_parent.pom (original)
>>>> +++ jmeter/trunk/res/maven/ApacheJMeter_parent.pom Sat Nov 22 15:36:37
>>>> 2014
>>>> @@ -66,7 +66,9 @@ under the License.
>>>>          <commons-jexl2.version>2.1.1</commons-jexl2.version>
>>>>          <commons-lang3.version>3.3.2</commons-lang3.version>
>>>>          <commons-logging.version>1.2</commons-logging.version>
>>>> +      <commons-math3.version>3.3</commons-math3.version>
>>>>          <commons-net.version>3.3</commons-net.version>
>>>> +      <commons-pool2.version>2.2</commons-pool2.version>
>>>>          <dnsjava.version>2.1.6</dnsjava.version>
>>>>          <excalibur-datasource.version>2.1</excalibur-datasource.
>>>> version>
>>>>          <excalibur-instrument.version>1.0</excalibur-instrument.
>>>> version>
>>>> @@ -181,11 +183,21 @@ under the License.
>>>>            <version>${commons-logging.version}</version>
>>>>          </dependency>
>>>>          <dependency>
>>>> +        <groupId>commons-math3</groupId>
>>>> +        <artifactId>commons-math3</artifactId>
>>>> +        <version>${commons-math3.version}</version>
>>>> +      </dependency>
>>>> +      <dependency>
>>>>            <groupId>commons-net</groupId>
>>>>            <artifactId>commons-net</artifactId>
>>>>            <version>${commons-net.version}</version>
>>>>          </dependency>
>>>>          <dependency>
>>>> +        <groupId>commons-pool2</groupId>
>>>> +        <artifactId>commons-pool2</artifactId>
>>>> +        <version>${commons-pool2.version}</version>
>>>> +      </dependency>
>>>> +      <dependency>
>>>>              <groupId>dnsjava</groupId>
>>>>              <artifactId>dnsjava</artifactId>
>>>>              <version>${dnsjava.version}</version>
>>>>
>>>> Added: jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>>>> backend/
>>>> AbstractBackendListenerClient.java
>>>> URL: http://svn.apache.org/viewvc/jmeter/trunk/src/components/
>>>> org/apache/jmeter/visualizers/backend/AbstractBackendListenerClient.
>>>> java?rev=1641081&view=auto
>>>> ============================================================
>>>> ==================
>>>> --- jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/
>>>> AbstractBackendListenerClient.java (added)
>>>> +++ jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/
>>>> AbstractBackendListenerClient.java Sat Nov 22 15:36:37 2014
>>>> @@ -0,0 +1,121 @@
>>>> +/*
>>>> + * 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.jmeter.visualizers.backend;
>>>> +
>>>> +import java.util.Map;
>>>> +import java.util.concurrent.ConcurrentHashMap;
>>>> +
>>>> +import org.apache.jmeter.config.Arguments;
>>>> +import org.apache.jmeter.samplers.SampleResult;
>>>> +import org.apache.jorphan.logging.LoggingManager;
>>>> +import org.apache.log.Logger;
>>>> +
>>>> +/**
>>>> + * An abstract implementation of the BackendListenerClient interface.
>>>> This
>>>> + * implementation provides default implementations of most of the
>>>> methods in the
>>>> + * interface, as well as some convenience methods, in order to simplify
>>>> + * development of BackendListenerClient implementations.
>>>> + *
>>>> + * While it may be necessary to make changes to the
>>>> BackendListenerClient interface
>>>> + * from time to time (therefore requiring changes to any
>>>> implementations
>>>> of this
>>>> + * interface), we intend to make this abstract class provide reasonable
>>>> + * implementations of any new methods so that subclasses do not
>>>> necessarily need
>>>> + * to be updated for new versions. Therefore, when creating a new
>>>> + * BackendListenerClient implementation, developers are encouraged to
>>>> subclass this
>>>> + * abstract class rather than implementing the BackendListenerClient
>>>> interface
>>>> + * directly. Implementing BackendListenerClient directly will continue
>>>> to be
>>>> + * supported for cases where extending this class is not possible (for
>>>> example,
>>>> + * when the client class is already a subclass of some other class).
>>>> + * <p>
>>>> + * The handleSampleResult() method of BackendListenerClient does not
>>>> have a default
>>>> + * implementation here, so subclasses must define at least this method.
>>>> It may
>>>> + * be useful to override other methods as well.
>>>> + *
>>>> + * @see BackendListener#sampleOccurred(org.apache.
>>>> jmeter.samplers.SampleEvent)
>>>> + * @since 2.13
>>>> + */
>>>> +public abstract class AbstractBackendListenerClient implements
>>>> BackendListenerClient {
>>>> +
>>>> +    private static final Logger log = LoggingManager.
>>>> getLoggerForClass();
>>>>
>>>>  In classes further down the logger is stored in variables named LOG and
>>> LOGGER, should we use one name?
>>> In this class we have a getter for the logger in other classes not. Why?
>>>
>>>  +
>>>> +    private ConcurrentHashMap<String, SamplerMetric> metricsPerSampler
>>>> =
>>>> new ConcurrentHashMap<String, SamplerMetric>();
>>>> +
>>>> +    /* Implements BackendListenerClient.setupTest(JavaSamplerContext)
>>>> */
>>>> +    @Override
>>>> +    public void setupTest(BackendListenerContext context) throws
>>>> Exception {
>>>> +        log.debug(getClass().getName() + ": setupTest");
>>>> +    }
>>>> +
>>>> +    /* Implements BackendListenerClient.teardownTest(
>>>> JavaSamplerContext)
>>>> */
>>>> +    @Override
>>>> +    public void teardownTest(BackendListenerContext context) throws
>>>> Exception {
>>>> +        log.debug(getClass().getName() + ": teardownTest");
>>>> +        metricsPerSampler.clear();
>>>> +    }
>>>> +
>>>> +    /* Implements BackendListenerClient.getDefaultParameters() */
>>>> +    @Override
>>>> +    public Arguments getDefaultParameters() {
>>>> +        return null;
>>>> +    }
>>>> +
>>>> +    /**
>>>> +     * Get a Logger instance which can be used by subclasses to log
>>>> information.
>>>> +     *
>>>> +     * @return a Logger instance which can be used for logging
>>>> +     */
>>>> +    protected Logger getLogger() {
>>>> +        return log;
>>>> +    }
>>>> +
>>>> +    /* (non-Javadoc)
>>>> +     * @see org.apache.jmeter.visualizers.
>>>> backend.BackendListenerClient#
>>>> createSampleResult(org.apache.jmeter.samplers.SampleResult)
>>>> +     */
>>>> +    @Override
>>>> +    public SampleResult createSampleResult(BackendListenerContext
>>>> context, SampleResult result) {
>>>> +        SampleResult sampleResult = (SampleResult) result.clone();
>>>> +        return sampleResult;
>>>> +    }
>>>> +
>>>> +    /**
>>>> +     *
>>>> +     * @param sampleLabel
>>>> +     * @return SamplerMetric
>>>>
>>>>  No description of the method and the parameters?
>>>
>>>  +     */
>>>> +    protected SamplerMetric getSamplerMetric(String sampleLabel) {
>>>> +        SamplerMetric samplerMetric = metricsPerSampler.get(
>>>> sampleLabel);
>>>> +        if(samplerMetric == null) {
>>>> +            samplerMetric = new SamplerMetric();
>>>> +            SamplerMetric oldValue = metricsPerSampler.putIfAbsent(
>>>> sampleLabel,
>>>> samplerMetric);
>>>> +            if(oldValue != null ){
>>>> +                samplerMetric = oldValue;
>>>> +            }
>>>> +        }
>>>> +        return samplerMetric;
>>>> +    }
>>>> +
>>>> +    /**
>>>> +     *
>>>> +     * @return Map<String, SamplerMetric>
>>>>
>>>>  No description of the method and usage of forbidden characters :) there
>>> are still more than 800 warnings in the javadoc to prune, so don't
>>> introduce new ones, please.
>>>
>>>  +     */
>>>> +    protected Map<String, SamplerMetric> getMetricsPerSampler() {
>>>> +        return metricsPerSampler;
>>>> +    }
>>>> +
>>>> +}
>>>>
>>>> Propchange: jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>>>> backend/AbstractBackendListenerClient.java
>>>> ------------------------------------------------------------
>>>> ------------------
>>>>       svn:mime-type = text/plain
>>>>
>>>> Added: jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>>>> backend/BackendListener.java
>>>> URL: http://svn.apache.org/viewvc/jmeter/trunk/src/components/
>>>> org/apache/jmeter/visualizers/backend/BackendListener.java?
>>>> rev=1641081&view=auto
>>>> ============================================================
>>>> ==================
>>>> --- jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>>>> backend/BackendListener.java
>>>> (added)
>>>> +++ jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>>>> backend/BackendListener.java
>>>> Sat Nov 22 15:36:37 2014
>>>> @@ -0,0 +1,448 @@
>>>> +/*
>>>> + * 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.jmeter.visualizers.backend;
>>>> +
>>>> +import java.io.Serializable;
>>>> +import java.lang.reflect.Method;
>>>> +import java.util.ArrayList;
>>>> +import java.util.HashSet;
>>>> +import java.util.List;
>>>> +import java.util.Set;
>>>> +import java.util.concurrent.ArrayBlockingQueue;
>>>> +import java.util.concurrent.BlockingQueue;
>>>> +import java.util.concurrent.locks.LockSupport;
>>>> +
>>>> +import org.apache.jmeter.config.Arguments;
>>>> +import org.apache.jmeter.engine.util.NoThreadClone;
>>>> +import org.apache.jmeter.protocol.java.sampler.JavaSamplerContext;
>>>> +import org.apache.jmeter.samplers.Remoteable;
>>>> +import org.apache.jmeter.samplers.SampleEvent;
>>>> +import org.apache.jmeter.samplers.SampleListener;
>>>> +import org.apache.jmeter.samplers.SampleResult;
>>>> +import org.apache.jmeter.testelement.AbstractTestElement;
>>>> +import org.apache.jmeter.testelement.TestElement;
>>>> +import org.apache.jmeter.testelement.TestStateListener;
>>>> +import org.apache.jmeter.testelement.property.TestElementProperty;
>>>> +import org.apache.jorphan.logging.LoggingManager;
>>>> +import org.apache.log.Logger;
>>>> +
>>>> +/**
>>>> + * Async Listener that delegates SampleResult handling to
>>>> implementations of {@link BackendListenerClient}
>>>> + * @since 2.13
>>>> + */
>>>> +public class BackendListener extends AbstractTestElement
>>>> +    implements Serializable, SampleListener, TestStateListener,
>>>> NoThreadClone, Remoteable  {
>>>> +
>>>> +    /**
>>>> +     *
>>>> +     */
>>>> +    private static final long serialVersionUID = 8184103677832024335L;
>>>> +
>>>> +    private static final Logger log = LoggingManager.
>>>> getLoggerForClass();
>>>>
>>>>  See naming comment of log from above
>>>
>>>  +
>>>> +    /**
>>>> +     * Set used to register instances which implement teardownTest.
>>>> +     * This is used so that the BackendListenerClient can be notified
>>>> when the test ends.
>>>> +     */
>>>> +    private static final Set<BackendListener> TEAR_DOWN_SET = new
>>>> HashSet<BackendListener>();
>>>> +
>>>> +    /**
>>>> +     * Property key representing the classname of the
>>>> BackendListenerClient to user.
>>>> +     */
>>>> +    public static final String CLASSNAME = "classname";
>>>> +
>>>> +    /**
>>>> +     * Queue size
>>>> +     */
>>>> +    public static final String QUEUE_SIZE = "QUEUE_SIZE";
>>>> +
>>>> +    /**
>>>> +     * Property key representing the arguments for the
>>>> BackendListenerClient.
>>>> +     */
>>>> +    public static final String ARGUMENTS = "arguments";
>>>> +
>>>> +    /**
>>>> +     * The BackendListenerClient class used by this sampler.
>>>> +     * Created by testStarted; copied to cloned instances.
>>>> +     */
>>>> +    private Class<?> javaClass;
>>>>
>>>>  Could probably named clientClass instead of javaClass, since we already
>>> know it is a java class.
>>>
>>>  +
>>>> +    /**
>>>> +     * If true, the BackendListenerClient class implements
>>>> teardownTest.
>>>> +     * Created by testStarted; copied to cloned instances.
>>>> +     */
>>>> +    private boolean isToBeRegistered;
>>>> +
>>>> +    /**
>>>> +     * The BackendListenerClient instance
>>>> +     */
>>>> +    private transient BackendListenerClient backendListenerClient =
>>>> null;
>>>> +
>>>> +    /**
>>>> +     * The JavaSamplerContext instance used by this sampler to hold
>>>> information
>>>>
>>>>  BackendListenerContext?
>>>
>>>  +     * related to the test run, such as the parameters specified for
>>>> the
>>>> sampler
>>>> +     * client.
>>>> +     */
>>>> +    private transient BackendListenerContext context = null;
>>>> +
>>>> +    private static final int DEFAULT_QUEUE_SIZE = 5000;
>>>> +
>>>> +    private transient BlockingQueue<SampleResult> queue; // created by
>>>> server in readResolve method
>>>> +
>>>> +    private transient long queueWaits; // how many times we had to wait
>>>> to queue a sample
>>>> +
>>>> +    private transient long queueWaitTime; // how long we had to wait
>>>> (nanoSeconds)
>>>> +
>>>> +    // Create unique object as marker for end of queue
>>>> +    private transient static final SampleResult FINAL_EVENT = new
>>>> SampleResult();
>>>> +
>>>> +    /**
>>>> +     * Create a BackendListener.
>>>> +     */
>>>> +    public BackendListener() {
>>>> +        setArguments(new Arguments());
>>>> +    }
>>>> +
>>>> +    /*
>>>> +     * Ensure that the required class variables are cloned,
>>>> +     * as this is not currently done by the super-implementation.
>>>> +     */
>>>> +    @Override
>>>> +    public Object clone() {
>>>> +        BackendListener clone = (BackendListener) super.clone();
>>>> +        clone.javaClass = this.javaClass;
>>>> +        clone.isToBeRegistered = this.isToBeRegistered;
>>>> +        return clone;
>>>> +    }
>>>> +
>>>> +    private void initClass() {
>>>> +        String name = getClassname().trim();
>>>> +        try {
>>>> +            javaClass = Class.forName(name, false,
>>>> Thread.currentThread().getContextClassLoader());
>>>> +            Method method = javaClass.getMethod("teardownTest", new
>>>> Class[]{BackendListenerContext.class});
>>>> +            isToBeRegistered = !method.getDeclaringClass().equals(
>>>> AbstractBackendListenerClient.class);
>>>> +            log.info("Created class: " + name + ". Uses teardownTest:
>>>> "
>>>> + isToBeRegistered);
>>>> +        } catch (Exception e) {
>>>> +            log.error(whoAmI() + "\tException initialising: " + name,
>>>> e);
>>>> +        }
>>>> +    }
>>>> +
>>>> +    /**
>>>> +     * Retrieves reference to BackendListenerClient.
>>>> +     *
>>>> +     * Convience method used to check for null reference without
>>>> actually
>>>> +     * creating a BackendListenerClient
>>>> +     *
>>>> +     * @return reference to BackendListenerClient NOTUSED private
>>>> BackendListenerClient
>>>> +     *         retrieveJavaClient() { return javaClient; }
>>>> +     */
>>>>
>>>>  Javadoc for non-existant method?
>>>
>>>  +
>>>> +    /**
>>>> +     * Generate a String identifier of this instance for debugging
>>>> purposes.
>>>> +     *
>>>> +     * @return a String identifier for this sampler instance
>>>> +     */
>>>> +    private String whoAmI() {
>>>> +        StringBuilder sb = new StringBuilder();
>>>> +        sb.append(Thread.currentThread().getName());
>>>> +        sb.append("@");
>>>> +        sb.append(Integer.toHexString(hashCode()));
>>>> +        sb.append("-");
>>>> +        sb.append(getName());
>>>> +        return sb.toString();
>>>> +    }
>>>> +
>>>> +    // TestStateListener implementation
>>>> +    /* Implements TestStateListener.testStarted() */
>>>> +    @Override
>>>> +    public void testStarted() {
>>>> +        testStarted("");
>>>> +    }
>>>> +
>>>> +    /* Implements TestStateListener.testStarted(String) */
>>>> +    @Override
>>>> +    public void testStarted(String host) {
>>>> +        log.debug(whoAmI() + "\ttestStarted(" + host + ")");
>>>>
>>>>  Maybe use isDebugEnabled to guard whoAmI() call?
>>>
>>>  +        queue = new ArrayBlockingQueue<SampleResult>(getQueueSize());
>>>> +        initClass();
>>>> +        queueWaits=0L;
>>>> +        queueWaitTime=0L;
>>>> +        log.info(getName()+":Starting worker with class:"+javaClass +"
>>>> and queue capacity:"+getQueueSize());
>>>> +
>>>> +        backendListenerClient = createBackendListenerClientImp
>>>> l(javaClass);
>>>> +        context = new BackendListenerContext((
>>>> Arguments)getArguments().
>>>> clone());
>>>> +        if(isToBeRegistered) {
>>>>
>>>>  space after if and before (?
>>>
>>>  +            TEAR_DOWN_SET.add(this);
>>>> +        }
>>>> +        try {
>>>> +            backendListenerClient.setupTest(context);
>>>> +        } catch (Exception e) {
>>>> +            throw new java.lang.IllegalStateException("Failed calling
>>>> setupTest", e);
>>>> +        }
>>>> +
>>>> +        Worker worker = new Worker(javaClass, backendListenerClient,
>>>> (Arguments) getArguments().clone(), queue);
>>>> +        worker.setDaemon(true);
>>>> +        worker.start();
>>>>
>>>>  Don't we want to stop worker after we're done with one test?
>>>
>>>  +        log.info(getName()+":Started  worker with class:"+javaClass);
>>>>
>>>>  Spaces after :?
>>>
>>>  +
>>>> +    }
>>>> +
>>>> +    /* (non-Javadoc)
>>>> +     * @see org.apache.jmeter.samplers.SampleListener#sampleOccurred(
>>>> org.apache.jmeter.samplers.SampleEvent)
>>>> +     */
>>>> +    @Override
>>>> +    public void sampleOccurred(SampleEvent e) {
>>>>
>>>>  Longer name then 'e'? I expect e to be an exception, not an event.
>>>
>>>  +        Arguments args = getArguments();
>>>> +        context = new BackendListenerContext(args);
>>>> +
>>>> +        SampleResult sr = backendListenerClient.
>>>> createSampleResult(context,
>>>> e.getResult());
>>>> +        try {
>>>> +            if (!queue.offer(sr)){ // we failed to add the element
>>>> first
>>>> time
>>>> +                queueWaits++;
>>>> +                long t1 = System.nanoTime();
>>>> +                queue.put(sr);
>>>> +                long t2 = System.nanoTime();
>>>> +                queueWaitTime += t2-t1;
>>>>
>>>>  Will sampleOccurred be called concurrently? If so, than queueWaitTime
>>> +=
>>> will not be correct.
>>>
>>>  +            }
>>>> +        } catch (Exception err) {
>>>> +            log.error("sampleOccurred, failed to queue the sample",
>>>> err);
>>>> +        }
>>>> +    }
>>>> +
>>>> +    private static final class Worker extends Thread {
>>>> +
>>>> +        private final BlockingQueue<SampleResult> queue;
>>>> +        private final BackendListenerContext context;
>>>> +        private final BackendListenerClient backendListenerClient;
>>>> +        private Worker(Class<?> javaClass, BackendListenerClient
>>>> backendListenerClient, Arguments arguments, BlockingQueue<SampleResult>
>>>> q){
>>>>
>>>>  Same naming argument as above. clientclass instead of javaClass?
>>>
>>>  +            queue = q;
>>>> +            // Allow BackendListenerClient implementations to get
>>>> access
>>>> to test element name
>>>> +            arguments.addArgument(TestElement.NAME, getName());
>>>> +            context = new BackendListenerContext(arguments);
>>>> +            this.backendListenerClient = backendListenerClient;
>>>> +        }
>>>> +
>>>> +
>>>> +        @Override
>>>> +        public void run() {
>>>> +            boolean isDebugEnabled = log.isDebugEnabled();
>>>> +            List<SampleResult> l = new ArrayList<SampleResult>(queue.
>>>> size());
>>>>
>>>>  samples instead of l?
>>>
>>>  +            try {
>>>> +                boolean eof = false;
>>>>
>>>>  endOfLoop?
>>>
>>>  +                while (!eof) {
>>>> +                    if(isDebugEnabled) {
>>>> +                        log.debug("Thread:"+Thread.
>>>> currentThread().getName()+"
>>>> taking SampleResult from queue:"+queue.size());
>>>> +                    }
>>>> +                    SampleResult e = queue.take();
>>>>
>>>>  Could be named result, or sample instead of e
>>>
>>>  +                    if(isDebugEnabled) {
>>>> +                        log.debug("Thread:"+Thread.
>>>> currentThread().getName()+"
>>>> took SampleResult:"+e+", isFinal:" + (e==FINAL_EVENT));
>>>> +                    }
>>>> +                    while (!(eof = (e == FINAL_EVENT)) && e != null ) {
>>>> // try to process as many as possible
>>>> +                        l.add(e);
>>>> +                        if(isDebugEnabled) {
>>>> +                            log.debug("Thread:"+Thread.
>>>> currentThread().getName()+"
>>>> polling from queue:"+queue.size());
>>>> +                        }
>>>> +                        e = queue.poll(); // returns null if nothing on
>>>> queue currently
>>>> +                        if(isDebugEnabled) {
>>>> +                            log.debug("Thread:"+Thread.
>>>> currentThread().getName()+"
>>>> took from queue:"+e+", isFinal:" + (e==FINAL_EVENT));
>>>> +                        }
>>>> +                    }
>>>> +                    if(isDebugEnabled) {
>>>> +                        log.debug("Thread:"+Thread.
>>>> currentThread().getName()+
>>>> +                                " exiting with FINAL EVENT:"+(e ==
>>>> FINAL_EVENT)
>>>> +                                +", null:" + (e==null));
>>>> +                    }
>>>> +                    int size = l.size();
>>>>
>>>>  No need for a temporary variable.
>>>
>>>  +                    if (size > 0) {
>>>> +                        backendListenerClient.handleSampleResults(l,
>>>> context);
>>>> +                        l.clear();
>>>> +                    }
>>>> +                    if(!eof) {
>>>> +                        LockSupport.parkNanos(100);
>>>> +                    }
>>>> +                }
>>>> +            } catch (InterruptedException e) {
>>>> +                // NOOP
>>>> +            }
>>>> +            // We may have been interrupted
>>>> +            int size = l.size();
>>>> +            if (size > 0) {
>>>> +                backendListenerClient.handleSampleResults(l, context);
>>>> +                l.clear();
>>>> +            }
>>>>
>>>>  Same code as a few lines above, could be factored out into a method
>>> handleSamples(l, context)
>>>
>>>  +            log.info("Worker ended");
>>>> +        }
>>>> +    }
>>>> +
>>>> +
>>>> +    /**
>>>> +     * Returns reference to <code>BackendListenerClient</code>.
>>>>
>>>>  Could use a {@link...}
>>>
>>>  +     *
>>>> +     *
>>>> +     * @return BackendListenerClient reference.
>>>> +     */
>>>> +    static BackendListenerClient createBackendListenerClientImp
>>>> l(Class<?>
>>>> javaClass) {
>>>> +        if (javaClass == null) { // failed to initialise the class
>>>> +            return new ErrorBackendListenerClient();
>>>> +        }
>>>> +        BackendListenerClient client;
>>>> +        try {
>>>> +            client = (BackendListenerClient) javaClass.newInstance();
>>>> +        } catch (Exception e) {
>>>> +            log.error("Exception creating: " + javaClass, e);
>>>> +            client = new ErrorBackendListenerClient();
>>>> +        }
>>>> +        return client;
>>>>
>>>>  I would return newInstance() in try Block and return new Error.. in
>>> catch
>>> Block. javaClass -> clientClass
>>>
>>>  +    }
>>>> +
>>>> +    /**
>>>> +     * Method called at the end of the test. This is called only on one
>>>> instance
>>>> +     * of BackendListener. This method will loop through all of the
>>>> other
>>>> +     * BackendListenerClients which have been registered (automatically
>>>> in the
>>>> +     * constructor) and notify them that the test has ended, allowing
>>>> the
>>>> +     * BackendListenerClients to cleanup.
>>>> +     */
>>>> +    @Override
>>>> +    public void testEnded() {
>>>> +        try {
>>>> +            queue.put(FINAL_EVENT);
>>>> +        } catch (Exception ex) {
>>>> +            log.warn("testEnded() with exception:"+ex.getMessage(),
>>>> ex);
>>>> +        }
>>>> +        if (queueWaits > 0) {
>>>> +            log.warn("QueueWaits: "+queueWaits+"; QueueWaitTime:
>>>> "+queueWaitTime+" (nanoseconds), you may need to increase queue
>>>> capacity,
>>>> see property 'backend_queue_capacity'");
>>>> +        }
>>>> +        synchronized (TEAR_DOWN_SET) {
>>>> +            for (BackendListener backendListener : TEAR_DOWN_SET) {
>>>> +                BackendListenerClient client = backendListener.
>>>> backendListenerClient;
>>>> +                if (client != null) {
>>>> +                    try {
>>>> +                        client.teardownTest(backendListener.context);
>>>> +                    } catch (Exception e) {
>>>> +                        throw new java.lang.
>>>> IllegalStateException("Failed
>>>> calling teardownTest", e);
>>>>
>>>>  If we throw an exception here, we will not try every client.
>>>
>>>  +                    }
>>>> +                }
>>>> +            }
>>>> +            TEAR_DOWN_SET.clear();
>>>> +        }
>>>> +    }
>>>> +
>>>> +    /* Implements TestStateListener.testEnded(String) */
>>>> +    @Override
>>>> +    public void testEnded(String host) {
>>>> +        testEnded();
>>>> +    }
>>>> +
>>>> +    /**
>>>> +     * A {@link BackendListenerClient} implementation used for error
>>>> handling. If an
>>>> +     * error occurs while creating the real BackendListenerClient
>>>> object, it is
>>>> +     * replaced with an instance of this class. Each time a sample
>>>> occurs with
>>>> +     * this class, the result is marked as a failure so the user can
>>>> see
>>>> that
>>>> +     * the test failed.
>>>> +     */
>>>> +    static class ErrorBackendListenerClient extends
>>>> AbstractBackendListenerClient {
>>>> +        /**
>>>> +         * Return SampleResult with data on error.
>>>> +         *
>>>> +         * @see BackendListenerClient#runTest(JavaSamplerContext)
>>>> +         */
>>>> +        @Override
>>>> +        public void handleSampleResults(List<SampleResult>
>>>> sampleResults, BackendListenerContext context) {
>>>> +            log.warn("ErrorBackendListenerClient#handleSampleResult
>>>> called, noop");
>>>> +            Thread.yield();
>>>> +        }
>>>> +    }
>>>> +
>>>> +    /* (non-Javadoc)
>>>> +     * @see org.apache.jmeter.samplers.SampleListener#sampleStarted(
>>>> org.apache.jmeter.samplers.SampleEvent)
>>>> +     */
>>>> +    @Override
>>>> +    public void sampleStarted(SampleEvent e) {
>>>> +        // NOOP
>>>> +
>>>> +    }
>>>> +
>>>> +    /* (non-Javadoc)
>>>> +     * @see org.apache.jmeter.samplers.SampleListener#sampleStopped(
>>>> org.apache.jmeter.samplers.SampleEvent)
>>>> +     */
>>>> +    @Override
>>>> +    public void sampleStopped(SampleEvent e) {
>>>> +        // NOOP
>>>> +
>>>> +    }
>>>> +
>>>> +    /**
>>>> +     * Set the arguments (parameters) for the BackendListenerClient to
>>>> be executed
>>>> +     * with.
>>>> +     *
>>>> +     * @param args
>>>> +     *            the new arguments. These replace any existing
>>>> arguments.
>>>> +     */
>>>> +    public void setArguments(Arguments args) {
>>>> +        setProperty(new TestElementProperty(ARGUMENTS, args));
>>>> +    }
>>>> +
>>>> +    /**
>>>> +     * Get the arguments (parameters) for the BackendListenerClient to
>>>> be executed
>>>> +     * with.
>>>> +     *
>>>> +     * @return the arguments
>>>> +     */
>>>> +    public Arguments getArguments() {
>>>> +        return (Arguments) getProperty(ARGUMENTS).getObjectValue();
>>>> +    }
>>>> +
>>>> +    /**
>>>> +     * Sets the Classname of the BackendListenerClient object
>>>> +     *
>>>> +     * @param classname
>>>> +     *            the new Classname value
>>>> +     */
>>>> +    public void setClassname(String classname) {
>>>> +        setProperty(CLASSNAME, classname);
>>>> +    }
>>>> +
>>>> +    /**
>>>> +     * Gets the Classname of the BackendListenerClient object
>>>> +     *
>>>> +     * @return the Classname value
>>>> +     */
>>>> +    public String getClassname() {
>>>> +        return getPropertyAsString(CLASSNAME);
>>>> +    }
>>>> +
>>>> +    /**
>>>> +     * Sets the queue size
>>>> +     *
>>>> +     * @param queueSize
>>>> +     *
>>>> +     */
>>>> +    public void setQueueSize(int queueSize) {
>>>> +        setProperty(QUEUE_SIZE, queueSize, DEFAULT_QUEUE_SIZE);
>>>> +    }
>>>> +
>>>> +    /**
>>>> +     * Gets the queue size
>>>> +     *
>>>> +     * @return int queueSize
>>>> +     */
>>>> +    public int getQueueSize() {
>>>> +        return getPropertyAsInt(QUEUE_SIZE, DEFAULT_QUEUE_SIZE);
>>>> +    }
>>>> +}
>>>>
>>>> Propchange: jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>>>> backend/BackendListener.java
>>>> ------------------------------------------------------------
>>>> ------------------
>>>>       svn:mime-type = text/plain
>>>>
>>>> Added: jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>>>> backend/BackendListenerClient.java
>>>> URL: http://svn.apache.org/viewvc/jmeter/trunk/src/components/
>>>> org/apache/jmeter/visualizers/backend/BackendListenerClient.
>>>> java?rev=1641081&view=auto
>>>> ============================================================
>>>> ==================
>>>> --- jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>>>> backend/BackendListenerClient.java (added)
>>>> +++ jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>>>> backend/BackendListenerClient.java Sat Nov 22 15:36:37 2014
>>>> @@ -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.jmeter.visualizers.backend;
>>>> +
>>>> +import java.util.List;
>>>> +
>>>> +import org.apache.jmeter.config.Arguments;
>>>> +import org.apache.jmeter.samplers.SampleResult;
>>>> +
>>>> +/**
>>>> + * This interface defines the interactions between the BackendListener
>>>> and external
>>>> + * Java programs which can be executed by JMeter. Any Java class which
>>>> wants to
>>>> + * be executed as a JMeter test must implement this interface (either
>>>> directly
>>>> + * or indirectly through AbstractBackendListenerClient).
>>>> + * <p>
>>>> + * JMeter will create one instance of a BackendListenerClient
>>>> implementation for
>>>> + * each user/thread in the test. Additional instances may be created
>>>> for
>>>> + * internal use by JMeter (for example, to find out what parameters are
>>>> + * supported by the client).
>>>> + * <p>
>>>> + * When the test is started, setupTest() will be called on each
>>>> thread's
>>>> + * BackendListenerClient instance to initialize the client. Then
>>>> handleSampleResult() will be
>>>> + * called for each SampleResult notification. Finally, teardownTest()
>>>> will be called
>>>> + * to allow the client to do any necessary clean-up.
>>>> + * <p>
>>>> + * The JMeter BackendListener GUI allows a list of parameters to be
>>>> defined for the
>>>> + * test. These are passed to the various test methods through the
>>>> + * {@link BackendListenerContext}. A list of default parameters can be
>>>> defined
>>>> + * through the getDefaultParameters() method. These parameters and any
>>>> default
>>>> + * values associated with them will be shown in the GUI. Users can add
>>>> other
>>>> + * parameters as well.
>>>> + * <p>
>>>> + * When possible, Listeners should extend {@link
>>>> AbstractBackendListenerClient
>>>> + * AbstractBackendListenerClient} rather than implementing
>>>> BackendListenerClient
>>>> + * directly. This should protect your tests from future changes to the
>>>> + * interface. While it may be necessary to make changes to the
>>>> BackendListenerClient
>>>> + * interface from time to time (therefore requiring changes to any
>>>> + * implementations of this interface), we intend to make this abstract
>>>> class
>>>> + * provide reasonable default implementations of any new methods so
>>>> that
>>>> + * subclasses do not necessarily need to be updated for new versions.
>>>> + * Implementing BackendListenerClient directly will continue to be
>>>> supported for
>>>> + * cases where extending this class is not possible (for example, when
>>>> the
>>>> + * client class is already a subclass of some other class).
>>>> + *
>>>> + * @since 2.13
>>>> + */
>>>> +public interface BackendListenerClient {
>>>> +    /**
>>>> +     * Do any initialization required by this client. It is generally
>>>> +     * recommended to do any initialization such as getting parameter
>>>> values in
>>>> +     * the setupTest method rather than the runTest method in order to
>>>> add as
>>>> +     * little overhead as possible to the test.
>>>> +     *
>>>> +     * @param context
>>>> +     *            the context to run with. This provides access to
>>>> +     *            initialization parameters.
>>>> +     */
>>>> +    void setupTest(BackendListenerContext context) throws Exception;
>>>> +
>>>> +    /**
>>>> +     * Perform a single sample for each iteration. This method returns
>>>> a
>>>> +     * <code>SampleResult</code> object. <code>SampleResult</code> has
>>>> many
>>>> +     * fields which can be used. At a minimum, the test should use
>>>> +     * <code>SampleResult.sampleStart</code> and
>>>> +     * <code>SampleResult.sampleEnd</code>to set the time that the
>>>> test
>>>>
>>>>  use {@link..} instead of <code>..?
>>>
>>>  +     * required to execute. It is also a good idea to set the
>>>> sampleLabel and
>>>> +     * the successful flag.
>>>> +     *
>>>> +     * @see org.apache.jmeter.samplers.SampleResult#sampleStart()
>>>> +     * @see org.apache.jmeter.samplers.SampleResult#sampleEnd()
>>>> +     * @see org.apache.jmeter.samplers.SampleResult#setSuccessful(
>>>> boolean)
>>>> +     * @see org.apache.jmeter.samplers.SampleResult#setSampleLabel(
>>>> String)
>>>> +     *
>>>> +     * @param context
>>>> +     *            the context to run with. This provides access to
>>>> +     *            initialization parameters.
>>>> +     *
>>>> +     */
>>>> +    void handleSampleResults(List<SampleResult> sampleResults,
>>>> BackendListenerContext context);
>>>> +
>>>> +    /**
>>>> +     * Do any clean-up required by this test at the end of a test run.
>>>> +     *
>>>> +     * @param context
>>>> +     *            the context to run with. This provides access to
>>>> +     *            initialization parameters.
>>>> +     */
>>>> +    void teardownTest(BackendListenerContext context) throws
>>>> Exception;
>>>> +
>>>> +    /**
>>>> +     * Provide a list of parameters which this test supports. Any
>>>> parameter
>>>> +     * names and associated values returned by this method will appear
>>>> in the
>>>> +     * GUI by default so the user doesn't have to remember the exact
>>>> names. The
>>>> +     * user can add other parameters which are not listed here. If this
>>>> method
>>>> +     * returns null then no parameters will be listed. If the value for
>>>> some
>>>> +     * parameter is null then that parameter will be listed in the GUI
>>>> with an
>>>> +     * empty value.
>>>> +     *
>>>> +     * @return a specification of the parameters used by this test
>>>> which
>>>> should
>>>> +     *         be listed in the GUI, or null if no parameters should be
>>>> listed.
>>>> +     */
>>>> +    Arguments getDefaultParameters();
>>>> +
>>>> +    /**
>>>> +     *
>>>> +     * @param context
>>>> +     * @param result
>>>> +     * @return
>>>> +     */
>>>> +    SampleResult createSampleResult(
>>>> +            BackendListenerContext context, SampleResult result);
>>>> +}
>>>>
>>>> Propchange: jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>>>> backend/BackendListenerClient.java
>>>> ------------------------------------------------------------
>>>> ------------------
>>>>       svn:mime-type = text/plain
>>>>
>>>> Added: jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>>>> backend/
>>>> BackendListenerContext.java
>>>> URL: http://svn.apache.org/viewvc/jmeter/trunk/src/components/
>>>> org/apache/jmeter/visualizers/backend/BackendListenerContext.java?
>>>> rev=1641081&view=auto
>>>> ============================================================
>>>> ==================
>>>> --- jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/
>>>> BackendListenerContext.java
>>>> (added)
>>>> +++ jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/
>>>> BackendListenerContext.java
>>>> Sat Nov 22 15:36:37 2014
>>>> @@ -0,0 +1,237 @@
>>>> +/*
>>>> +
>>>> + * 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.jmeter.visualizers.backend;
>>>> +
>>>> +import java.util.Iterator;
>>>> +import java.util.Map;
>>>> +
>>>> +import org.apache.jmeter.config.Arguments;
>>>> +import org.apache.jorphan.logging.LoggingManager;
>>>> +import org.apache.log.Logger;
>>>> +
>>>> +/**
>>>> + * BackendListenerContext is used to provide context information to a
>>>> + * BackendListenerClient implementation. This currently consists of the
>>>> + * initialization parameters which were specified in the GUI.
>>>> + * @since 2.13
>>>> + */
>>>> +public class BackendListenerContext {
>>>> +    /*
>>>> +     * Implementation notes:
>>>> +     *
>>>> +     * All of the methods in this class are currently read-only. If
>>>> update
>>>> +     * methods are included in the future, they should be defined so
>>>> that a
>>>> +     * single instance of BackendListenerContext can be associated with
>>>> each thread.
>>>> +     * Therefore, no synchronization should be needed. The same
>>>> instance
>>>> should
>>>> +     * be used for the call to setupTest, all calls to runTest, and the
>>>> call to
>>>> +     * teardownTest.
>>>> +     */
>>>> +
>>>> +    /** Logging */
>>>> +    private static final Logger log = LoggingManager.
>>>> getLoggerForClass();
>>>>
>>>>  See naming comments for logger above
>>>
>>>  +
>>>> +    /**
>>>> +     * Map containing the initialization parameters for the
>>>> BackendListenerClient.
>>>> +     */
>>>> +    private final Map<String, String> params;
>>>> +
>>>> +    /**
>>>> +     *
>>>> +     * @param args
>>>> +     *            the initialization parameters.
>>>> +     */
>>>> +    public BackendListenerContext(Arguments args) {
>>>> +        this.params = args.getArgumentsAsMap();
>>>> +    }
>>>> +
>>>> +    /**
>>>> +     * Determine whether or not a value has been specified for the
>>>> parameter
>>>> +     * with this name.
>>>> +     *
>>>> +     * @param name
>>>> +     *            the name of the parameter to test
>>>> +     * @return true if the parameter value has been specified, false
>>>> otherwise.
>>>> +     */
>>>> +    public boolean containsParameter(String name) {
>>>>
>>>>  hasParameter instead of containsParameter?
>>>
>>>  +        return params.containsKey(name);
>>>> +    }
>>>> +
>>>> +    /**
>>>> +     * Get an iterator of the parameter names. Each entry in the
>>>> Iterator is a
>>>> +     * String.
>>>> +     *
>>>> +     * @return an Iterator of Strings listing the names of the
>>>> parameters which
>>>> +     *         have been specified for this test.
>>>> +     */
>>>> +    public Iterator<String> getParameterNamesIterator() {
>>>> +        return params.keySet().iterator();
>>>> +    }
>>>> +
>>>> +    /**
>>>> +     * Get the value of a specific parameter as a String, or null if
>>>> the
>>>> value
>>>> +     * was not specified.
>>>> +     *
>>>> +     * @param name
>>>> +     *            the name of the parameter whose value should be
>>>> retrieved
>>>> +     * @return the value of the parameter, or null if the value was not
>>>> +     *         specified
>>>> +     */
>>>> +    public String getParameter(String name) {
>>>> +        return getParameter(name, null);
>>>> +    }
>>>> +
>>>> +    /**
>>>> +     * Get the value of a specified parameter as a String, or return
>>>> the
>>>> +     * specified default value if the value was not specified.
>>>> +     *
>>>> +     * @param name
>>>> +     *            the name of the parameter whose value should be
>>>> retrieved
>>>> +     * @param defaultValue
>>>> +     *            the default value to return if the value of this
>>>> parameter was
>>>> +     *            not specified
>>>> +     * @return the value of the parameter, or the default value if the
>>>> parameter
>>>> +     *         was not specified
>>>> +     */
>>>> +    public String getParameter(String name, String defaultValue) {
>>>> +        if (params == null || !params.containsKey(name)) {
>>>> +            return defaultValue;
>>>> +        }
>>>> +        return params.get(name);
>>>> +    }
>>>> +
>>>> +    /**
>>>> +     * Get the value of a specified parameter as an integer. An
>>>> exception will
>>>> +     * be thrown if the parameter is not specified or if it is not an
>>>> integer.
>>>> +     * The value may be specified in decimal, hexadecimal, or octal, as
>>>> defined
>>>> +     * by Integer.decode().
>>>> +     *
>>>> +     * @param name
>>>> +     *            the name of the parameter whose value should be
>>>> retrieved
>>>> +     * @return the value of the parameter
>>>> +     *
>>>> +     * @throws NumberFormatException
>>>> +     *             if the parameter is not specified or is not an
>>>> integer
>>>> +     *
>>>> +     * @see java.lang.Integer#decode(java.lang.String)
>>>> +     */
>>>> +    public int getIntParameter(String name) throws
>>>> NumberFormatException
>>>> {
>>>> +        if (params == null || !params.containsKey(name)) {
>>>> +            throw new NumberFormatException("No value for parameter
>>>> named '" + name + "'.");
>>>>
>>>>  I would expect an IllegalArgumentException, if no parameter of that
>>> name
>>> is found
>>>
>>>  +        }
>>>> +
>>>> +        return Integer.decode(params.get(name)).intValue();
>>>> +    }
>>>> +
>>>> +    /**
>>>> +     * Get the value of a specified parameter as an integer, or return
>>>> the
>>>> +     * specified default value if the value was not specified or is not
>>>> an
>>>> +     * integer. A warning will be logged if the value is not an
>>>> integer.
>>>> The
>>>> +     * value may be specified in decimal, hexadecimal, or octal, as
>>>> defined by
>>>> +     * Integer.decode().
>>>> +     *
>>>> +     * @param name
>>>> +     *            the name of the parameter whose value should be
>>>> retrieved
>>>> +     * @param defaultValue
>>>> +     *            the default value to return if the value of this
>>>> parameter was
>>>> +     *            not specified
>>>> +     * @return the value of the parameter, or the default value if the
>>>> parameter
>>>> +     *         was not specified
>>>> +     *
>>>> +     * @see java.lang.Integer#decode(java.lang.String)
>>>> +     */
>>>> +    public int getIntParameter(String name, int defaultValue) {
>>>> +        if (params == null || !params.containsKey(name)) {
>>>> +            return defaultValue;
>>>> +        }
>>>> +
>>>> +        try {
>>>> +            return Integer.decode(params.get(name)).intValue();
>>>> +        } catch (NumberFormatException e) {
>>>> +            log.warn("Value for parameter '" + name + "' not an
>>>> integer:
>>>> '" + params.get(name) + "'.  Using default: '"
>>>> +                    + defaultValue + "'.", e);
>>>> +            return defaultValue;
>>>> +        }
>>>> +    }
>>>> +
>>>> +    /**
>>>> +     * Get the value of a specified parameter as a long. An exception
>>>> will be
>>>> +     * thrown if the parameter is not specified or if it is not a long.
>>>> The
>>>> +     * value may be specified in decimal, hexadecimal, or octal, as
>>>> defined by
>>>> +     * Long.decode().
>>>> +     *
>>>> +     * @param name
>>>> +     *            the name of the parameter whose value should be
>>>> retrieved
>>>> +     * @return the value of the parameter
>>>> +     *
>>>> +     * @throws NumberFormatException
>>>> +     *             if the parameter is not specified or is not a long
>>>> +     *
>>>> +     * @see Long#decode(String)
>>>> +     */
>>>> +    public long getLongParameter(String name) throws
>>>> NumberFormatException {
>>>> +        if (params == null || !params.containsKey(name)) {
>>>> +            throw new NumberFormatException("No value for parameter
>>>> named '" + name + "'.");
>>>> +        }
>>>> +
>>>> +        return Long.decode(params.get(name)).longValue();
>>>> +    }
>>>> +
>>>> +    /**
>>>> +     * Get the value of a specified parameter as along, or return the
>>>> specified
>>>> +     * default value if the value was not specified or is not a long. A
>>>> warning
>>>> +     * will be logged if the value is not a long. The value may be
>>>> specified in
>>>> +     * decimal, hexadecimal, or octal, as defined by Long.decode().
>>>> +     *
>>>> +     * @param name
>>>> +     *            the name of the parameter whose value should be
>>>> retrieved
>>>> +     * @param defaultValue
>>>> +     *            the default value to return if the value of this
>>>> parameter was
>>>> +     *            not specified
>>>> +     * @return the value of the parameter, or the default value if the
>>>> parameter
>>>> +     *         was not specified
>>>> +     *
>>>> +     * @see Long#decode(String)
>>>> +     */
>>>> +    public long getLongParameter(String name, long defaultValue) {
>>>> +        if (params == null || !params.containsKey(name)) {
>>>> +            return defaultValue;
>>>> +        }
>>>> +        try {
>>>> +            return Long.decode(params.get(name)).longValue();
>>>> +        } catch (NumberFormatException e) {
>>>> +            log.warn("Value for parameter '" + name + "' not a long: '"
>>>> + params.get(name) + "'.  Using default: '"
>>>> +                    + defaultValue + "'.", e);
>>>> +            return defaultValue;
>>>> +        }
>>>> +    }
>>>> +
>>>> +    /**
>>>> +     *
>>>> +     * @param name
>>>> +     * @param defaultValue
>>>> +     * @return
>>>>
>>>>  No javadoc? Again three warnings more :)
>>>
>>>  +     */
>>>> +    public boolean getBooleanParameter(String name, boolean
>>>> defaultValue) {
>>>> +        if (params == null || !params.containsKey(name)) {
>>>> +            return defaultValue;
>>>> +        }
>>>> +        return Boolean.valueOf(params.get(name));
>>>> +    }
>>>> +}
>>>>
>>>> Propchange: jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>>>> backend/BackendListenerContext.java
>>>> ------------------------------------------------------------
>>>> ------------------
>>>>       svn:mime-type = text/plain
>>>>
>>>> Added: jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>>>> backend/BackendListenerGui.java
>>>> URL: http://svn.apache.org/viewvc/jmeter/trunk/src/components/
>>>> org/apache/jmeter/visualizers/backend/BackendListenerGui.
>>>> java?rev=1641081&view=auto
>>>> ============================================================
>>>> ==================
>>>> --- jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>>>> backend/BackendListenerGui.java (added)
>>>> +++ jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>>>> backend/BackendListenerGui.java Sat Nov 22 15:36:37 2014
>>>> @@ -0,0 +1,282 @@
>>>> +/*
>>>> + * 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.jmeter.visualizers.backend;
>>>> +
>>>> +import java.awt.BorderLayout;
>>>> +import java.awt.event.ActionEvent;
>>>> +import java.awt.event.ActionListener;
>>>> +import java.util.ArrayList;
>>>> +import java.util.HashSet;
>>>> +import java.util.List;
>>>> +import java.util.Map;
>>>> +import java.util.Set;
>>>> +
>>>> +import javax.swing.ComboBoxModel;
>>>> +import javax.swing.JComboBox;
>>>> +import javax.swing.JLabel;
>>>> +import javax.swing.JPanel;
>>>> +import javax.swing.JTextField;
>>>> +
>>>> +import org.apache.jmeter.config.Argument;
>>>> +import org.apache.jmeter.config.Arguments;
>>>> +import org.apache.jmeter.config.gui.ArgumentsPanel;
>>>> +import org.apache.jmeter.gui.util.HorizontalPanel;
>>>> +import org.apache.jmeter.testelement.TestElement;
>>>> +import org.apache.jmeter.testelement.property.PropertyIterator;
>>>> +import org.apache.jmeter.util.JMeterUtils;
>>>> +import org.apache.jmeter.visualizers.gui.AbstractListenerGui;
>>>> +import org.apache.jorphan.logging.LoggingManager;
>>>> +import org.apache.jorphan.reflect.ClassFinder;
>>>> +import org.apache.log.Logger;
>>>> +
>>>> +/**
>>>> + * The <code>BackendListenerGui</code> class provides the user
>>>> interface for the
>>>> + * {@link BackendListener} object.
>>>> + * @since 2.13
>>>> + */
>>>> +public class BackendListenerGui extends AbstractListenerGui implements
>>>> ActionListener {
>>>> +
>>>> +    /**
>>>> +     *
>>>> +     */
>>>> +    private static final long serialVersionUID = 4331668988576438604L;
>>>> +
>>>> +    /** Logging */
>>>> +    private static final Logger log = LoggingManager.
>>>> getLoggerForClass();
>>>> +
>>>> +    /** A combo box allowing the user to choose a backend class. */
>>>> +    private JComboBox classnameCombo;
>>>> +
>>>> +    /**
>>>> +     * A field allowing the user to specify the size of Queue
>>>> +     */
>>>> +    private JTextField queueSize;
>>>> +
>>>> +    /** A panel allowing the user to set arguments for this test. */
>>>> +    private ArgumentsPanel argsPanel;
>>>> +
>>>> +    /**
>>>> +     * Create a new BackendListenerGui as a standalone component.
>>>> +     */
>>>> +    public BackendListenerGui() {
>>>> +        super();
>>>> +        init();
>>>> +    }
>>>> +
>>>> +
>>>> +    /** {@inheritDoc} */
>>>> +    @Override
>>>> +    public String getLabelResource() {
>>>> +        return "backend_listener"; // $NON-NLS-1$
>>>> +    }
>>>> +
>>>> +    /**
>>>> +     * Initialize the GUI components and layout.
>>>> +     */
>>>> +    private void init() {// called from ctor, so must not be
>>>> overridable
>>>> +        setLayout(new BorderLayout(0, 5));
>>>> +
>>>> +        setBorder(makeBorder());
>>>> +        add(makeTitlePanel(), BorderLayout.NORTH);
>>>> +
>>>> +        JPanel classnameRequestPanel = new JPanel(new BorderLayout(0,
>>>> 5));
>>>> +        classnameRequestPanel.add(createClassnamePanel(),
>>>> BorderLayout.NORTH);
>>>> +        classnameRequestPanel.add(createParameterPanel(),
>>>> BorderLayout.CENTER);
>>>> +
>>>> +        add(classnameRequestPanel, BorderLayout.CENTER);
>>>> +    }
>>>> +
>>>> +    /**
>>>> +     * Create a panel with GUI components allowing the user to select a
>>>> test
>>>> +     * class.
>>>> +     *
>>>> +     * @return a panel containing the relevant components
>>>> +     */
>>>> +    private JPanel createClassnamePanel() {
>>>> +        List<String> possibleClasses = new ArrayList<String>();
>>>> +
>>>> +        try {
>>>> +            // Find all the classes which implement the
>>>> BackendListenerClient
>>>> +            // interface.
>>>> +            possibleClasses = ClassFinder.findClassesThatExtend(
>>>> JMeterUtils.getSearchPaths(),
>>>> +                    new Class[] { BackendListenerClient.class });
>>>> +
>>>> +            // Remove the BackendListener class from the list since it
>>>> only
>>>>
>>>>  ErrorBackendListener
>>>
>>>  +            // implements the interface for error conditions.
>>>> +
>>>> +            possibleClasses.remove(BackendListener.class.getName() +
>>>> "$ErrorBackendListenerClient");
>>>> +        } catch (Exception e) {
>>>> +            log.debug("Exception getting interfaces.", e);
>>>> +        }
>>>> +
>>>> +        JLabel label = new JLabel(JMeterUtils.getResString("backend_
>>>> listener_classname"));
>>>> // $NON-NLS-1$
>>>> +
>>>> +        classnameCombo = new JComboBox(possibleClasses.toArray());
>>>> +        classnameCombo.addActionListener(this);
>>>> +        classnameCombo.setEditable(false);
>>>> +        label.setLabelFor(classnameCombo);
>>>> +
>>>> +        HorizontalPanel classNamePanel = new HorizontalPanel();
>>>> +        classNamePanel.add(label);
>>>> +        classNamePanel.add(classnameCombo);
>>>> +
>>>> +        queueSize = new JTextField("", 5);
>>>> +        queueSize.setName("Queue Size"); //$NON-NLS-1$
>>>> +        JLabel queueSizeLabel = new JLabel(JMeterUtils.
>>>> getResString("backend_listener_queue_size")); // $NON-NLS-1$
>>>> +        queueSizeLabel.setLabelFor(queueSize);
>>>> +        HorizontalPanel queueSizePanel = new HorizontalPanel();
>>>> +        queueSizePanel.add(queueSizeLabel, BorderLayout.WEST);
>>>> +        queueSizePanel.add(queueSize);
>>>> +
>>>> +        JPanel panel = new JPanel(new BorderLayout(0, 5));
>>>> +        panel.add(classNamePanel, BorderLayout.NORTH);
>>>> +        panel.add(queueSizePanel, BorderLayout.CENTER);
>>>> +        return panel;
>>>> +    }
>>>> +
>>>> +    /**
>>>> +     * Handle action events for this component. This method currently
>>>> handles
>>>> +     * events for the classname combo box.
>>>> +     *
>>>> +     * @param evt
>>>>
>>>>  I would spend the few extra characters to make it event instead of evt
>>>
>>>  +     *            the ActionEvent to be handled
>>>> +     */
>>>> +    @Override
>>>> +    public void actionPerformed(ActionEvent evt) {
>>>> +        if (evt.getSource() == classnameCombo) {
>>>> +            String className = ((String) classnameCombo.
>>>> getSelectedItem()).trim();
>>>> +            try {
>>>> +                BackendListenerClient client = (BackendListenerClient)
>>>> Class.forName(className, true,
>>>> +                        Thread.currentThread().
>>>> getContextClassLoader()).
>>>> newInstance();
>>>> +
>>>> +                Arguments currArgs = new Arguments();
>>>> +                argsPanel.modifyTestElement(currArgs);
>>>> +                Map<String, String> currArgsMap =
>>>> currArgs.getArgumentsAsMap();
>>>> +
>>>> +                Arguments newArgs = new Arguments();
>>>> +                Arguments testParams = null;
>>>> +                try {
>>>> +                    testParams = client.getDefaultParameters();
>>>> +                } catch (AbstractMethodError e) {
>>>> +                    log.warn("BackendListenerClient doesn't implement
>>>> "
>>>> +                            + "getDefaultParameters.  Default
>>>> parameters
>>>> won't "
>>>> +                            + "be shown.  Please update your client
>>>> class: " + className);
>>>> +                }
>>>> +
>>>> +                if (testParams != null) {
>>>> +                    PropertyIterator i = testParams.getArguments().
>>>> iterator();
>>>>
>>>>  I would try a for loop instead of explicitly using an iterator
>>>
>>>  +                    while (i.hasNext()) {
>>>> +                        Argument arg = (Argument)
>>>> i.next().getObjectValue();
>>>> +                        String name = arg.getName();
>>>> +                        String value = arg.getValue();
>>>> +
>>>> +                        // If a user has set parameters in one test,
>>>> and
>>>> then
>>>> +                        // selects a different test which supports the
>>>> same
>>>> +                        // parameters, those parameters should have the
>>>> same
>>>> +                        // values that they did in the original test.
>>>> +                        if (currArgsMap.containsKey(name)) {
>>>> +                            String newVal = currArgsMap.get(name);
>>>> +                            if (newVal != null && newVal.length() > 0)
>>>> {
>>>> +                                value = newVal;
>>>> +                            }
>>>> +                        }
>>>> +                        newArgs.addArgument(name, value);
>>>> +                    }
>>>> +                }
>>>> +
>>>> +                argsPanel.configure(newArgs);
>>>> +            } catch (Exception e) {
>>>> +                log.error("Error getting argument list for " +
>>>> className, e);
>>>> +            }
>>>> +        }
>>>> +    }
>>>> +
>>>> +    /**
>>>> +     * Create a panel containing components allowing the user to
>>>> provide
>>>> +     * arguments to be passed to the test class instance.
>>>> +     *
>>>> +     * @return a panel containing the relevant components
>>>> +     */
>>>> +    private JPanel createParameterPanel() {
>>>> +        argsPanel = new ArgumentsPanel(JMeterUtils.
>>>> getResString("backend_listener_paramtable")); // $NON-NLS-1$
>>>> +        return argsPanel;
>>>> +    }
>>>> +
>>>> +    /** {@inheritDoc} */
>>>> +    @Override
>>>> +    public void configure(TestElement config) {
>>>> +        super.configure(config);
>>>> +
>>>> +        argsPanel.configure((Arguments) config.getProperty(
>>>> BackendListener.ARGUMENTS).getObjectValue());
>>>> +
>>>> +        String className = config.getPropertyAsString(
>>>> BackendListener.CLASSNAME);
>>>> +        if(checkContainsClassName(classnameCombo.getModel(),
>>>> className)) {
>>>> +            classnameCombo.setSelectedItem(className);
>>>> +        } else {
>>>> +            log.error("Error setting class:'"+className+"' in
>>>> BackendListener: "+getName()+
>>>> +                    ", check for a missing jar in your jmeter
>>>> 'search_paths' and 'plugin_dependency_paths' properties");
>>>> +        }
>>>> +        queueSize.setText(Integer.toString(((BackendListener)
>>>> config).getQueueSize()));
>>>> +    }
>>>> +
>>>> +    /**
>>>> +     * Check combo contains className
>>>> +     * @param model ComboBoxModel
>>>> +     * @param className String class name
>>>> +     * @return boolean
>>>>
>>>>  explain "boolean" or the other params a bit more?
>>>
>>>  +     */
>>>> +    private static final boolean checkContainsClassName(ComboBoxModel
>>>> model, String className) {
>>>> +        int size = model.getSize();
>>>> +        Set<String> set = new HashSet<String>(size);
>>>> +        for (int i = 0; i < size; i++) {
>>>> +            set.add((String)model.getElementAt(i));
>>>> +        }
>>>> +        return set.contains(className);
>>>> +    }
>>>> +
>>>> +    /** {@inheritDoc} */
>>>> +    @Override
>>>> +    public TestElement createTestElement() {
>>>> +        BackendListener config = new BackendListener();
>>>> +        modifyTestElement(config);
>>>> +        return config;
>>>> +    }
>>>> +
>>>> +    /** {@inheritDoc} */
>>>> +    @Override
>>>> +    public void modifyTestElement(TestElement config) {
>>>> +        configureTestElement(config);
>>>> +        BackendListener backendListener = (BackendListener) config;
>>>> +        backendListener.setArguments((Arguments)
>>>> argsPanel.createTestElement());
>>>> +        backendListener.setClassname(String.valueOf(classnameCombo.
>>>> getSelectedItem()));
>>>> +        backendListener.setQueueSize(Integer.parseInt(queueSize.
>>>> getText()));
>>>> +
>>>> +    }
>>>> +
>>>>
>>>

-- 
Cordialement.
Philippe Mouawad.

Re: svn commit: r1641081 - in /jmeter/trunk: ./ bin/ res/maven/ src/components/org/apache/jmeter/visualizers/backend/ src/core/org/apache/jmeter/resources/ src/core/org/apache/jmeter/samplers/ src/core/org/apache/jmeter/save/ xdocs/ xdocs/usermanual/

Posted by Felix Schumacher <fe...@internetallee.de>.
Am 30.11.2014 um 21:32 schrieb Philippe Mouawad:
> On Sun, Nov 30, 2014 at 10:19 AM, Felix Schumacher <
> felix.schumacher@internetallee.de> wrote:
>
>>
>> Am 29. November 2014 21:12:00 MEZ, schrieb Philippe Mouawad <
>> philippe.mouawad@gmail.com>:
>>> Hi Felix
>>>
>>> My answer inline.
>>> Regards
>>>
>>> On Sat, Nov 29, 2014 at 11:51 AM, Felix Schumacher <
>>> felix.schumacher@internetallee.de> wrote:
>>>
>>>> Hello Philippe,
>>>>
>>>> Am Sonntag, den 23.11.2014, 12:22 +0100 schrieb Philippe Mouawad:
>>>>> Thanks a lot for your review which pointed to a synchronisation
>>> issue
>>>> that
>>>>> I fixed, good catch!
>>>>>
>>>>> I think I took all your notes into account, let me know if I forgot
>>>>> something.
>>>> in SamplerMetric you have used a sliding window for the statistics.
>>>> * Should we make the length of the window configurable?
>>>>
>>> Yes but it's a new property and we have a lot :-)
>> But the size of the window depends on the number of samples per time slot.
>> Perhaps it could be dynamically sized?
>>
> You mean it needs to be increased if there is a big number of requests in
> time slot for 1 sample ?
> Please clarfify so that I am sure to understand. For now I made it
> configurable through a property.
Right, if you have only a few requests per second but report the stats 
for that window every second, you will get values from other time slots 
too. On the other hand, if you have a few hundred requests per second, 
you might not even report the correct values for the time slot.

Thus I thought it could be made more dynamic, but if it is configurable, 
that might be enough. I don't think many will actually change it. Would you?
>
>>>
>>>> * Should min/max and minThreads/maxThreads be limited to the sliding
>>>> window, also? At least min and max would be simple to do.
>>>>
>>> Dev team opinion is welcome, maybe it would be better
>>> - min would be percentile(0)
>>> - max would be percentile(100)
>> The stats field has methods to get the minimum and the maximum values. I
>> would take those.
>>
> OK , done
>
>>> for minThreads, maxThreads, how would you do it ?
>> Create another statistical field for the number of threads. Then we could
>> provide correct answers for max/min thread numbers plus
>> mean/average/percentile.
>>
>> For this one, I don't see in fact the use case, as number of threads will
> not vary a lot so in what way do you think it is incorrect ?
> Maybe my question is stupid as I don't see currently the problem but I may
> be wrong. Can you clarify ?
> Thx
If every value I get presented is part of a windowed look into the data, 
I would be surprised to find, that one value is actually computed using 
all data available.

The values could vary for example in ramp up time and they will again 
vary at the end of the test run. (They do at least in my tests)

But if we are not using a windowed representation the max threads will 
never go down and the min threads will probably represent the first time 
slot for the whole test.

Does that make sense?

Felix
>
>
>> Regards
>> Felix
>>
>>>
>>>> Regards
>>>>   Felix
>>>>> Regards
>>>>> Philippe
>>>>>
>>>>> On Sunday, November 23, 2014, Felix Schumacher <
>>>>> felix.schumacher@internetallee.de> wrote:
>>>>>
>>>>>> Hi Phillipe,
>>>>>> Am 22.11.2014 um 19:29 schrieb Philippe Mouawad:
>>>>>>
>>>>>>> Hi Felix,
>>>>>>> As I said in thread, I commited code and will improve, feel free
>>> to
>>>> fix
>>>>>>> javadocs issues on your side.
>>>>>>> I will review your comment.
>>>>>>>
>>>>>>> I have spent many hours if not days on this code and I am aware
>>> it is
>>>> not
>>>>>>> yet fully completed (although tests are promising) but my aim
>>> when
>>>>>>> commiting it was to have feedback and help to finish it.
>>>>>>>
>>>>>> I did not mean to offend you. I can clearly see, that you put a
>>> lot of
>>>>>> effort
>>>>>> in this listener and I will surely try to integrate jmeter into
>>> our
>>>>>> collectd server.
>>>>>>
>>>>>> Regards
>>>>>>   Felix
>>>>>>
>>>>>>> Regards
>>>>>>> Philippe
>>>>>>>
>>>>>>> On Sat, Nov 22, 2014 at 7:21 PM, Felix Schumacher <
>>>>>>> felix.schumacher@internetallee.de> wrote:
>>>>>>>
>>>>>>>   Hello Philippe,
>>>>>>>> I have hidden a few comments inside the cited code.
>>>>>>>> They are mostly around javadoc and naming things.
>>>>>>>>
>>>>>>>> Am 22.11.2014 um 16:36 schrieb pmouawad@apache.org:
>>>>>>>>
>>>>>>>>   Author: pmouawad
>>>>>>>>> Date: Sat Nov 22 15:36:37 2014
>>>>>>>>> New Revision: 1641081
>>>>>>>>>
>>>>>>>>> URL: http://svn.apache.org/r1641081
>>>>>>>>> Log:
>>>>>>>>> Bug 55932 - Create a Async BackendListener to allow easy plug
>>> of new
>>>>>>>>> listener (Graphite, JDBC, Console,...)
>>>>>>>>> Bugzilla Id: 55932
>>>>>>>>>
>>>>>>>>> Added:
>>>>>>>>>
>>> jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>>>>>>>>> backend/
>>>>>>>>>
>>> jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>>>>>>>>> backend/
>>>>>>>>> AbstractBackendListenerClient.java   (with props)
>>>>>>>>>
>>> jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>>>>>>>>> backend/BackendListener.java
>>>>>>>>>    (with props)
>>>>>>>>>
>>> jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>>>>>>>>> backend/BackendListenerClient.java   (with props)
>>>>>>>>>
>>> jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>>>>>>>>> backend/BackendListenerContext.java
>>>>>>>>>    (with props)
>>>>>>>>>
>>> jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>>>>>>>>> backend/BackendListenerGui.java   (with props)
>>>>>>>>>
>>> jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>>>>>>>>> backend/SamplerMetric.java
>>>>>>>>>    (with props)
>>>>>>>>> Modified:
>>>>>>>>>        jmeter/trunk/bin/saveservice.properties
>>>>>>>>>        jmeter/trunk/build.properties
>>>>>>>>>        jmeter/trunk/build.xml
>>>>>>>>>        jmeter/trunk/eclipse.classpath
>>>>>>>>>        jmeter/trunk/res/maven/ApacheJMeter_parent.pom
>>>>>>>>>        jmeter/trunk/src/core/org/apache/jmeter/resources/
>>>>>>>>> messages.properties
>>>>>>>>>        jmeter/trunk/src/core/org/apache/jmeter/resources/
>>>>>>>>> messages_fr.properties
>>>>>>>>>        jmeter/trunk/src/core/org/apache/jmeter/samplers/
>>>>>>>>> SampleResult.java
>>>>>>>>>
>>> jmeter/trunk/src/core/org/apache/jmeter/save/SaveService.java
>>>>>>>>>        jmeter/trunk/xdocs/changes.xml
>>>>>>>>>        jmeter/trunk/xdocs/usermanual/component_reference.xml
>>>>>>>>>
>>>>>>>>> Modified: jmeter/trunk/bin/saveservice.properties
>>>>>>>>> URL:
>>> http://svn.apache.org/viewvc/jmeter/trunk/bin/saveservice.
>>>>>>>>> properties?rev=1641081&r1=1641080&r2=1641081&view=diff
>>>>>>>>> ============================================================
>>>>>>>>> ==================
>>>>>>>>> --- jmeter/trunk/bin/saveservice.properties (original)
>>>>>>>>> +++ jmeter/trunk/bin/saveservice.properties Sat Nov 22
>>> 15:36:37 2014
>>>>>>>>> @@ -53,7 +53,8 @@ _file_version=$Revision$
>>>>>>>>>     # 2.5 = 2.10
>>>>>>>>>     # 2.6 = 2.11
>>>>>>>>>     # 2.7 = 2.12
>>>>>>>>> -_version=2.7
>>>>>>>>> +# 2.8 = 2.13
>>>>>>>>> +_version=2.8
>>>>>>>>>     #
>>>>>>>>>     #
>>>>>>>>>     # Character set encoding used to read and write JMeter XML
>>> files
>>>> and
>>>>>>>>> CSV results
>>>>>>>>> @@ -78,6 +79,8 @@ AssertionVisualizer=org.apache.jmeter.vi
>>>>>>>>>
>>> AuthManager=org.apache.jmeter.protocol.http.control.AuthManager
>>>> Authorization=org.apache.jmeter.protocol.http.control.Authorization
>>>>>>>>>     AuthPanel=org.apache.jmeter.protocol.http.gui.AuthPanel
>>>>>>>>>
>>> +BackendListener=org.apache.jmeter.visualizers.backend.BackendListener
>>>>>>>>> +BackendListenerGui=org.apache.jmeter.visualizers.
>>>>>>>>> backend.BackendListenerGui
>>>>>>>>>     BarChart=org.apache.jmeter.testelement.BarChart
>>>>>>>>>     BarChartGui=org.apache.jmeter.report.gui.BarChartGui
>>>>>>>>>
>>>> BeanShellAssertion=org.apache.jmeter.assertions.BeanShellAssertion
>>>>>>>>> Modified: jmeter/trunk/build.properties
>>>>>>>>> URL:
>>> http://svn.apache.org/viewvc/jmeter/trunk/build.properties?
>>>>>>>>> rev=1641081&r1=1641080&r2=1641081&view=diff
>>>>>>>>> ============================================================
>>>>>>>>> ==================
>>>>>>>>> --- jmeter/trunk/build.properties (original)
>>>>>>>>> +++ jmeter/trunk/build.properties Sat Nov 22 15:36:37 2014
>>>>>>>>> @@ -118,11 +118,21 @@ commons-logging.loc         = ${maven2.r
>>>>>>>>>     #commons-logging.md5         =
>>> E2C390FE739B2550A218262B28F290CE
>>>>>>>>>     commons-logging.md5         =
>>> 040b4b4d8eac886f6b4a2a3bd2f31b00
>>>>>>>>>     +commons-math3.version         = 3.3
>>>>>>>>> +commons-math3.jar             =
>>> commons-math3-${commons-math3.
>>>>>>>>> version}.jar
>>>>>>>>> +commons-math3.loc             = ${maven2.repo}/org/apache/
>>>>>>>>> commons/commons-math3/${commons-math3.version}
>>>>>>>>> +commons-math3.md5             =
>>> 87346cf2772dc2becf106c45e0f63863
>>>>>>>>> +
>>>>>>>>>     commons-net.version         = 3.3
>>>>>>>>>     commons-net.jar             =
>>>> commons-net-${commons-net.version}.jar
>>>>>>>>>     commons-net.loc             = ${maven2.repo}/commons-net/
>>>>>>>>> commons-net/${commons-net.version}
>>>>>>>>>     commons-net.md5             =
>>> c077ca61598e9c21f43f8b6488fbbee9
>>>>>>>>>     +commons-pool2.version         = 2.2
>>>>>>>>> +commons-pool2.jar             =
>>> commons-pool2-${commons-pool2.
>>>>>>>>> version}.jar
>>>>>>>>> +commons-pool2.loc             = ${maven2.repo}/org/apache/
>>>>>>>>> commons/commons-pool2/${commons-pool2.version}
>>>>>>>>> +commons-pool2.md5             =
>>> 51b56c92883812c56fbeb339866ce2df
>>>>>>>>> +
>>>>>>>>>     # dnsjava for DNSCacheManager
>>>>>>>>>     dnsjava.version             = 2.1.6
>>>>>>>>>     dnsjava.jar                 =
>>> dnsjava-${dnsjava.version}.jar
>>>>>>>>> Modified: jmeter/trunk/build.xml
>>>>>>>>> URL: http://svn.apache.org/viewvc/jmeter/trunk/build.xml?rev=
>>>>>>>>> 1641081&r1=1641080&r2=1641081&view=diff
>>>>>>>>> ============================================================
>>>>>>>>> ==================
>>>>>>>>> --- jmeter/trunk/build.xml (original)
>>>>>>>>> +++ jmeter/trunk/build.xml Sat Nov 22 15:36:37 2014
>>>>>>>>> @@ -365,7 +365,9 @@
>>>>>>>>>         <include name="${lib.dir}/${commons-jexl2.jar}"/>
>>>>>>>>>         <include name="${lib.dir}/${commons-lang3.jar}"/>
>>>>>>>>>         <include name="${lib.dir}/${commons-logging.jar}"/>
>>>>>>>>> +    <include name="${lib.dir}/${commons-math3}"/>
>>>>>>>>>         <include name="${lib.dir}/${commons-net.jar}"/>
>>>>>>>>> +    <include name="${lib.dir}/${commons-pool2.jar}"/>
>>>>>>>>>         <include name="${lib.dir}/${dnsjava.jar}"/>
>>>>>>>>>         <include
>>> name="${lib.dir}/${excalibur-datasource.jar}"/>
>>>>>>>>>         <include
>>> name="${lib.dir}/${excalibur-instrument.jar}"/>
>>>>>>>>> @@ -438,8 +440,10 @@
>>>>>>>>>         <pathelement
>>> location="${lib.dir}/${commons-jexl2.jar}"/>
>>>>>>>>>         <pathelement
>>> location="${lib.dir}/${commons-lang3.jar}"/>
>>>>>>>>>         <pathelement
>>> location="${lib.dir}/${commons-logging.jar}"/>
>>>>>>>>> +    <pathelement location="${lib.dir}/${commons-math3.jar}"/>
>>>>>>>>>         <pathelement location="${lib.dir}/${commons-net.jar}"/>
>>>>>>>>> -    <pathelement location="${lib.dir}/${dnsjava.jar}"/>
>>>>>>>>> +       <pathelement
>>> location="${lib.dir}/${commons-pool2.jar}"/>
>>>>>>>>> +       <pathelement location="${lib.dir}/${dnsjava.jar}"/>
>>>>>>>>>         <pathelement
>>>> location="${lib.dir}/${excalibur-datasource.jar}"/>
>>>>>>>>>         <pathelement
>>>> location="${lib.dir}/${excalibur-instrument.jar}"/>
>>>>>>>>>         <pathelement
>>> location="${lib.dir}/${excalibur-logger.jar}"/>
>>>>>>>>> @@ -2909,7 +2913,9 @@ run JMeter unless all the JMeter jars ar
>>>>>>>>>             <process_jarfile jarname="commons-jexl2"/>
>>>>>>>>>             <process_jarfile jarname="commons-lang3"/>
>>>>>>>>>             <process_jarfile jarname="commons-logging"/>
>>>>>>>>> +        <process_jarfile jarname="commons-math3"/>
>>>>>>>>>             <process_jarfile jarname="commons-net"/>
>>>>>>>>> +       <process_jarfile jarname="commons-pool2"/>
>>>>>>>>>             <process_jarfile jarname="dnsjava"/>
>>>>>>>>>             <process_jarfile jarname="excalibur-datasource"/>
>>>>>>>>>             <process_jarfile jarname="excalibur-instrument"/>
>>>>>>>>>
>>>>>>>>> Modified: jmeter/trunk/eclipse.classpath
>>>>>>>>> URL: http://svn.apache.org/viewvc/jmeter/trunk/eclipse.
>>>>>>>>> classpath?rev=1641081&r1=1641080&r2=1641081&view=diff
>>>>>>>>> ============================================================
>>>>>>>>> ==================
>>>>>>>>> --- jmeter/trunk/eclipse.classpath (original)
>>>>>>>>> +++ jmeter/trunk/eclipse.classpath Sat Nov 22 15:36:37 2014
>>>>>>>>> @@ -55,7 +55,9 @@
>>>>>>>>>           <classpathentry kind="lib"
>>>> path="lib/commons-jexl-2.1.1.jar"/>
>>>>>>>>>           <classpathentry kind="lib"
>>> path="lib/commons-lang3-3.3.2.
>>>>>>>>> jar"/>
>>>>>>>>>           <classpathentry kind="lib"
>>> path="lib/commons-logging-1.2.
>>>>>>>>> jar"/>
>>>>>>>>> +    <classpathentry kind="lib"
>>> path="lib/commons-math3-3.3.jar"/>
>>>>>>>>>           <classpathentry kind="lib"
>>> path="lib/commons-net-3.3.jar"/>
>>>>>>>>> +    <classpathentry kind="lib"
>>> path="lib/commons-pool2-2.2.jar"/>
>>>>>>>>>           <classpathentry kind="lib"
>>> path="lib/dnsjava-2.1.6.jar"/>
>>>>>>>>>           <classpathentry kind="lib" path="lib/excalibur-
>>>>>>>>> datasource-2.1.jar"/>
>>>>>>>>>           <classpathentry kind="lib" path="lib/excalibur-
>>>>>>>>> instrument-1.0.jar"/>
>>>>>>>>>
>>>>>>>>> Modified: jmeter/trunk/res/maven/ApacheJMeter_parent.pom
>>>>>>>>> URL: http://svn.apache.org/viewvc/jmeter/trunk/res/maven/
>>>>>>>>>
>>> ApacheJMeter_parent.pom?rev=1641081&r1=1641080&r2=1641081&view=diff
>>>>>>>>> ============================================================
>>>>>>>>> ==================
>>>>>>>>> --- jmeter/trunk/res/maven/ApacheJMeter_parent.pom (original)
>>>>>>>>> +++ jmeter/trunk/res/maven/ApacheJMeter_parent.pom Sat Nov 22
>>>> 15:36:37
>>>>>>>>> 2014
>>>>>>>>> @@ -66,7 +66,9 @@ under the License.
>>>>>>>>>           <commons-jexl2.version>2.1.1</commons-jexl2.version>
>>>>>>>>>           <commons-lang3.version>3.3.2</commons-lang3.version>
>>>>>>>>>
>>> <commons-logging.version>1.2</commons-logging.version>
>>>>>>>>> +      <commons-math3.version>3.3</commons-math3.version>
>>>>>>>>>           <commons-net.version>3.3</commons-net.version>
>>>>>>>>> +      <commons-pool2.version>2.2</commons-pool2.version>
>>>>>>>>>           <dnsjava.version>2.1.6</dnsjava.version>
>>>>>>>>>
>>> <excalibur-datasource.version>2.1</excalibur-datasource.
>>>>>>>>> version>
>>>>>>>>>
>>> <excalibur-instrument.version>1.0</excalibur-instrument.
>>>>>>>>> version>
>>>>>>>>> @@ -181,11 +183,21 @@ under the License.
>>>>>>>>>             <version>${commons-logging.version}</version>
>>>>>>>>>           </dependency>
>>>>>>>>>           <dependency>
>>>>>>>>> +        <groupId>commons-math3</groupId>
>>>>>>>>> +        <artifactId>commons-math3</artifactId>
>>>>>>>>> +        <version>${commons-math3.version}</version>
>>>>>>>>> +      </dependency>
>>>>>>>>> +      <dependency>
>>>>>>>>>             <groupId>commons-net</groupId>
>>>>>>>>>             <artifactId>commons-net</artifactId>
>>>>>>>>>             <version>${commons-net.version}</version>
>>>>>>>>>           </dependency>
>>>>>>>>>           <dependency>
>>>>>>>>> +        <groupId>commons-pool2</groupId>
>>>>>>>>> +        <artifactId>commons-pool2</artifactId>
>>>>>>>>> +        <version>${commons-pool2.version}</version>
>>>>>>>>> +      </dependency>
>>>>>>>>> +      <dependency>
>>>>>>>>>               <groupId>dnsjava</groupId>
>>>>>>>>>               <artifactId>dnsjava</artifactId>
>>>>>>>>>               <version>${dnsjava.version}</version>
>>>>>>>>>
>>>>>>>>> Added:
>>> jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>>>>>>>>> backend/
>>>>>>>>> AbstractBackendListenerClient.java
>>>>>>>>> URL: http://svn.apache.org/viewvc/jmeter/trunk/src/components/
>>>>>>>>>
>>> org/apache/jmeter/visualizers/backend/AbstractBackendListenerClient.
>>>>>>>>> java?rev=1641081&view=auto
>>>>>>>>> ============================================================
>>>>>>>>> ==================
>>>>>>>>> ---
>>>> jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/
>>>>>>>>> AbstractBackendListenerClient.java (added)
>>>>>>>>> +++
>>>> jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/
>>>>>>>>> AbstractBackendListenerClient.java Sat Nov 22 15:36:37 2014
>>>>>>>>> @@ -0,0 +1,121 @@
>>>>>>>>> +/*
>>>>>>>>> + * 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.jmeter.visualizers.backend;
>>>>>>>>> +
>>>>>>>>> +import java.util.Map;
>>>>>>>>> +import java.util.concurrent.ConcurrentHashMap;
>>>>>>>>> +
>>>>>>>>> +import org.apache.jmeter.config.Arguments;
>>>>>>>>> +import org.apache.jmeter.samplers.SampleResult;
>>>>>>>>> +import org.apache.jorphan.logging.LoggingManager;
>>>>>>>>> +import org.apache.log.Logger;
>>>>>>>>> +
>>>>>>>>> +/**
>>>>>>>>> + * An abstract implementation of the BackendListenerClient
>>>> interface.
>>>>>>>>> This
>>>>>>>>> + * implementation provides default implementations of most of
>>> the
>>>>>>>>> methods in the
>>>>>>>>> + * interface, as well as some convenience methods, in order
>>> to
>>>> simplify
>>>>>>>>> + * development of BackendListenerClient implementations.
>>>>>>>>> + *
>>>>>>>>> + * While it may be necessary to make changes to the
>>>>>>>>> BackendListenerClient interface
>>>>>>>>> + * from time to time (therefore requiring changes to any
>>>>>>>>> implementations
>>>>>>>>> of this
>>>>>>>>> + * interface), we intend to make this abstract class provide
>>>> reasonable
>>>>>>>>> + * implementations of any new methods so that subclasses do
>>> not
>>>>>>>>> necessarily need
>>>>>>>>> + * to be updated for new versions. Therefore, when creating a
>>> new
>>>>>>>>> + * BackendListenerClient implementation, developers are
>>> encouraged
>>>> to
>>>>>>>>> subclass this
>>>>>>>>> + * abstract class rather than implementing the
>>>> BackendListenerClient
>>>>>>>>> interface
>>>>>>>>> + * directly. Implementing BackendListenerClient directly will
>>>> continue
>>>>>>>>> to be
>>>>>>>>> + * supported for cases where extending this class is not
>>> possible
>>>> (for
>>>>>>>>> example,
>>>>>>>>> + * when the client class is already a subclass of some other
>>>> class).
>>>>>>>>> + * <p>
>>>>>>>>> + * The handleSampleResult() method of BackendListenerClient
>>> does
>>>> not
>>>>>>>>> have a default
>>>>>>>>> + * implementation here, so subclasses must define at least
>>> this
>>>> method.
>>>>>>>>> It may
>>>>>>>>> + * be useful to override other methods as well.
>>>>>>>>> + *
>>>>>>>>> + * @see BackendListener#sampleOccurred(org.apache.
>>>>>>>>> jmeter.samplers.SampleEvent)
>>>>>>>>> + * @since 2.13
>>>>>>>>> + */
>>>>>>>>> +public abstract class AbstractBackendListenerClient
>>> implements
>>>>>>>>> BackendListenerClient {
>>>>>>>>> +
>>>>>>>>> +    private static final Logger log = LoggingManager.
>>>>>>>>> getLoggerForClass();
>>>>>>>>>
>>>>>>>>>   In classes further down the logger is stored in variables
>>> named
>>>> LOG and
>>>>>>>> LOGGER, should we use one name?
>>>>>>>> In this class we have a getter for the logger in other classes
>>> not.
>>>> Why?
>>>>>>>>   +
>>>>>>>>> +    private ConcurrentHashMap<String, SamplerMetric>
>>>> metricsPerSampler
>>>>>>>>> =
>>>>>>>>> new ConcurrentHashMap<String, SamplerMetric>();
>>>>>>>>> +
>>>>>>>>> +    /* Implements
>>>> BackendListenerClient.setupTest(JavaSamplerContext)
>>>>>>>>> */
>>>>>>>>> +    @Override
>>>>>>>>> +    public void setupTest(BackendListenerContext context)
>>> throws
>>>>>>>>> Exception {
>>>>>>>>> +        log.debug(getClass().getName() + ": setupTest");
>>>>>>>>> +    }
>>>>>>>>> +
>>>>>>>>> +    /* Implements BackendListenerClient.teardownTest(
>>>>>>>>> JavaSamplerContext)
>>>>>>>>> */
>>>>>>>>> +    @Override
>>>>>>>>> +    public void teardownTest(BackendListenerContext context)
>>> throws
>>>>>>>>> Exception {
>>>>>>>>> +        log.debug(getClass().getName() + ": teardownTest");
>>>>>>>>> +        metricsPerSampler.clear();
>>>>>>>>> +    }
>>>>>>>>> +
>>>>>>>>> +    /* Implements
>>> BackendListenerClient.getDefaultParameters() */
>>>>>>>>> +    @Override
>>>>>>>>> +    public Arguments getDefaultParameters() {
>>>>>>>>> +        return null;
>>>>>>>>> +    }
>>>>>>>>> +
>>>>>>>>> +    /**
>>>>>>>>> +     * Get a Logger instance which can be used by subclasses
>>> to log
>>>>>>>>> information.
>>>>>>>>> +     *
>>>>>>>>> +     * @return a Logger instance which can be used for
>>> logging
>>>>>>>>> +     */
>>>>>>>>> +    protected Logger getLogger() {
>>>>>>>>> +        return log;
>>>>>>>>> +    }
>>>>>>>>> +
>>>>>>>>> +    /* (non-Javadoc)
>>>>>>>>> +     * @see org.apache.jmeter.visualizers.
>>>>>>>>> backend.BackendListenerClient#
>>>>>>>>> createSampleResult(org.apache.jmeter.samplers.SampleResult)
>>>>>>>>> +     */
>>>>>>>>> +    @Override
>>>>>>>>> +    public SampleResult
>>> createSampleResult(BackendListenerContext
>>>>>>>>> context, SampleResult result) {
>>>>>>>>> +        SampleResult sampleResult = (SampleResult)
>>> result.clone();
>>>>>>>>> +        return sampleResult;
>>>>>>>>> +    }
>>>>>>>>> +
>>>>>>>>> +    /**
>>>>>>>>> +     *
>>>>>>>>> +     * @param sampleLabel
>>>>>>>>> +     * @return SamplerMetric
>>>>>>>>>
>>>>>>>>>   No description of the method and the parameters?
>>>>>>>>   +     */
>>>>>>>>> +    protected SamplerMetric getSamplerMetric(String
>>> sampleLabel) {
>>>>>>>>> +        SamplerMetric samplerMetric = metricsPerSampler.get(
>>>>>>>>> sampleLabel);
>>>>>>>>> +        if(samplerMetric == null) {
>>>>>>>>> +            samplerMetric = new SamplerMetric();
>>>>>>>>> +            SamplerMetric oldValue =
>>> metricsPerSampler.putIfAbsent(
>>>>>>>>> sampleLabel,
>>>>>>>>> samplerMetric);
>>>>>>>>> +            if(oldValue != null ){
>>>>>>>>> +                samplerMetric = oldValue;
>>>>>>>>> +            }
>>>>>>>>> +        }
>>>>>>>>> +        return samplerMetric;
>>>>>>>>> +    }
>>>>>>>>> +
>>>>>>>>> +    /**
>>>>>>>>> +     *
>>>>>>>>> +     * @return Map<String, SamplerMetric>
>>>>>>>>>
>>>>>>>>>   No description of the method and usage of forbidden
>>> characters :)
>>>> there
>>>>>>>> are still more than 800 warnings in the javadoc to prune, so
>>> don't
>>>>>>>> introduce new ones, please.
>>>>>>>>
>>>>>>>>   +     */
>>>>>>>>> +    protected Map<String, SamplerMetric>
>>> getMetricsPerSampler() {
>>>>>>>>> +        return metricsPerSampler;
>>>>>>>>> +    }
>>>>>>>>> +
>>>>>>>>> +}
>>>>>>>>>
>>>>>>>>> Propchange:
>>>> jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>>>>>>>>> backend/AbstractBackendListenerClient.java
>>>>>>>>> ------------------------------------------------------------
>>>>>>>>> ------------------
>>>>>>>>>        svn:mime-type = text/plain
>>>>>>>>>
>>>>>>>>> Added:
>>> jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>>>>>>>>> backend/BackendListener.java
>>>>>>>>> URL: http://svn.apache.org/viewvc/jmeter/trunk/src/components/
>>>>>>>>> org/apache/jmeter/visualizers/backend/BackendListener.java?
>>>>>>>>> rev=1641081&view=auto
>>>>>>>>> ============================================================
>>>>>>>>> ==================
>>>>>>>>> --- jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>>>>>>>>> backend/BackendListener.java
>>>>>>>>> (added)
>>>>>>>>> +++ jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>>>>>>>>> backend/BackendListener.java
>>>>>>>>> Sat Nov 22 15:36:37 2014
>>>>>>>>> @@ -0,0 +1,448 @@
>>>>>>>>> +/*
>>>>>>>>> + * 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.jmeter.visualizers.backend;
>>>>>>>>> +
>>>>>>>>> +import java.io.Serializable;
>>>>>>>>> +import java.lang.reflect.Method;
>>>>>>>>> +import java.util.ArrayList;
>>>>>>>>> +import java.util.HashSet;
>>>>>>>>> +import java.util.List;
>>>>>>>>> +import java.util.Set;
>>>>>>>>> +import java.util.concurrent.ArrayBlockingQueue;
>>>>>>>>> +import java.util.concurrent.BlockingQueue;
>>>>>>>>> +import java.util.concurrent.locks.LockSupport;
>>>>>>>>> +
>>>>>>>>> +import org.apache.jmeter.config.Arguments;
>>>>>>>>> +import org.apache.jmeter.engine.util.NoThreadClone;
>>>>>>>>> +import
>>> org.apache.jmeter.protocol.java.sampler.JavaSamplerContext;
>>>>>>>>> +import org.apache.jmeter.samplers.Remoteable;
>>>>>>>>> +import org.apache.jmeter.samplers.SampleEvent;
>>>>>>>>> +import org.apache.jmeter.samplers.SampleListener;
>>>>>>>>> +import org.apache.jmeter.samplers.SampleResult;
>>>>>>>>> +import org.apache.jmeter.testelement.AbstractTestElement;
>>>>>>>>> +import org.apache.jmeter.testelement.TestElement;
>>>>>>>>> +import org.apache.jmeter.testelement.TestStateListener;
>>>>>>>>> +import
>>> org.apache.jmeter.testelement.property.TestElementProperty;
>>>>>>>>> +import org.apache.jorphan.logging.LoggingManager;
>>>>>>>>> +import org.apache.log.Logger;
>>>>>>>>> +
>>>>>>>>> +/**
>>>>>>>>> + * Async Listener that delegates SampleResult handling to
>>>>>>>>> implementations of {@link BackendListenerClient}
>>>>>>>>> + * @since 2.13
>>>>>>>>> + */
>>>>>>>>> +public class BackendListener extends AbstractTestElement
>>>>>>>>> +    implements Serializable, SampleListener,
>>> TestStateListener,
>>>>>>>>> NoThreadClone, Remoteable  {
>>>>>>>>> +
>>>>>>>>> +    /**
>>>>>>>>> +     *
>>>>>>>>> +     */
>>>>>>>>> +    private static final long serialVersionUID =
>>>> 8184103677832024335L;
>>>>>>>>> +
>>>>>>>>> +    private static final Logger log = LoggingManager.
>>>>>>>>> getLoggerForClass();
>>>>>>>>>
>>>>>>>>>   See naming comment of log from above
>>>>>>>>   +
>>>>>>>>> +    /**
>>>>>>>>> +     * Set used to register instances which implement
>>> teardownTest.
>>>>>>>>> +     * This is used so that the BackendListenerClient can be
>>>> notified
>>>>>>>>> when the test ends.
>>>>>>>>> +     */
>>>>>>>>> +    private static final Set<BackendListener> TEAR_DOWN_SET =
>>> new
>>>>>>>>> HashSet<BackendListener>();
>>>>>>>>> +
>>>>>>>>> +    /**
>>>>>>>>> +     * Property key representing the classname of the
>>>>>>>>> BackendListenerClient to user.
>>>>>>>>> +     */
>>>>>>>>> +    public static final String CLASSNAME = "classname";
>>>>>>>>> +
>>>>>>>>> +    /**
>>>>>>>>> +     * Queue size
>>>>>>>>> +     */
>>>>>>>>> +    public static final String QUEUE_SIZE = "QUEUE_SIZE";
>>>>>>>>> +
>>>>>>>>> +    /**
>>>>>>>>> +     * Property key representing the arguments for the
>>>>>>>>> BackendListenerClient.
>>>>>>>>> +     */
>>>>>>>>> +    public static final String ARGUMENTS = "arguments";
>>>>>>>>> +
>>>>>>>>> +    /**
>>>>>>>>> +     * The BackendListenerClient class used by this sampler.
>>>>>>>>> +     * Created by testStarted; copied to cloned instances.
>>>>>>>>> +     */
>>>>>>>>> +    private Class<?> javaClass;
>>>>>>>>>
>>>>>>>>>   Could probably named clientClass instead of javaClass, since
>>> we
>>>> already
>>>>>>>> know it is a java class.
>>>>>>>>
>>>>>>>>   +
>>>>>>>>> +    /**
>>>>>>>>> +     * If true, the BackendListenerClient class implements
>>>>>>>>> teardownTest.
>>>>>>>>> +     * Created by testStarted; copied to cloned instances.
>>>>>>>>> +     */
>>>>>>>>> +    private boolean isToBeRegistered;
>>>>>>>>> +
>>>>>>>>> +    /**
>>>>>>>>> +     * The BackendListenerClient instance
>>>>>>>>> +     */
>>>>>>>>> +    private transient BackendListenerClient
>>> backendListenerClient =
>>>>>>>>> null;
>>>>>>>>> +
>>>>>>>>> +    /**
>>>>>>>>> +     * The JavaSamplerContext instance used by this sampler
>>> to hold
>>>>>>>>> information
>>>>>>>>>
>>>>>>>>>   BackendListenerContext?
>>>>>>>>   +     * related to the test run, such as the parameters
>>> specified
>>>> for
>>>>>>>>> the
>>>>>>>>> sampler
>>>>>>>>> +     * client.
>>>>>>>>> +     */
>>>>>>>>> +    private transient BackendListenerContext context = null;
>>>>>>>>> +
>>>>>>>>> +    private static final int DEFAULT_QUEUE_SIZE = 5000;
>>>>>>>>> +
>>>>>>>>> +    private transient BlockingQueue<SampleResult> queue; //
>>>> created by
>>>>>>>>> server in readResolve method
>>>>>>>>> +
>>>>>>>>> +    private transient long queueWaits; // how many times we
>>> had to
>>>> wait
>>>>>>>>> to queue a sample
>>>>>>>>> +
>>>>>>>>> +    private transient long queueWaitTime; // how long we had
>>> to
>>>> wait
>>>>>>>>> (nanoSeconds)
>>>>>>>>> +
>>>>>>>>> +    // Create unique object as marker for end of queue
>>>>>>>>> +    private transient static final SampleResult FINAL_EVENT =
>>> new
>>>>>>>>> SampleResult();
>>>>>>>>> +
>>>>>>>>> +    /**
>>>>>>>>> +     * Create a BackendListener.
>>>>>>>>> +     */
>>>>>>>>> +    public BackendListener() {
>>>>>>>>> +        setArguments(new Arguments());
>>>>>>>>> +    }
>>>>>>>>> +
>>>>>>>>> +    /*
>>>>>>>>> +     * Ensure that the required class variables are cloned,
>>>>>>>>> +     * as this is not currently done by the
>>> super-implementation.
>>>>>>>>> +     */
>>>>>>>>> +    @Override
>>>>>>>>> +    public Object clone() {
>>>>>>>>> +        BackendListener clone = (BackendListener)
>>> super.clone();
>>>>>>>>> +        clone.javaClass = this.javaClass;
>>>>>>>>> +        clone.isToBeRegistered = this.isToBeRegistered;
>>>>>>>>> +        return clone;
>>>>>>>>> +    }
>>>>>>>>> +
>>>>>>>>> +    private void initClass() {
>>>>>>>>> +        String name = getClassname().trim();
>>>>>>>>> +        try {
>>>>>>>>> +            javaClass = Class.forName(name, false,
>>>>>>>>> Thread.currentThread().getContextClassLoader());
>>>>>>>>> +            Method method =
>>> javaClass.getMethod("teardownTest", new
>>>>>>>>> Class[]{BackendListenerContext.class});
>>>>>>>>> +            isToBeRegistered =
>>> !method.getDeclaringClass().equals(
>>>>>>>>> AbstractBackendListenerClient.class);
>>>>>>>>> +            log.info("Created class: " + name + ". Uses
>>>> teardownTest:
>>>>>>>>> "
>>>>>>>>> + isToBeRegistered);
>>>>>>>>> +        } catch (Exception e) {
>>>>>>>>> +            log.error(whoAmI() + "\tException initialising: "
>>> +
>>>> name,
>>>>>>>>> e);
>>>>>>>>> +        }
>>>>>>>>> +    }
>>>>>>>>> +
>>>>>>>>> +    /**
>>>>>>>>> +     * Retrieves reference to BackendListenerClient.
>>>>>>>>> +     *
>>>>>>>>> +     * Convience method used to check for null reference
>>> without
>>>>>>>>> actually
>>>>>>>>> +     * creating a BackendListenerClient
>>>>>>>>> +     *
>>>>>>>>> +     * @return reference to BackendListenerClient NOTUSED
>>> private
>>>>>>>>> BackendListenerClient
>>>>>>>>> +     *         retrieveJavaClient() { return javaClient; }
>>>>>>>>> +     */
>>>>>>>>>
>>>>>>>>>   Javadoc for non-existant method?
>>>>>>>>   +
>>>>>>>>> +    /**
>>>>>>>>> +     * Generate a String identifier of this instance for
>>> debugging
>>>>>>>>> purposes.
>>>>>>>>> +     *
>>>>>>>>> +     * @return a String identifier for this sampler instance
>>>>>>>>> +     */
>>>>>>>>> +    private String whoAmI() {
>>>>>>>>> +        StringBuilder sb = new StringBuilder();
>>>>>>>>> +        sb.append(Thread.currentThread().getName());
>>>>>>>>> +        sb.append("@");
>>>>>>>>> +        sb.append(Integer.toHexString(hashCode()));
>>>>>>>>> +        sb.append("-");
>>>>>>>>> +        sb.append(getName());
>>>>>>>>> +        return sb.toString();
>>>>>>>>> +    }
>>>>>>>>> +
>>>>>>>>> +    // TestStateListener implementation
>>>>>>>>> +    /* Implements TestStateListener.testStarted() */
>>>>>>>>> +    @Override
>>>>>>>>> +    public void testStarted() {
>>>>>>>>> +        testStarted("");
>>>>>>>>> +    }
>>>>>>>>> +
>>>>>>>>> +    /* Implements TestStateListener.testStarted(String) */
>>>>>>>>> +    @Override
>>>>>>>>> +    public void testStarted(String host) {
>>>>>>>>> +        log.debug(whoAmI() + "\ttestStarted(" + host + ")");
>>>>>>>>>
>>>>>>>>>   Maybe use isDebugEnabled to guard whoAmI() call?
>>>>>>>>   +        queue = new
>>>> ArrayBlockingQueue<SampleResult>(getQueueSize());
>>>>>>>>> +        initClass();
>>>>>>>>> +        queueWaits=0L;
>>>>>>>>> +        queueWaitTime=0L;
>>>>>>>>> +        log.info(getName()+":Starting worker with
>>>> class:"+javaClass +"
>>>>>>>>> and queue capacity:"+getQueueSize());
>>>>>>>>> +
>>>>>>>>> +        backendListenerClient =
>>> createBackendListenerClientImp
>>>>>>>>> l(javaClass);
>>>>>>>>> +        context = new BackendListenerContext((
>>>>>>>>> Arguments)getArguments().
>>>>>>>>> clone());
>>>>>>>>> +        if(isToBeRegistered) {
>>>>>>>>>
>>>>>>>>>   space after if and before (?
>>>>>>>>   +            TEAR_DOWN_SET.add(this);
>>>>>>>>> +        }
>>>>>>>>> +        try {
>>>>>>>>> +            backendListenerClient.setupTest(context);
>>>>>>>>> +        } catch (Exception e) {
>>>>>>>>> +            throw new java.lang.IllegalStateException("Failed
>>>> calling
>>>>>>>>> setupTest", e);
>>>>>>>>> +        }
>>>>>>>>> +
>>>>>>>>> +        Worker worker = new Worker(javaClass,
>>>> backendListenerClient,
>>>>>>>>> (Arguments) getArguments().clone(), queue);
>>>>>>>>> +        worker.setDaemon(true);
>>>>>>>>> +        worker.start();
>>>>>>>>>
>>>>>>>>>   Don't we want to stop worker after we're done with one test?
>>>>>>>>   +        log.info(getName()+":Started  worker with
>>>> class:"+javaClass);
>>>>>>>>>   Spaces after :?
>>>>>>>>   +
>>>>>>>>> +    }
>>>>>>>>> +
>>>>>>>>> +    /* (non-Javadoc)
>>>>>>>>> +     * @see
>>>> org.apache.jmeter.samplers.SampleListener#sampleOccurred(
>>>>>>>>> org.apache.jmeter.samplers.SampleEvent)
>>>>>>>>> +     */
>>>>>>>>> +    @Override
>>>>>>>>> +    public void sampleOccurred(SampleEvent e) {
>>>>>>>>>
>>>>>>>>>   Longer name then 'e'? I expect e to be an exception, not an
>>> event.
>>>>>>>>   +        Arguments args = getArguments();
>>>>>>>>> +        context = new BackendListenerContext(args);
>>>>>>>>> +
>>>>>>>>> +        SampleResult sr = backendListenerClient.
>>>>>>>>> createSampleResult(context,
>>>>>>>>> e.getResult());
>>>>>>>>> +        try {
>>>>>>>>> +            if (!queue.offer(sr)){ // we failed to add the
>>> element
>>>>>>>>> first
>>>>>>>>> time
>>>>>>>>> +                queueWaits++;
>>>>>>>>> +                long t1 = System.nanoTime();
>>>>>>>>> +                queue.put(sr);
>>>>>>>>> +                long t2 = System.nanoTime();
>>>>>>>>> +                queueWaitTime += t2-t1;
>>>>>>>>>
>>>>>>>>>   Will sampleOccurred be called concurrently? If so, than
>>>> queueWaitTime
>>>>>>>> +=
>>>>>>>> will not be correct.
>>>>>>>>
>>>>>>>>   +            }
>>>>>>>>> +        } catch (Exception err) {
>>>>>>>>> +            log.error("sampleOccurred, failed to queue the
>>> sample",
>>>>>>>>> err);
>>>>>>>>> +        }
>>>>>>>>> +    }
>>>>>>>>> +
>>>>>>>>> +    private static final class Worker extends Thread {
>>>>>>>>> +
>>>>>>>>> +        private final BlockingQueue<SampleResult> queue;
>>>>>>>>> +        private final BackendListenerContext context;
>>>>>>>>> +        private final BackendListenerClient
>>> backendListenerClient;
>>>>>>>>> +        private Worker(Class<?> javaClass,
>>> BackendListenerClient
>>>>>>>>> backendListenerClient, Arguments arguments,
>>>> BlockingQueue<SampleResult>
>>>>>>>>> q){
>>>>>>>>>
>>>>>>>>>   Same naming argument as above. clientclass instead of
>>> javaClass?
>>>>>>>>   +            queue = q;
>>>>>>>>> +            // Allow BackendListenerClient implementations to
>>> get
>>>>>>>>> access
>>>>>>>>> to test element name
>>>>>>>>> +            arguments.addArgument(TestElement.NAME,
>>> getName());
>>>>>>>>> +            context = new BackendListenerContext(arguments);
>>>>>>>>> +            this.backendListenerClient =
>>> backendListenerClient;
>>>>>>>>> +        }
>>>>>>>>> +
>>>>>>>>> +
>>>>>>>>> +        @Override
>>>>>>>>> +        public void run() {
>>>>>>>>> +            boolean isDebugEnabled = log.isDebugEnabled();
>>>>>>>>> +            List<SampleResult> l = new
>>>> ArrayList<SampleResult>(queue.
>>>>>>>>> size());
>>>>>>>>>
>>>>>>>>>   samples instead of l?
>>>>>>>>   +            try {
>>>>>>>>> +                boolean eof = false;
>>>>>>>>>
>>>>>>>>>   endOfLoop?
>>>>>>>>   +                while (!eof) {
>>>>>>>>> +                    if(isDebugEnabled) {
>>>>>>>>> +                        log.debug("Thread:"+Thread.
>>>>>>>>> currentThread().getName()+"
>>>>>>>>> taking SampleResult from queue:"+queue.size());
>>>>>>>>> +                    }
>>>>>>>>> +                    SampleResult e = queue.take();
>>>>>>>>>
>>>>>>>>>   Could be named result, or sample instead of e
>>>>>>>>   +                    if(isDebugEnabled) {
>>>>>>>>> +                        log.debug("Thread:"+Thread.
>>>>>>>>> currentThread().getName()+"
>>>>>>>>> took SampleResult:"+e+", isFinal:" + (e==FINAL_EVENT));
>>>>>>>>> +                    }
>>>>>>>>> +                    while (!(eof = (e == FINAL_EVENT)) && e
>>> !=
>>>> null ) {
>>>>>>>>> // try to process as many as possible
>>>>>>>>> +                        l.add(e);
>>>>>>>>> +                        if(isDebugEnabled) {
>>>>>>>>> +                            log.debug("Thread:"+Thread.
>>>>>>>>> currentThread().getName()+"
>>>>>>>>> polling from queue:"+queue.size());
>>>>>>>>> +                        }
>>>>>>>>> +                        e = queue.poll(); // returns null if
>>>> nothing on
>>>>>>>>> queue currently
>>>>>>>>> +                        if(isDebugEnabled) {
>>>>>>>>> +                            log.debug("Thread:"+Thread.
>>>>>>>>> currentThread().getName()+"
>>>>>>>>> took from queue:"+e+", isFinal:" + (e==FINAL_EVENT));
>>>>>>>>> +                        }
>>>>>>>>> +                    }
>>>>>>>>> +                    if(isDebugEnabled) {
>>>>>>>>> +                        log.debug("Thread:"+Thread.
>>>>>>>>> currentThread().getName()+
>>>>>>>>> +                                " exiting with FINAL
>>> EVENT:"+(e ==
>>>>>>>>> FINAL_EVENT)
>>>>>>>>> +                                +", null:" + (e==null));
>>>>>>>>> +                    }
>>>>>>>>> +                    int size = l.size();
>>>>>>>>>
>>>>>>>>>   No need for a temporary variable.
>>>>>>>>   +                    if (size > 0) {
>>>>>>>>> +
>>>> backendListenerClient.handleSampleResults(l,
>>>>>>>>> context);
>>>>>>>>> +                        l.clear();
>>>>>>>>> +                    }
>>>>>>>>> +                    if(!eof) {
>>>>>>>>> +                        LockSupport.parkNanos(100);
>>>>>>>>> +                    }
>>>>>>>>> +                }
>>>>>>>>> +            } catch (InterruptedException e) {
>>>>>>>>> +                // NOOP
>>>>>>>>> +            }
>>>>>>>>> +            // We may have been interrupted
>>>>>>>>> +            int size = l.size();
>>>>>>>>> +            if (size > 0) {
>>>>>>>>> +                backendListenerClient.handleSampleResults(l,
>>>> context);
>>>>>>>>> +                l.clear();
>>>>>>>>> +            }
>>>>>>>>>
>>>>>>>>>   Same code as a few lines above, could be factored out into a
>>> method
>>>>>>>> handleSamples(l, context)
>>>>>>>>
>>>>>>>>   +            log.info("Worker ended");
>>>>>>>>> +        }
>>>>>>>>> +    }
>>>>>>>>> +
>>>>>>>>> +
>>>>>>>>> +    /**
>>>>>>>>> +     * Returns reference to
>>> <code>BackendListenerClient</code>.
>>>>>>>>>   Could use a {@link...}
>>>>>>>>   +     *
>>>>>>>>> +     *
>>>>>>>>> +     * @return BackendListenerClient reference.
>>>>>>>>> +     */
>>>>>>>>> +    static BackendListenerClient
>>> createBackendListenerClientImp
>>>>>>>>> l(Class<?>
>>>>>>>>> javaClass) {
>>>>>>>>> +        if (javaClass == null) { // failed to initialise the
>>> class
>>>>>>>>> +            return new ErrorBackendListenerClient();
>>>>>>>>> +        }
>>>>>>>>> +        BackendListenerClient client;
>>>>>>>>> +        try {
>>>>>>>>> +            client = (BackendListenerClient)
>>>> javaClass.newInstance();
>>>>>>>>> +        } catch (Exception e) {
>>>>>>>>> +            log.error("Exception creating: " + javaClass, e);
>>>>>>>>> +            client = new ErrorBackendListenerClient();
>>>>>>>>> +        }
>>>>>>>>> +        return client;
>>>>>>>>>
>>>>>>>>>   I would return newInstance() in try Block and return new
>>> Error.. in
>>>>>>>> catch
>>>>>>>> Block. javaClass -> clientClass
>>>>>>>>
>>>>>>>>   +    }
>>>>>>>>> +
>>>>>>>>> +    /**
>>>>>>>>> +     * Method called at the end of the test. This is called
>>> only
>>>> on one
>>>>>>>>> instance
>>>>>>>>> +     * of BackendListener. This method will loop through all
>>> of the
>>>>>>>>> other
>>>>>>>>> +     * BackendListenerClients which have been registered
>>>> (automatically
>>>>>>>>> in the
>>>>>>>>> +     * constructor) and notify them that the test has ended,
>>>> allowing
>>>>>>>>> the
>>>>>>>>> +     * BackendListenerClients to cleanup.
>>>>>>>>> +     */
>>>>>>>>> +    @Override
>>>>>>>>> +    public void testEnded() {
>>>>>>>>> +        try {
>>>>>>>>> +            queue.put(FINAL_EVENT);
>>>>>>>>> +        } catch (Exception ex) {
>>>>>>>>> +            log.warn("testEnded() with
>>> exception:"+ex.getMessage(),
>>>>>>>>> ex);
>>>>>>>>> +        }
>>>>>>>>> +        if (queueWaits > 0) {
>>>>>>>>> +            log.warn("QueueWaits: "+queueWaits+";
>>> QueueWaitTime:
>>>>>>>>> "+queueWaitTime+" (nanoseconds), you may need to increase
>>> queue
>>>>>>>>> capacity,
>>>>>>>>> see property 'backend_queue_capacity'");
>>>>>>>>> +        }
>>>>>>>>> +        synchronized (TEAR_DOWN_SET) {
>>>>>>>>> +            for (BackendListener backendListener :
>>> TEAR_DOWN_SET) {
>>>>>>>>> +                BackendListenerClient client =
>>> backendListener.
>>>>>>>>> backendListenerClient;
>>>>>>>>> +                if (client != null) {
>>>>>>>>> +                    try {
>>>>>>>>> +
>>>> client.teardownTest(backendListener.context);
>>>>>>>>> +                    } catch (Exception e) {
>>>>>>>>> +                        throw new java.lang.
>>>>>>>>> IllegalStateException("Failed
>>>>>>>>> calling teardownTest", e);
>>>>>>>>>
>>>>>>>>>   If we throw an exception here, we will not try every client.
>>>>>>>>   +                    }
>>>>>>>>> +                }
>>>>>>>>> +            }
>>>>>>>>> +            TEAR_DOWN_SET.clear();
>>>>>>>>> +        }
>>>>>>>>> +    }
>>>>>>>>> +
>>>>>>>>> +    /* Implements TestStateListener.testEnded(String) */
>>>>>>>>> +    @Override
>>>>>>>>> +    public void testEnded(String host) {
>>>>>>>>> +        testEnded();
>>>>>>>>> +    }
>>>>>>>>> +
>>>>>>>>> +    /**
>>>>>>>>> +     * A {@link BackendListenerClient} implementation used
>>> for
>>>> error
>>>>>>>>> handling. If an
>>>>>>>>> +     * error occurs while creating the real
>>> BackendListenerClient
>>>>>>>>> object, it is
>>>>>>>>> +     * replaced with an instance of this class. Each time a
>>> sample
>>>>>>>>> occurs with
>>>>>>>>> +     * this class, the result is marked as a failure so the
>>> user
>>>> can
>>>>>>>>> see
>>>>>>>>> that
>>>>>>>>> +     * the test failed.
>>>>>>>>> +     */
>>>>>>>>> +    static class ErrorBackendListenerClient extends
>>>>>>>>> AbstractBackendListenerClient {
>>>>>>>>> +        /**
>>>>>>>>> +         * Return SampleResult with data on error.
>>>>>>>>> +         *
>>>>>>>>> +         * @see
>>> BackendListenerClient#runTest(JavaSamplerContext)
>>>>>>>>> +         */
>>>>>>>>> +        @Override
>>>>>>>>> +        public void handleSampleResults(List<SampleResult>
>>>>>>>>> sampleResults, BackendListenerContext context) {
>>>>>>>>> +
>>> log.warn("ErrorBackendListenerClient#handleSampleResult
>>>>>>>>> called, noop");
>>>>>>>>> +            Thread.yield();
>>>>>>>>> +        }
>>>>>>>>> +    }
>>>>>>>>> +
>>>>>>>>> +    /* (non-Javadoc)
>>>>>>>>> +     * @see
>>>> org.apache.jmeter.samplers.SampleListener#sampleStarted(
>>>>>>>>> org.apache.jmeter.samplers.SampleEvent)
>>>>>>>>> +     */
>>>>>>>>> +    @Override
>>>>>>>>> +    public void sampleStarted(SampleEvent e) {
>>>>>>>>> +        // NOOP
>>>>>>>>> +
>>>>>>>>> +    }
>>>>>>>>> +
>>>>>>>>> +    /* (non-Javadoc)
>>>>>>>>> +     * @see
>>>> org.apache.jmeter.samplers.SampleListener#sampleStopped(
>>>>>>>>> org.apache.jmeter.samplers.SampleEvent)
>>>>>>>>> +     */
>>>>>>>>> +    @Override
>>>>>>>>> +    public void sampleStopped(SampleEvent e) {
>>>>>>>>> +        // NOOP
>>>>>>>>> +
>>>>>>>>> +    }
>>>>>>>>> +
>>>>>>>>> +    /**
>>>>>>>>> +     * Set the arguments (parameters) for the
>>>> BackendListenerClient to
>>>>>>>>> be executed
>>>>>>>>> +     * with.
>>>>>>>>> +     *
>>>>>>>>> +     * @param args
>>>>>>>>> +     *            the new arguments. These replace any
>>> existing
>>>>>>>>> arguments.
>>>>>>>>> +     */
>>>>>>>>> +    public void setArguments(Arguments args) {
>>>>>>>>> +        setProperty(new TestElementProperty(ARGUMENTS,
>>> args));
>>>>>>>>> +    }
>>>>>>>>> +
>>>>>>>>> +    /**
>>>>>>>>> +     * Get the arguments (parameters) for the
>>>> BackendListenerClient to
>>>>>>>>> be executed
>>>>>>>>> +     * with.
>>>>>>>>> +     *
>>>>>>>>> +     * @return the arguments
>>>>>>>>> +     */
>>>>>>>>> +    public Arguments getArguments() {
>>>>>>>>> +        return (Arguments)
>>> getProperty(ARGUMENTS).getObjectValue();
>>>>>>>>> +    }
>>>>>>>>> +
>>>>>>>>> +    /**
>>>>>>>>> +     * Sets the Classname of the BackendListenerClient object
>>>>>>>>> +     *
>>>>>>>>> +     * @param classname
>>>>>>>>> +     *            the new Classname value
>>>>>>>>> +     */
>>>>>>>>> +    public void setClassname(String classname) {
>>>>>>>>> +        setProperty(CLASSNAME, classname);
>>>>>>>>> +    }
>>>>>>>>> +
>>>>>>>>> +    /**
>>>>>>>>> +     * Gets the Classname of the BackendListenerClient object
>>>>>>>>> +     *
>>>>>>>>> +     * @return the Classname value
>>>>>>>>> +     */
>>>>>>>>> +    public String getClassname() {
>>>>>>>>> +        return getPropertyAsString(CLASSNAME);
>>>>>>>>> +    }
>>>>>>>>> +
>>>>>>>>> +    /**
>>>>>>>>> +     * Sets the queue size
>>>>>>>>> +     *
>>>>>>>>> +     * @param queueSize
>>>>>>>>> +     *
>>>>>>>>> +     */
>>>>>>>>> +    public void setQueueSize(int queueSize) {
>>>>>>>>> +        setProperty(QUEUE_SIZE, queueSize,
>>> DEFAULT_QUEUE_SIZE);
>>>>>>>>> +    }
>>>>>>>>> +
>>>>>>>>> +    /**
>>>>>>>>> +     * Gets the queue size
>>>>>>>>> +     *
>>>>>>>>> +     * @return int queueSize
>>>>>>>>> +     */
>>>>>>>>> +    public int getQueueSize() {
>>>>>>>>> +        return getPropertyAsInt(QUEUE_SIZE,
>>> DEFAULT_QUEUE_SIZE);
>>>>>>>>> +    }
>>>>>>>>> +}
>>>>>>>>>
>>>>>>>>> Propchange:
>>>> jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>>>>>>>>> backend/BackendListener.java
>>>>>>>>> ------------------------------------------------------------
>>>>>>>>> ------------------
>>>>>>>>>        svn:mime-type = text/plain
>>>>>>>>>
>>>>>>>>> Added:
>>> jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>>>>>>>>> backend/BackendListenerClient.java
>>>>>>>>> URL: http://svn.apache.org/viewvc/jmeter/trunk/src/components/
>>>>>>>>> org/apache/jmeter/visualizers/backend/BackendListenerClient.
>>>>>>>>> java?rev=1641081&view=auto
>>>>>>>>> ============================================================
>>>>>>>>> ==================
>>>>>>>>> --- jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>>>>>>>>> backend/BackendListenerClient.java (added)
>>>>>>>>> +++ jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>>>>>>>>> backend/BackendListenerClient.java Sat Nov 22 15:36:37 2014
>>>>>>>>> @@ -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.jmeter.visualizers.backend;
>>>>>>>>> +
>>>>>>>>> +import java.util.List;
>>>>>>>>> +
>>>>>>>>> +import org.apache.jmeter.config.Arguments;
>>>>>>>>> +import org.apache.jmeter.samplers.SampleResult;
>>>>>>>>> +
>>>>>>>>> +/**
>>>>>>>>> + * This interface defines the interactions between the
>>>> BackendListener
>>>>>>>>> and external
>>>>>>>>> + * Java programs which can be executed by JMeter. Any Java
>>> class
>>>> which
>>>>>>>>> wants to
>>>>>>>>> + * be executed as a JMeter test must implement this interface
>>>> (either
>>>>>>>>> directly
>>>>>>>>> + * or indirectly through AbstractBackendListenerClient).
>>>>>>>>> + * <p>
>>>>>>>>> + * JMeter will create one instance of a BackendListenerClient
>>>>>>>>> implementation for
>>>>>>>>> + * each user/thread in the test. Additional instances may be
>>>> created
>>>>>>>>> for
>>>>>>>>> + * internal use by JMeter (for example, to find out what
>>>> parameters are
>>>>>>>>> + * supported by the client).
>>>>>>>>> + * <p>
>>>>>>>>> + * When the test is started, setupTest() will be called on
>>> each
>>>>>>>>> thread's
>>>>>>>>> + * BackendListenerClient instance to initialize the client.
>>> Then
>>>>>>>>> handleSampleResult() will be
>>>>>>>>> + * called for each SampleResult notification. Finally,
>>>> teardownTest()
>>>>>>>>> will be called
>>>>>>>>> + * to allow the client to do any necessary clean-up.
>>>>>>>>> + * <p>
>>>>>>>>> + * The JMeter BackendListener GUI allows a list of parameters
>>> to be
>>>>>>>>> defined for the
>>>>>>>>> + * test. These are passed to the various test methods through
>>> the
>>>>>>>>> + * {@link BackendListenerContext}. A list of default
>>> parameters
>>>> can be
>>>>>>>>> defined
>>>>>>>>> + * through the getDefaultParameters() method. These
>>> parameters and
>>>> any
>>>>>>>>> default
>>>>>>>>> + * values associated with them will be shown in the GUI.
>>> Users can
>>>> add
>>>>>>>>> other
>>>>>>>>> + * parameters as well.
>>>>>>>>> + * <p>
>>>>>>>>> + * When possible, Listeners should extend {@link
>>>>>>>>> AbstractBackendListenerClient
>>>>>>>>> + * AbstractBackendListenerClient} rather than implementing
>>>>>>>>> BackendListenerClient
>>>>>>>>> + * directly. This should protect your tests from future
>>> changes to
>>>> the
>>>>>>>>> + * interface. While it may be necessary to make changes to
>>> the
>>>>>>>>> BackendListenerClient
>>>>>>>>> + * interface from time to time (therefore requiring changes
>>> to any
>>>>>>>>> + * implementations of this interface), we intend to make this
>>>> abstract
>>>>>>>>> class
>>>>>>>>> + * provide reasonable default implementations of any new
>>> methods so
>>>>>>>>> that
>>>>>>>>> + * subclasses do not necessarily need to be updated for new
>>>> versions.
>>>>>>>>> + * Implementing BackendListenerClient directly will continue
>>> to be
>>>>>>>>> supported for
>>>>>>>>> + * cases where extending this class is not possible (for
>>> example,
>>>> when
>>>>>>>>> the
>>>>>>>>> + * client class is already a subclass of some other class).
>>>>>>>>> + *
>>>>>>>>> + * @since 2.13
>>>>>>>>> + */
>>>>>>>>> +public interface BackendListenerClient {
>>>>>>>>> +    /**
>>>>>>>>> +     * Do any initialization required by this client. It is
>>>> generally
>>>>>>>>> +     * recommended to do any initialization such as getting
>>>> parameter
>>>>>>>>> values in
>>>>>>>>> +     * the setupTest method rather than the runTest method in
>>>> order to
>>>>>>>>> add as
>>>>>>>>> +     * little overhead as possible to the test.
>>>>>>>>> +     *
>>>>>>>>> +     * @param context
>>>>>>>>> +     *            the context to run with. This provides
>>> access to
>>>>>>>>> +     *            initialization parameters.
>>>>>>>>> +     */
>>>>>>>>> +    void setupTest(BackendListenerContext context) throws
>>>> Exception;
>>>>>>>>> +
>>>>>>>>> +    /**
>>>>>>>>> +     * Perform a single sample for each iteration. This
>>> method
>>>> returns
>>>>>>>>> a
>>>>>>>>> +     * <code>SampleResult</code> object.
>>> <code>SampleResult</code>
>>>> has
>>>>>>>>> many
>>>>>>>>> +     * fields which can be used. At a minimum, the test
>>> should use
>>>>>>>>> +     * <code>SampleResult.sampleStart</code> and
>>>>>>>>> +     * <code>SampleResult.sampleEnd</code>to set the time
>>> that the
>>>>>>>>> test
>>>>>>>>>
>>>>>>>>>   use {@link..} instead of <code>..?
>>>>>>>>   +     * required to execute. It is also a good idea to set the
>>>>>>>>> sampleLabel and
>>>>>>>>> +     * the successful flag.
>>>>>>>>> +     *
>>>>>>>>> +     * @see
>>> org.apache.jmeter.samplers.SampleResult#sampleStart()
>>>>>>>>> +     * @see
>>> org.apache.jmeter.samplers.SampleResult#sampleEnd()
>>>>>>>>> +     * @see
>>> org.apache.jmeter.samplers.SampleResult#setSuccessful(
>>>>>>>>> boolean)
>>>>>>>>> +     * @see
>>> org.apache.jmeter.samplers.SampleResult#setSampleLabel(
>>>>>>>>> String)
>>>>>>>>> +     *
>>>>>>>>> +     * @param context
>>>>>>>>> +     *            the context to run with. This provides
>>> access to
>>>>>>>>> +     *            initialization parameters.
>>>>>>>>> +     *
>>>>>>>>> +     */
>>>>>>>>> +    void handleSampleResults(List<SampleResult>
>>> sampleResults,
>>>>>>>>> BackendListenerContext context);
>>>>>>>>> +
>>>>>>>>> +    /**
>>>>>>>>> +     * Do any clean-up required by this test at the end of a
>>> test
>>>> run.
>>>>>>>>> +     *
>>>>>>>>> +     * @param context
>>>>>>>>> +     *            the context to run with. This provides
>>> access to
>>>>>>>>> +     *            initialization parameters.
>>>>>>>>> +     */
>>>>>>>>> +    void teardownTest(BackendListenerContext context) throws
>>>>>>>>> Exception;
>>>>>>>>> +
>>>>>>>>> +    /**
>>>>>>>>> +     * Provide a list of parameters which this test supports.
>>> Any
>>>>>>>>> parameter
>>>>>>>>> +     * names and associated values returned by this method
>>> will
>>>> appear
>>>>>>>>> in the
>>>>>>>>> +     * GUI by default so the user doesn't have to remember
>>> the
>>>> exact
>>>>>>>>> names. The
>>>>>>>>> +     * user can add other parameters which are not listed
>>> here. If
>>>> this
>>>>>>>>> method
>>>>>>>>> +     * returns null then no parameters will be listed. If the
>>>> value for
>>>>>>>>> some
>>>>>>>>> +     * parameter is null then that parameter will be listed
>>> in the
>>>> GUI
>>>>>>>>> with an
>>>>>>>>> +     * empty value.
>>>>>>>>> +     *
>>>>>>>>> +     * @return a specification of the parameters used by this
>>> test
>>>>>>>>> which
>>>>>>>>> should
>>>>>>>>> +     *         be listed in the GUI, or null if no parameters
>>>> should be
>>>>>>>>> listed.
>>>>>>>>> +     */
>>>>>>>>> +    Arguments getDefaultParameters();
>>>>>>>>> +
>>>>>>>>> +    /**
>>>>>>>>> +     *
>>>>>>>>> +     * @param context
>>>>>>>>> +     * @param result
>>>>>>>>> +     * @return
>>>>>>>>> +     */
>>>>>>>>> +    SampleResult createSampleResult(
>>>>>>>>> +            BackendListenerContext context, SampleResult
>>> result);
>>>>>>>>> +}
>>>>>>>>>
>>>>>>>>> Propchange:
>>>> jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>>>>>>>>> backend/BackendListenerClient.java
>>>>>>>>> ------------------------------------------------------------
>>>>>>>>> ------------------
>>>>>>>>>        svn:mime-type = text/plain
>>>>>>>>>
>>>>>>>>> Added:
>>> jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>>>>>>>>> backend/
>>>>>>>>> BackendListenerContext.java
>>>>>>>>> URL: http://svn.apache.org/viewvc/jmeter/trunk/src/components/
>>>>>>>>>
>>> org/apache/jmeter/visualizers/backend/BackendListenerContext.java?
>>>>>>>>> rev=1641081&view=auto
>>>>>>>>> ============================================================
>>>>>>>>> ==================
>>>>>>>>> ---
>>>> jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/
>>>>>>>>> BackendListenerContext.java
>>>>>>>>> (added)
>>>>>>>>> +++
>>>> jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/
>>>>>>>>> BackendListenerContext.java
>>>>>>>>> Sat Nov 22 15:36:37 2014
>>>>>>>>> @@ -0,0 +1,237 @@
>>>>>>>>> +/*
>>>>>>>>> +
>>>>>>>>> + * 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.jmeter.visualizers.backend;
>>>>>>>>> +
>>>>>>>>> +import java.util.Iterator;
>>>>>>>>> +import java.util.Map;
>>>>>>>>> +
>>>>>>>>> +import org.apache.jmeter.config.Arguments;
>>>>>>>>> +import org.apache.jorphan.logging.LoggingManager;
>>>>>>>>> +import org.apache.log.Logger;
>>>>>>>>> +
>>>>>>>>> +/**
>>>>>>>>> + * BackendListenerContext is used to provide context
>>> information
>>>> to a
>>>>>>>>> + * BackendListenerClient implementation. This currently
>>> consists
>>>> of the
>>>>>>>>> + * initialization parameters which were specified in the GUI.
>>>>>>>>> + * @since 2.13
>>>>>>>>> + */
>>>>>>>>> +public class BackendListenerContext {
>>>>>>>>> +    /*
>>>>>>>>> +     * Implementation notes:
>>>>>>>>> +     *
>>>>>>>>> +     * All of the methods in this class are currently
>>> read-only. If
>>>>>>>>> update
>>>>>>>>> +     * methods are included in the future, they should be
>>> defined
>>>> so
>>>>>>>>> that a
>>>>>>>>> +     * single instance of BackendListenerContext can be
>>> associated
>>>> with
>>>>>>>>> each thread.
>>>>>>>>> +     * Therefore, no synchronization should be needed. The
>>> same
>>>>>>>>> instance
>>>>>>>>> should
>>>>>>>>> +     * be used for the call to setupTest, all calls to
>>> runTest,
>>>> and the
>>>>>>>>> call to
>>>>>>>>> +     * teardownTest.
>>>>>>>>> +     */
>>>>>>>>> +
>>>>>>>>> +    /** Logging */
>>>>>>>>> +    private static final Logger log = LoggingManager.
>>>>>>>>> getLoggerForClass();
>>>>>>>>>
>>>>>>>>>   See naming comments for logger above
>>>>>>>>   +
>>>>>>>>> +    /**
>>>>>>>>> +     * Map containing the initialization parameters for the
>>>>>>>>> BackendListenerClient.
>>>>>>>>> +     */
>>>>>>>>> +    private final Map<String, String> params;
>>>>>>>>> +
>>>>>>>>> +    /**
>>>>>>>>> +     *
>>>>>>>>> +     * @param args
>>>>>>>>> +     *            the initialization parameters.
>>>>>>>>> +     */
>>>>>>>>> +    public BackendListenerContext(Arguments args) {
>>>>>>>>> +        this.params = args.getArgumentsAsMap();
>>>>>>>>> +    }
>>>>>>>>> +
>>>>>>>>> +    /**
>>>>>>>>> +     * Determine whether or not a value has been specified
>>> for the
>>>>>>>>> parameter
>>>>>>>>> +     * with this name.
>>>>>>>>> +     *
>>>>>>>>> +     * @param name
>>>>>>>>> +     *            the name of the parameter to test
>>>>>>>>> +     * @return true if the parameter value has been
>>> specified,
>>>> false
>>>>>>>>> otherwise.
>>>>>>>>> +     */
>>>>>>>>> +    public boolean containsParameter(String name) {
>>>>>>>>>
>>>>>>>>>   hasParameter instead of containsParameter?
>>>>>>>>   +        return params.containsKey(name);
>>>>>>>>> +    }
>>>>>>>>> +
>>>>>>>>> +    /**
>>>>>>>>> +     * Get an iterator of the parameter names. Each entry in
>>> the
>>>>>>>>> Iterator is a
>>>>>>>>> +     * String.
>>>>>>>>> +     *
>>>>>>>>> +     * @return an Iterator of Strings listing the names of
>>> the
>>>>>>>>> parameters which
>>>>>>>>> +     *         have been specified for this test.
>>>>>>>>> +     */
>>>>>>>>> +    public Iterator<String> getParameterNamesIterator() {
>>>>>>>>> +        return params.keySet().iterator();
>>>>>>>>> +    }
>>>>>>>>> +
>>>>>>>>> +    /**
>>>>>>>>> +     * Get the value of a specific parameter as a String, or
>>> null
>>>> if
>>>>>>>>> the
>>>>>>>>> value
>>>>>>>>> +     * was not specified.
>>>>>>>>> +     *
>>>>>>>>> +     * @param name
>>>>>>>>> +     *            the name of the parameter whose value
>>> should be
>>>>>>>>> retrieved
>>>>>>>>> +     * @return the value of the parameter, or null if the
>>> value
>>>> was not
>>>>>>>>> +     *         specified
>>>>>>>>> +     */
>>>>>>>>> +    public String getParameter(String name) {
>>>>>>>>> +        return getParameter(name, null);
>>>>>>>>> +    }
>>>>>>>>> +
>>>>>>>>> +    /**
>>>>>>>>> +     * Get the value of a specified parameter as a String, or
>>>> return
>>>>>>>>> the
>>>>>>>>> +     * specified default value if the value was not
>>> specified.
>>>>>>>>> +     *
>>>>>>>>> +     * @param name
>>>>>>>>> +     *            the name of the parameter whose value
>>> should be
>>>>>>>>> retrieved
>>>>>>>>> +     * @param defaultValue
>>>>>>>>> +     *            the default value to return if the value of
>>> this
>>>>>>>>> parameter was
>>>>>>>>> +     *            not specified
>>>>>>>>> +     * @return the value of the parameter, or the default
>>> value if
>>>> the
>>>>>>>>> parameter
>>>>>>>>> +     *         was not specified
>>>>>>>>> +     */
>>>>>>>>> +    public String getParameter(String name, String
>>> defaultValue) {
>>>>>>>>> +        if (params == null || !params.containsKey(name)) {
>>>>>>>>> +            return defaultValue;
>>>>>>>>> +        }
>>>>>>>>> +        return params.get(name);
>>>>>>>>> +    }
>>>>>>>>> +
>>>>>>>>> +    /**
>>>>>>>>> +     * Get the value of a specified parameter as an integer.
>>> An
>>>>>>>>> exception will
>>>>>>>>> +     * be thrown if the parameter is not specified or if it
>>> is not
>>>> an
>>>>>>>>> integer.
>>>>>>>>> +     * The value may be specified in decimal, hexadecimal, or
>>>> octal, as
>>>>>>>>> defined
>>>>>>>>> +     * by Integer.decode().
>>>>>>>>> +     *
>>>>>>>>> +     * @param name
>>>>>>>>> +     *            the name of the parameter whose value
>>> should be
>>>>>>>>> retrieved
>>>>>>>>> +     * @return the value of the parameter
>>>>>>>>> +     *
>>>>>>>>> +     * @throws NumberFormatException
>>>>>>>>> +     *             if the parameter is not specified or is
>>> not an
>>>>>>>>> integer
>>>>>>>>> +     *
>>>>>>>>> +     * @see java.lang.Integer#decode(java.lang.String)
>>>>>>>>> +     */
>>>>>>>>> +    public int getIntParameter(String name) throws
>>>>>>>>> NumberFormatException
>>>>>>>>> {
>>>>>>>>> +        if (params == null || !params.containsKey(name)) {
>>>>>>>>> +            throw new NumberFormatException("No value for
>>> parameter
>>>>>>>>> named '" + name + "'.");
>>>>>>>>>
>>>>>>>>>   I would expect an IllegalArgumentException, if no parameter
>>> of that
>>>>>>>> name
>>>>>>>> is found
>>>>>>>>
>>>>>>>>   +        }
>>>>>>>>> +
>>>>>>>>> +        return Integer.decode(params.get(name)).intValue();
>>>>>>>>> +    }
>>>>>>>>> +
>>>>>>>>> +    /**
>>>>>>>>> +     * Get the value of a specified parameter as an integer,
>>> or
>>>> return
>>>>>>>>> the
>>>>>>>>> +     * specified default value if the value was not specified
>>> or
>>>> is not
>>>>>>>>> an
>>>>>>>>> +     * integer. A warning will be logged if the value is not
>>> an
>>>>>>>>> integer.
>>>>>>>>> The
>>>>>>>>> +     * value may be specified in decimal, hexadecimal, or
>>> octal, as
>>>>>>>>> defined by
>>>>>>>>> +     * Integer.decode().
>>>>>>>>> +     *
>>>>>>>>> +     * @param name
>>>>>>>>> +     *            the name of the parameter whose value
>>> should be
>>>>>>>>> retrieved
>>>>>>>>> +     * @param defaultValue
>>>>>>>>> +     *            the default value to return if the value of
>>> this
>>>>>>>>> parameter was
>>>>>>>>> +     *            not specified
>>>>>>>>> +     * @return the value of the parameter, or the default
>>> value if
>>>> the
>>>>>>>>> parameter
>>>>>>>>> +     *         was not specified
>>>>>>>>> +     *
>>>>>>>>> +     * @see java.lang.Integer#decode(java.lang.String)
>>>>>>>>> +     */
>>>>>>>>> +    public int getIntParameter(String name, int defaultValue)
>>> {
>>>>>>>>> +        if (params == null || !params.containsKey(name)) {
>>>>>>>>> +            return defaultValue;
>>>>>>>>> +        }
>>>>>>>>> +
>>>>>>>>> +        try {
>>>>>>>>> +            return
>>> Integer.decode(params.get(name)).intValue();
>>>>>>>>> +        } catch (NumberFormatException e) {
>>>>>>>>> +            log.warn("Value for parameter '" + name + "' not
>>> an
>>>>>>>>> integer:
>>>>>>>>> '" + params.get(name) + "'.  Using default: '"
>>>>>>>>> +                    + defaultValue + "'.", e);
>>>>>>>>> +            return defaultValue;
>>>>>>>>> +        }
>>>>>>>>> +    }
>>>>>>>>> +
>>>>>>>>> +    /**
>>>>>>>>> +     * Get the value of a specified parameter as a long. An
>>>> exception
>>>>>>>>> will be
>>>>>>>>> +     * thrown if the parameter is not specified or if it is
>>> not a
>>>> long.
>>>>>>>>> The
>>>>>>>>> +     * value may be specified in decimal, hexadecimal, or
>>> octal, as
>>>>>>>>> defined by
>>>>>>>>> +     * Long.decode().
>>>>>>>>> +     *
>>>>>>>>> +     * @param name
>>>>>>>>> +     *            the name of the parameter whose value
>>> should be
>>>>>>>>> retrieved
>>>>>>>>> +     * @return the value of the parameter
>>>>>>>>> +     *
>>>>>>>>> +     * @throws NumberFormatException
>>>>>>>>> +     *             if the parameter is not specified or is
>>> not a
>>>> long
>>>>>>>>> +     *
>>>>>>>>> +     * @see Long#decode(String)
>>>>>>>>> +     */
>>>>>>>>> +    public long getLongParameter(String name) throws
>>>>>>>>> NumberFormatException {
>>>>>>>>> +        if (params == null || !params.containsKey(name)) {
>>>>>>>>> +            throw new NumberFormatException("No value for
>>> parameter
>>>>>>>>> named '" + name + "'.");
>>>>>>>>> +        }
>>>>>>>>> +
>>>>>>>>> +        return Long.decode(params.get(name)).longValue();
>>>>>>>>> +    }
>>>>>>>>> +
>>>>>>>>> +    /**
>>>>>>>>> +     * Get the value of a specified parameter as along, or
>>> return
>>>> the
>>>>>>>>> specified
>>>>>>>>> +     * default value if the value was not specified or is not
>>> a
>>>> long. A
>>>>>>>>> warning
>>>>>>>>> +     * will be logged if the value is not a long. The value
>>> may be
>>>>>>>>> specified in
>>>>>>>>> +     * decimal, hexadecimal, or octal, as defined by
>>> Long.decode().
>>>>>>>>> +     *
>>>>>>>>> +     * @param name
>>>>>>>>> +     *            the name of the parameter whose value
>>> should be
>>>>>>>>> retrieved
>>>>>>>>> +     * @param defaultValue
>>>>>>>>> +     *            the default value to return if the value of
>>> this
>>>>>>>>> parameter was
>>>>>>>>> +     *            not specified
>>>>>>>>> +     * @return the value of the parameter, or the default
>>> value if
>>>> the
>>>>>>>>> parameter
>>>>>>>>> +     *         was not specified
>>>>>>>>> +     *
>>>>>>>>> +     * @see Long#decode(String)
>>>>>>>>> +     */
>>>>>>>>> +    public long getLongParameter(String name, long
>>> defaultValue) {
>>>>>>>>> +        if (params == null || !params.containsKey(name)) {
>>>>>>>>> +            return defaultValue;
>>>>>>>>> +        }
>>>>>>>>> +        try {
>>>>>>>>> +            return Long.decode(params.get(name)).longValue();
>>>>>>>>> +        } catch (NumberFormatException e) {
>>>>>>>>> +            log.warn("Value for parameter '" + name + "' not
>>> a
>>>> long: '"
>>>>>>>>> + params.get(name) + "'.  Using default: '"
>>>>>>>>> +                    + defaultValue + "'.", e);
>>>>>>>>> +            return defaultValue;
>>>>>>>>> +        }
>>>>>>>>> +    }
>>>>>>>>> +
>>>>>>>>> +    /**
>>>>>>>>> +     *
>>>>>>>>> +     * @param name
>>>>>>>>> +     * @param defaultValue
>>>>>>>>> +     * @return
>>>>>>>>>
>>>>>>>>>   No javadoc? Again three warnings more :)
>>>>>>>>   +     */
>>>>>>>>> +    public boolean getBooleanParameter(String name, boolean
>>>>>>>>> defaultValue) {
>>>>>>>>> +        if (params == null || !params.containsKey(name)) {
>>>>>>>>> +            return defaultValue;
>>>>>>>>> +        }
>>>>>>>>> +        return Boolean.valueOf(params.get(name));
>>>>>>>>> +    }
>>>>>>>>> +}
>>>>>>>>>
>>>>>>>>> Propchange:
>>>> jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>>>>>>>>> backend/BackendListenerContext.java
>>>>>>>>> ------------------------------------------------------------
>>>>>>>>> ------------------
>>>>>>>>>        svn:mime-type = text/plain
>>>>>>>>>
>>>>>>>>> Added:
>>> jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>>>>>>>>> backend/BackendListenerGui.java
>>>>>>>>> URL: http://svn.apache.org/viewvc/jmeter/trunk/src/components/
>>>>>>>>> org/apache/jmeter/visualizers/backend/BackendListenerGui.
>>>>>>>>> java?rev=1641081&view=auto
>>>>>>>>> ============================================================
>>>>>>>>> ==================
>>>>>>>>> --- jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>>>>>>>>> backend/BackendListenerGui.java (added)
>>>>>>>>> +++ jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>>>>>>>>> backend/BackendListenerGui.java Sat Nov 22 15:36:37 2014
>>>>>>>>> @@ -0,0 +1,282 @@
>>>>>>>>> +/*
>>>>>>>>> + * 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.jmeter.visualizers.backend;
>>>>>>>>> +
>>>>>>>>> +import java.awt.BorderLayout;
>>>>>>>>> +import java.awt.event.ActionEvent;
>>>>>>>>> +import java.awt.event.ActionListener;
>>>>>>>>> +import java.util.ArrayList;
>>>>>>>>> +import java.util.HashSet;
>>>>>>>>> +import java.util.List;
>>>>>>>>> +import java.util.Map;
>>>>>>>>> +import java.util.Set;
>>>>>>>>> +
>>>>>>>>> +import javax.swing.ComboBoxModel;
>>>>>>>>> +import javax.swing.JComboBox;
>>>>>>>>> +import javax.swing.JLabel;
>>>>>>>>> +import javax.swing.JPanel;
>>>>>>>>> +import javax.swing.JTextField;
>>>>>>>>> +
>>>>>>>>> +import org.apache.jmeter.config.Argument;
>>>>>>>>> +import org.apache.jmeter.config.Arguments;
>>>>>>>>> +import org.apache.jmeter.config.gui.ArgumentsPanel;
>>>>>>>>> +import org.apache.jmeter.gui.util.HorizontalPanel;
>>>>>>>>> +import org.apache.jmeter.testelement.TestElement;
>>>>>>>>> +import
>>> org.apache.jmeter.testelement.property.PropertyIterator;
>>>>>>>>> +import org.apache.jmeter.util.JMeterUtils;
>>>>>>>>> +import org.apache.jmeter.visualizers.gui.AbstractListenerGui;
>>>>>>>>> +import org.apache.jorphan.logging.LoggingManager;
>>>>>>>>> +import org.apache.jorphan.reflect.ClassFinder;
>>>>>>>>> +import org.apache.log.Logger;
>>>>>>>>> +
>>>>>>>>> +/**
>>>>>>>>> + * The <code>BackendListenerGui</code> class provides the
>>> user
>>>>>>>>> interface for the
>>>>>>>>> + * {@link BackendListener} object.
>>>>>>>>> + * @since 2.13
>>>>>>>>> + */
>>>>>>>>> +public class BackendListenerGui extends AbstractListenerGui
>>>> implements
>>>>>>>>> ActionListener {
>>>>>>>>> +
>>>>>>>>> +    /**
>>>>>>>>> +     *
>>>>>>>>> +     */
>>>>>>>>> +    private static final long serialVersionUID =
>>>> 4331668988576438604L;
>>>>>>>>> +
>>>>>>>>> +    /** Logging */
>>>>>>>>> +    private static final Logger log = LoggingManager.
>>>>>>>>> getLoggerForClass();
>>>>>>>>> +
>>>>>>>>> +    /** A combo box allowing the user to choose a backend
>>> class. */
>>>>>>>>> +    private JComboBox classnameCombo;
>>>>>>>>> +
>>>>>>>>> +    /**
>>>>>>>>> +     * A field allowing the user to specify the size of Queue
>>>>>>>>> +     */
>>>>>>>>> +    private JTextField queueSize;
>>>>>>>>> +
>>>>>>>>> +    /** A panel allowing the user to set arguments for this
>>> test.
>>>> */
>>>>>>>>> +    private ArgumentsPanel argsPanel;
>>>>>>>>> +
>>>>>>>>> +    /**
>>>>>>>>> +     * Create a new BackendListenerGui as a standalone
>>> component.
>>>>>>>>> +     */
>>>>>>>>> +    public BackendListenerGui() {
>>>>>>>>> +        super();
>>>>>>>>> +        init();
>>>>>>>>> +    }
>>>>>>>>> +
>>>>>>>>> +
>>>>>>>>> +    /** {@inheritDoc} */
>>>>>>>>> +    @Override
>>>>>>>>> +    public String getLabelResource() {
>>>>>>>>> +        return "backend_listener"; // $NON-NLS-1$
>>>>>>>>> +    }
>>>>>>>>> +
>>>>>>>>> +    /**
>>>>>>>>> +     * Initialize the GUI components and layout.
>>>>>>>>> +     */
>>>>>>>>> +    private void init() {// called from ctor, so must not be
>>>>>>>>> overridable
>>>>>>>>> +        setLayout(new BorderLayout(0, 5));
>>>>>>>>> +
>>>>>>>>> +        setBorder(makeBorder());
>>>>>>>>> +        add(makeTitlePanel(), BorderLayout.NORTH);
>>>>>>>>> +
>>>>>>>>> +        JPanel classnameRequestPanel = new JPanel(new
>>>> BorderLayout(0,
>>>>>>>>> 5));
>>>>>>>>> +        classnameRequestPanel.add(createClassnamePanel(),
>>>>>>>>> BorderLayout.NORTH);
>>>>>>>>> +        classnameRequestPanel.add(createParameterPanel(),
>>>>>>>>> BorderLayout.CENTER);
>>>>>>>>> +
>>>>>>>>> +        add(classnameRequestPanel, BorderLayout.CENTER);
>>>>>>>>> +    }
>>>>>>>>> +
>>>>>>>>> +    /**
>>>>>>>>> +     * Create a panel with GUI components allowing the user
>>> to
>>>> select a
>>>>>>>>> test
>>>>>>>>> +     * class.
>>>>>>>>> +     *
>>>>>>>>> +     * @return a panel containing the relevant components
>>>>>>>>> +     */
>>>>>>>>> +    private JPanel createClassnamePanel() {
>>>>>>>>> +        List<String> possibleClasses = new
>>> ArrayList<String>();
>>>>>>>>> +
>>>>>>>>> +        try {
>>>>>>>>> +            // Find all the classes which implement the
>>>>>>>>> BackendListenerClient
>>>>>>>>> +            // interface.
>>>>>>>>> +            possibleClasses =
>>> ClassFinder.findClassesThatExtend(
>>>>>>>>> JMeterUtils.getSearchPaths(),
>>>>>>>>> +                    new Class[] { BackendListenerClient.class
>>> });
>>>>>>>>> +
>>>>>>>>> +            // Remove the BackendListener class from the list
>>>> since it
>>>>>>>>> only
>>>>>>>>>
>>>>>>>>>   ErrorBackendListener
>>>>>>>>   +            // implements the interface for error conditions.
>>>>>>>>> +
>>>>>>>>> +
>>> possibleClasses.remove(BackendListener.class.getName()
>>>> +
>>>>>>>>> "$ErrorBackendListenerClient");
>>>>>>>>> +        } catch (Exception e) {
>>>>>>>>> +            log.debug("Exception getting interfaces.", e);
>>>>>>>>> +        }
>>>>>>>>> +
>>>>>>>>> +        JLabel label = new
>>>> JLabel(JMeterUtils.getResString("backend_
>>>>>>>>> listener_classname"));
>>>>>>>>> // $NON-NLS-1$
>>>>>>>>> +
>>>>>>>>> +        classnameCombo = new
>>> JComboBox(possibleClasses.toArray());
>>>>>>>>> +        classnameCombo.addActionListener(this);
>>>>>>>>> +        classnameCombo.setEditable(false);
>>>>>>>>> +        label.setLabelFor(classnameCombo);
>>>>>>>>> +
>>>>>>>>> +        HorizontalPanel classNamePanel = new
>>> HorizontalPanel();
>>>>>>>>> +        classNamePanel.add(label);
>>>>>>>>> +        classNamePanel.add(classnameCombo);
>>>>>>>>> +
>>>>>>>>> +        queueSize = new JTextField("", 5);
>>>>>>>>> +        queueSize.setName("Queue Size"); //$NON-NLS-1$
>>>>>>>>> +        JLabel queueSizeLabel = new JLabel(JMeterUtils.
>>>>>>>>> getResString("backend_listener_queue_size")); // $NON-NLS-1$
>>>>>>>>> +        queueSizeLabel.setLabelFor(queueSize);
>>>>>>>>> +        HorizontalPanel queueSizePanel = new
>>> HorizontalPanel();
>>>>>>>>> +        queueSizePanel.add(queueSizeLabel,
>>> BorderLayout.WEST);
>>>>>>>>> +        queueSizePanel.add(queueSize);
>>>>>>>>> +
>>>>>>>>> +        JPanel panel = new JPanel(new BorderLayout(0, 5));
>>>>>>>>> +        panel.add(classNamePanel, BorderLayout.NORTH);
>>>>>>>>> +        panel.add(queueSizePanel, BorderLayout.CENTER);
>>>>>>>>> +        return panel;
>>>>>>>>> +    }
>>>>>>>>> +
>>>>>>>>> +    /**
>>>>>>>>> +     * Handle action events for this component. This method
>>>> currently
>>>>>>>>> handles
>>>>>>>>> +     * events for the classname combo box.
>>>>>>>>> +     *
>>>>>>>>> +     * @param evt
>>>>>>>>>
>>>>>>>>>   I would spend the few extra characters to make it event
>>> instead of
>>>> evt
>>>>>>>>   +     *            the ActionEvent to be handled
>>>>>>>>> +     */
>>>>>>>>> +    @Override
>>>>>>>>> +    public void actionPerformed(ActionEvent evt) {
>>>>>>>>> +        if (evt.getSource() == classnameCombo) {
>>>>>>>>> +            String className = ((String) classnameCombo.
>>>>>>>>> getSelectedItem()).trim();
>>>>>>>>> +            try {
>>>>>>>>> +                BackendListenerClient client =
>>>> (BackendListenerClient)
>>>>>>>>> Class.forName(className, true,
>>>>>>>>> +                        Thread.currentThread().
>>>>>>>>> getContextClassLoader()).
>>>>>>>>> newInstance();
>>>>>>>>> +
>>>>>>>>> +                Arguments currArgs = new Arguments();
>>>>>>>>> +                argsPanel.modifyTestElement(currArgs);
>>>>>>>>> +                Map<String, String> currArgsMap =
>>>>>>>>> currArgs.getArgumentsAsMap();
>>>>>>>>> +
>>>>>>>>> +                Arguments newArgs = new Arguments();
>>>>>>>>> +                Arguments testParams = null;
>>>>>>>>> +                try {
>>>>>>>>> +                    testParams =
>>> client.getDefaultParameters();
>>>>>>>>> +                } catch (AbstractMethodError e) {
>>>>>>>>> +                    log.warn("BackendListenerClient doesn't
>>>> implement
>>>>>>>>> "
>>>>>>>>> +                            + "getDefaultParameters.  Default
>>>>>>>>> parameters
>>>>>>>>> won't "
>>>>>>>>> +                            + "be shown.  Please update your
>>> client
>>>>>>>>> class: " + className);
>>>>>>>>> +                }
>>>>>>>>> +
>>>>>>>>> +                if (testParams != null) {
>>>>>>>>> +                    PropertyIterator i =
>>> testParams.getArguments().
>>>>>>>>> iterator();
>>>>>>>>>
>>>>>>>>>   I would try a for loop instead of explicitly using an
>>> iterator
>>>>>>>>   +                    while (i.hasNext()) {
>>>>>>>>> +                        Argument arg = (Argument)
>>>>>>>>> i.next().getObjectValue();
>>>>>>>>> +                        String name = arg.getName();
>>>>>>>>> +                        String value = arg.getValue();
>>>>>>>>> +
>>>>>>>>> +                        // If a user has set parameters in
>>> one
>>>> test,
>>>>>>>>> and
>>>>>>>>> then
>>>>>>>>> +                        // selects a different test which
>>> supports
>>>> the
>>>>>>>>> same
>>>>>>>>> +                        // parameters, those parameters
>>> should
>>>> have the
>>>>>>>>> same
>>>>>>>>> +                        // values that they did in the
>>> original
>>>> test.
>>>>>>>>> +                        if (currArgsMap.containsKey(name)) {
>>>>>>>>> +                            String newVal =
>>> currArgsMap.get(name);
>>>>>>>>> +                            if (newVal != null &&
>>> newVal.length()
>>>>> 0)
>>>>>>>>> {
>>>>>>>>> +                                value = newVal;
>>>>>>>>> +                            }
>>>>>>>>> +                        }
>>>>>>>>> +                        newArgs.addArgument(name, value);
>>>>>>>>> +                    }
>>>>>>>>> +                }
>>>>>>>>> +
>>>>>>>>> +                argsPanel.configure(newArgs);
>>>>>>>>> +            } catch (Exception e) {
>>>>>>>>> +                log.error("Error getting argument list for "
>>> +
>>>>>>>>> className, e);
>>>>>>>>> +            }
>>>>>>>>> +        }
>>>>>>>>> +    }
>>>>>>>>> +
>>>>>>>>> +    /**
>>>>>>>>> +     * Create a panel containing components allowing the user
>>> to
>>>>>>>>> provide
>>>>>>>>> +     * arguments to be passed to the test class instance.
>>>>>>>>> +     *
>>>>>>>>> +     * @return a panel containing the relevant components
>>>>>>>>> +     */
>>>>>>>>> +    private JPanel createParameterPanel() {
>>>>>>>>> +        argsPanel = new ArgumentsPanel(JMeterUtils.
>>>>>>>>> getResString("backend_listener_paramtable")); // $NON-NLS-1$
>>>>>>>>> +        return argsPanel;
>>>>>>>>> +    }
>>>>>>>>> +
>>>>>>>>> +    /** {@inheritDoc} */
>>>>>>>>> +    @Override
>>>>>>>>> +    public void configure(TestElement config) {
>>>>>>>>> +        super.configure(config);
>>>>>>>>> +
>>>>>>>>> +        argsPanel.configure((Arguments) config.getProperty(
>>>>>>>>> BackendListener.ARGUMENTS).getObjectValue());
>>>>>>>>> +
>>>>>>>>> +        String className = config.getPropertyAsString(
>>>>>>>>> BackendListener.CLASSNAME);
>>>>>>>>> +        if(checkContainsClassName(classnameCombo.getModel(),
>>>>>>>>> className)) {
>>>>>>>>> +            classnameCombo.setSelectedItem(className);
>>>>>>>>> +        } else {
>>>>>>>>> +            log.error("Error setting class:'"+className+"' in
>>>>>>>>> BackendListener: "+getName()+
>>>>>>>>> +                    ", check for a missing jar in your jmeter
>>>>>>>>> 'search_paths' and 'plugin_dependency_paths' properties");
>>>>>>>>> +        }
>>>>>>>>> +        queueSize.setText(Integer.toString(((BackendListener)
>>>>>>>>> config).getQueueSize()));
>>>>>>>>> +    }
>>>>>>>>> +
>>>>>>>>> +    /**
>>>>>>>>> +     * Check combo contains className
>>>>>>>>> +     * @param model ComboBoxModel
>>>>>>>>> +     * @param className String class name
>>>>>>>>> +     * @return boolean
>>>>>>>>>
>>>>>>>>>   explain "boolean" or the other params a bit more?
>>>>>>>>   +     */
>>>>>>>>> +    private static final boolean
>>>> checkContainsClassName(ComboBoxModel
>>>>>>>>> model, String className) {
>>>>>>>>> +        int size = model.getSize();
>>>>>>>>> +        Set<String> set = new HashSet<String>(size);
>>>>>>>>> +        for (int i = 0; i < size; i++) {
>>>>>>>>> +            set.add((String)model.getElementAt(i));
>>>>>>>>> +        }
>>>>>>>>> +        return set.contains(className);
>>>>>>>>> +    }
>>>>>>>>> +
>>>>>>>>> +    /** {@inheritDoc} */
>>>>>>>>> +    @Override
>>>>>>>>> +    public TestElement createTestElement() {
>>>>>>>>> +        BackendListener config = new BackendListener();
>>>>>>>>> +        modifyTestElement(config);
>>>>>>>>> +        return config;
>>>>>>>>> +    }
>>>>>>>>> +
>>>>>>>>> +    /** {@inheritDoc} */
>>>>>>>>> +    @Override
>>>>>>>>> +    public void modifyTestElement(TestElement config) {
>>>>>>>>> +        configureTestElement(config);
>>>>>>>>> +        BackendListener backendListener = (BackendListener)
>>> config;
>>>>>>>>> +        backendListener.setArguments((Arguments)
>>>>>>>>> argsPanel.createTestElement());
>>>>>>>>> +
>>> backendListener.setClassname(String.valueOf(classnameCombo.
>>>>>>>>> getSelectedItem()));
>>>>>>>>> +
>>> backendListener.setQueueSize(Integer.parseInt(queueSize.
>>>>>>>>> getText()));
>>>>>>>>> +
>>>>>>>>> +    }
>>>>>>>>> +
>>>>>>>>>
>>>>
>>>>
>>
>


Re: svn commit: r1641081 - in /jmeter/trunk: ./ bin/ res/maven/ src/components/org/apache/jmeter/visualizers/backend/ src/core/org/apache/jmeter/resources/ src/core/org/apache/jmeter/samplers/ src/core/org/apache/jmeter/save/ xdocs/ xdocs/usermanual/

Posted by Philippe Mouawad <ph...@gmail.com>.
On Sun, Nov 30, 2014 at 10:19 AM, Felix Schumacher <
felix.schumacher@internetallee.de> wrote:

>
>
> Am 29. November 2014 21:12:00 MEZ, schrieb Philippe Mouawad <
> philippe.mouawad@gmail.com>:
> >Hi Felix
> >
> >My answer inline.
> >Regards
> >
> >On Sat, Nov 29, 2014 at 11:51 AM, Felix Schumacher <
> >felix.schumacher@internetallee.de> wrote:
> >
> >> Hello Philippe,
> >>
> >> Am Sonntag, den 23.11.2014, 12:22 +0100 schrieb Philippe Mouawad:
> >> > Thanks a lot for your review which pointed to a synchronisation
> >issue
> >> that
> >> > I fixed, good catch!
> >> >
> >> > I think I took all your notes into account, let me know if I forgot
> >> > something.
> >> in SamplerMetric you have used a sliding window for the statistics.
> >> * Should we make the length of the window configurable?
> >>
> >
> >Yes but it's a new property and we have a lot :-)
> But the size of the window depends on the number of samples per time slot.
> Perhaps it could be dynamically sized?
>

You mean it needs to be increased if there is a big number of requests in
time slot for 1 sample ?
Please clarfify so that I am sure to understand. For now I made it
configurable through a property.

>
> >
> >
> >> * Should min/max and minThreads/maxThreads be limited to the sliding
> >> window, also? At least min and max would be simple to do.
> >>
> >
> >Dev team opinion is welcome, maybe it would be better
> >- min would be percentile(0)
> >- max would be percentile(100)
>
> The stats field has methods to get the minimum and the maximum values. I
> would take those.
>
OK , done

>
> >for minThreads, maxThreads, how would you do it ?
>
> Create another statistical field for the number of threads. Then we could
> provide correct answers for max/min thread numbers plus
> mean/average/percentile.
>
> For this one, I don't see in fact the use case, as number of threads will
not vary a lot so in what way do you think it is incorrect ?
Maybe my question is stupid as I don't see currently the problem but I may
be wrong. Can you clarify ?
Thx


> Regards
> Felix
>
> >
> >
> >> Regards
> >>  Felix
> >> >
> >> > Regards
> >> > Philippe
> >> >
> >> > On Sunday, November 23, 2014, Felix Schumacher <
> >> > felix.schumacher@internetallee.de> wrote:
> >> >
> >> > > Hi Phillipe,
> >> > > Am 22.11.2014 um 19:29 schrieb Philippe Mouawad:
> >> > >
> >> > >> Hi Felix,
> >> > >> As I said in thread, I commited code and will improve, feel free
> >to
> >> fix
> >> > >> javadocs issues on your side.
> >> > >> I will review your comment.
> >> > >>
> >> > >> I have spent many hours if not days on this code and I am aware
> >it is
> >> not
> >> > >> yet fully completed (although tests are promising) but my aim
> >when
> >> > >> commiting it was to have feedback and help to finish it.
> >> > >>
> >> > > I did not mean to offend you. I can clearly see, that you put a
> >lot of
> >> > > effort
> >> > > in this listener and I will surely try to integrate jmeter into
> >our
> >> > > collectd server.
> >> > >
> >> > > Regards
> >> > >  Felix
> >> > >
> >> > >>
> >> > >> Regards
> >> > >> Philippe
> >> > >>
> >> > >> On Sat, Nov 22, 2014 at 7:21 PM, Felix Schumacher <
> >> > >> felix.schumacher@internetallee.de> wrote:
> >> > >>
> >> > >>  Hello Philippe,
> >> > >>>
> >> > >>> I have hidden a few comments inside the cited code.
> >> > >>> They are mostly around javadoc and naming things.
> >> > >>>
> >> > >>> Am 22.11.2014 um 16:36 schrieb pmouawad@apache.org:
> >> > >>>
> >> > >>>  Author: pmouawad
> >> > >>>> Date: Sat Nov 22 15:36:37 2014
> >> > >>>> New Revision: 1641081
> >> > >>>>
> >> > >>>> URL: http://svn.apache.org/r1641081
> >> > >>>> Log:
> >> > >>>> Bug 55932 - Create a Async BackendListener to allow easy plug
> >of new
> >> > >>>> listener (Graphite, JDBC, Console,...)
> >> > >>>> Bugzilla Id: 55932
> >> > >>>>
> >> > >>>> Added:
> >> > >>>>
> >jmeter/trunk/src/components/org/apache/jmeter/visualizers/
> >> > >>>> backend/
> >> > >>>>
> >jmeter/trunk/src/components/org/apache/jmeter/visualizers/
> >> > >>>> backend/
> >> > >>>> AbstractBackendListenerClient.java   (with props)
> >> > >>>>
> >jmeter/trunk/src/components/org/apache/jmeter/visualizers/
> >> > >>>> backend/BackendListener.java
> >> > >>>>   (with props)
> >> > >>>>
> >jmeter/trunk/src/components/org/apache/jmeter/visualizers/
> >> > >>>> backend/BackendListenerClient.java   (with props)
> >> > >>>>
> >jmeter/trunk/src/components/org/apache/jmeter/visualizers/
> >> > >>>> backend/BackendListenerContext.java
> >> > >>>>   (with props)
> >> > >>>>
> >jmeter/trunk/src/components/org/apache/jmeter/visualizers/
> >> > >>>> backend/BackendListenerGui.java   (with props)
> >> > >>>>
> >jmeter/trunk/src/components/org/apache/jmeter/visualizers/
> >> > >>>> backend/SamplerMetric.java
> >> > >>>>   (with props)
> >> > >>>> Modified:
> >> > >>>>       jmeter/trunk/bin/saveservice.properties
> >> > >>>>       jmeter/trunk/build.properties
> >> > >>>>       jmeter/trunk/build.xml
> >> > >>>>       jmeter/trunk/eclipse.classpath
> >> > >>>>       jmeter/trunk/res/maven/ApacheJMeter_parent.pom
> >> > >>>>       jmeter/trunk/src/core/org/apache/jmeter/resources/
> >> > >>>> messages.properties
> >> > >>>>       jmeter/trunk/src/core/org/apache/jmeter/resources/
> >> > >>>> messages_fr.properties
> >> > >>>>       jmeter/trunk/src/core/org/apache/jmeter/samplers/
> >> > >>>> SampleResult.java
> >> > >>>>
> >jmeter/trunk/src/core/org/apache/jmeter/save/SaveService.java
> >> > >>>>       jmeter/trunk/xdocs/changes.xml
> >> > >>>>       jmeter/trunk/xdocs/usermanual/component_reference.xml
> >> > >>>>
> >> > >>>> Modified: jmeter/trunk/bin/saveservice.properties
> >> > >>>> URL:
> >http://svn.apache.org/viewvc/jmeter/trunk/bin/saveservice.
> >> > >>>> properties?rev=1641081&r1=1641080&r2=1641081&view=diff
> >> > >>>> ============================================================
> >> > >>>> ==================
> >> > >>>> --- jmeter/trunk/bin/saveservice.properties (original)
> >> > >>>> +++ jmeter/trunk/bin/saveservice.properties Sat Nov 22
> >15:36:37 2014
> >> > >>>> @@ -53,7 +53,8 @@ _file_version=$Revision$
> >> > >>>>    # 2.5 = 2.10
> >> > >>>>    # 2.6 = 2.11
> >> > >>>>    # 2.7 = 2.12
> >> > >>>> -_version=2.7
> >> > >>>> +# 2.8 = 2.13
> >> > >>>> +_version=2.8
> >> > >>>>    #
> >> > >>>>    #
> >> > >>>>    # Character set encoding used to read and write JMeter XML
> >files
> >> and
> >> > >>>> CSV results
> >> > >>>> @@ -78,6 +79,8 @@ AssertionVisualizer=org.apache.jmeter.vi
> >> > >>>>
> >AuthManager=org.apache.jmeter.protocol.http.control.AuthManager
> >> > >>>>
> >> Authorization=org.apache.jmeter.protocol.http.control.Authorization
> >> > >>>>    AuthPanel=org.apache.jmeter.protocol.http.gui.AuthPanel
> >> > >>>>
> >>
> >+BackendListener=org.apache.jmeter.visualizers.backend.BackendListener
> >> > >>>> +BackendListenerGui=org.apache.jmeter.visualizers.
> >> > >>>> backend.BackendListenerGui
> >> > >>>>    BarChart=org.apache.jmeter.testelement.BarChart
> >> > >>>>    BarChartGui=org.apache.jmeter.report.gui.BarChartGui
> >> > >>>>
> >> BeanShellAssertion=org.apache.jmeter.assertions.BeanShellAssertion
> >> > >>>>
> >> > >>>> Modified: jmeter/trunk/build.properties
> >> > >>>> URL:
> >http://svn.apache.org/viewvc/jmeter/trunk/build.properties?
> >> > >>>> rev=1641081&r1=1641080&r2=1641081&view=diff
> >> > >>>> ============================================================
> >> > >>>> ==================
> >> > >>>> --- jmeter/trunk/build.properties (original)
> >> > >>>> +++ jmeter/trunk/build.properties Sat Nov 22 15:36:37 2014
> >> > >>>> @@ -118,11 +118,21 @@ commons-logging.loc         = ${maven2.r
> >> > >>>>    #commons-logging.md5         =
> >E2C390FE739B2550A218262B28F290CE
> >> > >>>>    commons-logging.md5         =
> >040b4b4d8eac886f6b4a2a3bd2f31b00
> >> > >>>>    +commons-math3.version         = 3.3
> >> > >>>> +commons-math3.jar             =
> >commons-math3-${commons-math3.
> >> > >>>> version}.jar
> >> > >>>> +commons-math3.loc             = ${maven2.repo}/org/apache/
> >> > >>>> commons/commons-math3/${commons-math3.version}
> >> > >>>> +commons-math3.md5             =
> >87346cf2772dc2becf106c45e0f63863
> >> > >>>> +
> >> > >>>>    commons-net.version         = 3.3
> >> > >>>>    commons-net.jar             =
> >> commons-net-${commons-net.version}.jar
> >> > >>>>    commons-net.loc             = ${maven2.repo}/commons-net/
> >> > >>>> commons-net/${commons-net.version}
> >> > >>>>    commons-net.md5             =
> >c077ca61598e9c21f43f8b6488fbbee9
> >> > >>>>    +commons-pool2.version         = 2.2
> >> > >>>> +commons-pool2.jar             =
> >commons-pool2-${commons-pool2.
> >> > >>>> version}.jar
> >> > >>>> +commons-pool2.loc             = ${maven2.repo}/org/apache/
> >> > >>>> commons/commons-pool2/${commons-pool2.version}
> >> > >>>> +commons-pool2.md5             =
> >51b56c92883812c56fbeb339866ce2df
> >> > >>>> +
> >> > >>>>    # dnsjava for DNSCacheManager
> >> > >>>>    dnsjava.version             = 2.1.6
> >> > >>>>    dnsjava.jar                 =
> >dnsjava-${dnsjava.version}.jar
> >> > >>>>
> >> > >>>> Modified: jmeter/trunk/build.xml
> >> > >>>> URL: http://svn.apache.org/viewvc/jmeter/trunk/build.xml?rev=
> >> > >>>> 1641081&r1=1641080&r2=1641081&view=diff
> >> > >>>> ============================================================
> >> > >>>> ==================
> >> > >>>> --- jmeter/trunk/build.xml (original)
> >> > >>>> +++ jmeter/trunk/build.xml Sat Nov 22 15:36:37 2014
> >> > >>>> @@ -365,7 +365,9 @@
> >> > >>>>        <include name="${lib.dir}/${commons-jexl2.jar}"/>
> >> > >>>>        <include name="${lib.dir}/${commons-lang3.jar}"/>
> >> > >>>>        <include name="${lib.dir}/${commons-logging.jar}"/>
> >> > >>>> +    <include name="${lib.dir}/${commons-math3}"/>
> >> > >>>>        <include name="${lib.dir}/${commons-net.jar}"/>
> >> > >>>> +    <include name="${lib.dir}/${commons-pool2.jar}"/>
> >> > >>>>        <include name="${lib.dir}/${dnsjava.jar}"/>
> >> > >>>>        <include
> >name="${lib.dir}/${excalibur-datasource.jar}"/>
> >> > >>>>        <include
> >name="${lib.dir}/${excalibur-instrument.jar}"/>
> >> > >>>> @@ -438,8 +440,10 @@
> >> > >>>>        <pathelement
> >location="${lib.dir}/${commons-jexl2.jar}"/>
> >> > >>>>        <pathelement
> >location="${lib.dir}/${commons-lang3.jar}"/>
> >> > >>>>        <pathelement
> >location="${lib.dir}/${commons-logging.jar}"/>
> >> > >>>> +    <pathelement location="${lib.dir}/${commons-math3.jar}"/>
> >> > >>>>        <pathelement location="${lib.dir}/${commons-net.jar}"/>
> >> > >>>> -    <pathelement location="${lib.dir}/${dnsjava.jar}"/>
> >> > >>>> +       <pathelement
> >location="${lib.dir}/${commons-pool2.jar}"/>
> >> > >>>> +       <pathelement location="${lib.dir}/${dnsjava.jar}"/>
> >> > >>>>        <pathelement
> >> location="${lib.dir}/${excalibur-datasource.jar}"/>
> >> > >>>>        <pathelement
> >> location="${lib.dir}/${excalibur-instrument.jar}"/>
> >> > >>>>        <pathelement
> >location="${lib.dir}/${excalibur-logger.jar}"/>
> >> > >>>> @@ -2909,7 +2913,9 @@ run JMeter unless all the JMeter jars ar
> >> > >>>>            <process_jarfile jarname="commons-jexl2"/>
> >> > >>>>            <process_jarfile jarname="commons-lang3"/>
> >> > >>>>            <process_jarfile jarname="commons-logging"/>
> >> > >>>> +        <process_jarfile jarname="commons-math3"/>
> >> > >>>>            <process_jarfile jarname="commons-net"/>
> >> > >>>> +       <process_jarfile jarname="commons-pool2"/>
> >> > >>>>            <process_jarfile jarname="dnsjava"/>
> >> > >>>>            <process_jarfile jarname="excalibur-datasource"/>
> >> > >>>>            <process_jarfile jarname="excalibur-instrument"/>
> >> > >>>>
> >> > >>>> Modified: jmeter/trunk/eclipse.classpath
> >> > >>>> URL: http://svn.apache.org/viewvc/jmeter/trunk/eclipse.
> >> > >>>> classpath?rev=1641081&r1=1641080&r2=1641081&view=diff
> >> > >>>> ============================================================
> >> > >>>> ==================
> >> > >>>> --- jmeter/trunk/eclipse.classpath (original)
> >> > >>>> +++ jmeter/trunk/eclipse.classpath Sat Nov 22 15:36:37 2014
> >> > >>>> @@ -55,7 +55,9 @@
> >> > >>>>          <classpathentry kind="lib"
> >> path="lib/commons-jexl-2.1.1.jar"/>
> >> > >>>>          <classpathentry kind="lib"
> >path="lib/commons-lang3-3.3.2.
> >> > >>>> jar"/>
> >> > >>>>          <classpathentry kind="lib"
> >path="lib/commons-logging-1.2.
> >> > >>>> jar"/>
> >> > >>>> +    <classpathentry kind="lib"
> >path="lib/commons-math3-3.3.jar"/>
> >> > >>>>          <classpathentry kind="lib"
> >path="lib/commons-net-3.3.jar"/>
> >> > >>>> +    <classpathentry kind="lib"
> >path="lib/commons-pool2-2.2.jar"/>
> >> > >>>>          <classpathentry kind="lib"
> >path="lib/dnsjava-2.1.6.jar"/>
> >> > >>>>          <classpathentry kind="lib" path="lib/excalibur-
> >> > >>>> datasource-2.1.jar"/>
> >> > >>>>          <classpathentry kind="lib" path="lib/excalibur-
> >> > >>>> instrument-1.0.jar"/>
> >> > >>>>
> >> > >>>> Modified: jmeter/trunk/res/maven/ApacheJMeter_parent.pom
> >> > >>>> URL: http://svn.apache.org/viewvc/jmeter/trunk/res/maven/
> >> > >>>>
> >ApacheJMeter_parent.pom?rev=1641081&r1=1641080&r2=1641081&view=diff
> >> > >>>> ============================================================
> >> > >>>> ==================
> >> > >>>> --- jmeter/trunk/res/maven/ApacheJMeter_parent.pom (original)
> >> > >>>> +++ jmeter/trunk/res/maven/ApacheJMeter_parent.pom Sat Nov 22
> >> 15:36:37
> >> > >>>> 2014
> >> > >>>> @@ -66,7 +66,9 @@ under the License.
> >> > >>>>          <commons-jexl2.version>2.1.1</commons-jexl2.version>
> >> > >>>>          <commons-lang3.version>3.3.2</commons-lang3.version>
> >> > >>>>
> ><commons-logging.version>1.2</commons-logging.version>
> >> > >>>> +      <commons-math3.version>3.3</commons-math3.version>
> >> > >>>>          <commons-net.version>3.3</commons-net.version>
> >> > >>>> +      <commons-pool2.version>2.2</commons-pool2.version>
> >> > >>>>          <dnsjava.version>2.1.6</dnsjava.version>
> >> > >>>>
> ><excalibur-datasource.version>2.1</excalibur-datasource.
> >> > >>>> version>
> >> > >>>>
> ><excalibur-instrument.version>1.0</excalibur-instrument.
> >> > >>>> version>
> >> > >>>> @@ -181,11 +183,21 @@ under the License.
> >> > >>>>            <version>${commons-logging.version}</version>
> >> > >>>>          </dependency>
> >> > >>>>          <dependency>
> >> > >>>> +        <groupId>commons-math3</groupId>
> >> > >>>> +        <artifactId>commons-math3</artifactId>
> >> > >>>> +        <version>${commons-math3.version}</version>
> >> > >>>> +      </dependency>
> >> > >>>> +      <dependency>
> >> > >>>>            <groupId>commons-net</groupId>
> >> > >>>>            <artifactId>commons-net</artifactId>
> >> > >>>>            <version>${commons-net.version}</version>
> >> > >>>>          </dependency>
> >> > >>>>          <dependency>
> >> > >>>> +        <groupId>commons-pool2</groupId>
> >> > >>>> +        <artifactId>commons-pool2</artifactId>
> >> > >>>> +        <version>${commons-pool2.version}</version>
> >> > >>>> +      </dependency>
> >> > >>>> +      <dependency>
> >> > >>>>              <groupId>dnsjava</groupId>
> >> > >>>>              <artifactId>dnsjava</artifactId>
> >> > >>>>              <version>${dnsjava.version}</version>
> >> > >>>>
> >> > >>>> Added:
> >jmeter/trunk/src/components/org/apache/jmeter/visualizers/
> >> > >>>> backend/
> >> > >>>> AbstractBackendListenerClient.java
> >> > >>>> URL: http://svn.apache.org/viewvc/jmeter/trunk/src/components/
> >> > >>>>
> >org/apache/jmeter/visualizers/backend/AbstractBackendListenerClient.
> >> > >>>> java?rev=1641081&view=auto
> >> > >>>> ============================================================
> >> > >>>> ==================
> >> > >>>> ---
> >> jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/
> >> > >>>> AbstractBackendListenerClient.java (added)
> >> > >>>> +++
> >> jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/
> >> > >>>> AbstractBackendListenerClient.java Sat Nov 22 15:36:37 2014
> >> > >>>> @@ -0,0 +1,121 @@
> >> > >>>> +/*
> >> > >>>> + * 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.jmeter.visualizers.backend;
> >> > >>>> +
> >> > >>>> +import java.util.Map;
> >> > >>>> +import java.util.concurrent.ConcurrentHashMap;
> >> > >>>> +
> >> > >>>> +import org.apache.jmeter.config.Arguments;
> >> > >>>> +import org.apache.jmeter.samplers.SampleResult;
> >> > >>>> +import org.apache.jorphan.logging.LoggingManager;
> >> > >>>> +import org.apache.log.Logger;
> >> > >>>> +
> >> > >>>> +/**
> >> > >>>> + * An abstract implementation of the BackendListenerClient
> >> interface.
> >> > >>>> This
> >> > >>>> + * implementation provides default implementations of most of
> >the
> >> > >>>> methods in the
> >> > >>>> + * interface, as well as some convenience methods, in order
> >to
> >> simplify
> >> > >>>> + * development of BackendListenerClient implementations.
> >> > >>>> + *
> >> > >>>> + * While it may be necessary to make changes to the
> >> > >>>> BackendListenerClient interface
> >> > >>>> + * from time to time (therefore requiring changes to any
> >> > >>>> implementations
> >> > >>>> of this
> >> > >>>> + * interface), we intend to make this abstract class provide
> >> reasonable
> >> > >>>> + * implementations of any new methods so that subclasses do
> >not
> >> > >>>> necessarily need
> >> > >>>> + * to be updated for new versions. Therefore, when creating a
> >new
> >> > >>>> + * BackendListenerClient implementation, developers are
> >encouraged
> >> to
> >> > >>>> subclass this
> >> > >>>> + * abstract class rather than implementing the
> >> BackendListenerClient
> >> > >>>> interface
> >> > >>>> + * directly. Implementing BackendListenerClient directly will
> >> continue
> >> > >>>> to be
> >> > >>>> + * supported for cases where extending this class is not
> >possible
> >> (for
> >> > >>>> example,
> >> > >>>> + * when the client class is already a subclass of some other
> >> class).
> >> > >>>> + * <p>
> >> > >>>> + * The handleSampleResult() method of BackendListenerClient
> >does
> >> not
> >> > >>>> have a default
> >> > >>>> + * implementation here, so subclasses must define at least
> >this
> >> method.
> >> > >>>> It may
> >> > >>>> + * be useful to override other methods as well.
> >> > >>>> + *
> >> > >>>> + * @see BackendListener#sampleOccurred(org.apache.
> >> > >>>> jmeter.samplers.SampleEvent)
> >> > >>>> + * @since 2.13
> >> > >>>> + */
> >> > >>>> +public abstract class AbstractBackendListenerClient
> >implements
> >> > >>>> BackendListenerClient {
> >> > >>>> +
> >> > >>>> +    private static final Logger log = LoggingManager.
> >> > >>>> getLoggerForClass();
> >> > >>>>
> >> > >>>>  In classes further down the logger is stored in variables
> >named
> >> LOG and
> >> > >>> LOGGER, should we use one name?
> >> > >>> In this class we have a getter for the logger in other classes
> >not.
> >> Why?
> >> > >>>
> >> > >>>  +
> >> > >>>> +    private ConcurrentHashMap<String, SamplerMetric>
> >> metricsPerSampler
> >> > >>>> =
> >> > >>>> new ConcurrentHashMap<String, SamplerMetric>();
> >> > >>>> +
> >> > >>>> +    /* Implements
> >> BackendListenerClient.setupTest(JavaSamplerContext)
> >> > >>>> */
> >> > >>>> +    @Override
> >> > >>>> +    public void setupTest(BackendListenerContext context)
> >throws
> >> > >>>> Exception {
> >> > >>>> +        log.debug(getClass().getName() + ": setupTest");
> >> > >>>> +    }
> >> > >>>> +
> >> > >>>> +    /* Implements BackendListenerClient.teardownTest(
> >> > >>>> JavaSamplerContext)
> >> > >>>> */
> >> > >>>> +    @Override
> >> > >>>> +    public void teardownTest(BackendListenerContext context)
> >throws
> >> > >>>> Exception {
> >> > >>>> +        log.debug(getClass().getName() + ": teardownTest");
> >> > >>>> +        metricsPerSampler.clear();
> >> > >>>> +    }
> >> > >>>> +
> >> > >>>> +    /* Implements
> >BackendListenerClient.getDefaultParameters() */
> >> > >>>> +    @Override
> >> > >>>> +    public Arguments getDefaultParameters() {
> >> > >>>> +        return null;
> >> > >>>> +    }
> >> > >>>> +
> >> > >>>> +    /**
> >> > >>>> +     * Get a Logger instance which can be used by subclasses
> >to log
> >> > >>>> information.
> >> > >>>> +     *
> >> > >>>> +     * @return a Logger instance which can be used for
> >logging
> >> > >>>> +     */
> >> > >>>> +    protected Logger getLogger() {
> >> > >>>> +        return log;
> >> > >>>> +    }
> >> > >>>> +
> >> > >>>> +    /* (non-Javadoc)
> >> > >>>> +     * @see org.apache.jmeter.visualizers.
> >> > >>>> backend.BackendListenerClient#
> >> > >>>> createSampleResult(org.apache.jmeter.samplers.SampleResult)
> >> > >>>> +     */
> >> > >>>> +    @Override
> >> > >>>> +    public SampleResult
> >createSampleResult(BackendListenerContext
> >> > >>>> context, SampleResult result) {
> >> > >>>> +        SampleResult sampleResult = (SampleResult)
> >result.clone();
> >> > >>>> +        return sampleResult;
> >> > >>>> +    }
> >> > >>>> +
> >> > >>>> +    /**
> >> > >>>> +     *
> >> > >>>> +     * @param sampleLabel
> >> > >>>> +     * @return SamplerMetric
> >> > >>>>
> >> > >>>>  No description of the method and the parameters?
> >> > >>>
> >> > >>>  +     */
> >> > >>>> +    protected SamplerMetric getSamplerMetric(String
> >sampleLabel) {
> >> > >>>> +        SamplerMetric samplerMetric = metricsPerSampler.get(
> >> > >>>> sampleLabel);
> >> > >>>> +        if(samplerMetric == null) {
> >> > >>>> +            samplerMetric = new SamplerMetric();
> >> > >>>> +            SamplerMetric oldValue =
> >metricsPerSampler.putIfAbsent(
> >> > >>>> sampleLabel,
> >> > >>>> samplerMetric);
> >> > >>>> +            if(oldValue != null ){
> >> > >>>> +                samplerMetric = oldValue;
> >> > >>>> +            }
> >> > >>>> +        }
> >> > >>>> +        return samplerMetric;
> >> > >>>> +    }
> >> > >>>> +
> >> > >>>> +    /**
> >> > >>>> +     *
> >> > >>>> +     * @return Map<String, SamplerMetric>
> >> > >>>>
> >> > >>>>  No description of the method and usage of forbidden
> >characters :)
> >> there
> >> > >>> are still more than 800 warnings in the javadoc to prune, so
> >don't
> >> > >>> introduce new ones, please.
> >> > >>>
> >> > >>>  +     */
> >> > >>>> +    protected Map<String, SamplerMetric>
> >getMetricsPerSampler() {
> >> > >>>> +        return metricsPerSampler;
> >> > >>>> +    }
> >> > >>>> +
> >> > >>>> +}
> >> > >>>>
> >> > >>>> Propchange:
> >> jmeter/trunk/src/components/org/apache/jmeter/visualizers/
> >> > >>>> backend/AbstractBackendListenerClient.java
> >> > >>>> ------------------------------------------------------------
> >> > >>>> ------------------
> >> > >>>>       svn:mime-type = text/plain
> >> > >>>>
> >> > >>>> Added:
> >jmeter/trunk/src/components/org/apache/jmeter/visualizers/
> >> > >>>> backend/BackendListener.java
> >> > >>>> URL: http://svn.apache.org/viewvc/jmeter/trunk/src/components/
> >> > >>>> org/apache/jmeter/visualizers/backend/BackendListener.java?
> >> > >>>> rev=1641081&view=auto
> >> > >>>> ============================================================
> >> > >>>> ==================
> >> > >>>> --- jmeter/trunk/src/components/org/apache/jmeter/visualizers/
> >> > >>>> backend/BackendListener.java
> >> > >>>> (added)
> >> > >>>> +++ jmeter/trunk/src/components/org/apache/jmeter/visualizers/
> >> > >>>> backend/BackendListener.java
> >> > >>>> Sat Nov 22 15:36:37 2014
> >> > >>>> @@ -0,0 +1,448 @@
> >> > >>>> +/*
> >> > >>>> + * 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.jmeter.visualizers.backend;
> >> > >>>> +
> >> > >>>> +import java.io.Serializable;
> >> > >>>> +import java.lang.reflect.Method;
> >> > >>>> +import java.util.ArrayList;
> >> > >>>> +import java.util.HashSet;
> >> > >>>> +import java.util.List;
> >> > >>>> +import java.util.Set;
> >> > >>>> +import java.util.concurrent.ArrayBlockingQueue;
> >> > >>>> +import java.util.concurrent.BlockingQueue;
> >> > >>>> +import java.util.concurrent.locks.LockSupport;
> >> > >>>> +
> >> > >>>> +import org.apache.jmeter.config.Arguments;
> >> > >>>> +import org.apache.jmeter.engine.util.NoThreadClone;
> >> > >>>> +import
> >org.apache.jmeter.protocol.java.sampler.JavaSamplerContext;
> >> > >>>> +import org.apache.jmeter.samplers.Remoteable;
> >> > >>>> +import org.apache.jmeter.samplers.SampleEvent;
> >> > >>>> +import org.apache.jmeter.samplers.SampleListener;
> >> > >>>> +import org.apache.jmeter.samplers.SampleResult;
> >> > >>>> +import org.apache.jmeter.testelement.AbstractTestElement;
> >> > >>>> +import org.apache.jmeter.testelement.TestElement;
> >> > >>>> +import org.apache.jmeter.testelement.TestStateListener;
> >> > >>>> +import
> >org.apache.jmeter.testelement.property.TestElementProperty;
> >> > >>>> +import org.apache.jorphan.logging.LoggingManager;
> >> > >>>> +import org.apache.log.Logger;
> >> > >>>> +
> >> > >>>> +/**
> >> > >>>> + * Async Listener that delegates SampleResult handling to
> >> > >>>> implementations of {@link BackendListenerClient}
> >> > >>>> + * @since 2.13
> >> > >>>> + */
> >> > >>>> +public class BackendListener extends AbstractTestElement
> >> > >>>> +    implements Serializable, SampleListener,
> >TestStateListener,
> >> > >>>> NoThreadClone, Remoteable  {
> >> > >>>> +
> >> > >>>> +    /**
> >> > >>>> +     *
> >> > >>>> +     */
> >> > >>>> +    private static final long serialVersionUID =
> >> 8184103677832024335L;
> >> > >>>> +
> >> > >>>> +    private static final Logger log = LoggingManager.
> >> > >>>> getLoggerForClass();
> >> > >>>>
> >> > >>>>  See naming comment of log from above
> >> > >>>
> >> > >>>  +
> >> > >>>> +    /**
> >> > >>>> +     * Set used to register instances which implement
> >teardownTest.
> >> > >>>> +     * This is used so that the BackendListenerClient can be
> >> notified
> >> > >>>> when the test ends.
> >> > >>>> +     */
> >> > >>>> +    private static final Set<BackendListener> TEAR_DOWN_SET =
> >new
> >> > >>>> HashSet<BackendListener>();
> >> > >>>> +
> >> > >>>> +    /**
> >> > >>>> +     * Property key representing the classname of the
> >> > >>>> BackendListenerClient to user.
> >> > >>>> +     */
> >> > >>>> +    public static final String CLASSNAME = "classname";
> >> > >>>> +
> >> > >>>> +    /**
> >> > >>>> +     * Queue size
> >> > >>>> +     */
> >> > >>>> +    public static final String QUEUE_SIZE = "QUEUE_SIZE";
> >> > >>>> +
> >> > >>>> +    /**
> >> > >>>> +     * Property key representing the arguments for the
> >> > >>>> BackendListenerClient.
> >> > >>>> +     */
> >> > >>>> +    public static final String ARGUMENTS = "arguments";
> >> > >>>> +
> >> > >>>> +    /**
> >> > >>>> +     * The BackendListenerClient class used by this sampler.
> >> > >>>> +     * Created by testStarted; copied to cloned instances.
> >> > >>>> +     */
> >> > >>>> +    private Class<?> javaClass;
> >> > >>>>
> >> > >>>>  Could probably named clientClass instead of javaClass, since
> >we
> >> already
> >> > >>> know it is a java class.
> >> > >>>
> >> > >>>  +
> >> > >>>> +    /**
> >> > >>>> +     * If true, the BackendListenerClient class implements
> >> > >>>> teardownTest.
> >> > >>>> +     * Created by testStarted; copied to cloned instances.
> >> > >>>> +     */
> >> > >>>> +    private boolean isToBeRegistered;
> >> > >>>> +
> >> > >>>> +    /**
> >> > >>>> +     * The BackendListenerClient instance
> >> > >>>> +     */
> >> > >>>> +    private transient BackendListenerClient
> >backendListenerClient =
> >> > >>>> null;
> >> > >>>> +
> >> > >>>> +    /**
> >> > >>>> +     * The JavaSamplerContext instance used by this sampler
> >to hold
> >> > >>>> information
> >> > >>>>
> >> > >>>>  BackendListenerContext?
> >> > >>>
> >> > >>>  +     * related to the test run, such as the parameters
> >specified
> >> for
> >> > >>>> the
> >> > >>>> sampler
> >> > >>>> +     * client.
> >> > >>>> +     */
> >> > >>>> +    private transient BackendListenerContext context = null;
> >> > >>>> +
> >> > >>>> +    private static final int DEFAULT_QUEUE_SIZE = 5000;
> >> > >>>> +
> >> > >>>> +    private transient BlockingQueue<SampleResult> queue; //
> >> created by
> >> > >>>> server in readResolve method
> >> > >>>> +
> >> > >>>> +    private transient long queueWaits; // how many times we
> >had to
> >> wait
> >> > >>>> to queue a sample
> >> > >>>> +
> >> > >>>> +    private transient long queueWaitTime; // how long we had
> >to
> >> wait
> >> > >>>> (nanoSeconds)
> >> > >>>> +
> >> > >>>> +    // Create unique object as marker for end of queue
> >> > >>>> +    private transient static final SampleResult FINAL_EVENT =
> >new
> >> > >>>> SampleResult();
> >> > >>>> +
> >> > >>>> +    /**
> >> > >>>> +     * Create a BackendListener.
> >> > >>>> +     */
> >> > >>>> +    public BackendListener() {
> >> > >>>> +        setArguments(new Arguments());
> >> > >>>> +    }
> >> > >>>> +
> >> > >>>> +    /*
> >> > >>>> +     * Ensure that the required class variables are cloned,
> >> > >>>> +     * as this is not currently done by the
> >super-implementation.
> >> > >>>> +     */
> >> > >>>> +    @Override
> >> > >>>> +    public Object clone() {
> >> > >>>> +        BackendListener clone = (BackendListener)
> >super.clone();
> >> > >>>> +        clone.javaClass = this.javaClass;
> >> > >>>> +        clone.isToBeRegistered = this.isToBeRegistered;
> >> > >>>> +        return clone;
> >> > >>>> +    }
> >> > >>>> +
> >> > >>>> +    private void initClass() {
> >> > >>>> +        String name = getClassname().trim();
> >> > >>>> +        try {
> >> > >>>> +            javaClass = Class.forName(name, false,
> >> > >>>> Thread.currentThread().getContextClassLoader());
> >> > >>>> +            Method method =
> >javaClass.getMethod("teardownTest", new
> >> > >>>> Class[]{BackendListenerContext.class});
> >> > >>>> +            isToBeRegistered =
> >!method.getDeclaringClass().equals(
> >> > >>>> AbstractBackendListenerClient.class);
> >> > >>>> +            log.info("Created class: " + name + ". Uses
> >> teardownTest:
> >> > >>>> "
> >> > >>>> + isToBeRegistered);
> >> > >>>> +        } catch (Exception e) {
> >> > >>>> +            log.error(whoAmI() + "\tException initialising: "
> >+
> >> name,
> >> > >>>> e);
> >> > >>>> +        }
> >> > >>>> +    }
> >> > >>>> +
> >> > >>>> +    /**
> >> > >>>> +     * Retrieves reference to BackendListenerClient.
> >> > >>>> +     *
> >> > >>>> +     * Convience method used to check for null reference
> >without
> >> > >>>> actually
> >> > >>>> +     * creating a BackendListenerClient
> >> > >>>> +     *
> >> > >>>> +     * @return reference to BackendListenerClient NOTUSED
> >private
> >> > >>>> BackendListenerClient
> >> > >>>> +     *         retrieveJavaClient() { return javaClient; }
> >> > >>>> +     */
> >> > >>>>
> >> > >>>>  Javadoc for non-existant method?
> >> > >>>
> >> > >>>  +
> >> > >>>> +    /**
> >> > >>>> +     * Generate a String identifier of this instance for
> >debugging
> >> > >>>> purposes.
> >> > >>>> +     *
> >> > >>>> +     * @return a String identifier for this sampler instance
> >> > >>>> +     */
> >> > >>>> +    private String whoAmI() {
> >> > >>>> +        StringBuilder sb = new StringBuilder();
> >> > >>>> +        sb.append(Thread.currentThread().getName());
> >> > >>>> +        sb.append("@");
> >> > >>>> +        sb.append(Integer.toHexString(hashCode()));
> >> > >>>> +        sb.append("-");
> >> > >>>> +        sb.append(getName());
> >> > >>>> +        return sb.toString();
> >> > >>>> +    }
> >> > >>>> +
> >> > >>>> +    // TestStateListener implementation
> >> > >>>> +    /* Implements TestStateListener.testStarted() */
> >> > >>>> +    @Override
> >> > >>>> +    public void testStarted() {
> >> > >>>> +        testStarted("");
> >> > >>>> +    }
> >> > >>>> +
> >> > >>>> +    /* Implements TestStateListener.testStarted(String) */
> >> > >>>> +    @Override
> >> > >>>> +    public void testStarted(String host) {
> >> > >>>> +        log.debug(whoAmI() + "\ttestStarted(" + host + ")");
> >> > >>>>
> >> > >>>>  Maybe use isDebugEnabled to guard whoAmI() call?
> >> > >>>
> >> > >>>  +        queue = new
> >> ArrayBlockingQueue<SampleResult>(getQueueSize());
> >> > >>>> +        initClass();
> >> > >>>> +        queueWaits=0L;
> >> > >>>> +        queueWaitTime=0L;
> >> > >>>> +        log.info(getName()+":Starting worker with
> >> class:"+javaClass +"
> >> > >>>> and queue capacity:"+getQueueSize());
> >> > >>>> +
> >> > >>>> +        backendListenerClient =
> >createBackendListenerClientImp
> >> > >>>> l(javaClass);
> >> > >>>> +        context = new BackendListenerContext((
> >> > >>>> Arguments)getArguments().
> >> > >>>> clone());
> >> > >>>> +        if(isToBeRegistered) {
> >> > >>>>
> >> > >>>>  space after if and before (?
> >> > >>>
> >> > >>>  +            TEAR_DOWN_SET.add(this);
> >> > >>>> +        }
> >> > >>>> +        try {
> >> > >>>> +            backendListenerClient.setupTest(context);
> >> > >>>> +        } catch (Exception e) {
> >> > >>>> +            throw new java.lang.IllegalStateException("Failed
> >> calling
> >> > >>>> setupTest", e);
> >> > >>>> +        }
> >> > >>>> +
> >> > >>>> +        Worker worker = new Worker(javaClass,
> >> backendListenerClient,
> >> > >>>> (Arguments) getArguments().clone(), queue);
> >> > >>>> +        worker.setDaemon(true);
> >> > >>>> +        worker.start();
> >> > >>>>
> >> > >>>>  Don't we want to stop worker after we're done with one test?
> >> > >>>
> >> > >>>  +        log.info(getName()+":Started  worker with
> >> class:"+javaClass);
> >> > >>>>
> >> > >>>>  Spaces after :?
> >> > >>>
> >> > >>>  +
> >> > >>>> +    }
> >> > >>>> +
> >> > >>>> +    /* (non-Javadoc)
> >> > >>>> +     * @see
> >> org.apache.jmeter.samplers.SampleListener#sampleOccurred(
> >> > >>>> org.apache.jmeter.samplers.SampleEvent)
> >> > >>>> +     */
> >> > >>>> +    @Override
> >> > >>>> +    public void sampleOccurred(SampleEvent e) {
> >> > >>>>
> >> > >>>>  Longer name then 'e'? I expect e to be an exception, not an
> >event.
> >> > >>>
> >> > >>>  +        Arguments args = getArguments();
> >> > >>>> +        context = new BackendListenerContext(args);
> >> > >>>> +
> >> > >>>> +        SampleResult sr = backendListenerClient.
> >> > >>>> createSampleResult(context,
> >> > >>>> e.getResult());
> >> > >>>> +        try {
> >> > >>>> +            if (!queue.offer(sr)){ // we failed to add the
> >element
> >> > >>>> first
> >> > >>>> time
> >> > >>>> +                queueWaits++;
> >> > >>>> +                long t1 = System.nanoTime();
> >> > >>>> +                queue.put(sr);
> >> > >>>> +                long t2 = System.nanoTime();
> >> > >>>> +                queueWaitTime += t2-t1;
> >> > >>>>
> >> > >>>>  Will sampleOccurred be called concurrently? If so, than
> >> queueWaitTime
> >> > >>> +=
> >> > >>> will not be correct.
> >> > >>>
> >> > >>>  +            }
> >> > >>>> +        } catch (Exception err) {
> >> > >>>> +            log.error("sampleOccurred, failed to queue the
> >sample",
> >> > >>>> err);
> >> > >>>> +        }
> >> > >>>> +    }
> >> > >>>> +
> >> > >>>> +    private static final class Worker extends Thread {
> >> > >>>> +
> >> > >>>> +        private final BlockingQueue<SampleResult> queue;
> >> > >>>> +        private final BackendListenerContext context;
> >> > >>>> +        private final BackendListenerClient
> >backendListenerClient;
> >> > >>>> +        private Worker(Class<?> javaClass,
> >BackendListenerClient
> >> > >>>> backendListenerClient, Arguments arguments,
> >> BlockingQueue<SampleResult>
> >> > >>>> q){
> >> > >>>>
> >> > >>>>  Same naming argument as above. clientclass instead of
> >javaClass?
> >> > >>>
> >> > >>>  +            queue = q;
> >> > >>>> +            // Allow BackendListenerClient implementations to
> >get
> >> > >>>> access
> >> > >>>> to test element name
> >> > >>>> +            arguments.addArgument(TestElement.NAME,
> >getName());
> >> > >>>> +            context = new BackendListenerContext(arguments);
> >> > >>>> +            this.backendListenerClient =
> >backendListenerClient;
> >> > >>>> +        }
> >> > >>>> +
> >> > >>>> +
> >> > >>>> +        @Override
> >> > >>>> +        public void run() {
> >> > >>>> +            boolean isDebugEnabled = log.isDebugEnabled();
> >> > >>>> +            List<SampleResult> l = new
> >> ArrayList<SampleResult>(queue.
> >> > >>>> size());
> >> > >>>>
> >> > >>>>  samples instead of l?
> >> > >>>
> >> > >>>  +            try {
> >> > >>>> +                boolean eof = false;
> >> > >>>>
> >> > >>>>  endOfLoop?
> >> > >>>
> >> > >>>  +                while (!eof) {
> >> > >>>> +                    if(isDebugEnabled) {
> >> > >>>> +                        log.debug("Thread:"+Thread.
> >> > >>>> currentThread().getName()+"
> >> > >>>> taking SampleResult from queue:"+queue.size());
> >> > >>>> +                    }
> >> > >>>> +                    SampleResult e = queue.take();
> >> > >>>>
> >> > >>>>  Could be named result, or sample instead of e
> >> > >>>
> >> > >>>  +                    if(isDebugEnabled) {
> >> > >>>> +                        log.debug("Thread:"+Thread.
> >> > >>>> currentThread().getName()+"
> >> > >>>> took SampleResult:"+e+", isFinal:" + (e==FINAL_EVENT));
> >> > >>>> +                    }
> >> > >>>> +                    while (!(eof = (e == FINAL_EVENT)) && e
> >!=
> >> null ) {
> >> > >>>> // try to process as many as possible
> >> > >>>> +                        l.add(e);
> >> > >>>> +                        if(isDebugEnabled) {
> >> > >>>> +                            log.debug("Thread:"+Thread.
> >> > >>>> currentThread().getName()+"
> >> > >>>> polling from queue:"+queue.size());
> >> > >>>> +                        }
> >> > >>>> +                        e = queue.poll(); // returns null if
> >> nothing on
> >> > >>>> queue currently
> >> > >>>> +                        if(isDebugEnabled) {
> >> > >>>> +                            log.debug("Thread:"+Thread.
> >> > >>>> currentThread().getName()+"
> >> > >>>> took from queue:"+e+", isFinal:" + (e==FINAL_EVENT));
> >> > >>>> +                        }
> >> > >>>> +                    }
> >> > >>>> +                    if(isDebugEnabled) {
> >> > >>>> +                        log.debug("Thread:"+Thread.
> >> > >>>> currentThread().getName()+
> >> > >>>> +                                " exiting with FINAL
> >EVENT:"+(e ==
> >> > >>>> FINAL_EVENT)
> >> > >>>> +                                +", null:" + (e==null));
> >> > >>>> +                    }
> >> > >>>> +                    int size = l.size();
> >> > >>>>
> >> > >>>>  No need for a temporary variable.
> >> > >>>
> >> > >>>  +                    if (size > 0) {
> >> > >>>> +
> >> backendListenerClient.handleSampleResults(l,
> >> > >>>> context);
> >> > >>>> +                        l.clear();
> >> > >>>> +                    }
> >> > >>>> +                    if(!eof) {
> >> > >>>> +                        LockSupport.parkNanos(100);
> >> > >>>> +                    }
> >> > >>>> +                }
> >> > >>>> +            } catch (InterruptedException e) {
> >> > >>>> +                // NOOP
> >> > >>>> +            }
> >> > >>>> +            // We may have been interrupted
> >> > >>>> +            int size = l.size();
> >> > >>>> +            if (size > 0) {
> >> > >>>> +                backendListenerClient.handleSampleResults(l,
> >> context);
> >> > >>>> +                l.clear();
> >> > >>>> +            }
> >> > >>>>
> >> > >>>>  Same code as a few lines above, could be factored out into a
> >method
> >> > >>> handleSamples(l, context)
> >> > >>>
> >> > >>>  +            log.info("Worker ended");
> >> > >>>> +        }
> >> > >>>> +    }
> >> > >>>> +
> >> > >>>> +
> >> > >>>> +    /**
> >> > >>>> +     * Returns reference to
> ><code>BackendListenerClient</code>.
> >> > >>>>
> >> > >>>>  Could use a {@link...}
> >> > >>>
> >> > >>>  +     *
> >> > >>>> +     *
> >> > >>>> +     * @return BackendListenerClient reference.
> >> > >>>> +     */
> >> > >>>> +    static BackendListenerClient
> >createBackendListenerClientImp
> >> > >>>> l(Class<?>
> >> > >>>> javaClass) {
> >> > >>>> +        if (javaClass == null) { // failed to initialise the
> >class
> >> > >>>> +            return new ErrorBackendListenerClient();
> >> > >>>> +        }
> >> > >>>> +        BackendListenerClient client;
> >> > >>>> +        try {
> >> > >>>> +            client = (BackendListenerClient)
> >> javaClass.newInstance();
> >> > >>>> +        } catch (Exception e) {
> >> > >>>> +            log.error("Exception creating: " + javaClass, e);
> >> > >>>> +            client = new ErrorBackendListenerClient();
> >> > >>>> +        }
> >> > >>>> +        return client;
> >> > >>>>
> >> > >>>>  I would return newInstance() in try Block and return new
> >Error.. in
> >> > >>> catch
> >> > >>> Block. javaClass -> clientClass
> >> > >>>
> >> > >>>  +    }
> >> > >>>> +
> >> > >>>> +    /**
> >> > >>>> +     * Method called at the end of the test. This is called
> >only
> >> on one
> >> > >>>> instance
> >> > >>>> +     * of BackendListener. This method will loop through all
> >of the
> >> > >>>> other
> >> > >>>> +     * BackendListenerClients which have been registered
> >> (automatically
> >> > >>>> in the
> >> > >>>> +     * constructor) and notify them that the test has ended,
> >> allowing
> >> > >>>> the
> >> > >>>> +     * BackendListenerClients to cleanup.
> >> > >>>> +     */
> >> > >>>> +    @Override
> >> > >>>> +    public void testEnded() {
> >> > >>>> +        try {
> >> > >>>> +            queue.put(FINAL_EVENT);
> >> > >>>> +        } catch (Exception ex) {
> >> > >>>> +            log.warn("testEnded() with
> >exception:"+ex.getMessage(),
> >> > >>>> ex);
> >> > >>>> +        }
> >> > >>>> +        if (queueWaits > 0) {
> >> > >>>> +            log.warn("QueueWaits: "+queueWaits+";
> >QueueWaitTime:
> >> > >>>> "+queueWaitTime+" (nanoseconds), you may need to increase
> >queue
> >> > >>>> capacity,
> >> > >>>> see property 'backend_queue_capacity'");
> >> > >>>> +        }
> >> > >>>> +        synchronized (TEAR_DOWN_SET) {
> >> > >>>> +            for (BackendListener backendListener :
> >TEAR_DOWN_SET) {
> >> > >>>> +                BackendListenerClient client =
> >backendListener.
> >> > >>>> backendListenerClient;
> >> > >>>> +                if (client != null) {
> >> > >>>> +                    try {
> >> > >>>> +
> >> client.teardownTest(backendListener.context);
> >> > >>>> +                    } catch (Exception e) {
> >> > >>>> +                        throw new java.lang.
> >> > >>>> IllegalStateException("Failed
> >> > >>>> calling teardownTest", e);
> >> > >>>>
> >> > >>>>  If we throw an exception here, we will not try every client.
> >> > >>>
> >> > >>>  +                    }
> >> > >>>> +                }
> >> > >>>> +            }
> >> > >>>> +            TEAR_DOWN_SET.clear();
> >> > >>>> +        }
> >> > >>>> +    }
> >> > >>>> +
> >> > >>>> +    /* Implements TestStateListener.testEnded(String) */
> >> > >>>> +    @Override
> >> > >>>> +    public void testEnded(String host) {
> >> > >>>> +        testEnded();
> >> > >>>> +    }
> >> > >>>> +
> >> > >>>> +    /**
> >> > >>>> +     * A {@link BackendListenerClient} implementation used
> >for
> >> error
> >> > >>>> handling. If an
> >> > >>>> +     * error occurs while creating the real
> >BackendListenerClient
> >> > >>>> object, it is
> >> > >>>> +     * replaced with an instance of this class. Each time a
> >sample
> >> > >>>> occurs with
> >> > >>>> +     * this class, the result is marked as a failure so the
> >user
> >> can
> >> > >>>> see
> >> > >>>> that
> >> > >>>> +     * the test failed.
> >> > >>>> +     */
> >> > >>>> +    static class ErrorBackendListenerClient extends
> >> > >>>> AbstractBackendListenerClient {
> >> > >>>> +        /**
> >> > >>>> +         * Return SampleResult with data on error.
> >> > >>>> +         *
> >> > >>>> +         * @see
> >BackendListenerClient#runTest(JavaSamplerContext)
> >> > >>>> +         */
> >> > >>>> +        @Override
> >> > >>>> +        public void handleSampleResults(List<SampleResult>
> >> > >>>> sampleResults, BackendListenerContext context) {
> >> > >>>> +
> >log.warn("ErrorBackendListenerClient#handleSampleResult
> >> > >>>> called, noop");
> >> > >>>> +            Thread.yield();
> >> > >>>> +        }
> >> > >>>> +    }
> >> > >>>> +
> >> > >>>> +    /* (non-Javadoc)
> >> > >>>> +     * @see
> >> org.apache.jmeter.samplers.SampleListener#sampleStarted(
> >> > >>>> org.apache.jmeter.samplers.SampleEvent)
> >> > >>>> +     */
> >> > >>>> +    @Override
> >> > >>>> +    public void sampleStarted(SampleEvent e) {
> >> > >>>> +        // NOOP
> >> > >>>> +
> >> > >>>> +    }
> >> > >>>> +
> >> > >>>> +    /* (non-Javadoc)
> >> > >>>> +     * @see
> >> org.apache.jmeter.samplers.SampleListener#sampleStopped(
> >> > >>>> org.apache.jmeter.samplers.SampleEvent)
> >> > >>>> +     */
> >> > >>>> +    @Override
> >> > >>>> +    public void sampleStopped(SampleEvent e) {
> >> > >>>> +        // NOOP
> >> > >>>> +
> >> > >>>> +    }
> >> > >>>> +
> >> > >>>> +    /**
> >> > >>>> +     * Set the arguments (parameters) for the
> >> BackendListenerClient to
> >> > >>>> be executed
> >> > >>>> +     * with.
> >> > >>>> +     *
> >> > >>>> +     * @param args
> >> > >>>> +     *            the new arguments. These replace any
> >existing
> >> > >>>> arguments.
> >> > >>>> +     */
> >> > >>>> +    public void setArguments(Arguments args) {
> >> > >>>> +        setProperty(new TestElementProperty(ARGUMENTS,
> >args));
> >> > >>>> +    }
> >> > >>>> +
> >> > >>>> +    /**
> >> > >>>> +     * Get the arguments (parameters) for the
> >> BackendListenerClient to
> >> > >>>> be executed
> >> > >>>> +     * with.
> >> > >>>> +     *
> >> > >>>> +     * @return the arguments
> >> > >>>> +     */
> >> > >>>> +    public Arguments getArguments() {
> >> > >>>> +        return (Arguments)
> >getProperty(ARGUMENTS).getObjectValue();
> >> > >>>> +    }
> >> > >>>> +
> >> > >>>> +    /**
> >> > >>>> +     * Sets the Classname of the BackendListenerClient object
> >> > >>>> +     *
> >> > >>>> +     * @param classname
> >> > >>>> +     *            the new Classname value
> >> > >>>> +     */
> >> > >>>> +    public void setClassname(String classname) {
> >> > >>>> +        setProperty(CLASSNAME, classname);
> >> > >>>> +    }
> >> > >>>> +
> >> > >>>> +    /**
> >> > >>>> +     * Gets the Classname of the BackendListenerClient object
> >> > >>>> +     *
> >> > >>>> +     * @return the Classname value
> >> > >>>> +     */
> >> > >>>> +    public String getClassname() {
> >> > >>>> +        return getPropertyAsString(CLASSNAME);
> >> > >>>> +    }
> >> > >>>> +
> >> > >>>> +    /**
> >> > >>>> +     * Sets the queue size
> >> > >>>> +     *
> >> > >>>> +     * @param queueSize
> >> > >>>> +     *
> >> > >>>> +     */
> >> > >>>> +    public void setQueueSize(int queueSize) {
> >> > >>>> +        setProperty(QUEUE_SIZE, queueSize,
> >DEFAULT_QUEUE_SIZE);
> >> > >>>> +    }
> >> > >>>> +
> >> > >>>> +    /**
> >> > >>>> +     * Gets the queue size
> >> > >>>> +     *
> >> > >>>> +     * @return int queueSize
> >> > >>>> +     */
> >> > >>>> +    public int getQueueSize() {
> >> > >>>> +        return getPropertyAsInt(QUEUE_SIZE,
> >DEFAULT_QUEUE_SIZE);
> >> > >>>> +    }
> >> > >>>> +}
> >> > >>>>
> >> > >>>> Propchange:
> >> jmeter/trunk/src/components/org/apache/jmeter/visualizers/
> >> > >>>> backend/BackendListener.java
> >> > >>>> ------------------------------------------------------------
> >> > >>>> ------------------
> >> > >>>>       svn:mime-type = text/plain
> >> > >>>>
> >> > >>>> Added:
> >jmeter/trunk/src/components/org/apache/jmeter/visualizers/
> >> > >>>> backend/BackendListenerClient.java
> >> > >>>> URL: http://svn.apache.org/viewvc/jmeter/trunk/src/components/
> >> > >>>> org/apache/jmeter/visualizers/backend/BackendListenerClient.
> >> > >>>> java?rev=1641081&view=auto
> >> > >>>> ============================================================
> >> > >>>> ==================
> >> > >>>> --- jmeter/trunk/src/components/org/apache/jmeter/visualizers/
> >> > >>>> backend/BackendListenerClient.java (added)
> >> > >>>> +++ jmeter/trunk/src/components/org/apache/jmeter/visualizers/
> >> > >>>> backend/BackendListenerClient.java Sat Nov 22 15:36:37 2014
> >> > >>>> @@ -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.jmeter.visualizers.backend;
> >> > >>>> +
> >> > >>>> +import java.util.List;
> >> > >>>> +
> >> > >>>> +import org.apache.jmeter.config.Arguments;
> >> > >>>> +import org.apache.jmeter.samplers.SampleResult;
> >> > >>>> +
> >> > >>>> +/**
> >> > >>>> + * This interface defines the interactions between the
> >> BackendListener
> >> > >>>> and external
> >> > >>>> + * Java programs which can be executed by JMeter. Any Java
> >class
> >> which
> >> > >>>> wants to
> >> > >>>> + * be executed as a JMeter test must implement this interface
> >> (either
> >> > >>>> directly
> >> > >>>> + * or indirectly through AbstractBackendListenerClient).
> >> > >>>> + * <p>
> >> > >>>> + * JMeter will create one instance of a BackendListenerClient
> >> > >>>> implementation for
> >> > >>>> + * each user/thread in the test. Additional instances may be
> >> created
> >> > >>>> for
> >> > >>>> + * internal use by JMeter (for example, to find out what
> >> parameters are
> >> > >>>> + * supported by the client).
> >> > >>>> + * <p>
> >> > >>>> + * When the test is started, setupTest() will be called on
> >each
> >> > >>>> thread's
> >> > >>>> + * BackendListenerClient instance to initialize the client.
> >Then
> >> > >>>> handleSampleResult() will be
> >> > >>>> + * called for each SampleResult notification. Finally,
> >> teardownTest()
> >> > >>>> will be called
> >> > >>>> + * to allow the client to do any necessary clean-up.
> >> > >>>> + * <p>
> >> > >>>> + * The JMeter BackendListener GUI allows a list of parameters
> >to be
> >> > >>>> defined for the
> >> > >>>> + * test. These are passed to the various test methods through
> >the
> >> > >>>> + * {@link BackendListenerContext}. A list of default
> >parameters
> >> can be
> >> > >>>> defined
> >> > >>>> + * through the getDefaultParameters() method. These
> >parameters and
> >> any
> >> > >>>> default
> >> > >>>> + * values associated with them will be shown in the GUI.
> >Users can
> >> add
> >> > >>>> other
> >> > >>>> + * parameters as well.
> >> > >>>> + * <p>
> >> > >>>> + * When possible, Listeners should extend {@link
> >> > >>>> AbstractBackendListenerClient
> >> > >>>> + * AbstractBackendListenerClient} rather than implementing
> >> > >>>> BackendListenerClient
> >> > >>>> + * directly. This should protect your tests from future
> >changes to
> >> the
> >> > >>>> + * interface. While it may be necessary to make changes to
> >the
> >> > >>>> BackendListenerClient
> >> > >>>> + * interface from time to time (therefore requiring changes
> >to any
> >> > >>>> + * implementations of this interface), we intend to make this
> >> abstract
> >> > >>>> class
> >> > >>>> + * provide reasonable default implementations of any new
> >methods so
> >> > >>>> that
> >> > >>>> + * subclasses do not necessarily need to be updated for new
> >> versions.
> >> > >>>> + * Implementing BackendListenerClient directly will continue
> >to be
> >> > >>>> supported for
> >> > >>>> + * cases where extending this class is not possible (for
> >example,
> >> when
> >> > >>>> the
> >> > >>>> + * client class is already a subclass of some other class).
> >> > >>>> + *
> >> > >>>> + * @since 2.13
> >> > >>>> + */
> >> > >>>> +public interface BackendListenerClient {
> >> > >>>> +    /**
> >> > >>>> +     * Do any initialization required by this client. It is
> >> generally
> >> > >>>> +     * recommended to do any initialization such as getting
> >> parameter
> >> > >>>> values in
> >> > >>>> +     * the setupTest method rather than the runTest method in
> >> order to
> >> > >>>> add as
> >> > >>>> +     * little overhead as possible to the test.
> >> > >>>> +     *
> >> > >>>> +     * @param context
> >> > >>>> +     *            the context to run with. This provides
> >access to
> >> > >>>> +     *            initialization parameters.
> >> > >>>> +     */
> >> > >>>> +    void setupTest(BackendListenerContext context) throws
> >> Exception;
> >> > >>>> +
> >> > >>>> +    /**
> >> > >>>> +     * Perform a single sample for each iteration. This
> >method
> >> returns
> >> > >>>> a
> >> > >>>> +     * <code>SampleResult</code> object.
> ><code>SampleResult</code>
> >> has
> >> > >>>> many
> >> > >>>> +     * fields which can be used. At a minimum, the test
> >should use
> >> > >>>> +     * <code>SampleResult.sampleStart</code> and
> >> > >>>> +     * <code>SampleResult.sampleEnd</code>to set the time
> >that the
> >> > >>>> test
> >> > >>>>
> >> > >>>>  use {@link..} instead of <code>..?
> >> > >>>
> >> > >>>  +     * required to execute. It is also a good idea to set the
> >> > >>>> sampleLabel and
> >> > >>>> +     * the successful flag.
> >> > >>>> +     *
> >> > >>>> +     * @see
> >org.apache.jmeter.samplers.SampleResult#sampleStart()
> >> > >>>> +     * @see
> >org.apache.jmeter.samplers.SampleResult#sampleEnd()
> >> > >>>> +     * @see
> >org.apache.jmeter.samplers.SampleResult#setSuccessful(
> >> > >>>> boolean)
> >> > >>>> +     * @see
> >org.apache.jmeter.samplers.SampleResult#setSampleLabel(
> >> > >>>> String)
> >> > >>>> +     *
> >> > >>>> +     * @param context
> >> > >>>> +     *            the context to run with. This provides
> >access to
> >> > >>>> +     *            initialization parameters.
> >> > >>>> +     *
> >> > >>>> +     */
> >> > >>>> +    void handleSampleResults(List<SampleResult>
> >sampleResults,
> >> > >>>> BackendListenerContext context);
> >> > >>>> +
> >> > >>>> +    /**
> >> > >>>> +     * Do any clean-up required by this test at the end of a
> >test
> >> run.
> >> > >>>> +     *
> >> > >>>> +     * @param context
> >> > >>>> +     *            the context to run with. This provides
> >access to
> >> > >>>> +     *            initialization parameters.
> >> > >>>> +     */
> >> > >>>> +    void teardownTest(BackendListenerContext context) throws
> >> > >>>> Exception;
> >> > >>>> +
> >> > >>>> +    /**
> >> > >>>> +     * Provide a list of parameters which this test supports.
> >Any
> >> > >>>> parameter
> >> > >>>> +     * names and associated values returned by this method
> >will
> >> appear
> >> > >>>> in the
> >> > >>>> +     * GUI by default so the user doesn't have to remember
> >the
> >> exact
> >> > >>>> names. The
> >> > >>>> +     * user can add other parameters which are not listed
> >here. If
> >> this
> >> > >>>> method
> >> > >>>> +     * returns null then no parameters will be listed. If the
> >> value for
> >> > >>>> some
> >> > >>>> +     * parameter is null then that parameter will be listed
> >in the
> >> GUI
> >> > >>>> with an
> >> > >>>> +     * empty value.
> >> > >>>> +     *
> >> > >>>> +     * @return a specification of the parameters used by this
> >test
> >> > >>>> which
> >> > >>>> should
> >> > >>>> +     *         be listed in the GUI, or null if no parameters
> >> should be
> >> > >>>> listed.
> >> > >>>> +     */
> >> > >>>> +    Arguments getDefaultParameters();
> >> > >>>> +
> >> > >>>> +    /**
> >> > >>>> +     *
> >> > >>>> +     * @param context
> >> > >>>> +     * @param result
> >> > >>>> +     * @return
> >> > >>>> +     */
> >> > >>>> +    SampleResult createSampleResult(
> >> > >>>> +            BackendListenerContext context, SampleResult
> >result);
> >> > >>>> +}
> >> > >>>>
> >> > >>>> Propchange:
> >> jmeter/trunk/src/components/org/apache/jmeter/visualizers/
> >> > >>>> backend/BackendListenerClient.java
> >> > >>>> ------------------------------------------------------------
> >> > >>>> ------------------
> >> > >>>>       svn:mime-type = text/plain
> >> > >>>>
> >> > >>>> Added:
> >jmeter/trunk/src/components/org/apache/jmeter/visualizers/
> >> > >>>> backend/
> >> > >>>> BackendListenerContext.java
> >> > >>>> URL: http://svn.apache.org/viewvc/jmeter/trunk/src/components/
> >> > >>>>
> >org/apache/jmeter/visualizers/backend/BackendListenerContext.java?
> >> > >>>> rev=1641081&view=auto
> >> > >>>> ============================================================
> >> > >>>> ==================
> >> > >>>> ---
> >> jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/
> >> > >>>> BackendListenerContext.java
> >> > >>>> (added)
> >> > >>>> +++
> >> jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/
> >> > >>>> BackendListenerContext.java
> >> > >>>> Sat Nov 22 15:36:37 2014
> >> > >>>> @@ -0,0 +1,237 @@
> >> > >>>> +/*
> >> > >>>> +
> >> > >>>> + * 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.jmeter.visualizers.backend;
> >> > >>>> +
> >> > >>>> +import java.util.Iterator;
> >> > >>>> +import java.util.Map;
> >> > >>>> +
> >> > >>>> +import org.apache.jmeter.config.Arguments;
> >> > >>>> +import org.apache.jorphan.logging.LoggingManager;
> >> > >>>> +import org.apache.log.Logger;
> >> > >>>> +
> >> > >>>> +/**
> >> > >>>> + * BackendListenerContext is used to provide context
> >information
> >> to a
> >> > >>>> + * BackendListenerClient implementation. This currently
> >consists
> >> of the
> >> > >>>> + * initialization parameters which were specified in the GUI.
> >> > >>>> + * @since 2.13
> >> > >>>> + */
> >> > >>>> +public class BackendListenerContext {
> >> > >>>> +    /*
> >> > >>>> +     * Implementation notes:
> >> > >>>> +     *
> >> > >>>> +     * All of the methods in this class are currently
> >read-only. If
> >> > >>>> update
> >> > >>>> +     * methods are included in the future, they should be
> >defined
> >> so
> >> > >>>> that a
> >> > >>>> +     * single instance of BackendListenerContext can be
> >associated
> >> with
> >> > >>>> each thread.
> >> > >>>> +     * Therefore, no synchronization should be needed. The
> >same
> >> > >>>> instance
> >> > >>>> should
> >> > >>>> +     * be used for the call to setupTest, all calls to
> >runTest,
> >> and the
> >> > >>>> call to
> >> > >>>> +     * teardownTest.
> >> > >>>> +     */
> >> > >>>> +
> >> > >>>> +    /** Logging */
> >> > >>>> +    private static final Logger log = LoggingManager.
> >> > >>>> getLoggerForClass();
> >> > >>>>
> >> > >>>>  See naming comments for logger above
> >> > >>>
> >> > >>>  +
> >> > >>>> +    /**
> >> > >>>> +     * Map containing the initialization parameters for the
> >> > >>>> BackendListenerClient.
> >> > >>>> +     */
> >> > >>>> +    private final Map<String, String> params;
> >> > >>>> +
> >> > >>>> +    /**
> >> > >>>> +     *
> >> > >>>> +     * @param args
> >> > >>>> +     *            the initialization parameters.
> >> > >>>> +     */
> >> > >>>> +    public BackendListenerContext(Arguments args) {
> >> > >>>> +        this.params = args.getArgumentsAsMap();
> >> > >>>> +    }
> >> > >>>> +
> >> > >>>> +    /**
> >> > >>>> +     * Determine whether or not a value has been specified
> >for the
> >> > >>>> parameter
> >> > >>>> +     * with this name.
> >> > >>>> +     *
> >> > >>>> +     * @param name
> >> > >>>> +     *            the name of the parameter to test
> >> > >>>> +     * @return true if the parameter value has been
> >specified,
> >> false
> >> > >>>> otherwise.
> >> > >>>> +     */
> >> > >>>> +    public boolean containsParameter(String name) {
> >> > >>>>
> >> > >>>>  hasParameter instead of containsParameter?
> >> > >>>
> >> > >>>  +        return params.containsKey(name);
> >> > >>>> +    }
> >> > >>>> +
> >> > >>>> +    /**
> >> > >>>> +     * Get an iterator of the parameter names. Each entry in
> >the
> >> > >>>> Iterator is a
> >> > >>>> +     * String.
> >> > >>>> +     *
> >> > >>>> +     * @return an Iterator of Strings listing the names of
> >the
> >> > >>>> parameters which
> >> > >>>> +     *         have been specified for this test.
> >> > >>>> +     */
> >> > >>>> +    public Iterator<String> getParameterNamesIterator() {
> >> > >>>> +        return params.keySet().iterator();
> >> > >>>> +    }
> >> > >>>> +
> >> > >>>> +    /**
> >> > >>>> +     * Get the value of a specific parameter as a String, or
> >null
> >> if
> >> > >>>> the
> >> > >>>> value
> >> > >>>> +     * was not specified.
> >> > >>>> +     *
> >> > >>>> +     * @param name
> >> > >>>> +     *            the name of the parameter whose value
> >should be
> >> > >>>> retrieved
> >> > >>>> +     * @return the value of the parameter, or null if the
> >value
> >> was not
> >> > >>>> +     *         specified
> >> > >>>> +     */
> >> > >>>> +    public String getParameter(String name) {
> >> > >>>> +        return getParameter(name, null);
> >> > >>>> +    }
> >> > >>>> +
> >> > >>>> +    /**
> >> > >>>> +     * Get the value of a specified parameter as a String, or
> >> return
> >> > >>>> the
> >> > >>>> +     * specified default value if the value was not
> >specified.
> >> > >>>> +     *
> >> > >>>> +     * @param name
> >> > >>>> +     *            the name of the parameter whose value
> >should be
> >> > >>>> retrieved
> >> > >>>> +     * @param defaultValue
> >> > >>>> +     *            the default value to return if the value of
> >this
> >> > >>>> parameter was
> >> > >>>> +     *            not specified
> >> > >>>> +     * @return the value of the parameter, or the default
> >value if
> >> the
> >> > >>>> parameter
> >> > >>>> +     *         was not specified
> >> > >>>> +     */
> >> > >>>> +    public String getParameter(String name, String
> >defaultValue) {
> >> > >>>> +        if (params == null || !params.containsKey(name)) {
> >> > >>>> +            return defaultValue;
> >> > >>>> +        }
> >> > >>>> +        return params.get(name);
> >> > >>>> +    }
> >> > >>>> +
> >> > >>>> +    /**
> >> > >>>> +     * Get the value of a specified parameter as an integer.
> >An
> >> > >>>> exception will
> >> > >>>> +     * be thrown if the parameter is not specified or if it
> >is not
> >> an
> >> > >>>> integer.
> >> > >>>> +     * The value may be specified in decimal, hexadecimal, or
> >> octal, as
> >> > >>>> defined
> >> > >>>> +     * by Integer.decode().
> >> > >>>> +     *
> >> > >>>> +     * @param name
> >> > >>>> +     *            the name of the parameter whose value
> >should be
> >> > >>>> retrieved
> >> > >>>> +     * @return the value of the parameter
> >> > >>>> +     *
> >> > >>>> +     * @throws NumberFormatException
> >> > >>>> +     *             if the parameter is not specified or is
> >not an
> >> > >>>> integer
> >> > >>>> +     *
> >> > >>>> +     * @see java.lang.Integer#decode(java.lang.String)
> >> > >>>> +     */
> >> > >>>> +    public int getIntParameter(String name) throws
> >> > >>>> NumberFormatException
> >> > >>>> {
> >> > >>>> +        if (params == null || !params.containsKey(name)) {
> >> > >>>> +            throw new NumberFormatException("No value for
> >parameter
> >> > >>>> named '" + name + "'.");
> >> > >>>>
> >> > >>>>  I would expect an IllegalArgumentException, if no parameter
> >of that
> >> > >>> name
> >> > >>> is found
> >> > >>>
> >> > >>>  +        }
> >> > >>>> +
> >> > >>>> +        return Integer.decode(params.get(name)).intValue();
> >> > >>>> +    }
> >> > >>>> +
> >> > >>>> +    /**
> >> > >>>> +     * Get the value of a specified parameter as an integer,
> >or
> >> return
> >> > >>>> the
> >> > >>>> +     * specified default value if the value was not specified
> >or
> >> is not
> >> > >>>> an
> >> > >>>> +     * integer. A warning will be logged if the value is not
> >an
> >> > >>>> integer.
> >> > >>>> The
> >> > >>>> +     * value may be specified in decimal, hexadecimal, or
> >octal, as
> >> > >>>> defined by
> >> > >>>> +     * Integer.decode().
> >> > >>>> +     *
> >> > >>>> +     * @param name
> >> > >>>> +     *            the name of the parameter whose value
> >should be
> >> > >>>> retrieved
> >> > >>>> +     * @param defaultValue
> >> > >>>> +     *            the default value to return if the value of
> >this
> >> > >>>> parameter was
> >> > >>>> +     *            not specified
> >> > >>>> +     * @return the value of the parameter, or the default
> >value if
> >> the
> >> > >>>> parameter
> >> > >>>> +     *         was not specified
> >> > >>>> +     *
> >> > >>>> +     * @see java.lang.Integer#decode(java.lang.String)
> >> > >>>> +     */
> >> > >>>> +    public int getIntParameter(String name, int defaultValue)
> >{
> >> > >>>> +        if (params == null || !params.containsKey(name)) {
> >> > >>>> +            return defaultValue;
> >> > >>>> +        }
> >> > >>>> +
> >> > >>>> +        try {
> >> > >>>> +            return
> >Integer.decode(params.get(name)).intValue();
> >> > >>>> +        } catch (NumberFormatException e) {
> >> > >>>> +            log.warn("Value for parameter '" + name + "' not
> >an
> >> > >>>> integer:
> >> > >>>> '" + params.get(name) + "'.  Using default: '"
> >> > >>>> +                    + defaultValue + "'.", e);
> >> > >>>> +            return defaultValue;
> >> > >>>> +        }
> >> > >>>> +    }
> >> > >>>> +
> >> > >>>> +    /**
> >> > >>>> +     * Get the value of a specified parameter as a long. An
> >> exception
> >> > >>>> will be
> >> > >>>> +     * thrown if the parameter is not specified or if it is
> >not a
> >> long.
> >> > >>>> The
> >> > >>>> +     * value may be specified in decimal, hexadecimal, or
> >octal, as
> >> > >>>> defined by
> >> > >>>> +     * Long.decode().
> >> > >>>> +     *
> >> > >>>> +     * @param name
> >> > >>>> +     *            the name of the parameter whose value
> >should be
> >> > >>>> retrieved
> >> > >>>> +     * @return the value of the parameter
> >> > >>>> +     *
> >> > >>>> +     * @throws NumberFormatException
> >> > >>>> +     *             if the parameter is not specified or is
> >not a
> >> long
> >> > >>>> +     *
> >> > >>>> +     * @see Long#decode(String)
> >> > >>>> +     */
> >> > >>>> +    public long getLongParameter(String name) throws
> >> > >>>> NumberFormatException {
> >> > >>>> +        if (params == null || !params.containsKey(name)) {
> >> > >>>> +            throw new NumberFormatException("No value for
> >parameter
> >> > >>>> named '" + name + "'.");
> >> > >>>> +        }
> >> > >>>> +
> >> > >>>> +        return Long.decode(params.get(name)).longValue();
> >> > >>>> +    }
> >> > >>>> +
> >> > >>>> +    /**
> >> > >>>> +     * Get the value of a specified parameter as along, or
> >return
> >> the
> >> > >>>> specified
> >> > >>>> +     * default value if the value was not specified or is not
> >a
> >> long. A
> >> > >>>> warning
> >> > >>>> +     * will be logged if the value is not a long. The value
> >may be
> >> > >>>> specified in
> >> > >>>> +     * decimal, hexadecimal, or octal, as defined by
> >Long.decode().
> >> > >>>> +     *
> >> > >>>> +     * @param name
> >> > >>>> +     *            the name of the parameter whose value
> >should be
> >> > >>>> retrieved
> >> > >>>> +     * @param defaultValue
> >> > >>>> +     *            the default value to return if the value of
> >this
> >> > >>>> parameter was
> >> > >>>> +     *            not specified
> >> > >>>> +     * @return the value of the parameter, or the default
> >value if
> >> the
> >> > >>>> parameter
> >> > >>>> +     *         was not specified
> >> > >>>> +     *
> >> > >>>> +     * @see Long#decode(String)
> >> > >>>> +     */
> >> > >>>> +    public long getLongParameter(String name, long
> >defaultValue) {
> >> > >>>> +        if (params == null || !params.containsKey(name)) {
> >> > >>>> +            return defaultValue;
> >> > >>>> +        }
> >> > >>>> +        try {
> >> > >>>> +            return Long.decode(params.get(name)).longValue();
> >> > >>>> +        } catch (NumberFormatException e) {
> >> > >>>> +            log.warn("Value for parameter '" + name + "' not
> >a
> >> long: '"
> >> > >>>> + params.get(name) + "'.  Using default: '"
> >> > >>>> +                    + defaultValue + "'.", e);
> >> > >>>> +            return defaultValue;
> >> > >>>> +        }
> >> > >>>> +    }
> >> > >>>> +
> >> > >>>> +    /**
> >> > >>>> +     *
> >> > >>>> +     * @param name
> >> > >>>> +     * @param defaultValue
> >> > >>>> +     * @return
> >> > >>>>
> >> > >>>>  No javadoc? Again three warnings more :)
> >> > >>>
> >> > >>>  +     */
> >> > >>>> +    public boolean getBooleanParameter(String name, boolean
> >> > >>>> defaultValue) {
> >> > >>>> +        if (params == null || !params.containsKey(name)) {
> >> > >>>> +            return defaultValue;
> >> > >>>> +        }
> >> > >>>> +        return Boolean.valueOf(params.get(name));
> >> > >>>> +    }
> >> > >>>> +}
> >> > >>>>
> >> > >>>> Propchange:
> >> jmeter/trunk/src/components/org/apache/jmeter/visualizers/
> >> > >>>> backend/BackendListenerContext.java
> >> > >>>> ------------------------------------------------------------
> >> > >>>> ------------------
> >> > >>>>       svn:mime-type = text/plain
> >> > >>>>
> >> > >>>> Added:
> >jmeter/trunk/src/components/org/apache/jmeter/visualizers/
> >> > >>>> backend/BackendListenerGui.java
> >> > >>>> URL: http://svn.apache.org/viewvc/jmeter/trunk/src/components/
> >> > >>>> org/apache/jmeter/visualizers/backend/BackendListenerGui.
> >> > >>>> java?rev=1641081&view=auto
> >> > >>>> ============================================================
> >> > >>>> ==================
> >> > >>>> --- jmeter/trunk/src/components/org/apache/jmeter/visualizers/
> >> > >>>> backend/BackendListenerGui.java (added)
> >> > >>>> +++ jmeter/trunk/src/components/org/apache/jmeter/visualizers/
> >> > >>>> backend/BackendListenerGui.java Sat Nov 22 15:36:37 2014
> >> > >>>> @@ -0,0 +1,282 @@
> >> > >>>> +/*
> >> > >>>> + * 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.jmeter.visualizers.backend;
> >> > >>>> +
> >> > >>>> +import java.awt.BorderLayout;
> >> > >>>> +import java.awt.event.ActionEvent;
> >> > >>>> +import java.awt.event.ActionListener;
> >> > >>>> +import java.util.ArrayList;
> >> > >>>> +import java.util.HashSet;
> >> > >>>> +import java.util.List;
> >> > >>>> +import java.util.Map;
> >> > >>>> +import java.util.Set;
> >> > >>>> +
> >> > >>>> +import javax.swing.ComboBoxModel;
> >> > >>>> +import javax.swing.JComboBox;
> >> > >>>> +import javax.swing.JLabel;
> >> > >>>> +import javax.swing.JPanel;
> >> > >>>> +import javax.swing.JTextField;
> >> > >>>> +
> >> > >>>> +import org.apache.jmeter.config.Argument;
> >> > >>>> +import org.apache.jmeter.config.Arguments;
> >> > >>>> +import org.apache.jmeter.config.gui.ArgumentsPanel;
> >> > >>>> +import org.apache.jmeter.gui.util.HorizontalPanel;
> >> > >>>> +import org.apache.jmeter.testelement.TestElement;
> >> > >>>> +import
> >org.apache.jmeter.testelement.property.PropertyIterator;
> >> > >>>> +import org.apache.jmeter.util.JMeterUtils;
> >> > >>>> +import org.apache.jmeter.visualizers.gui.AbstractListenerGui;
> >> > >>>> +import org.apache.jorphan.logging.LoggingManager;
> >> > >>>> +import org.apache.jorphan.reflect.ClassFinder;
> >> > >>>> +import org.apache.log.Logger;
> >> > >>>> +
> >> > >>>> +/**
> >> > >>>> + * The <code>BackendListenerGui</code> class provides the
> >user
> >> > >>>> interface for the
> >> > >>>> + * {@link BackendListener} object.
> >> > >>>> + * @since 2.13
> >> > >>>> + */
> >> > >>>> +public class BackendListenerGui extends AbstractListenerGui
> >> implements
> >> > >>>> ActionListener {
> >> > >>>> +
> >> > >>>> +    /**
> >> > >>>> +     *
> >> > >>>> +     */
> >> > >>>> +    private static final long serialVersionUID =
> >> 4331668988576438604L;
> >> > >>>> +
> >> > >>>> +    /** Logging */
> >> > >>>> +    private static final Logger log = LoggingManager.
> >> > >>>> getLoggerForClass();
> >> > >>>> +
> >> > >>>> +    /** A combo box allowing the user to choose a backend
> >class. */
> >> > >>>> +    private JComboBox classnameCombo;
> >> > >>>> +
> >> > >>>> +    /**
> >> > >>>> +     * A field allowing the user to specify the size of Queue
> >> > >>>> +     */
> >> > >>>> +    private JTextField queueSize;
> >> > >>>> +
> >> > >>>> +    /** A panel allowing the user to set arguments for this
> >test.
> >> */
> >> > >>>> +    private ArgumentsPanel argsPanel;
> >> > >>>> +
> >> > >>>> +    /**
> >> > >>>> +     * Create a new BackendListenerGui as a standalone
> >component.
> >> > >>>> +     */
> >> > >>>> +    public BackendListenerGui() {
> >> > >>>> +        super();
> >> > >>>> +        init();
> >> > >>>> +    }
> >> > >>>> +
> >> > >>>> +
> >> > >>>> +    /** {@inheritDoc} */
> >> > >>>> +    @Override
> >> > >>>> +    public String getLabelResource() {
> >> > >>>> +        return "backend_listener"; // $NON-NLS-1$
> >> > >>>> +    }
> >> > >>>> +
> >> > >>>> +    /**
> >> > >>>> +     * Initialize the GUI components and layout.
> >> > >>>> +     */
> >> > >>>> +    private void init() {// called from ctor, so must not be
> >> > >>>> overridable
> >> > >>>> +        setLayout(new BorderLayout(0, 5));
> >> > >>>> +
> >> > >>>> +        setBorder(makeBorder());
> >> > >>>> +        add(makeTitlePanel(), BorderLayout.NORTH);
> >> > >>>> +
> >> > >>>> +        JPanel classnameRequestPanel = new JPanel(new
> >> BorderLayout(0,
> >> > >>>> 5));
> >> > >>>> +        classnameRequestPanel.add(createClassnamePanel(),
> >> > >>>> BorderLayout.NORTH);
> >> > >>>> +        classnameRequestPanel.add(createParameterPanel(),
> >> > >>>> BorderLayout.CENTER);
> >> > >>>> +
> >> > >>>> +        add(classnameRequestPanel, BorderLayout.CENTER);
> >> > >>>> +    }
> >> > >>>> +
> >> > >>>> +    /**
> >> > >>>> +     * Create a panel with GUI components allowing the user
> >to
> >> select a
> >> > >>>> test
> >> > >>>> +     * class.
> >> > >>>> +     *
> >> > >>>> +     * @return a panel containing the relevant components
> >> > >>>> +     */
> >> > >>>> +    private JPanel createClassnamePanel() {
> >> > >>>> +        List<String> possibleClasses = new
> >ArrayList<String>();
> >> > >>>> +
> >> > >>>> +        try {
> >> > >>>> +            // Find all the classes which implement the
> >> > >>>> BackendListenerClient
> >> > >>>> +            // interface.
> >> > >>>> +            possibleClasses =
> >ClassFinder.findClassesThatExtend(
> >> > >>>> JMeterUtils.getSearchPaths(),
> >> > >>>> +                    new Class[] { BackendListenerClient.class
> >});
> >> > >>>> +
> >> > >>>> +            // Remove the BackendListener class from the list
> >> since it
> >> > >>>> only
> >> > >>>>
> >> > >>>>  ErrorBackendListener
> >> > >>>
> >> > >>>  +            // implements the interface for error conditions.
> >> > >>>> +
> >> > >>>> +
> >possibleClasses.remove(BackendListener.class.getName()
> >> +
> >> > >>>> "$ErrorBackendListenerClient");
> >> > >>>> +        } catch (Exception e) {
> >> > >>>> +            log.debug("Exception getting interfaces.", e);
> >> > >>>> +        }
> >> > >>>> +
> >> > >>>> +        JLabel label = new
> >> JLabel(JMeterUtils.getResString("backend_
> >> > >>>> listener_classname"));
> >> > >>>> // $NON-NLS-1$
> >> > >>>> +
> >> > >>>> +        classnameCombo = new
> >JComboBox(possibleClasses.toArray());
> >> > >>>> +        classnameCombo.addActionListener(this);
> >> > >>>> +        classnameCombo.setEditable(false);
> >> > >>>> +        label.setLabelFor(classnameCombo);
> >> > >>>> +
> >> > >>>> +        HorizontalPanel classNamePanel = new
> >HorizontalPanel();
> >> > >>>> +        classNamePanel.add(label);
> >> > >>>> +        classNamePanel.add(classnameCombo);
> >> > >>>> +
> >> > >>>> +        queueSize = new JTextField("", 5);
> >> > >>>> +        queueSize.setName("Queue Size"); //$NON-NLS-1$
> >> > >>>> +        JLabel queueSizeLabel = new JLabel(JMeterUtils.
> >> > >>>> getResString("backend_listener_queue_size")); // $NON-NLS-1$
> >> > >>>> +        queueSizeLabel.setLabelFor(queueSize);
> >> > >>>> +        HorizontalPanel queueSizePanel = new
> >HorizontalPanel();
> >> > >>>> +        queueSizePanel.add(queueSizeLabel,
> >BorderLayout.WEST);
> >> > >>>> +        queueSizePanel.add(queueSize);
> >> > >>>> +
> >> > >>>> +        JPanel panel = new JPanel(new BorderLayout(0, 5));
> >> > >>>> +        panel.add(classNamePanel, BorderLayout.NORTH);
> >> > >>>> +        panel.add(queueSizePanel, BorderLayout.CENTER);
> >> > >>>> +        return panel;
> >> > >>>> +    }
> >> > >>>> +
> >> > >>>> +    /**
> >> > >>>> +     * Handle action events for this component. This method
> >> currently
> >> > >>>> handles
> >> > >>>> +     * events for the classname combo box.
> >> > >>>> +     *
> >> > >>>> +     * @param evt
> >> > >>>>
> >> > >>>>  I would spend the few extra characters to make it event
> >instead of
> >> evt
> >> > >>>
> >> > >>>  +     *            the ActionEvent to be handled
> >> > >>>> +     */
> >> > >>>> +    @Override
> >> > >>>> +    public void actionPerformed(ActionEvent evt) {
> >> > >>>> +        if (evt.getSource() == classnameCombo) {
> >> > >>>> +            String className = ((String) classnameCombo.
> >> > >>>> getSelectedItem()).trim();
> >> > >>>> +            try {
> >> > >>>> +                BackendListenerClient client =
> >> (BackendListenerClient)
> >> > >>>> Class.forName(className, true,
> >> > >>>> +                        Thread.currentThread().
> >> > >>>> getContextClassLoader()).
> >> > >>>> newInstance();
> >> > >>>> +
> >> > >>>> +                Arguments currArgs = new Arguments();
> >> > >>>> +                argsPanel.modifyTestElement(currArgs);
> >> > >>>> +                Map<String, String> currArgsMap =
> >> > >>>> currArgs.getArgumentsAsMap();
> >> > >>>> +
> >> > >>>> +                Arguments newArgs = new Arguments();
> >> > >>>> +                Arguments testParams = null;
> >> > >>>> +                try {
> >> > >>>> +                    testParams =
> >client.getDefaultParameters();
> >> > >>>> +                } catch (AbstractMethodError e) {
> >> > >>>> +                    log.warn("BackendListenerClient doesn't
> >> implement
> >> > >>>> "
> >> > >>>> +                            + "getDefaultParameters.  Default
> >> > >>>> parameters
> >> > >>>> won't "
> >> > >>>> +                            + "be shown.  Please update your
> >client
> >> > >>>> class: " + className);
> >> > >>>> +                }
> >> > >>>> +
> >> > >>>> +                if (testParams != null) {
> >> > >>>> +                    PropertyIterator i =
> >testParams.getArguments().
> >> > >>>> iterator();
> >> > >>>>
> >> > >>>>  I would try a for loop instead of explicitly using an
> >iterator
> >> > >>>
> >> > >>>  +                    while (i.hasNext()) {
> >> > >>>> +                        Argument arg = (Argument)
> >> > >>>> i.next().getObjectValue();
> >> > >>>> +                        String name = arg.getName();
> >> > >>>> +                        String value = arg.getValue();
> >> > >>>> +
> >> > >>>> +                        // If a user has set parameters in
> >one
> >> test,
> >> > >>>> and
> >> > >>>> then
> >> > >>>> +                        // selects a different test which
> >supports
> >> the
> >> > >>>> same
> >> > >>>> +                        // parameters, those parameters
> >should
> >> have the
> >> > >>>> same
> >> > >>>> +                        // values that they did in the
> >original
> >> test.
> >> > >>>> +                        if (currArgsMap.containsKey(name)) {
> >> > >>>> +                            String newVal =
> >currArgsMap.get(name);
> >> > >>>> +                            if (newVal != null &&
> >newVal.length()
> >> > 0)
> >> > >>>> {
> >> > >>>> +                                value = newVal;
> >> > >>>> +                            }
> >> > >>>> +                        }
> >> > >>>> +                        newArgs.addArgument(name, value);
> >> > >>>> +                    }
> >> > >>>> +                }
> >> > >>>> +
> >> > >>>> +                argsPanel.configure(newArgs);
> >> > >>>> +            } catch (Exception e) {
> >> > >>>> +                log.error("Error getting argument list for "
> >+
> >> > >>>> className, e);
> >> > >>>> +            }
> >> > >>>> +        }
> >> > >>>> +    }
> >> > >>>> +
> >> > >>>> +    /**
> >> > >>>> +     * Create a panel containing components allowing the user
> >to
> >> > >>>> provide
> >> > >>>> +     * arguments to be passed to the test class instance.
> >> > >>>> +     *
> >> > >>>> +     * @return a panel containing the relevant components
> >> > >>>> +     */
> >> > >>>> +    private JPanel createParameterPanel() {
> >> > >>>> +        argsPanel = new ArgumentsPanel(JMeterUtils.
> >> > >>>> getResString("backend_listener_paramtable")); // $NON-NLS-1$
> >> > >>>> +        return argsPanel;
> >> > >>>> +    }
> >> > >>>> +
> >> > >>>> +    /** {@inheritDoc} */
> >> > >>>> +    @Override
> >> > >>>> +    public void configure(TestElement config) {
> >> > >>>> +        super.configure(config);
> >> > >>>> +
> >> > >>>> +        argsPanel.configure((Arguments) config.getProperty(
> >> > >>>> BackendListener.ARGUMENTS).getObjectValue());
> >> > >>>> +
> >> > >>>> +        String className = config.getPropertyAsString(
> >> > >>>> BackendListener.CLASSNAME);
> >> > >>>> +        if(checkContainsClassName(classnameCombo.getModel(),
> >> > >>>> className)) {
> >> > >>>> +            classnameCombo.setSelectedItem(className);
> >> > >>>> +        } else {
> >> > >>>> +            log.error("Error setting class:'"+className+"' in
> >> > >>>> BackendListener: "+getName()+
> >> > >>>> +                    ", check for a missing jar in your jmeter
> >> > >>>> 'search_paths' and 'plugin_dependency_paths' properties");
> >> > >>>> +        }
> >> > >>>> +        queueSize.setText(Integer.toString(((BackendListener)
> >> > >>>> config).getQueueSize()));
> >> > >>>> +    }
> >> > >>>> +
> >> > >>>> +    /**
> >> > >>>> +     * Check combo contains className
> >> > >>>> +     * @param model ComboBoxModel
> >> > >>>> +     * @param className String class name
> >> > >>>> +     * @return boolean
> >> > >>>>
> >> > >>>>  explain "boolean" or the other params a bit more?
> >> > >>>
> >> > >>>  +     */
> >> > >>>> +    private static final boolean
> >> checkContainsClassName(ComboBoxModel
> >> > >>>> model, String className) {
> >> > >>>> +        int size = model.getSize();
> >> > >>>> +        Set<String> set = new HashSet<String>(size);
> >> > >>>> +        for (int i = 0; i < size; i++) {
> >> > >>>> +            set.add((String)model.getElementAt(i));
> >> > >>>> +        }
> >> > >>>> +        return set.contains(className);
> >> > >>>> +    }
> >> > >>>> +
> >> > >>>> +    /** {@inheritDoc} */
> >> > >>>> +    @Override
> >> > >>>> +    public TestElement createTestElement() {
> >> > >>>> +        BackendListener config = new BackendListener();
> >> > >>>> +        modifyTestElement(config);
> >> > >>>> +        return config;
> >> > >>>> +    }
> >> > >>>> +
> >> > >>>> +    /** {@inheritDoc} */
> >> > >>>> +    @Override
> >> > >>>> +    public void modifyTestElement(TestElement config) {
> >> > >>>> +        configureTestElement(config);
> >> > >>>> +        BackendListener backendListener = (BackendListener)
> >config;
> >> > >>>> +        backendListener.setArguments((Arguments)
> >> > >>>> argsPanel.createTestElement());
> >> > >>>> +
> >backendListener.setClassname(String.valueOf(classnameCombo.
> >> > >>>> getSelectedItem()));
> >> > >>>> +
> >backendListener.setQueueSize(Integer.parseInt(queueSize.
> >> > >>>> getText()));
> >> > >>>> +
> >> > >>>> +    }
> >> > >>>> +
> >> > >>>>
> >> > >>>
> >> >
> >>
> >>
> >>
>
>


-- 
Cordialement.
Philippe Mouawad.

Re: svn commit: r1641081 - in /jmeter/trunk: ./ bin/ res/maven/ src/components/org/apache/jmeter/visualizers/backend/ src/core/org/apache/jmeter/resources/ src/core/org/apache/jmeter/samplers/ src/core/org/apache/jmeter/save/ xdocs/ xdocs/usermanual/

Posted by Felix Schumacher <fe...@internetallee.de>.

Am 29. November 2014 21:12:00 MEZ, schrieb Philippe Mouawad <ph...@gmail.com>:
>Hi Felix
>
>My answer inline.
>Regards
>
>On Sat, Nov 29, 2014 at 11:51 AM, Felix Schumacher <
>felix.schumacher@internetallee.de> wrote:
>
>> Hello Philippe,
>>
>> Am Sonntag, den 23.11.2014, 12:22 +0100 schrieb Philippe Mouawad:
>> > Thanks a lot for your review which pointed to a synchronisation
>issue
>> that
>> > I fixed, good catch!
>> >
>> > I think I took all your notes into account, let me know if I forgot
>> > something.
>> in SamplerMetric you have used a sliding window for the statistics.
>> * Should we make the length of the window configurable?
>>
>
>Yes but it's a new property and we have a lot :-)
But the size of the window depends on the number of samples per time slot. Perhaps it could be dynamically sized? 

>
>
>> * Should min/max and minThreads/maxThreads be limited to the sliding
>> window, also? At least min and max would be simple to do.
>>
>
>Dev team opinion is welcome, maybe it would be better
>- min would be percentile(0)
>- max would be percentile(100)

The stats field has methods to get the minimum and the maximum values. I would take those. 

>for minThreads, maxThreads, how would you do it ?

Create another statistical field for the number of threads. Then we could provide correct answers for max/min thread numbers plus mean/average/percentile. 

Regards
Felix

>
>
>> Regards
>>  Felix
>> >
>> > Regards
>> > Philippe
>> >
>> > On Sunday, November 23, 2014, Felix Schumacher <
>> > felix.schumacher@internetallee.de> wrote:
>> >
>> > > Hi Phillipe,
>> > > Am 22.11.2014 um 19:29 schrieb Philippe Mouawad:
>> > >
>> > >> Hi Felix,
>> > >> As I said in thread, I commited code and will improve, feel free
>to
>> fix
>> > >> javadocs issues on your side.
>> > >> I will review your comment.
>> > >>
>> > >> I have spent many hours if not days on this code and I am aware
>it is
>> not
>> > >> yet fully completed (although tests are promising) but my aim
>when
>> > >> commiting it was to have feedback and help to finish it.
>> > >>
>> > > I did not mean to offend you. I can clearly see, that you put a
>lot of
>> > > effort
>> > > in this listener and I will surely try to integrate jmeter into
>our
>> > > collectd server.
>> > >
>> > > Regards
>> > >  Felix
>> > >
>> > >>
>> > >> Regards
>> > >> Philippe
>> > >>
>> > >> On Sat, Nov 22, 2014 at 7:21 PM, Felix Schumacher <
>> > >> felix.schumacher@internetallee.de> wrote:
>> > >>
>> > >>  Hello Philippe,
>> > >>>
>> > >>> I have hidden a few comments inside the cited code.
>> > >>> They are mostly around javadoc and naming things.
>> > >>>
>> > >>> Am 22.11.2014 um 16:36 schrieb pmouawad@apache.org:
>> > >>>
>> > >>>  Author: pmouawad
>> > >>>> Date: Sat Nov 22 15:36:37 2014
>> > >>>> New Revision: 1641081
>> > >>>>
>> > >>>> URL: http://svn.apache.org/r1641081
>> > >>>> Log:
>> > >>>> Bug 55932 - Create a Async BackendListener to allow easy plug
>of new
>> > >>>> listener (Graphite, JDBC, Console,...)
>> > >>>> Bugzilla Id: 55932
>> > >>>>
>> > >>>> Added:
>> > >>>>      
>jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>> > >>>> backend/
>> > >>>>      
>jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>> > >>>> backend/
>> > >>>> AbstractBackendListenerClient.java   (with props)
>> > >>>>      
>jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>> > >>>> backend/BackendListener.java
>> > >>>>   (with props)
>> > >>>>      
>jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>> > >>>> backend/BackendListenerClient.java   (with props)
>> > >>>>      
>jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>> > >>>> backend/BackendListenerContext.java
>> > >>>>   (with props)
>> > >>>>      
>jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>> > >>>> backend/BackendListenerGui.java   (with props)
>> > >>>>      
>jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>> > >>>> backend/SamplerMetric.java
>> > >>>>   (with props)
>> > >>>> Modified:
>> > >>>>       jmeter/trunk/bin/saveservice.properties
>> > >>>>       jmeter/trunk/build.properties
>> > >>>>       jmeter/trunk/build.xml
>> > >>>>       jmeter/trunk/eclipse.classpath
>> > >>>>       jmeter/trunk/res/maven/ApacheJMeter_parent.pom
>> > >>>>       jmeter/trunk/src/core/org/apache/jmeter/resources/
>> > >>>> messages.properties
>> > >>>>       jmeter/trunk/src/core/org/apache/jmeter/resources/
>> > >>>> messages_fr.properties
>> > >>>>       jmeter/trunk/src/core/org/apache/jmeter/samplers/
>> > >>>> SampleResult.java
>> > >>>>      
>jmeter/trunk/src/core/org/apache/jmeter/save/SaveService.java
>> > >>>>       jmeter/trunk/xdocs/changes.xml
>> > >>>>       jmeter/trunk/xdocs/usermanual/component_reference.xml
>> > >>>>
>> > >>>> Modified: jmeter/trunk/bin/saveservice.properties
>> > >>>> URL:
>http://svn.apache.org/viewvc/jmeter/trunk/bin/saveservice.
>> > >>>> properties?rev=1641081&r1=1641080&r2=1641081&view=diff
>> > >>>> ============================================================
>> > >>>> ==================
>> > >>>> --- jmeter/trunk/bin/saveservice.properties (original)
>> > >>>> +++ jmeter/trunk/bin/saveservice.properties Sat Nov 22
>15:36:37 2014
>> > >>>> @@ -53,7 +53,8 @@ _file_version=$Revision$
>> > >>>>    # 2.5 = 2.10
>> > >>>>    # 2.6 = 2.11
>> > >>>>    # 2.7 = 2.12
>> > >>>> -_version=2.7
>> > >>>> +# 2.8 = 2.13
>> > >>>> +_version=2.8
>> > >>>>    #
>> > >>>>    #
>> > >>>>    # Character set encoding used to read and write JMeter XML
>files
>> and
>> > >>>> CSV results
>> > >>>> @@ -78,6 +79,8 @@ AssertionVisualizer=org.apache.jmeter.vi
>> > >>>>   
>AuthManager=org.apache.jmeter.protocol.http.control.AuthManager
>> > >>>>
>> Authorization=org.apache.jmeter.protocol.http.control.Authorization
>> > >>>>    AuthPanel=org.apache.jmeter.protocol.http.gui.AuthPanel
>> > >>>>
>>
>+BackendListener=org.apache.jmeter.visualizers.backend.BackendListener
>> > >>>> +BackendListenerGui=org.apache.jmeter.visualizers.
>> > >>>> backend.BackendListenerGui
>> > >>>>    BarChart=org.apache.jmeter.testelement.BarChart
>> > >>>>    BarChartGui=org.apache.jmeter.report.gui.BarChartGui
>> > >>>>
>> BeanShellAssertion=org.apache.jmeter.assertions.BeanShellAssertion
>> > >>>>
>> > >>>> Modified: jmeter/trunk/build.properties
>> > >>>> URL:
>http://svn.apache.org/viewvc/jmeter/trunk/build.properties?
>> > >>>> rev=1641081&r1=1641080&r2=1641081&view=diff
>> > >>>> ============================================================
>> > >>>> ==================
>> > >>>> --- jmeter/trunk/build.properties (original)
>> > >>>> +++ jmeter/trunk/build.properties Sat Nov 22 15:36:37 2014
>> > >>>> @@ -118,11 +118,21 @@ commons-logging.loc         = ${maven2.r
>> > >>>>    #commons-logging.md5         =
>E2C390FE739B2550A218262B28F290CE
>> > >>>>    commons-logging.md5         =
>040b4b4d8eac886f6b4a2a3bd2f31b00
>> > >>>>    +commons-math3.version         = 3.3
>> > >>>> +commons-math3.jar             =
>commons-math3-${commons-math3.
>> > >>>> version}.jar
>> > >>>> +commons-math3.loc             = ${maven2.repo}/org/apache/
>> > >>>> commons/commons-math3/${commons-math3.version}
>> > >>>> +commons-math3.md5             =
>87346cf2772dc2becf106c45e0f63863
>> > >>>> +
>> > >>>>    commons-net.version         = 3.3
>> > >>>>    commons-net.jar             =
>> commons-net-${commons-net.version}.jar
>> > >>>>    commons-net.loc             = ${maven2.repo}/commons-net/
>> > >>>> commons-net/${commons-net.version}
>> > >>>>    commons-net.md5             =
>c077ca61598e9c21f43f8b6488fbbee9
>> > >>>>    +commons-pool2.version         = 2.2
>> > >>>> +commons-pool2.jar             =
>commons-pool2-${commons-pool2.
>> > >>>> version}.jar
>> > >>>> +commons-pool2.loc             = ${maven2.repo}/org/apache/
>> > >>>> commons/commons-pool2/${commons-pool2.version}
>> > >>>> +commons-pool2.md5             =
>51b56c92883812c56fbeb339866ce2df
>> > >>>> +
>> > >>>>    # dnsjava for DNSCacheManager
>> > >>>>    dnsjava.version             = 2.1.6
>> > >>>>    dnsjava.jar                 =
>dnsjava-${dnsjava.version}.jar
>> > >>>>
>> > >>>> Modified: jmeter/trunk/build.xml
>> > >>>> URL: http://svn.apache.org/viewvc/jmeter/trunk/build.xml?rev=
>> > >>>> 1641081&r1=1641080&r2=1641081&view=diff
>> > >>>> ============================================================
>> > >>>> ==================
>> > >>>> --- jmeter/trunk/build.xml (original)
>> > >>>> +++ jmeter/trunk/build.xml Sat Nov 22 15:36:37 2014
>> > >>>> @@ -365,7 +365,9 @@
>> > >>>>        <include name="${lib.dir}/${commons-jexl2.jar}"/>
>> > >>>>        <include name="${lib.dir}/${commons-lang3.jar}"/>
>> > >>>>        <include name="${lib.dir}/${commons-logging.jar}"/>
>> > >>>> +    <include name="${lib.dir}/${commons-math3}"/>
>> > >>>>        <include name="${lib.dir}/${commons-net.jar}"/>
>> > >>>> +    <include name="${lib.dir}/${commons-pool2.jar}"/>
>> > >>>>        <include name="${lib.dir}/${dnsjava.jar}"/>
>> > >>>>        <include
>name="${lib.dir}/${excalibur-datasource.jar}"/>
>> > >>>>        <include
>name="${lib.dir}/${excalibur-instrument.jar}"/>
>> > >>>> @@ -438,8 +440,10 @@
>> > >>>>        <pathelement
>location="${lib.dir}/${commons-jexl2.jar}"/>
>> > >>>>        <pathelement
>location="${lib.dir}/${commons-lang3.jar}"/>
>> > >>>>        <pathelement
>location="${lib.dir}/${commons-logging.jar}"/>
>> > >>>> +    <pathelement location="${lib.dir}/${commons-math3.jar}"/>
>> > >>>>        <pathelement location="${lib.dir}/${commons-net.jar}"/>
>> > >>>> -    <pathelement location="${lib.dir}/${dnsjava.jar}"/>
>> > >>>> +       <pathelement
>location="${lib.dir}/${commons-pool2.jar}"/>
>> > >>>> +       <pathelement location="${lib.dir}/${dnsjava.jar}"/>
>> > >>>>        <pathelement
>> location="${lib.dir}/${excalibur-datasource.jar}"/>
>> > >>>>        <pathelement
>> location="${lib.dir}/${excalibur-instrument.jar}"/>
>> > >>>>        <pathelement
>location="${lib.dir}/${excalibur-logger.jar}"/>
>> > >>>> @@ -2909,7 +2913,9 @@ run JMeter unless all the JMeter jars ar
>> > >>>>            <process_jarfile jarname="commons-jexl2"/>
>> > >>>>            <process_jarfile jarname="commons-lang3"/>
>> > >>>>            <process_jarfile jarname="commons-logging"/>
>> > >>>> +        <process_jarfile jarname="commons-math3"/>
>> > >>>>            <process_jarfile jarname="commons-net"/>
>> > >>>> +       <process_jarfile jarname="commons-pool2"/>
>> > >>>>            <process_jarfile jarname="dnsjava"/>
>> > >>>>            <process_jarfile jarname="excalibur-datasource"/>
>> > >>>>            <process_jarfile jarname="excalibur-instrument"/>
>> > >>>>
>> > >>>> Modified: jmeter/trunk/eclipse.classpath
>> > >>>> URL: http://svn.apache.org/viewvc/jmeter/trunk/eclipse.
>> > >>>> classpath?rev=1641081&r1=1641080&r2=1641081&view=diff
>> > >>>> ============================================================
>> > >>>> ==================
>> > >>>> --- jmeter/trunk/eclipse.classpath (original)
>> > >>>> +++ jmeter/trunk/eclipse.classpath Sat Nov 22 15:36:37 2014
>> > >>>> @@ -55,7 +55,9 @@
>> > >>>>          <classpathentry kind="lib"
>> path="lib/commons-jexl-2.1.1.jar"/>
>> > >>>>          <classpathentry kind="lib"
>path="lib/commons-lang3-3.3.2.
>> > >>>> jar"/>
>> > >>>>          <classpathentry kind="lib"
>path="lib/commons-logging-1.2.
>> > >>>> jar"/>
>> > >>>> +    <classpathentry kind="lib"
>path="lib/commons-math3-3.3.jar"/>
>> > >>>>          <classpathentry kind="lib"
>path="lib/commons-net-3.3.jar"/>
>> > >>>> +    <classpathentry kind="lib"
>path="lib/commons-pool2-2.2.jar"/>
>> > >>>>          <classpathentry kind="lib"
>path="lib/dnsjava-2.1.6.jar"/>
>> > >>>>          <classpathentry kind="lib" path="lib/excalibur-
>> > >>>> datasource-2.1.jar"/>
>> > >>>>          <classpathentry kind="lib" path="lib/excalibur-
>> > >>>> instrument-1.0.jar"/>
>> > >>>>
>> > >>>> Modified: jmeter/trunk/res/maven/ApacheJMeter_parent.pom
>> > >>>> URL: http://svn.apache.org/viewvc/jmeter/trunk/res/maven/
>> > >>>>
>ApacheJMeter_parent.pom?rev=1641081&r1=1641080&r2=1641081&view=diff
>> > >>>> ============================================================
>> > >>>> ==================
>> > >>>> --- jmeter/trunk/res/maven/ApacheJMeter_parent.pom (original)
>> > >>>> +++ jmeter/trunk/res/maven/ApacheJMeter_parent.pom Sat Nov 22
>> 15:36:37
>> > >>>> 2014
>> > >>>> @@ -66,7 +66,9 @@ under the License.
>> > >>>>          <commons-jexl2.version>2.1.1</commons-jexl2.version>
>> > >>>>          <commons-lang3.version>3.3.2</commons-lang3.version>
>> > >>>>         
><commons-logging.version>1.2</commons-logging.version>
>> > >>>> +      <commons-math3.version>3.3</commons-math3.version>
>> > >>>>          <commons-net.version>3.3</commons-net.version>
>> > >>>> +      <commons-pool2.version>2.2</commons-pool2.version>
>> > >>>>          <dnsjava.version>2.1.6</dnsjava.version>
>> > >>>>         
><excalibur-datasource.version>2.1</excalibur-datasource.
>> > >>>> version>
>> > >>>>         
><excalibur-instrument.version>1.0</excalibur-instrument.
>> > >>>> version>
>> > >>>> @@ -181,11 +183,21 @@ under the License.
>> > >>>>            <version>${commons-logging.version}</version>
>> > >>>>          </dependency>
>> > >>>>          <dependency>
>> > >>>> +        <groupId>commons-math3</groupId>
>> > >>>> +        <artifactId>commons-math3</artifactId>
>> > >>>> +        <version>${commons-math3.version}</version>
>> > >>>> +      </dependency>
>> > >>>> +      <dependency>
>> > >>>>            <groupId>commons-net</groupId>
>> > >>>>            <artifactId>commons-net</artifactId>
>> > >>>>            <version>${commons-net.version}</version>
>> > >>>>          </dependency>
>> > >>>>          <dependency>
>> > >>>> +        <groupId>commons-pool2</groupId>
>> > >>>> +        <artifactId>commons-pool2</artifactId>
>> > >>>> +        <version>${commons-pool2.version}</version>
>> > >>>> +      </dependency>
>> > >>>> +      <dependency>
>> > >>>>              <groupId>dnsjava</groupId>
>> > >>>>              <artifactId>dnsjava</artifactId>
>> > >>>>              <version>${dnsjava.version}</version>
>> > >>>>
>> > >>>> Added:
>jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>> > >>>> backend/
>> > >>>> AbstractBackendListenerClient.java
>> > >>>> URL: http://svn.apache.org/viewvc/jmeter/trunk/src/components/
>> > >>>>
>org/apache/jmeter/visualizers/backend/AbstractBackendListenerClient.
>> > >>>> java?rev=1641081&view=auto
>> > >>>> ============================================================
>> > >>>> ==================
>> > >>>> ---
>> jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/
>> > >>>> AbstractBackendListenerClient.java (added)
>> > >>>> +++
>> jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/
>> > >>>> AbstractBackendListenerClient.java Sat Nov 22 15:36:37 2014
>> > >>>> @@ -0,0 +1,121 @@
>> > >>>> +/*
>> > >>>> + * 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.jmeter.visualizers.backend;
>> > >>>> +
>> > >>>> +import java.util.Map;
>> > >>>> +import java.util.concurrent.ConcurrentHashMap;
>> > >>>> +
>> > >>>> +import org.apache.jmeter.config.Arguments;
>> > >>>> +import org.apache.jmeter.samplers.SampleResult;
>> > >>>> +import org.apache.jorphan.logging.LoggingManager;
>> > >>>> +import org.apache.log.Logger;
>> > >>>> +
>> > >>>> +/**
>> > >>>> + * An abstract implementation of the BackendListenerClient
>> interface.
>> > >>>> This
>> > >>>> + * implementation provides default implementations of most of
>the
>> > >>>> methods in the
>> > >>>> + * interface, as well as some convenience methods, in order
>to
>> simplify
>> > >>>> + * development of BackendListenerClient implementations.
>> > >>>> + *
>> > >>>> + * While it may be necessary to make changes to the
>> > >>>> BackendListenerClient interface
>> > >>>> + * from time to time (therefore requiring changes to any
>> > >>>> implementations
>> > >>>> of this
>> > >>>> + * interface), we intend to make this abstract class provide
>> reasonable
>> > >>>> + * implementations of any new methods so that subclasses do
>not
>> > >>>> necessarily need
>> > >>>> + * to be updated for new versions. Therefore, when creating a
>new
>> > >>>> + * BackendListenerClient implementation, developers are
>encouraged
>> to
>> > >>>> subclass this
>> > >>>> + * abstract class rather than implementing the
>> BackendListenerClient
>> > >>>> interface
>> > >>>> + * directly. Implementing BackendListenerClient directly will
>> continue
>> > >>>> to be
>> > >>>> + * supported for cases where extending this class is not
>possible
>> (for
>> > >>>> example,
>> > >>>> + * when the client class is already a subclass of some other
>> class).
>> > >>>> + * <p>
>> > >>>> + * The handleSampleResult() method of BackendListenerClient
>does
>> not
>> > >>>> have a default
>> > >>>> + * implementation here, so subclasses must define at least
>this
>> method.
>> > >>>> It may
>> > >>>> + * be useful to override other methods as well.
>> > >>>> + *
>> > >>>> + * @see BackendListener#sampleOccurred(org.apache.
>> > >>>> jmeter.samplers.SampleEvent)
>> > >>>> + * @since 2.13
>> > >>>> + */
>> > >>>> +public abstract class AbstractBackendListenerClient
>implements
>> > >>>> BackendListenerClient {
>> > >>>> +
>> > >>>> +    private static final Logger log = LoggingManager.
>> > >>>> getLoggerForClass();
>> > >>>>
>> > >>>>  In classes further down the logger is stored in variables
>named
>> LOG and
>> > >>> LOGGER, should we use one name?
>> > >>> In this class we have a getter for the logger in other classes
>not.
>> Why?
>> > >>>
>> > >>>  +
>> > >>>> +    private ConcurrentHashMap<String, SamplerMetric>
>> metricsPerSampler
>> > >>>> =
>> > >>>> new ConcurrentHashMap<String, SamplerMetric>();
>> > >>>> +
>> > >>>> +    /* Implements
>> BackendListenerClient.setupTest(JavaSamplerContext)
>> > >>>> */
>> > >>>> +    @Override
>> > >>>> +    public void setupTest(BackendListenerContext context)
>throws
>> > >>>> Exception {
>> > >>>> +        log.debug(getClass().getName() + ": setupTest");
>> > >>>> +    }
>> > >>>> +
>> > >>>> +    /* Implements BackendListenerClient.teardownTest(
>> > >>>> JavaSamplerContext)
>> > >>>> */
>> > >>>> +    @Override
>> > >>>> +    public void teardownTest(BackendListenerContext context)
>throws
>> > >>>> Exception {
>> > >>>> +        log.debug(getClass().getName() + ": teardownTest");
>> > >>>> +        metricsPerSampler.clear();
>> > >>>> +    }
>> > >>>> +
>> > >>>> +    /* Implements
>BackendListenerClient.getDefaultParameters() */
>> > >>>> +    @Override
>> > >>>> +    public Arguments getDefaultParameters() {
>> > >>>> +        return null;
>> > >>>> +    }
>> > >>>> +
>> > >>>> +    /**
>> > >>>> +     * Get a Logger instance which can be used by subclasses
>to log
>> > >>>> information.
>> > >>>> +     *
>> > >>>> +     * @return a Logger instance which can be used for
>logging
>> > >>>> +     */
>> > >>>> +    protected Logger getLogger() {
>> > >>>> +        return log;
>> > >>>> +    }
>> > >>>> +
>> > >>>> +    /* (non-Javadoc)
>> > >>>> +     * @see org.apache.jmeter.visualizers.
>> > >>>> backend.BackendListenerClient#
>> > >>>> createSampleResult(org.apache.jmeter.samplers.SampleResult)
>> > >>>> +     */
>> > >>>> +    @Override
>> > >>>> +    public SampleResult
>createSampleResult(BackendListenerContext
>> > >>>> context, SampleResult result) {
>> > >>>> +        SampleResult sampleResult = (SampleResult)
>result.clone();
>> > >>>> +        return sampleResult;
>> > >>>> +    }
>> > >>>> +
>> > >>>> +    /**
>> > >>>> +     *
>> > >>>> +     * @param sampleLabel
>> > >>>> +     * @return SamplerMetric
>> > >>>>
>> > >>>>  No description of the method and the parameters?
>> > >>>
>> > >>>  +     */
>> > >>>> +    protected SamplerMetric getSamplerMetric(String
>sampleLabel) {
>> > >>>> +        SamplerMetric samplerMetric = metricsPerSampler.get(
>> > >>>> sampleLabel);
>> > >>>> +        if(samplerMetric == null) {
>> > >>>> +            samplerMetric = new SamplerMetric();
>> > >>>> +            SamplerMetric oldValue =
>metricsPerSampler.putIfAbsent(
>> > >>>> sampleLabel,
>> > >>>> samplerMetric);
>> > >>>> +            if(oldValue != null ){
>> > >>>> +                samplerMetric = oldValue;
>> > >>>> +            }
>> > >>>> +        }
>> > >>>> +        return samplerMetric;
>> > >>>> +    }
>> > >>>> +
>> > >>>> +    /**
>> > >>>> +     *
>> > >>>> +     * @return Map<String, SamplerMetric>
>> > >>>>
>> > >>>>  No description of the method and usage of forbidden
>characters :)
>> there
>> > >>> are still more than 800 warnings in the javadoc to prune, so
>don't
>> > >>> introduce new ones, please.
>> > >>>
>> > >>>  +     */
>> > >>>> +    protected Map<String, SamplerMetric>
>getMetricsPerSampler() {
>> > >>>> +        return metricsPerSampler;
>> > >>>> +    }
>> > >>>> +
>> > >>>> +}
>> > >>>>
>> > >>>> Propchange:
>> jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>> > >>>> backend/AbstractBackendListenerClient.java
>> > >>>> ------------------------------------------------------------
>> > >>>> ------------------
>> > >>>>       svn:mime-type = text/plain
>> > >>>>
>> > >>>> Added:
>jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>> > >>>> backend/BackendListener.java
>> > >>>> URL: http://svn.apache.org/viewvc/jmeter/trunk/src/components/
>> > >>>> org/apache/jmeter/visualizers/backend/BackendListener.java?
>> > >>>> rev=1641081&view=auto
>> > >>>> ============================================================
>> > >>>> ==================
>> > >>>> --- jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>> > >>>> backend/BackendListener.java
>> > >>>> (added)
>> > >>>> +++ jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>> > >>>> backend/BackendListener.java
>> > >>>> Sat Nov 22 15:36:37 2014
>> > >>>> @@ -0,0 +1,448 @@
>> > >>>> +/*
>> > >>>> + * 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.jmeter.visualizers.backend;
>> > >>>> +
>> > >>>> +import java.io.Serializable;
>> > >>>> +import java.lang.reflect.Method;
>> > >>>> +import java.util.ArrayList;
>> > >>>> +import java.util.HashSet;
>> > >>>> +import java.util.List;
>> > >>>> +import java.util.Set;
>> > >>>> +import java.util.concurrent.ArrayBlockingQueue;
>> > >>>> +import java.util.concurrent.BlockingQueue;
>> > >>>> +import java.util.concurrent.locks.LockSupport;
>> > >>>> +
>> > >>>> +import org.apache.jmeter.config.Arguments;
>> > >>>> +import org.apache.jmeter.engine.util.NoThreadClone;
>> > >>>> +import
>org.apache.jmeter.protocol.java.sampler.JavaSamplerContext;
>> > >>>> +import org.apache.jmeter.samplers.Remoteable;
>> > >>>> +import org.apache.jmeter.samplers.SampleEvent;
>> > >>>> +import org.apache.jmeter.samplers.SampleListener;
>> > >>>> +import org.apache.jmeter.samplers.SampleResult;
>> > >>>> +import org.apache.jmeter.testelement.AbstractTestElement;
>> > >>>> +import org.apache.jmeter.testelement.TestElement;
>> > >>>> +import org.apache.jmeter.testelement.TestStateListener;
>> > >>>> +import
>org.apache.jmeter.testelement.property.TestElementProperty;
>> > >>>> +import org.apache.jorphan.logging.LoggingManager;
>> > >>>> +import org.apache.log.Logger;
>> > >>>> +
>> > >>>> +/**
>> > >>>> + * Async Listener that delegates SampleResult handling to
>> > >>>> implementations of {@link BackendListenerClient}
>> > >>>> + * @since 2.13
>> > >>>> + */
>> > >>>> +public class BackendListener extends AbstractTestElement
>> > >>>> +    implements Serializable, SampleListener,
>TestStateListener,
>> > >>>> NoThreadClone, Remoteable  {
>> > >>>> +
>> > >>>> +    /**
>> > >>>> +     *
>> > >>>> +     */
>> > >>>> +    private static final long serialVersionUID =
>> 8184103677832024335L;
>> > >>>> +
>> > >>>> +    private static final Logger log = LoggingManager.
>> > >>>> getLoggerForClass();
>> > >>>>
>> > >>>>  See naming comment of log from above
>> > >>>
>> > >>>  +
>> > >>>> +    /**
>> > >>>> +     * Set used to register instances which implement
>teardownTest.
>> > >>>> +     * This is used so that the BackendListenerClient can be
>> notified
>> > >>>> when the test ends.
>> > >>>> +     */
>> > >>>> +    private static final Set<BackendListener> TEAR_DOWN_SET =
>new
>> > >>>> HashSet<BackendListener>();
>> > >>>> +
>> > >>>> +    /**
>> > >>>> +     * Property key representing the classname of the
>> > >>>> BackendListenerClient to user.
>> > >>>> +     */
>> > >>>> +    public static final String CLASSNAME = "classname";
>> > >>>> +
>> > >>>> +    /**
>> > >>>> +     * Queue size
>> > >>>> +     */
>> > >>>> +    public static final String QUEUE_SIZE = "QUEUE_SIZE";
>> > >>>> +
>> > >>>> +    /**
>> > >>>> +     * Property key representing the arguments for the
>> > >>>> BackendListenerClient.
>> > >>>> +     */
>> > >>>> +    public static final String ARGUMENTS = "arguments";
>> > >>>> +
>> > >>>> +    /**
>> > >>>> +     * The BackendListenerClient class used by this sampler.
>> > >>>> +     * Created by testStarted; copied to cloned instances.
>> > >>>> +     */
>> > >>>> +    private Class<?> javaClass;
>> > >>>>
>> > >>>>  Could probably named clientClass instead of javaClass, since
>we
>> already
>> > >>> know it is a java class.
>> > >>>
>> > >>>  +
>> > >>>> +    /**
>> > >>>> +     * If true, the BackendListenerClient class implements
>> > >>>> teardownTest.
>> > >>>> +     * Created by testStarted; copied to cloned instances.
>> > >>>> +     */
>> > >>>> +    private boolean isToBeRegistered;
>> > >>>> +
>> > >>>> +    /**
>> > >>>> +     * The BackendListenerClient instance
>> > >>>> +     */
>> > >>>> +    private transient BackendListenerClient
>backendListenerClient =
>> > >>>> null;
>> > >>>> +
>> > >>>> +    /**
>> > >>>> +     * The JavaSamplerContext instance used by this sampler
>to hold
>> > >>>> information
>> > >>>>
>> > >>>>  BackendListenerContext?
>> > >>>
>> > >>>  +     * related to the test run, such as the parameters
>specified
>> for
>> > >>>> the
>> > >>>> sampler
>> > >>>> +     * client.
>> > >>>> +     */
>> > >>>> +    private transient BackendListenerContext context = null;
>> > >>>> +
>> > >>>> +    private static final int DEFAULT_QUEUE_SIZE = 5000;
>> > >>>> +
>> > >>>> +    private transient BlockingQueue<SampleResult> queue; //
>> created by
>> > >>>> server in readResolve method
>> > >>>> +
>> > >>>> +    private transient long queueWaits; // how many times we
>had to
>> wait
>> > >>>> to queue a sample
>> > >>>> +
>> > >>>> +    private transient long queueWaitTime; // how long we had
>to
>> wait
>> > >>>> (nanoSeconds)
>> > >>>> +
>> > >>>> +    // Create unique object as marker for end of queue
>> > >>>> +    private transient static final SampleResult FINAL_EVENT =
>new
>> > >>>> SampleResult();
>> > >>>> +
>> > >>>> +    /**
>> > >>>> +     * Create a BackendListener.
>> > >>>> +     */
>> > >>>> +    public BackendListener() {
>> > >>>> +        setArguments(new Arguments());
>> > >>>> +    }
>> > >>>> +
>> > >>>> +    /*
>> > >>>> +     * Ensure that the required class variables are cloned,
>> > >>>> +     * as this is not currently done by the
>super-implementation.
>> > >>>> +     */
>> > >>>> +    @Override
>> > >>>> +    public Object clone() {
>> > >>>> +        BackendListener clone = (BackendListener)
>super.clone();
>> > >>>> +        clone.javaClass = this.javaClass;
>> > >>>> +        clone.isToBeRegistered = this.isToBeRegistered;
>> > >>>> +        return clone;
>> > >>>> +    }
>> > >>>> +
>> > >>>> +    private void initClass() {
>> > >>>> +        String name = getClassname().trim();
>> > >>>> +        try {
>> > >>>> +            javaClass = Class.forName(name, false,
>> > >>>> Thread.currentThread().getContextClassLoader());
>> > >>>> +            Method method =
>javaClass.getMethod("teardownTest", new
>> > >>>> Class[]{BackendListenerContext.class});
>> > >>>> +            isToBeRegistered =
>!method.getDeclaringClass().equals(
>> > >>>> AbstractBackendListenerClient.class);
>> > >>>> +            log.info("Created class: " + name + ". Uses
>> teardownTest:
>> > >>>> "
>> > >>>> + isToBeRegistered);
>> > >>>> +        } catch (Exception e) {
>> > >>>> +            log.error(whoAmI() + "\tException initialising: "
>+
>> name,
>> > >>>> e);
>> > >>>> +        }
>> > >>>> +    }
>> > >>>> +
>> > >>>> +    /**
>> > >>>> +     * Retrieves reference to BackendListenerClient.
>> > >>>> +     *
>> > >>>> +     * Convience method used to check for null reference
>without
>> > >>>> actually
>> > >>>> +     * creating a BackendListenerClient
>> > >>>> +     *
>> > >>>> +     * @return reference to BackendListenerClient NOTUSED
>private
>> > >>>> BackendListenerClient
>> > >>>> +     *         retrieveJavaClient() { return javaClient; }
>> > >>>> +     */
>> > >>>>
>> > >>>>  Javadoc for non-existant method?
>> > >>>
>> > >>>  +
>> > >>>> +    /**
>> > >>>> +     * Generate a String identifier of this instance for
>debugging
>> > >>>> purposes.
>> > >>>> +     *
>> > >>>> +     * @return a String identifier for this sampler instance
>> > >>>> +     */
>> > >>>> +    private String whoAmI() {
>> > >>>> +        StringBuilder sb = new StringBuilder();
>> > >>>> +        sb.append(Thread.currentThread().getName());
>> > >>>> +        sb.append("@");
>> > >>>> +        sb.append(Integer.toHexString(hashCode()));
>> > >>>> +        sb.append("-");
>> > >>>> +        sb.append(getName());
>> > >>>> +        return sb.toString();
>> > >>>> +    }
>> > >>>> +
>> > >>>> +    // TestStateListener implementation
>> > >>>> +    /* Implements TestStateListener.testStarted() */
>> > >>>> +    @Override
>> > >>>> +    public void testStarted() {
>> > >>>> +        testStarted("");
>> > >>>> +    }
>> > >>>> +
>> > >>>> +    /* Implements TestStateListener.testStarted(String) */
>> > >>>> +    @Override
>> > >>>> +    public void testStarted(String host) {
>> > >>>> +        log.debug(whoAmI() + "\ttestStarted(" + host + ")");
>> > >>>>
>> > >>>>  Maybe use isDebugEnabled to guard whoAmI() call?
>> > >>>
>> > >>>  +        queue = new
>> ArrayBlockingQueue<SampleResult>(getQueueSize());
>> > >>>> +        initClass();
>> > >>>> +        queueWaits=0L;
>> > >>>> +        queueWaitTime=0L;
>> > >>>> +        log.info(getName()+":Starting worker with
>> class:"+javaClass +"
>> > >>>> and queue capacity:"+getQueueSize());
>> > >>>> +
>> > >>>> +        backendListenerClient =
>createBackendListenerClientImp
>> > >>>> l(javaClass);
>> > >>>> +        context = new BackendListenerContext((
>> > >>>> Arguments)getArguments().
>> > >>>> clone());
>> > >>>> +        if(isToBeRegistered) {
>> > >>>>
>> > >>>>  space after if and before (?
>> > >>>
>> > >>>  +            TEAR_DOWN_SET.add(this);
>> > >>>> +        }
>> > >>>> +        try {
>> > >>>> +            backendListenerClient.setupTest(context);
>> > >>>> +        } catch (Exception e) {
>> > >>>> +            throw new java.lang.IllegalStateException("Failed
>> calling
>> > >>>> setupTest", e);
>> > >>>> +        }
>> > >>>> +
>> > >>>> +        Worker worker = new Worker(javaClass,
>> backendListenerClient,
>> > >>>> (Arguments) getArguments().clone(), queue);
>> > >>>> +        worker.setDaemon(true);
>> > >>>> +        worker.start();
>> > >>>>
>> > >>>>  Don't we want to stop worker after we're done with one test?
>> > >>>
>> > >>>  +        log.info(getName()+":Started  worker with
>> class:"+javaClass);
>> > >>>>
>> > >>>>  Spaces after :?
>> > >>>
>> > >>>  +
>> > >>>> +    }
>> > >>>> +
>> > >>>> +    /* (non-Javadoc)
>> > >>>> +     * @see
>> org.apache.jmeter.samplers.SampleListener#sampleOccurred(
>> > >>>> org.apache.jmeter.samplers.SampleEvent)
>> > >>>> +     */
>> > >>>> +    @Override
>> > >>>> +    public void sampleOccurred(SampleEvent e) {
>> > >>>>
>> > >>>>  Longer name then 'e'? I expect e to be an exception, not an
>event.
>> > >>>
>> > >>>  +        Arguments args = getArguments();
>> > >>>> +        context = new BackendListenerContext(args);
>> > >>>> +
>> > >>>> +        SampleResult sr = backendListenerClient.
>> > >>>> createSampleResult(context,
>> > >>>> e.getResult());
>> > >>>> +        try {
>> > >>>> +            if (!queue.offer(sr)){ // we failed to add the
>element
>> > >>>> first
>> > >>>> time
>> > >>>> +                queueWaits++;
>> > >>>> +                long t1 = System.nanoTime();
>> > >>>> +                queue.put(sr);
>> > >>>> +                long t2 = System.nanoTime();
>> > >>>> +                queueWaitTime += t2-t1;
>> > >>>>
>> > >>>>  Will sampleOccurred be called concurrently? If so, than
>> queueWaitTime
>> > >>> +=
>> > >>> will not be correct.
>> > >>>
>> > >>>  +            }
>> > >>>> +        } catch (Exception err) {
>> > >>>> +            log.error("sampleOccurred, failed to queue the
>sample",
>> > >>>> err);
>> > >>>> +        }
>> > >>>> +    }
>> > >>>> +
>> > >>>> +    private static final class Worker extends Thread {
>> > >>>> +
>> > >>>> +        private final BlockingQueue<SampleResult> queue;
>> > >>>> +        private final BackendListenerContext context;
>> > >>>> +        private final BackendListenerClient
>backendListenerClient;
>> > >>>> +        private Worker(Class<?> javaClass,
>BackendListenerClient
>> > >>>> backendListenerClient, Arguments arguments,
>> BlockingQueue<SampleResult>
>> > >>>> q){
>> > >>>>
>> > >>>>  Same naming argument as above. clientclass instead of
>javaClass?
>> > >>>
>> > >>>  +            queue = q;
>> > >>>> +            // Allow BackendListenerClient implementations to
>get
>> > >>>> access
>> > >>>> to test element name
>> > >>>> +            arguments.addArgument(TestElement.NAME,
>getName());
>> > >>>> +            context = new BackendListenerContext(arguments);
>> > >>>> +            this.backendListenerClient =
>backendListenerClient;
>> > >>>> +        }
>> > >>>> +
>> > >>>> +
>> > >>>> +        @Override
>> > >>>> +        public void run() {
>> > >>>> +            boolean isDebugEnabled = log.isDebugEnabled();
>> > >>>> +            List<SampleResult> l = new
>> ArrayList<SampleResult>(queue.
>> > >>>> size());
>> > >>>>
>> > >>>>  samples instead of l?
>> > >>>
>> > >>>  +            try {
>> > >>>> +                boolean eof = false;
>> > >>>>
>> > >>>>  endOfLoop?
>> > >>>
>> > >>>  +                while (!eof) {
>> > >>>> +                    if(isDebugEnabled) {
>> > >>>> +                        log.debug("Thread:"+Thread.
>> > >>>> currentThread().getName()+"
>> > >>>> taking SampleResult from queue:"+queue.size());
>> > >>>> +                    }
>> > >>>> +                    SampleResult e = queue.take();
>> > >>>>
>> > >>>>  Could be named result, or sample instead of e
>> > >>>
>> > >>>  +                    if(isDebugEnabled) {
>> > >>>> +                        log.debug("Thread:"+Thread.
>> > >>>> currentThread().getName()+"
>> > >>>> took SampleResult:"+e+", isFinal:" + (e==FINAL_EVENT));
>> > >>>> +                    }
>> > >>>> +                    while (!(eof = (e == FINAL_EVENT)) && e
>!=
>> null ) {
>> > >>>> // try to process as many as possible
>> > >>>> +                        l.add(e);
>> > >>>> +                        if(isDebugEnabled) {
>> > >>>> +                            log.debug("Thread:"+Thread.
>> > >>>> currentThread().getName()+"
>> > >>>> polling from queue:"+queue.size());
>> > >>>> +                        }
>> > >>>> +                        e = queue.poll(); // returns null if
>> nothing on
>> > >>>> queue currently
>> > >>>> +                        if(isDebugEnabled) {
>> > >>>> +                            log.debug("Thread:"+Thread.
>> > >>>> currentThread().getName()+"
>> > >>>> took from queue:"+e+", isFinal:" + (e==FINAL_EVENT));
>> > >>>> +                        }
>> > >>>> +                    }
>> > >>>> +                    if(isDebugEnabled) {
>> > >>>> +                        log.debug("Thread:"+Thread.
>> > >>>> currentThread().getName()+
>> > >>>> +                                " exiting with FINAL
>EVENT:"+(e ==
>> > >>>> FINAL_EVENT)
>> > >>>> +                                +", null:" + (e==null));
>> > >>>> +                    }
>> > >>>> +                    int size = l.size();
>> > >>>>
>> > >>>>  No need for a temporary variable.
>> > >>>
>> > >>>  +                    if (size > 0) {
>> > >>>> +
>> backendListenerClient.handleSampleResults(l,
>> > >>>> context);
>> > >>>> +                        l.clear();
>> > >>>> +                    }
>> > >>>> +                    if(!eof) {
>> > >>>> +                        LockSupport.parkNanos(100);
>> > >>>> +                    }
>> > >>>> +                }
>> > >>>> +            } catch (InterruptedException e) {
>> > >>>> +                // NOOP
>> > >>>> +            }
>> > >>>> +            // We may have been interrupted
>> > >>>> +            int size = l.size();
>> > >>>> +            if (size > 0) {
>> > >>>> +                backendListenerClient.handleSampleResults(l,
>> context);
>> > >>>> +                l.clear();
>> > >>>> +            }
>> > >>>>
>> > >>>>  Same code as a few lines above, could be factored out into a
>method
>> > >>> handleSamples(l, context)
>> > >>>
>> > >>>  +            log.info("Worker ended");
>> > >>>> +        }
>> > >>>> +    }
>> > >>>> +
>> > >>>> +
>> > >>>> +    /**
>> > >>>> +     * Returns reference to
><code>BackendListenerClient</code>.
>> > >>>>
>> > >>>>  Could use a {@link...}
>> > >>>
>> > >>>  +     *
>> > >>>> +     *
>> > >>>> +     * @return BackendListenerClient reference.
>> > >>>> +     */
>> > >>>> +    static BackendListenerClient
>createBackendListenerClientImp
>> > >>>> l(Class<?>
>> > >>>> javaClass) {
>> > >>>> +        if (javaClass == null) { // failed to initialise the
>class
>> > >>>> +            return new ErrorBackendListenerClient();
>> > >>>> +        }
>> > >>>> +        BackendListenerClient client;
>> > >>>> +        try {
>> > >>>> +            client = (BackendListenerClient)
>> javaClass.newInstance();
>> > >>>> +        } catch (Exception e) {
>> > >>>> +            log.error("Exception creating: " + javaClass, e);
>> > >>>> +            client = new ErrorBackendListenerClient();
>> > >>>> +        }
>> > >>>> +        return client;
>> > >>>>
>> > >>>>  I would return newInstance() in try Block and return new
>Error.. in
>> > >>> catch
>> > >>> Block. javaClass -> clientClass
>> > >>>
>> > >>>  +    }
>> > >>>> +
>> > >>>> +    /**
>> > >>>> +     * Method called at the end of the test. This is called
>only
>> on one
>> > >>>> instance
>> > >>>> +     * of BackendListener. This method will loop through all
>of the
>> > >>>> other
>> > >>>> +     * BackendListenerClients which have been registered
>> (automatically
>> > >>>> in the
>> > >>>> +     * constructor) and notify them that the test has ended,
>> allowing
>> > >>>> the
>> > >>>> +     * BackendListenerClients to cleanup.
>> > >>>> +     */
>> > >>>> +    @Override
>> > >>>> +    public void testEnded() {
>> > >>>> +        try {
>> > >>>> +            queue.put(FINAL_EVENT);
>> > >>>> +        } catch (Exception ex) {
>> > >>>> +            log.warn("testEnded() with
>exception:"+ex.getMessage(),
>> > >>>> ex);
>> > >>>> +        }
>> > >>>> +        if (queueWaits > 0) {
>> > >>>> +            log.warn("QueueWaits: "+queueWaits+";
>QueueWaitTime:
>> > >>>> "+queueWaitTime+" (nanoseconds), you may need to increase
>queue
>> > >>>> capacity,
>> > >>>> see property 'backend_queue_capacity'");
>> > >>>> +        }
>> > >>>> +        synchronized (TEAR_DOWN_SET) {
>> > >>>> +            for (BackendListener backendListener :
>TEAR_DOWN_SET) {
>> > >>>> +                BackendListenerClient client =
>backendListener.
>> > >>>> backendListenerClient;
>> > >>>> +                if (client != null) {
>> > >>>> +                    try {
>> > >>>> +
>> client.teardownTest(backendListener.context);
>> > >>>> +                    } catch (Exception e) {
>> > >>>> +                        throw new java.lang.
>> > >>>> IllegalStateException("Failed
>> > >>>> calling teardownTest", e);
>> > >>>>
>> > >>>>  If we throw an exception here, we will not try every client.
>> > >>>
>> > >>>  +                    }
>> > >>>> +                }
>> > >>>> +            }
>> > >>>> +            TEAR_DOWN_SET.clear();
>> > >>>> +        }
>> > >>>> +    }
>> > >>>> +
>> > >>>> +    /* Implements TestStateListener.testEnded(String) */
>> > >>>> +    @Override
>> > >>>> +    public void testEnded(String host) {
>> > >>>> +        testEnded();
>> > >>>> +    }
>> > >>>> +
>> > >>>> +    /**
>> > >>>> +     * A {@link BackendListenerClient} implementation used
>for
>> error
>> > >>>> handling. If an
>> > >>>> +     * error occurs while creating the real
>BackendListenerClient
>> > >>>> object, it is
>> > >>>> +     * replaced with an instance of this class. Each time a
>sample
>> > >>>> occurs with
>> > >>>> +     * this class, the result is marked as a failure so the
>user
>> can
>> > >>>> see
>> > >>>> that
>> > >>>> +     * the test failed.
>> > >>>> +     */
>> > >>>> +    static class ErrorBackendListenerClient extends
>> > >>>> AbstractBackendListenerClient {
>> > >>>> +        /**
>> > >>>> +         * Return SampleResult with data on error.
>> > >>>> +         *
>> > >>>> +         * @see
>BackendListenerClient#runTest(JavaSamplerContext)
>> > >>>> +         */
>> > >>>> +        @Override
>> > >>>> +        public void handleSampleResults(List<SampleResult>
>> > >>>> sampleResults, BackendListenerContext context) {
>> > >>>> +           
>log.warn("ErrorBackendListenerClient#handleSampleResult
>> > >>>> called, noop");
>> > >>>> +            Thread.yield();
>> > >>>> +        }
>> > >>>> +    }
>> > >>>> +
>> > >>>> +    /* (non-Javadoc)
>> > >>>> +     * @see
>> org.apache.jmeter.samplers.SampleListener#sampleStarted(
>> > >>>> org.apache.jmeter.samplers.SampleEvent)
>> > >>>> +     */
>> > >>>> +    @Override
>> > >>>> +    public void sampleStarted(SampleEvent e) {
>> > >>>> +        // NOOP
>> > >>>> +
>> > >>>> +    }
>> > >>>> +
>> > >>>> +    /* (non-Javadoc)
>> > >>>> +     * @see
>> org.apache.jmeter.samplers.SampleListener#sampleStopped(
>> > >>>> org.apache.jmeter.samplers.SampleEvent)
>> > >>>> +     */
>> > >>>> +    @Override
>> > >>>> +    public void sampleStopped(SampleEvent e) {
>> > >>>> +        // NOOP
>> > >>>> +
>> > >>>> +    }
>> > >>>> +
>> > >>>> +    /**
>> > >>>> +     * Set the arguments (parameters) for the
>> BackendListenerClient to
>> > >>>> be executed
>> > >>>> +     * with.
>> > >>>> +     *
>> > >>>> +     * @param args
>> > >>>> +     *            the new arguments. These replace any
>existing
>> > >>>> arguments.
>> > >>>> +     */
>> > >>>> +    public void setArguments(Arguments args) {
>> > >>>> +        setProperty(new TestElementProperty(ARGUMENTS,
>args));
>> > >>>> +    }
>> > >>>> +
>> > >>>> +    /**
>> > >>>> +     * Get the arguments (parameters) for the
>> BackendListenerClient to
>> > >>>> be executed
>> > >>>> +     * with.
>> > >>>> +     *
>> > >>>> +     * @return the arguments
>> > >>>> +     */
>> > >>>> +    public Arguments getArguments() {
>> > >>>> +        return (Arguments)
>getProperty(ARGUMENTS).getObjectValue();
>> > >>>> +    }
>> > >>>> +
>> > >>>> +    /**
>> > >>>> +     * Sets the Classname of the BackendListenerClient object
>> > >>>> +     *
>> > >>>> +     * @param classname
>> > >>>> +     *            the new Classname value
>> > >>>> +     */
>> > >>>> +    public void setClassname(String classname) {
>> > >>>> +        setProperty(CLASSNAME, classname);
>> > >>>> +    }
>> > >>>> +
>> > >>>> +    /**
>> > >>>> +     * Gets the Classname of the BackendListenerClient object
>> > >>>> +     *
>> > >>>> +     * @return the Classname value
>> > >>>> +     */
>> > >>>> +    public String getClassname() {
>> > >>>> +        return getPropertyAsString(CLASSNAME);
>> > >>>> +    }
>> > >>>> +
>> > >>>> +    /**
>> > >>>> +     * Sets the queue size
>> > >>>> +     *
>> > >>>> +     * @param queueSize
>> > >>>> +     *
>> > >>>> +     */
>> > >>>> +    public void setQueueSize(int queueSize) {
>> > >>>> +        setProperty(QUEUE_SIZE, queueSize,
>DEFAULT_QUEUE_SIZE);
>> > >>>> +    }
>> > >>>> +
>> > >>>> +    /**
>> > >>>> +     * Gets the queue size
>> > >>>> +     *
>> > >>>> +     * @return int queueSize
>> > >>>> +     */
>> > >>>> +    public int getQueueSize() {
>> > >>>> +        return getPropertyAsInt(QUEUE_SIZE,
>DEFAULT_QUEUE_SIZE);
>> > >>>> +    }
>> > >>>> +}
>> > >>>>
>> > >>>> Propchange:
>> jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>> > >>>> backend/BackendListener.java
>> > >>>> ------------------------------------------------------------
>> > >>>> ------------------
>> > >>>>       svn:mime-type = text/plain
>> > >>>>
>> > >>>> Added:
>jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>> > >>>> backend/BackendListenerClient.java
>> > >>>> URL: http://svn.apache.org/viewvc/jmeter/trunk/src/components/
>> > >>>> org/apache/jmeter/visualizers/backend/BackendListenerClient.
>> > >>>> java?rev=1641081&view=auto
>> > >>>> ============================================================
>> > >>>> ==================
>> > >>>> --- jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>> > >>>> backend/BackendListenerClient.java (added)
>> > >>>> +++ jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>> > >>>> backend/BackendListenerClient.java Sat Nov 22 15:36:37 2014
>> > >>>> @@ -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.jmeter.visualizers.backend;
>> > >>>> +
>> > >>>> +import java.util.List;
>> > >>>> +
>> > >>>> +import org.apache.jmeter.config.Arguments;
>> > >>>> +import org.apache.jmeter.samplers.SampleResult;
>> > >>>> +
>> > >>>> +/**
>> > >>>> + * This interface defines the interactions between the
>> BackendListener
>> > >>>> and external
>> > >>>> + * Java programs which can be executed by JMeter. Any Java
>class
>> which
>> > >>>> wants to
>> > >>>> + * be executed as a JMeter test must implement this interface
>> (either
>> > >>>> directly
>> > >>>> + * or indirectly through AbstractBackendListenerClient).
>> > >>>> + * <p>
>> > >>>> + * JMeter will create one instance of a BackendListenerClient
>> > >>>> implementation for
>> > >>>> + * each user/thread in the test. Additional instances may be
>> created
>> > >>>> for
>> > >>>> + * internal use by JMeter (for example, to find out what
>> parameters are
>> > >>>> + * supported by the client).
>> > >>>> + * <p>
>> > >>>> + * When the test is started, setupTest() will be called on
>each
>> > >>>> thread's
>> > >>>> + * BackendListenerClient instance to initialize the client.
>Then
>> > >>>> handleSampleResult() will be
>> > >>>> + * called for each SampleResult notification. Finally,
>> teardownTest()
>> > >>>> will be called
>> > >>>> + * to allow the client to do any necessary clean-up.
>> > >>>> + * <p>
>> > >>>> + * The JMeter BackendListener GUI allows a list of parameters
>to be
>> > >>>> defined for the
>> > >>>> + * test. These are passed to the various test methods through
>the
>> > >>>> + * {@link BackendListenerContext}. A list of default
>parameters
>> can be
>> > >>>> defined
>> > >>>> + * through the getDefaultParameters() method. These
>parameters and
>> any
>> > >>>> default
>> > >>>> + * values associated with them will be shown in the GUI.
>Users can
>> add
>> > >>>> other
>> > >>>> + * parameters as well.
>> > >>>> + * <p>
>> > >>>> + * When possible, Listeners should extend {@link
>> > >>>> AbstractBackendListenerClient
>> > >>>> + * AbstractBackendListenerClient} rather than implementing
>> > >>>> BackendListenerClient
>> > >>>> + * directly. This should protect your tests from future
>changes to
>> the
>> > >>>> + * interface. While it may be necessary to make changes to
>the
>> > >>>> BackendListenerClient
>> > >>>> + * interface from time to time (therefore requiring changes
>to any
>> > >>>> + * implementations of this interface), we intend to make this
>> abstract
>> > >>>> class
>> > >>>> + * provide reasonable default implementations of any new
>methods so
>> > >>>> that
>> > >>>> + * subclasses do not necessarily need to be updated for new
>> versions.
>> > >>>> + * Implementing BackendListenerClient directly will continue
>to be
>> > >>>> supported for
>> > >>>> + * cases where extending this class is not possible (for
>example,
>> when
>> > >>>> the
>> > >>>> + * client class is already a subclass of some other class).
>> > >>>> + *
>> > >>>> + * @since 2.13
>> > >>>> + */
>> > >>>> +public interface BackendListenerClient {
>> > >>>> +    /**
>> > >>>> +     * Do any initialization required by this client. It is
>> generally
>> > >>>> +     * recommended to do any initialization such as getting
>> parameter
>> > >>>> values in
>> > >>>> +     * the setupTest method rather than the runTest method in
>> order to
>> > >>>> add as
>> > >>>> +     * little overhead as possible to the test.
>> > >>>> +     *
>> > >>>> +     * @param context
>> > >>>> +     *            the context to run with. This provides
>access to
>> > >>>> +     *            initialization parameters.
>> > >>>> +     */
>> > >>>> +    void setupTest(BackendListenerContext context) throws
>> Exception;
>> > >>>> +
>> > >>>> +    /**
>> > >>>> +     * Perform a single sample for each iteration. This
>method
>> returns
>> > >>>> a
>> > >>>> +     * <code>SampleResult</code> object.
><code>SampleResult</code>
>> has
>> > >>>> many
>> > >>>> +     * fields which can be used. At a minimum, the test
>should use
>> > >>>> +     * <code>SampleResult.sampleStart</code> and
>> > >>>> +     * <code>SampleResult.sampleEnd</code>to set the time
>that the
>> > >>>> test
>> > >>>>
>> > >>>>  use {@link..} instead of <code>..?
>> > >>>
>> > >>>  +     * required to execute. It is also a good idea to set the
>> > >>>> sampleLabel and
>> > >>>> +     * the successful flag.
>> > >>>> +     *
>> > >>>> +     * @see
>org.apache.jmeter.samplers.SampleResult#sampleStart()
>> > >>>> +     * @see
>org.apache.jmeter.samplers.SampleResult#sampleEnd()
>> > >>>> +     * @see
>org.apache.jmeter.samplers.SampleResult#setSuccessful(
>> > >>>> boolean)
>> > >>>> +     * @see
>org.apache.jmeter.samplers.SampleResult#setSampleLabel(
>> > >>>> String)
>> > >>>> +     *
>> > >>>> +     * @param context
>> > >>>> +     *            the context to run with. This provides
>access to
>> > >>>> +     *            initialization parameters.
>> > >>>> +     *
>> > >>>> +     */
>> > >>>> +    void handleSampleResults(List<SampleResult>
>sampleResults,
>> > >>>> BackendListenerContext context);
>> > >>>> +
>> > >>>> +    /**
>> > >>>> +     * Do any clean-up required by this test at the end of a
>test
>> run.
>> > >>>> +     *
>> > >>>> +     * @param context
>> > >>>> +     *            the context to run with. This provides
>access to
>> > >>>> +     *            initialization parameters.
>> > >>>> +     */
>> > >>>> +    void teardownTest(BackendListenerContext context) throws
>> > >>>> Exception;
>> > >>>> +
>> > >>>> +    /**
>> > >>>> +     * Provide a list of parameters which this test supports.
>Any
>> > >>>> parameter
>> > >>>> +     * names and associated values returned by this method
>will
>> appear
>> > >>>> in the
>> > >>>> +     * GUI by default so the user doesn't have to remember
>the
>> exact
>> > >>>> names. The
>> > >>>> +     * user can add other parameters which are not listed
>here. If
>> this
>> > >>>> method
>> > >>>> +     * returns null then no parameters will be listed. If the
>> value for
>> > >>>> some
>> > >>>> +     * parameter is null then that parameter will be listed
>in the
>> GUI
>> > >>>> with an
>> > >>>> +     * empty value.
>> > >>>> +     *
>> > >>>> +     * @return a specification of the parameters used by this
>test
>> > >>>> which
>> > >>>> should
>> > >>>> +     *         be listed in the GUI, or null if no parameters
>> should be
>> > >>>> listed.
>> > >>>> +     */
>> > >>>> +    Arguments getDefaultParameters();
>> > >>>> +
>> > >>>> +    /**
>> > >>>> +     *
>> > >>>> +     * @param context
>> > >>>> +     * @param result
>> > >>>> +     * @return
>> > >>>> +     */
>> > >>>> +    SampleResult createSampleResult(
>> > >>>> +            BackendListenerContext context, SampleResult
>result);
>> > >>>> +}
>> > >>>>
>> > >>>> Propchange:
>> jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>> > >>>> backend/BackendListenerClient.java
>> > >>>> ------------------------------------------------------------
>> > >>>> ------------------
>> > >>>>       svn:mime-type = text/plain
>> > >>>>
>> > >>>> Added:
>jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>> > >>>> backend/
>> > >>>> BackendListenerContext.java
>> > >>>> URL: http://svn.apache.org/viewvc/jmeter/trunk/src/components/
>> > >>>>
>org/apache/jmeter/visualizers/backend/BackendListenerContext.java?
>> > >>>> rev=1641081&view=auto
>> > >>>> ============================================================
>> > >>>> ==================
>> > >>>> ---
>> jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/
>> > >>>> BackendListenerContext.java
>> > >>>> (added)
>> > >>>> +++
>> jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/
>> > >>>> BackendListenerContext.java
>> > >>>> Sat Nov 22 15:36:37 2014
>> > >>>> @@ -0,0 +1,237 @@
>> > >>>> +/*
>> > >>>> +
>> > >>>> + * 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.jmeter.visualizers.backend;
>> > >>>> +
>> > >>>> +import java.util.Iterator;
>> > >>>> +import java.util.Map;
>> > >>>> +
>> > >>>> +import org.apache.jmeter.config.Arguments;
>> > >>>> +import org.apache.jorphan.logging.LoggingManager;
>> > >>>> +import org.apache.log.Logger;
>> > >>>> +
>> > >>>> +/**
>> > >>>> + * BackendListenerContext is used to provide context
>information
>> to a
>> > >>>> + * BackendListenerClient implementation. This currently
>consists
>> of the
>> > >>>> + * initialization parameters which were specified in the GUI.
>> > >>>> + * @since 2.13
>> > >>>> + */
>> > >>>> +public class BackendListenerContext {
>> > >>>> +    /*
>> > >>>> +     * Implementation notes:
>> > >>>> +     *
>> > >>>> +     * All of the methods in this class are currently
>read-only. If
>> > >>>> update
>> > >>>> +     * methods are included in the future, they should be
>defined
>> so
>> > >>>> that a
>> > >>>> +     * single instance of BackendListenerContext can be
>associated
>> with
>> > >>>> each thread.
>> > >>>> +     * Therefore, no synchronization should be needed. The
>same
>> > >>>> instance
>> > >>>> should
>> > >>>> +     * be used for the call to setupTest, all calls to
>runTest,
>> and the
>> > >>>> call to
>> > >>>> +     * teardownTest.
>> > >>>> +     */
>> > >>>> +
>> > >>>> +    /** Logging */
>> > >>>> +    private static final Logger log = LoggingManager.
>> > >>>> getLoggerForClass();
>> > >>>>
>> > >>>>  See naming comments for logger above
>> > >>>
>> > >>>  +
>> > >>>> +    /**
>> > >>>> +     * Map containing the initialization parameters for the
>> > >>>> BackendListenerClient.
>> > >>>> +     */
>> > >>>> +    private final Map<String, String> params;
>> > >>>> +
>> > >>>> +    /**
>> > >>>> +     *
>> > >>>> +     * @param args
>> > >>>> +     *            the initialization parameters.
>> > >>>> +     */
>> > >>>> +    public BackendListenerContext(Arguments args) {
>> > >>>> +        this.params = args.getArgumentsAsMap();
>> > >>>> +    }
>> > >>>> +
>> > >>>> +    /**
>> > >>>> +     * Determine whether or not a value has been specified
>for the
>> > >>>> parameter
>> > >>>> +     * with this name.
>> > >>>> +     *
>> > >>>> +     * @param name
>> > >>>> +     *            the name of the parameter to test
>> > >>>> +     * @return true if the parameter value has been
>specified,
>> false
>> > >>>> otherwise.
>> > >>>> +     */
>> > >>>> +    public boolean containsParameter(String name) {
>> > >>>>
>> > >>>>  hasParameter instead of containsParameter?
>> > >>>
>> > >>>  +        return params.containsKey(name);
>> > >>>> +    }
>> > >>>> +
>> > >>>> +    /**
>> > >>>> +     * Get an iterator of the parameter names. Each entry in
>the
>> > >>>> Iterator is a
>> > >>>> +     * String.
>> > >>>> +     *
>> > >>>> +     * @return an Iterator of Strings listing the names of
>the
>> > >>>> parameters which
>> > >>>> +     *         have been specified for this test.
>> > >>>> +     */
>> > >>>> +    public Iterator<String> getParameterNamesIterator() {
>> > >>>> +        return params.keySet().iterator();
>> > >>>> +    }
>> > >>>> +
>> > >>>> +    /**
>> > >>>> +     * Get the value of a specific parameter as a String, or
>null
>> if
>> > >>>> the
>> > >>>> value
>> > >>>> +     * was not specified.
>> > >>>> +     *
>> > >>>> +     * @param name
>> > >>>> +     *            the name of the parameter whose value
>should be
>> > >>>> retrieved
>> > >>>> +     * @return the value of the parameter, or null if the
>value
>> was not
>> > >>>> +     *         specified
>> > >>>> +     */
>> > >>>> +    public String getParameter(String name) {
>> > >>>> +        return getParameter(name, null);
>> > >>>> +    }
>> > >>>> +
>> > >>>> +    /**
>> > >>>> +     * Get the value of a specified parameter as a String, or
>> return
>> > >>>> the
>> > >>>> +     * specified default value if the value was not
>specified.
>> > >>>> +     *
>> > >>>> +     * @param name
>> > >>>> +     *            the name of the parameter whose value
>should be
>> > >>>> retrieved
>> > >>>> +     * @param defaultValue
>> > >>>> +     *            the default value to return if the value of
>this
>> > >>>> parameter was
>> > >>>> +     *            not specified
>> > >>>> +     * @return the value of the parameter, or the default
>value if
>> the
>> > >>>> parameter
>> > >>>> +     *         was not specified
>> > >>>> +     */
>> > >>>> +    public String getParameter(String name, String
>defaultValue) {
>> > >>>> +        if (params == null || !params.containsKey(name)) {
>> > >>>> +            return defaultValue;
>> > >>>> +        }
>> > >>>> +        return params.get(name);
>> > >>>> +    }
>> > >>>> +
>> > >>>> +    /**
>> > >>>> +     * Get the value of a specified parameter as an integer.
>An
>> > >>>> exception will
>> > >>>> +     * be thrown if the parameter is not specified or if it
>is not
>> an
>> > >>>> integer.
>> > >>>> +     * The value may be specified in decimal, hexadecimal, or
>> octal, as
>> > >>>> defined
>> > >>>> +     * by Integer.decode().
>> > >>>> +     *
>> > >>>> +     * @param name
>> > >>>> +     *            the name of the parameter whose value
>should be
>> > >>>> retrieved
>> > >>>> +     * @return the value of the parameter
>> > >>>> +     *
>> > >>>> +     * @throws NumberFormatException
>> > >>>> +     *             if the parameter is not specified or is
>not an
>> > >>>> integer
>> > >>>> +     *
>> > >>>> +     * @see java.lang.Integer#decode(java.lang.String)
>> > >>>> +     */
>> > >>>> +    public int getIntParameter(String name) throws
>> > >>>> NumberFormatException
>> > >>>> {
>> > >>>> +        if (params == null || !params.containsKey(name)) {
>> > >>>> +            throw new NumberFormatException("No value for
>parameter
>> > >>>> named '" + name + "'.");
>> > >>>>
>> > >>>>  I would expect an IllegalArgumentException, if no parameter
>of that
>> > >>> name
>> > >>> is found
>> > >>>
>> > >>>  +        }
>> > >>>> +
>> > >>>> +        return Integer.decode(params.get(name)).intValue();
>> > >>>> +    }
>> > >>>> +
>> > >>>> +    /**
>> > >>>> +     * Get the value of a specified parameter as an integer,
>or
>> return
>> > >>>> the
>> > >>>> +     * specified default value if the value was not specified
>or
>> is not
>> > >>>> an
>> > >>>> +     * integer. A warning will be logged if the value is not
>an
>> > >>>> integer.
>> > >>>> The
>> > >>>> +     * value may be specified in decimal, hexadecimal, or
>octal, as
>> > >>>> defined by
>> > >>>> +     * Integer.decode().
>> > >>>> +     *
>> > >>>> +     * @param name
>> > >>>> +     *            the name of the parameter whose value
>should be
>> > >>>> retrieved
>> > >>>> +     * @param defaultValue
>> > >>>> +     *            the default value to return if the value of
>this
>> > >>>> parameter was
>> > >>>> +     *            not specified
>> > >>>> +     * @return the value of the parameter, or the default
>value if
>> the
>> > >>>> parameter
>> > >>>> +     *         was not specified
>> > >>>> +     *
>> > >>>> +     * @see java.lang.Integer#decode(java.lang.String)
>> > >>>> +     */
>> > >>>> +    public int getIntParameter(String name, int defaultValue)
>{
>> > >>>> +        if (params == null || !params.containsKey(name)) {
>> > >>>> +            return defaultValue;
>> > >>>> +        }
>> > >>>> +
>> > >>>> +        try {
>> > >>>> +            return
>Integer.decode(params.get(name)).intValue();
>> > >>>> +        } catch (NumberFormatException e) {
>> > >>>> +            log.warn("Value for parameter '" + name + "' not
>an
>> > >>>> integer:
>> > >>>> '" + params.get(name) + "'.  Using default: '"
>> > >>>> +                    + defaultValue + "'.", e);
>> > >>>> +            return defaultValue;
>> > >>>> +        }
>> > >>>> +    }
>> > >>>> +
>> > >>>> +    /**
>> > >>>> +     * Get the value of a specified parameter as a long. An
>> exception
>> > >>>> will be
>> > >>>> +     * thrown if the parameter is not specified or if it is
>not a
>> long.
>> > >>>> The
>> > >>>> +     * value may be specified in decimal, hexadecimal, or
>octal, as
>> > >>>> defined by
>> > >>>> +     * Long.decode().
>> > >>>> +     *
>> > >>>> +     * @param name
>> > >>>> +     *            the name of the parameter whose value
>should be
>> > >>>> retrieved
>> > >>>> +     * @return the value of the parameter
>> > >>>> +     *
>> > >>>> +     * @throws NumberFormatException
>> > >>>> +     *             if the parameter is not specified or is
>not a
>> long
>> > >>>> +     *
>> > >>>> +     * @see Long#decode(String)
>> > >>>> +     */
>> > >>>> +    public long getLongParameter(String name) throws
>> > >>>> NumberFormatException {
>> > >>>> +        if (params == null || !params.containsKey(name)) {
>> > >>>> +            throw new NumberFormatException("No value for
>parameter
>> > >>>> named '" + name + "'.");
>> > >>>> +        }
>> > >>>> +
>> > >>>> +        return Long.decode(params.get(name)).longValue();
>> > >>>> +    }
>> > >>>> +
>> > >>>> +    /**
>> > >>>> +     * Get the value of a specified parameter as along, or
>return
>> the
>> > >>>> specified
>> > >>>> +     * default value if the value was not specified or is not
>a
>> long. A
>> > >>>> warning
>> > >>>> +     * will be logged if the value is not a long. The value
>may be
>> > >>>> specified in
>> > >>>> +     * decimal, hexadecimal, or octal, as defined by
>Long.decode().
>> > >>>> +     *
>> > >>>> +     * @param name
>> > >>>> +     *            the name of the parameter whose value
>should be
>> > >>>> retrieved
>> > >>>> +     * @param defaultValue
>> > >>>> +     *            the default value to return if the value of
>this
>> > >>>> parameter was
>> > >>>> +     *            not specified
>> > >>>> +     * @return the value of the parameter, or the default
>value if
>> the
>> > >>>> parameter
>> > >>>> +     *         was not specified
>> > >>>> +     *
>> > >>>> +     * @see Long#decode(String)
>> > >>>> +     */
>> > >>>> +    public long getLongParameter(String name, long
>defaultValue) {
>> > >>>> +        if (params == null || !params.containsKey(name)) {
>> > >>>> +            return defaultValue;
>> > >>>> +        }
>> > >>>> +        try {
>> > >>>> +            return Long.decode(params.get(name)).longValue();
>> > >>>> +        } catch (NumberFormatException e) {
>> > >>>> +            log.warn("Value for parameter '" + name + "' not
>a
>> long: '"
>> > >>>> + params.get(name) + "'.  Using default: '"
>> > >>>> +                    + defaultValue + "'.", e);
>> > >>>> +            return defaultValue;
>> > >>>> +        }
>> > >>>> +    }
>> > >>>> +
>> > >>>> +    /**
>> > >>>> +     *
>> > >>>> +     * @param name
>> > >>>> +     * @param defaultValue
>> > >>>> +     * @return
>> > >>>>
>> > >>>>  No javadoc? Again three warnings more :)
>> > >>>
>> > >>>  +     */
>> > >>>> +    public boolean getBooleanParameter(String name, boolean
>> > >>>> defaultValue) {
>> > >>>> +        if (params == null || !params.containsKey(name)) {
>> > >>>> +            return defaultValue;
>> > >>>> +        }
>> > >>>> +        return Boolean.valueOf(params.get(name));
>> > >>>> +    }
>> > >>>> +}
>> > >>>>
>> > >>>> Propchange:
>> jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>> > >>>> backend/BackendListenerContext.java
>> > >>>> ------------------------------------------------------------
>> > >>>> ------------------
>> > >>>>       svn:mime-type = text/plain
>> > >>>>
>> > >>>> Added:
>jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>> > >>>> backend/BackendListenerGui.java
>> > >>>> URL: http://svn.apache.org/viewvc/jmeter/trunk/src/components/
>> > >>>> org/apache/jmeter/visualizers/backend/BackendListenerGui.
>> > >>>> java?rev=1641081&view=auto
>> > >>>> ============================================================
>> > >>>> ==================
>> > >>>> --- jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>> > >>>> backend/BackendListenerGui.java (added)
>> > >>>> +++ jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>> > >>>> backend/BackendListenerGui.java Sat Nov 22 15:36:37 2014
>> > >>>> @@ -0,0 +1,282 @@
>> > >>>> +/*
>> > >>>> + * 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.jmeter.visualizers.backend;
>> > >>>> +
>> > >>>> +import java.awt.BorderLayout;
>> > >>>> +import java.awt.event.ActionEvent;
>> > >>>> +import java.awt.event.ActionListener;
>> > >>>> +import java.util.ArrayList;
>> > >>>> +import java.util.HashSet;
>> > >>>> +import java.util.List;
>> > >>>> +import java.util.Map;
>> > >>>> +import java.util.Set;
>> > >>>> +
>> > >>>> +import javax.swing.ComboBoxModel;
>> > >>>> +import javax.swing.JComboBox;
>> > >>>> +import javax.swing.JLabel;
>> > >>>> +import javax.swing.JPanel;
>> > >>>> +import javax.swing.JTextField;
>> > >>>> +
>> > >>>> +import org.apache.jmeter.config.Argument;
>> > >>>> +import org.apache.jmeter.config.Arguments;
>> > >>>> +import org.apache.jmeter.config.gui.ArgumentsPanel;
>> > >>>> +import org.apache.jmeter.gui.util.HorizontalPanel;
>> > >>>> +import org.apache.jmeter.testelement.TestElement;
>> > >>>> +import
>org.apache.jmeter.testelement.property.PropertyIterator;
>> > >>>> +import org.apache.jmeter.util.JMeterUtils;
>> > >>>> +import org.apache.jmeter.visualizers.gui.AbstractListenerGui;
>> > >>>> +import org.apache.jorphan.logging.LoggingManager;
>> > >>>> +import org.apache.jorphan.reflect.ClassFinder;
>> > >>>> +import org.apache.log.Logger;
>> > >>>> +
>> > >>>> +/**
>> > >>>> + * The <code>BackendListenerGui</code> class provides the
>user
>> > >>>> interface for the
>> > >>>> + * {@link BackendListener} object.
>> > >>>> + * @since 2.13
>> > >>>> + */
>> > >>>> +public class BackendListenerGui extends AbstractListenerGui
>> implements
>> > >>>> ActionListener {
>> > >>>> +
>> > >>>> +    /**
>> > >>>> +     *
>> > >>>> +     */
>> > >>>> +    private static final long serialVersionUID =
>> 4331668988576438604L;
>> > >>>> +
>> > >>>> +    /** Logging */
>> > >>>> +    private static final Logger log = LoggingManager.
>> > >>>> getLoggerForClass();
>> > >>>> +
>> > >>>> +    /** A combo box allowing the user to choose a backend
>class. */
>> > >>>> +    private JComboBox classnameCombo;
>> > >>>> +
>> > >>>> +    /**
>> > >>>> +     * A field allowing the user to specify the size of Queue
>> > >>>> +     */
>> > >>>> +    private JTextField queueSize;
>> > >>>> +
>> > >>>> +    /** A panel allowing the user to set arguments for this
>test.
>> */
>> > >>>> +    private ArgumentsPanel argsPanel;
>> > >>>> +
>> > >>>> +    /**
>> > >>>> +     * Create a new BackendListenerGui as a standalone
>component.
>> > >>>> +     */
>> > >>>> +    public BackendListenerGui() {
>> > >>>> +        super();
>> > >>>> +        init();
>> > >>>> +    }
>> > >>>> +
>> > >>>> +
>> > >>>> +    /** {@inheritDoc} */
>> > >>>> +    @Override
>> > >>>> +    public String getLabelResource() {
>> > >>>> +        return "backend_listener"; // $NON-NLS-1$
>> > >>>> +    }
>> > >>>> +
>> > >>>> +    /**
>> > >>>> +     * Initialize the GUI components and layout.
>> > >>>> +     */
>> > >>>> +    private void init() {// called from ctor, so must not be
>> > >>>> overridable
>> > >>>> +        setLayout(new BorderLayout(0, 5));
>> > >>>> +
>> > >>>> +        setBorder(makeBorder());
>> > >>>> +        add(makeTitlePanel(), BorderLayout.NORTH);
>> > >>>> +
>> > >>>> +        JPanel classnameRequestPanel = new JPanel(new
>> BorderLayout(0,
>> > >>>> 5));
>> > >>>> +        classnameRequestPanel.add(createClassnamePanel(),
>> > >>>> BorderLayout.NORTH);
>> > >>>> +        classnameRequestPanel.add(createParameterPanel(),
>> > >>>> BorderLayout.CENTER);
>> > >>>> +
>> > >>>> +        add(classnameRequestPanel, BorderLayout.CENTER);
>> > >>>> +    }
>> > >>>> +
>> > >>>> +    /**
>> > >>>> +     * Create a panel with GUI components allowing the user
>to
>> select a
>> > >>>> test
>> > >>>> +     * class.
>> > >>>> +     *
>> > >>>> +     * @return a panel containing the relevant components
>> > >>>> +     */
>> > >>>> +    private JPanel createClassnamePanel() {
>> > >>>> +        List<String> possibleClasses = new
>ArrayList<String>();
>> > >>>> +
>> > >>>> +        try {
>> > >>>> +            // Find all the classes which implement the
>> > >>>> BackendListenerClient
>> > >>>> +            // interface.
>> > >>>> +            possibleClasses =
>ClassFinder.findClassesThatExtend(
>> > >>>> JMeterUtils.getSearchPaths(),
>> > >>>> +                    new Class[] { BackendListenerClient.class
>});
>> > >>>> +
>> > >>>> +            // Remove the BackendListener class from the list
>> since it
>> > >>>> only
>> > >>>>
>> > >>>>  ErrorBackendListener
>> > >>>
>> > >>>  +            // implements the interface for error conditions.
>> > >>>> +
>> > >>>> +           
>possibleClasses.remove(BackendListener.class.getName()
>> +
>> > >>>> "$ErrorBackendListenerClient");
>> > >>>> +        } catch (Exception e) {
>> > >>>> +            log.debug("Exception getting interfaces.", e);
>> > >>>> +        }
>> > >>>> +
>> > >>>> +        JLabel label = new
>> JLabel(JMeterUtils.getResString("backend_
>> > >>>> listener_classname"));
>> > >>>> // $NON-NLS-1$
>> > >>>> +
>> > >>>> +        classnameCombo = new
>JComboBox(possibleClasses.toArray());
>> > >>>> +        classnameCombo.addActionListener(this);
>> > >>>> +        classnameCombo.setEditable(false);
>> > >>>> +        label.setLabelFor(classnameCombo);
>> > >>>> +
>> > >>>> +        HorizontalPanel classNamePanel = new
>HorizontalPanel();
>> > >>>> +        classNamePanel.add(label);
>> > >>>> +        classNamePanel.add(classnameCombo);
>> > >>>> +
>> > >>>> +        queueSize = new JTextField("", 5);
>> > >>>> +        queueSize.setName("Queue Size"); //$NON-NLS-1$
>> > >>>> +        JLabel queueSizeLabel = new JLabel(JMeterUtils.
>> > >>>> getResString("backend_listener_queue_size")); // $NON-NLS-1$
>> > >>>> +        queueSizeLabel.setLabelFor(queueSize);
>> > >>>> +        HorizontalPanel queueSizePanel = new
>HorizontalPanel();
>> > >>>> +        queueSizePanel.add(queueSizeLabel,
>BorderLayout.WEST);
>> > >>>> +        queueSizePanel.add(queueSize);
>> > >>>> +
>> > >>>> +        JPanel panel = new JPanel(new BorderLayout(0, 5));
>> > >>>> +        panel.add(classNamePanel, BorderLayout.NORTH);
>> > >>>> +        panel.add(queueSizePanel, BorderLayout.CENTER);
>> > >>>> +        return panel;
>> > >>>> +    }
>> > >>>> +
>> > >>>> +    /**
>> > >>>> +     * Handle action events for this component. This method
>> currently
>> > >>>> handles
>> > >>>> +     * events for the classname combo box.
>> > >>>> +     *
>> > >>>> +     * @param evt
>> > >>>>
>> > >>>>  I would spend the few extra characters to make it event
>instead of
>> evt
>> > >>>
>> > >>>  +     *            the ActionEvent to be handled
>> > >>>> +     */
>> > >>>> +    @Override
>> > >>>> +    public void actionPerformed(ActionEvent evt) {
>> > >>>> +        if (evt.getSource() == classnameCombo) {
>> > >>>> +            String className = ((String) classnameCombo.
>> > >>>> getSelectedItem()).trim();
>> > >>>> +            try {
>> > >>>> +                BackendListenerClient client =
>> (BackendListenerClient)
>> > >>>> Class.forName(className, true,
>> > >>>> +                        Thread.currentThread().
>> > >>>> getContextClassLoader()).
>> > >>>> newInstance();
>> > >>>> +
>> > >>>> +                Arguments currArgs = new Arguments();
>> > >>>> +                argsPanel.modifyTestElement(currArgs);
>> > >>>> +                Map<String, String> currArgsMap =
>> > >>>> currArgs.getArgumentsAsMap();
>> > >>>> +
>> > >>>> +                Arguments newArgs = new Arguments();
>> > >>>> +                Arguments testParams = null;
>> > >>>> +                try {
>> > >>>> +                    testParams =
>client.getDefaultParameters();
>> > >>>> +                } catch (AbstractMethodError e) {
>> > >>>> +                    log.warn("BackendListenerClient doesn't
>> implement
>> > >>>> "
>> > >>>> +                            + "getDefaultParameters.  Default
>> > >>>> parameters
>> > >>>> won't "
>> > >>>> +                            + "be shown.  Please update your
>client
>> > >>>> class: " + className);
>> > >>>> +                }
>> > >>>> +
>> > >>>> +                if (testParams != null) {
>> > >>>> +                    PropertyIterator i =
>testParams.getArguments().
>> > >>>> iterator();
>> > >>>>
>> > >>>>  I would try a for loop instead of explicitly using an
>iterator
>> > >>>
>> > >>>  +                    while (i.hasNext()) {
>> > >>>> +                        Argument arg = (Argument)
>> > >>>> i.next().getObjectValue();
>> > >>>> +                        String name = arg.getName();
>> > >>>> +                        String value = arg.getValue();
>> > >>>> +
>> > >>>> +                        // If a user has set parameters in
>one
>> test,
>> > >>>> and
>> > >>>> then
>> > >>>> +                        // selects a different test which
>supports
>> the
>> > >>>> same
>> > >>>> +                        // parameters, those parameters
>should
>> have the
>> > >>>> same
>> > >>>> +                        // values that they did in the
>original
>> test.
>> > >>>> +                        if (currArgsMap.containsKey(name)) {
>> > >>>> +                            String newVal =
>currArgsMap.get(name);
>> > >>>> +                            if (newVal != null &&
>newVal.length()
>> > 0)
>> > >>>> {
>> > >>>> +                                value = newVal;
>> > >>>> +                            }
>> > >>>> +                        }
>> > >>>> +                        newArgs.addArgument(name, value);
>> > >>>> +                    }
>> > >>>> +                }
>> > >>>> +
>> > >>>> +                argsPanel.configure(newArgs);
>> > >>>> +            } catch (Exception e) {
>> > >>>> +                log.error("Error getting argument list for "
>+
>> > >>>> className, e);
>> > >>>> +            }
>> > >>>> +        }
>> > >>>> +    }
>> > >>>> +
>> > >>>> +    /**
>> > >>>> +     * Create a panel containing components allowing the user
>to
>> > >>>> provide
>> > >>>> +     * arguments to be passed to the test class instance.
>> > >>>> +     *
>> > >>>> +     * @return a panel containing the relevant components
>> > >>>> +     */
>> > >>>> +    private JPanel createParameterPanel() {
>> > >>>> +        argsPanel = new ArgumentsPanel(JMeterUtils.
>> > >>>> getResString("backend_listener_paramtable")); // $NON-NLS-1$
>> > >>>> +        return argsPanel;
>> > >>>> +    }
>> > >>>> +
>> > >>>> +    /** {@inheritDoc} */
>> > >>>> +    @Override
>> > >>>> +    public void configure(TestElement config) {
>> > >>>> +        super.configure(config);
>> > >>>> +
>> > >>>> +        argsPanel.configure((Arguments) config.getProperty(
>> > >>>> BackendListener.ARGUMENTS).getObjectValue());
>> > >>>> +
>> > >>>> +        String className = config.getPropertyAsString(
>> > >>>> BackendListener.CLASSNAME);
>> > >>>> +        if(checkContainsClassName(classnameCombo.getModel(),
>> > >>>> className)) {
>> > >>>> +            classnameCombo.setSelectedItem(className);
>> > >>>> +        } else {
>> > >>>> +            log.error("Error setting class:'"+className+"' in
>> > >>>> BackendListener: "+getName()+
>> > >>>> +                    ", check for a missing jar in your jmeter
>> > >>>> 'search_paths' and 'plugin_dependency_paths' properties");
>> > >>>> +        }
>> > >>>> +        queueSize.setText(Integer.toString(((BackendListener)
>> > >>>> config).getQueueSize()));
>> > >>>> +    }
>> > >>>> +
>> > >>>> +    /**
>> > >>>> +     * Check combo contains className
>> > >>>> +     * @param model ComboBoxModel
>> > >>>> +     * @param className String class name
>> > >>>> +     * @return boolean
>> > >>>>
>> > >>>>  explain "boolean" or the other params a bit more?
>> > >>>
>> > >>>  +     */
>> > >>>> +    private static final boolean
>> checkContainsClassName(ComboBoxModel
>> > >>>> model, String className) {
>> > >>>> +        int size = model.getSize();
>> > >>>> +        Set<String> set = new HashSet<String>(size);
>> > >>>> +        for (int i = 0; i < size; i++) {
>> > >>>> +            set.add((String)model.getElementAt(i));
>> > >>>> +        }
>> > >>>> +        return set.contains(className);
>> > >>>> +    }
>> > >>>> +
>> > >>>> +    /** {@inheritDoc} */
>> > >>>> +    @Override
>> > >>>> +    public TestElement createTestElement() {
>> > >>>> +        BackendListener config = new BackendListener();
>> > >>>> +        modifyTestElement(config);
>> > >>>> +        return config;
>> > >>>> +    }
>> > >>>> +
>> > >>>> +    /** {@inheritDoc} */
>> > >>>> +    @Override
>> > >>>> +    public void modifyTestElement(TestElement config) {
>> > >>>> +        configureTestElement(config);
>> > >>>> +        BackendListener backendListener = (BackendListener)
>config;
>> > >>>> +        backendListener.setArguments((Arguments)
>> > >>>> argsPanel.createTestElement());
>> > >>>> +       
>backendListener.setClassname(String.valueOf(classnameCombo.
>> > >>>> getSelectedItem()));
>> > >>>> +       
>backendListener.setQueueSize(Integer.parseInt(queueSize.
>> > >>>> getText()));
>> > >>>> +
>> > >>>> +    }
>> > >>>> +
>> > >>>>
>> > >>>
>> >
>>
>>
>>


Re: svn commit: r1641081 - in /jmeter/trunk: ./ bin/ res/maven/ src/components/org/apache/jmeter/visualizers/backend/ src/core/org/apache/jmeter/resources/ src/core/org/apache/jmeter/samplers/ src/core/org/apache/jmeter/save/ xdocs/ xdocs/usermanual/

Posted by Philippe Mouawad <ph...@gmail.com>.
Hi Felix

My answer inline.
Regards

On Sat, Nov 29, 2014 at 11:51 AM, Felix Schumacher <
felix.schumacher@internetallee.de> wrote:

> Hello Philippe,
>
> Am Sonntag, den 23.11.2014, 12:22 +0100 schrieb Philippe Mouawad:
> > Thanks a lot for your review which pointed to a synchronisation issue
> that
> > I fixed, good catch!
> >
> > I think I took all your notes into account, let me know if I forgot
> > something.
> in SamplerMetric you have used a sliding window for the statistics.
> * Should we make the length of the window configurable?
>

Yes but it's a new property and we have a lot :-)


> * Should min/max and minThreads/maxThreads be limited to the sliding
> window, also? At least min and max would be simple to do.
>

Dev team opinion is welcome, maybe it would be better
- min would be percentile(0)
- max would be percentile(100)
for minThreads, maxThreads, how would you do it ?


> Regards
>  Felix
> >
> > Regards
> > Philippe
> >
> > On Sunday, November 23, 2014, Felix Schumacher <
> > felix.schumacher@internetallee.de> wrote:
> >
> > > Hi Phillipe,
> > > Am 22.11.2014 um 19:29 schrieb Philippe Mouawad:
> > >
> > >> Hi Felix,
> > >> As I said in thread, I commited code and will improve, feel free to
> fix
> > >> javadocs issues on your side.
> > >> I will review your comment.
> > >>
> > >> I have spent many hours if not days on this code and I am aware it is
> not
> > >> yet fully completed (although tests are promising) but my aim when
> > >> commiting it was to have feedback and help to finish it.
> > >>
> > > I did not mean to offend you. I can clearly see, that you put a lot of
> > > effort
> > > in this listener and I will surely try to integrate jmeter into our
> > > collectd server.
> > >
> > > Regards
> > >  Felix
> > >
> > >>
> > >> Regards
> > >> Philippe
> > >>
> > >> On Sat, Nov 22, 2014 at 7:21 PM, Felix Schumacher <
> > >> felix.schumacher@internetallee.de> wrote:
> > >>
> > >>  Hello Philippe,
> > >>>
> > >>> I have hidden a few comments inside the cited code.
> > >>> They are mostly around javadoc and naming things.
> > >>>
> > >>> Am 22.11.2014 um 16:36 schrieb pmouawad@apache.org:
> > >>>
> > >>>  Author: pmouawad
> > >>>> Date: Sat Nov 22 15:36:37 2014
> > >>>> New Revision: 1641081
> > >>>>
> > >>>> URL: http://svn.apache.org/r1641081
> > >>>> Log:
> > >>>> Bug 55932 - Create a Async BackendListener to allow easy plug of new
> > >>>> listener (Graphite, JDBC, Console,...)
> > >>>> Bugzilla Id: 55932
> > >>>>
> > >>>> Added:
> > >>>>       jmeter/trunk/src/components/org/apache/jmeter/visualizers/
> > >>>> backend/
> > >>>>       jmeter/trunk/src/components/org/apache/jmeter/visualizers/
> > >>>> backend/
> > >>>> AbstractBackendListenerClient.java   (with props)
> > >>>>       jmeter/trunk/src/components/org/apache/jmeter/visualizers/
> > >>>> backend/BackendListener.java
> > >>>>   (with props)
> > >>>>       jmeter/trunk/src/components/org/apache/jmeter/visualizers/
> > >>>> backend/BackendListenerClient.java   (with props)
> > >>>>       jmeter/trunk/src/components/org/apache/jmeter/visualizers/
> > >>>> backend/BackendListenerContext.java
> > >>>>   (with props)
> > >>>>       jmeter/trunk/src/components/org/apache/jmeter/visualizers/
> > >>>> backend/BackendListenerGui.java   (with props)
> > >>>>       jmeter/trunk/src/components/org/apache/jmeter/visualizers/
> > >>>> backend/SamplerMetric.java
> > >>>>   (with props)
> > >>>> Modified:
> > >>>>       jmeter/trunk/bin/saveservice.properties
> > >>>>       jmeter/trunk/build.properties
> > >>>>       jmeter/trunk/build.xml
> > >>>>       jmeter/trunk/eclipse.classpath
> > >>>>       jmeter/trunk/res/maven/ApacheJMeter_parent.pom
> > >>>>       jmeter/trunk/src/core/org/apache/jmeter/resources/
> > >>>> messages.properties
> > >>>>       jmeter/trunk/src/core/org/apache/jmeter/resources/
> > >>>> messages_fr.properties
> > >>>>       jmeter/trunk/src/core/org/apache/jmeter/samplers/
> > >>>> SampleResult.java
> > >>>>       jmeter/trunk/src/core/org/apache/jmeter/save/SaveService.java
> > >>>>       jmeter/trunk/xdocs/changes.xml
> > >>>>       jmeter/trunk/xdocs/usermanual/component_reference.xml
> > >>>>
> > >>>> Modified: jmeter/trunk/bin/saveservice.properties
> > >>>> URL: http://svn.apache.org/viewvc/jmeter/trunk/bin/saveservice.
> > >>>> properties?rev=1641081&r1=1641080&r2=1641081&view=diff
> > >>>> ============================================================
> > >>>> ==================
> > >>>> --- jmeter/trunk/bin/saveservice.properties (original)
> > >>>> +++ jmeter/trunk/bin/saveservice.properties Sat Nov 22 15:36:37 2014
> > >>>> @@ -53,7 +53,8 @@ _file_version=$Revision$
> > >>>>    # 2.5 = 2.10
> > >>>>    # 2.6 = 2.11
> > >>>>    # 2.7 = 2.12
> > >>>> -_version=2.7
> > >>>> +# 2.8 = 2.13
> > >>>> +_version=2.8
> > >>>>    #
> > >>>>    #
> > >>>>    # Character set encoding used to read and write JMeter XML files
> and
> > >>>> CSV results
> > >>>> @@ -78,6 +79,8 @@ AssertionVisualizer=org.apache.jmeter.vi
> > >>>>    AuthManager=org.apache.jmeter.protocol.http.control.AuthManager
> > >>>>
> Authorization=org.apache.jmeter.protocol.http.control.Authorization
> > >>>>    AuthPanel=org.apache.jmeter.protocol.http.gui.AuthPanel
> > >>>>
> +BackendListener=org.apache.jmeter.visualizers.backend.BackendListener
> > >>>> +BackendListenerGui=org.apache.jmeter.visualizers.
> > >>>> backend.BackendListenerGui
> > >>>>    BarChart=org.apache.jmeter.testelement.BarChart
> > >>>>    BarChartGui=org.apache.jmeter.report.gui.BarChartGui
> > >>>>
> BeanShellAssertion=org.apache.jmeter.assertions.BeanShellAssertion
> > >>>>
> > >>>> Modified: jmeter/trunk/build.properties
> > >>>> URL: http://svn.apache.org/viewvc/jmeter/trunk/build.properties?
> > >>>> rev=1641081&r1=1641080&r2=1641081&view=diff
> > >>>> ============================================================
> > >>>> ==================
> > >>>> --- jmeter/trunk/build.properties (original)
> > >>>> +++ jmeter/trunk/build.properties Sat Nov 22 15:36:37 2014
> > >>>> @@ -118,11 +118,21 @@ commons-logging.loc         = ${maven2.r
> > >>>>    #commons-logging.md5         = E2C390FE739B2550A218262B28F290CE
> > >>>>    commons-logging.md5         = 040b4b4d8eac886f6b4a2a3bd2f31b00
> > >>>>    +commons-math3.version         = 3.3
> > >>>> +commons-math3.jar             = commons-math3-${commons-math3.
> > >>>> version}.jar
> > >>>> +commons-math3.loc             = ${maven2.repo}/org/apache/
> > >>>> commons/commons-math3/${commons-math3.version}
> > >>>> +commons-math3.md5             = 87346cf2772dc2becf106c45e0f63863
> > >>>> +
> > >>>>    commons-net.version         = 3.3
> > >>>>    commons-net.jar             =
> commons-net-${commons-net.version}.jar
> > >>>>    commons-net.loc             = ${maven2.repo}/commons-net/
> > >>>> commons-net/${commons-net.version}
> > >>>>    commons-net.md5             = c077ca61598e9c21f43f8b6488fbbee9
> > >>>>    +commons-pool2.version         = 2.2
> > >>>> +commons-pool2.jar             = commons-pool2-${commons-pool2.
> > >>>> version}.jar
> > >>>> +commons-pool2.loc             = ${maven2.repo}/org/apache/
> > >>>> commons/commons-pool2/${commons-pool2.version}
> > >>>> +commons-pool2.md5             = 51b56c92883812c56fbeb339866ce2df
> > >>>> +
> > >>>>    # dnsjava for DNSCacheManager
> > >>>>    dnsjava.version             = 2.1.6
> > >>>>    dnsjava.jar                 = dnsjava-${dnsjava.version}.jar
> > >>>>
> > >>>> Modified: jmeter/trunk/build.xml
> > >>>> URL: http://svn.apache.org/viewvc/jmeter/trunk/build.xml?rev=
> > >>>> 1641081&r1=1641080&r2=1641081&view=diff
> > >>>> ============================================================
> > >>>> ==================
> > >>>> --- jmeter/trunk/build.xml (original)
> > >>>> +++ jmeter/trunk/build.xml Sat Nov 22 15:36:37 2014
> > >>>> @@ -365,7 +365,9 @@
> > >>>>        <include name="${lib.dir}/${commons-jexl2.jar}"/>
> > >>>>        <include name="${lib.dir}/${commons-lang3.jar}"/>
> > >>>>        <include name="${lib.dir}/${commons-logging.jar}"/>
> > >>>> +    <include name="${lib.dir}/${commons-math3}"/>
> > >>>>        <include name="${lib.dir}/${commons-net.jar}"/>
> > >>>> +    <include name="${lib.dir}/${commons-pool2.jar}"/>
> > >>>>        <include name="${lib.dir}/${dnsjava.jar}"/>
> > >>>>        <include name="${lib.dir}/${excalibur-datasource.jar}"/>
> > >>>>        <include name="${lib.dir}/${excalibur-instrument.jar}"/>
> > >>>> @@ -438,8 +440,10 @@
> > >>>>        <pathelement location="${lib.dir}/${commons-jexl2.jar}"/>
> > >>>>        <pathelement location="${lib.dir}/${commons-lang3.jar}"/>
> > >>>>        <pathelement location="${lib.dir}/${commons-logging.jar}"/>
> > >>>> +    <pathelement location="${lib.dir}/${commons-math3.jar}"/>
> > >>>>        <pathelement location="${lib.dir}/${commons-net.jar}"/>
> > >>>> -    <pathelement location="${lib.dir}/${dnsjava.jar}"/>
> > >>>> +       <pathelement location="${lib.dir}/${commons-pool2.jar}"/>
> > >>>> +       <pathelement location="${lib.dir}/${dnsjava.jar}"/>
> > >>>>        <pathelement
> location="${lib.dir}/${excalibur-datasource.jar}"/>
> > >>>>        <pathelement
> location="${lib.dir}/${excalibur-instrument.jar}"/>
> > >>>>        <pathelement location="${lib.dir}/${excalibur-logger.jar}"/>
> > >>>> @@ -2909,7 +2913,9 @@ run JMeter unless all the JMeter jars ar
> > >>>>            <process_jarfile jarname="commons-jexl2"/>
> > >>>>            <process_jarfile jarname="commons-lang3"/>
> > >>>>            <process_jarfile jarname="commons-logging"/>
> > >>>> +        <process_jarfile jarname="commons-math3"/>
> > >>>>            <process_jarfile jarname="commons-net"/>
> > >>>> +       <process_jarfile jarname="commons-pool2"/>
> > >>>>            <process_jarfile jarname="dnsjava"/>
> > >>>>            <process_jarfile jarname="excalibur-datasource"/>
> > >>>>            <process_jarfile jarname="excalibur-instrument"/>
> > >>>>
> > >>>> Modified: jmeter/trunk/eclipse.classpath
> > >>>> URL: http://svn.apache.org/viewvc/jmeter/trunk/eclipse.
> > >>>> classpath?rev=1641081&r1=1641080&r2=1641081&view=diff
> > >>>> ============================================================
> > >>>> ==================
> > >>>> --- jmeter/trunk/eclipse.classpath (original)
> > >>>> +++ jmeter/trunk/eclipse.classpath Sat Nov 22 15:36:37 2014
> > >>>> @@ -55,7 +55,9 @@
> > >>>>          <classpathentry kind="lib"
> path="lib/commons-jexl-2.1.1.jar"/>
> > >>>>          <classpathentry kind="lib" path="lib/commons-lang3-3.3.2.
> > >>>> jar"/>
> > >>>>          <classpathentry kind="lib" path="lib/commons-logging-1.2.
> > >>>> jar"/>
> > >>>> +    <classpathentry kind="lib" path="lib/commons-math3-3.3.jar"/>
> > >>>>          <classpathentry kind="lib" path="lib/commons-net-3.3.jar"/>
> > >>>> +    <classpathentry kind="lib" path="lib/commons-pool2-2.2.jar"/>
> > >>>>          <classpathentry kind="lib" path="lib/dnsjava-2.1.6.jar"/>
> > >>>>          <classpathentry kind="lib" path="lib/excalibur-
> > >>>> datasource-2.1.jar"/>
> > >>>>          <classpathentry kind="lib" path="lib/excalibur-
> > >>>> instrument-1.0.jar"/>
> > >>>>
> > >>>> Modified: jmeter/trunk/res/maven/ApacheJMeter_parent.pom
> > >>>> URL: http://svn.apache.org/viewvc/jmeter/trunk/res/maven/
> > >>>> ApacheJMeter_parent.pom?rev=1641081&r1=1641080&r2=1641081&view=diff
> > >>>> ============================================================
> > >>>> ==================
> > >>>> --- jmeter/trunk/res/maven/ApacheJMeter_parent.pom (original)
> > >>>> +++ jmeter/trunk/res/maven/ApacheJMeter_parent.pom Sat Nov 22
> 15:36:37
> > >>>> 2014
> > >>>> @@ -66,7 +66,9 @@ under the License.
> > >>>>          <commons-jexl2.version>2.1.1</commons-jexl2.version>
> > >>>>          <commons-lang3.version>3.3.2</commons-lang3.version>
> > >>>>          <commons-logging.version>1.2</commons-logging.version>
> > >>>> +      <commons-math3.version>3.3</commons-math3.version>
> > >>>>          <commons-net.version>3.3</commons-net.version>
> > >>>> +      <commons-pool2.version>2.2</commons-pool2.version>
> > >>>>          <dnsjava.version>2.1.6</dnsjava.version>
> > >>>>          <excalibur-datasource.version>2.1</excalibur-datasource.
> > >>>> version>
> > >>>>          <excalibur-instrument.version>1.0</excalibur-instrument.
> > >>>> version>
> > >>>> @@ -181,11 +183,21 @@ under the License.
> > >>>>            <version>${commons-logging.version}</version>
> > >>>>          </dependency>
> > >>>>          <dependency>
> > >>>> +        <groupId>commons-math3</groupId>
> > >>>> +        <artifactId>commons-math3</artifactId>
> > >>>> +        <version>${commons-math3.version}</version>
> > >>>> +      </dependency>
> > >>>> +      <dependency>
> > >>>>            <groupId>commons-net</groupId>
> > >>>>            <artifactId>commons-net</artifactId>
> > >>>>            <version>${commons-net.version}</version>
> > >>>>          </dependency>
> > >>>>          <dependency>
> > >>>> +        <groupId>commons-pool2</groupId>
> > >>>> +        <artifactId>commons-pool2</artifactId>
> > >>>> +        <version>${commons-pool2.version}</version>
> > >>>> +      </dependency>
> > >>>> +      <dependency>
> > >>>>              <groupId>dnsjava</groupId>
> > >>>>              <artifactId>dnsjava</artifactId>
> > >>>>              <version>${dnsjava.version}</version>
> > >>>>
> > >>>> Added: jmeter/trunk/src/components/org/apache/jmeter/visualizers/
> > >>>> backend/
> > >>>> AbstractBackendListenerClient.java
> > >>>> URL: http://svn.apache.org/viewvc/jmeter/trunk/src/components/
> > >>>> org/apache/jmeter/visualizers/backend/AbstractBackendListenerClient.
> > >>>> java?rev=1641081&view=auto
> > >>>> ============================================================
> > >>>> ==================
> > >>>> ---
> jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/
> > >>>> AbstractBackendListenerClient.java (added)
> > >>>> +++
> jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/
> > >>>> AbstractBackendListenerClient.java Sat Nov 22 15:36:37 2014
> > >>>> @@ -0,0 +1,121 @@
> > >>>> +/*
> > >>>> + * 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.jmeter.visualizers.backend;
> > >>>> +
> > >>>> +import java.util.Map;
> > >>>> +import java.util.concurrent.ConcurrentHashMap;
> > >>>> +
> > >>>> +import org.apache.jmeter.config.Arguments;
> > >>>> +import org.apache.jmeter.samplers.SampleResult;
> > >>>> +import org.apache.jorphan.logging.LoggingManager;
> > >>>> +import org.apache.log.Logger;
> > >>>> +
> > >>>> +/**
> > >>>> + * An abstract implementation of the BackendListenerClient
> interface.
> > >>>> This
> > >>>> + * implementation provides default implementations of most of the
> > >>>> methods in the
> > >>>> + * interface, as well as some convenience methods, in order to
> simplify
> > >>>> + * development of BackendListenerClient implementations.
> > >>>> + *
> > >>>> + * While it may be necessary to make changes to the
> > >>>> BackendListenerClient interface
> > >>>> + * from time to time (therefore requiring changes to any
> > >>>> implementations
> > >>>> of this
> > >>>> + * interface), we intend to make this abstract class provide
> reasonable
> > >>>> + * implementations of any new methods so that subclasses do not
> > >>>> necessarily need
> > >>>> + * to be updated for new versions. Therefore, when creating a new
> > >>>> + * BackendListenerClient implementation, developers are encouraged
> to
> > >>>> subclass this
> > >>>> + * abstract class rather than implementing the
> BackendListenerClient
> > >>>> interface
> > >>>> + * directly. Implementing BackendListenerClient directly will
> continue
> > >>>> to be
> > >>>> + * supported for cases where extending this class is not possible
> (for
> > >>>> example,
> > >>>> + * when the client class is already a subclass of some other
> class).
> > >>>> + * <p>
> > >>>> + * The handleSampleResult() method of BackendListenerClient does
> not
> > >>>> have a default
> > >>>> + * implementation here, so subclasses must define at least this
> method.
> > >>>> It may
> > >>>> + * be useful to override other methods as well.
> > >>>> + *
> > >>>> + * @see BackendListener#sampleOccurred(org.apache.
> > >>>> jmeter.samplers.SampleEvent)
> > >>>> + * @since 2.13
> > >>>> + */
> > >>>> +public abstract class AbstractBackendListenerClient implements
> > >>>> BackendListenerClient {
> > >>>> +
> > >>>> +    private static final Logger log = LoggingManager.
> > >>>> getLoggerForClass();
> > >>>>
> > >>>>  In classes further down the logger is stored in variables named
> LOG and
> > >>> LOGGER, should we use one name?
> > >>> In this class we have a getter for the logger in other classes not.
> Why?
> > >>>
> > >>>  +
> > >>>> +    private ConcurrentHashMap<String, SamplerMetric>
> metricsPerSampler
> > >>>> =
> > >>>> new ConcurrentHashMap<String, SamplerMetric>();
> > >>>> +
> > >>>> +    /* Implements
> BackendListenerClient.setupTest(JavaSamplerContext)
> > >>>> */
> > >>>> +    @Override
> > >>>> +    public void setupTest(BackendListenerContext context) throws
> > >>>> Exception {
> > >>>> +        log.debug(getClass().getName() + ": setupTest");
> > >>>> +    }
> > >>>> +
> > >>>> +    /* Implements BackendListenerClient.teardownTest(
> > >>>> JavaSamplerContext)
> > >>>> */
> > >>>> +    @Override
> > >>>> +    public void teardownTest(BackendListenerContext context) throws
> > >>>> Exception {
> > >>>> +        log.debug(getClass().getName() + ": teardownTest");
> > >>>> +        metricsPerSampler.clear();
> > >>>> +    }
> > >>>> +
> > >>>> +    /* Implements BackendListenerClient.getDefaultParameters() */
> > >>>> +    @Override
> > >>>> +    public Arguments getDefaultParameters() {
> > >>>> +        return null;
> > >>>> +    }
> > >>>> +
> > >>>> +    /**
> > >>>> +     * Get a Logger instance which can be used by subclasses to log
> > >>>> information.
> > >>>> +     *
> > >>>> +     * @return a Logger instance which can be used for logging
> > >>>> +     */
> > >>>> +    protected Logger getLogger() {
> > >>>> +        return log;
> > >>>> +    }
> > >>>> +
> > >>>> +    /* (non-Javadoc)
> > >>>> +     * @see org.apache.jmeter.visualizers.
> > >>>> backend.BackendListenerClient#
> > >>>> createSampleResult(org.apache.jmeter.samplers.SampleResult)
> > >>>> +     */
> > >>>> +    @Override
> > >>>> +    public SampleResult createSampleResult(BackendListenerContext
> > >>>> context, SampleResult result) {
> > >>>> +        SampleResult sampleResult = (SampleResult) result.clone();
> > >>>> +        return sampleResult;
> > >>>> +    }
> > >>>> +
> > >>>> +    /**
> > >>>> +     *
> > >>>> +     * @param sampleLabel
> > >>>> +     * @return SamplerMetric
> > >>>>
> > >>>>  No description of the method and the parameters?
> > >>>
> > >>>  +     */
> > >>>> +    protected SamplerMetric getSamplerMetric(String sampleLabel) {
> > >>>> +        SamplerMetric samplerMetric = metricsPerSampler.get(
> > >>>> sampleLabel);
> > >>>> +        if(samplerMetric == null) {
> > >>>> +            samplerMetric = new SamplerMetric();
> > >>>> +            SamplerMetric oldValue = metricsPerSampler.putIfAbsent(
> > >>>> sampleLabel,
> > >>>> samplerMetric);
> > >>>> +            if(oldValue != null ){
> > >>>> +                samplerMetric = oldValue;
> > >>>> +            }
> > >>>> +        }
> > >>>> +        return samplerMetric;
> > >>>> +    }
> > >>>> +
> > >>>> +    /**
> > >>>> +     *
> > >>>> +     * @return Map<String, SamplerMetric>
> > >>>>
> > >>>>  No description of the method and usage of forbidden characters :)
> there
> > >>> are still more than 800 warnings in the javadoc to prune, so don't
> > >>> introduce new ones, please.
> > >>>
> > >>>  +     */
> > >>>> +    protected Map<String, SamplerMetric> getMetricsPerSampler() {
> > >>>> +        return metricsPerSampler;
> > >>>> +    }
> > >>>> +
> > >>>> +}
> > >>>>
> > >>>> Propchange:
> jmeter/trunk/src/components/org/apache/jmeter/visualizers/
> > >>>> backend/AbstractBackendListenerClient.java
> > >>>> ------------------------------------------------------------
> > >>>> ------------------
> > >>>>       svn:mime-type = text/plain
> > >>>>
> > >>>> Added: jmeter/trunk/src/components/org/apache/jmeter/visualizers/
> > >>>> backend/BackendListener.java
> > >>>> URL: http://svn.apache.org/viewvc/jmeter/trunk/src/components/
> > >>>> org/apache/jmeter/visualizers/backend/BackendListener.java?
> > >>>> rev=1641081&view=auto
> > >>>> ============================================================
> > >>>> ==================
> > >>>> --- jmeter/trunk/src/components/org/apache/jmeter/visualizers/
> > >>>> backend/BackendListener.java
> > >>>> (added)
> > >>>> +++ jmeter/trunk/src/components/org/apache/jmeter/visualizers/
> > >>>> backend/BackendListener.java
> > >>>> Sat Nov 22 15:36:37 2014
> > >>>> @@ -0,0 +1,448 @@
> > >>>> +/*
> > >>>> + * 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.jmeter.visualizers.backend;
> > >>>> +
> > >>>> +import java.io.Serializable;
> > >>>> +import java.lang.reflect.Method;
> > >>>> +import java.util.ArrayList;
> > >>>> +import java.util.HashSet;
> > >>>> +import java.util.List;
> > >>>> +import java.util.Set;
> > >>>> +import java.util.concurrent.ArrayBlockingQueue;
> > >>>> +import java.util.concurrent.BlockingQueue;
> > >>>> +import java.util.concurrent.locks.LockSupport;
> > >>>> +
> > >>>> +import org.apache.jmeter.config.Arguments;
> > >>>> +import org.apache.jmeter.engine.util.NoThreadClone;
> > >>>> +import org.apache.jmeter.protocol.java.sampler.JavaSamplerContext;
> > >>>> +import org.apache.jmeter.samplers.Remoteable;
> > >>>> +import org.apache.jmeter.samplers.SampleEvent;
> > >>>> +import org.apache.jmeter.samplers.SampleListener;
> > >>>> +import org.apache.jmeter.samplers.SampleResult;
> > >>>> +import org.apache.jmeter.testelement.AbstractTestElement;
> > >>>> +import org.apache.jmeter.testelement.TestElement;
> > >>>> +import org.apache.jmeter.testelement.TestStateListener;
> > >>>> +import org.apache.jmeter.testelement.property.TestElementProperty;
> > >>>> +import org.apache.jorphan.logging.LoggingManager;
> > >>>> +import org.apache.log.Logger;
> > >>>> +
> > >>>> +/**
> > >>>> + * Async Listener that delegates SampleResult handling to
> > >>>> implementations of {@link BackendListenerClient}
> > >>>> + * @since 2.13
> > >>>> + */
> > >>>> +public class BackendListener extends AbstractTestElement
> > >>>> +    implements Serializable, SampleListener, TestStateListener,
> > >>>> NoThreadClone, Remoteable  {
> > >>>> +
> > >>>> +    /**
> > >>>> +     *
> > >>>> +     */
> > >>>> +    private static final long serialVersionUID =
> 8184103677832024335L;
> > >>>> +
> > >>>> +    private static final Logger log = LoggingManager.
> > >>>> getLoggerForClass();
> > >>>>
> > >>>>  See naming comment of log from above
> > >>>
> > >>>  +
> > >>>> +    /**
> > >>>> +     * Set used to register instances which implement teardownTest.
> > >>>> +     * This is used so that the BackendListenerClient can be
> notified
> > >>>> when the test ends.
> > >>>> +     */
> > >>>> +    private static final Set<BackendListener> TEAR_DOWN_SET = new
> > >>>> HashSet<BackendListener>();
> > >>>> +
> > >>>> +    /**
> > >>>> +     * Property key representing the classname of the
> > >>>> BackendListenerClient to user.
> > >>>> +     */
> > >>>> +    public static final String CLASSNAME = "classname";
> > >>>> +
> > >>>> +    /**
> > >>>> +     * Queue size
> > >>>> +     */
> > >>>> +    public static final String QUEUE_SIZE = "QUEUE_SIZE";
> > >>>> +
> > >>>> +    /**
> > >>>> +     * Property key representing the arguments for the
> > >>>> BackendListenerClient.
> > >>>> +     */
> > >>>> +    public static final String ARGUMENTS = "arguments";
> > >>>> +
> > >>>> +    /**
> > >>>> +     * The BackendListenerClient class used by this sampler.
> > >>>> +     * Created by testStarted; copied to cloned instances.
> > >>>> +     */
> > >>>> +    private Class<?> javaClass;
> > >>>>
> > >>>>  Could probably named clientClass instead of javaClass, since we
> already
> > >>> know it is a java class.
> > >>>
> > >>>  +
> > >>>> +    /**
> > >>>> +     * If true, the BackendListenerClient class implements
> > >>>> teardownTest.
> > >>>> +     * Created by testStarted; copied to cloned instances.
> > >>>> +     */
> > >>>> +    private boolean isToBeRegistered;
> > >>>> +
> > >>>> +    /**
> > >>>> +     * The BackendListenerClient instance
> > >>>> +     */
> > >>>> +    private transient BackendListenerClient backendListenerClient =
> > >>>> null;
> > >>>> +
> > >>>> +    /**
> > >>>> +     * The JavaSamplerContext instance used by this sampler to hold
> > >>>> information
> > >>>>
> > >>>>  BackendListenerContext?
> > >>>
> > >>>  +     * related to the test run, such as the parameters specified
> for
> > >>>> the
> > >>>> sampler
> > >>>> +     * client.
> > >>>> +     */
> > >>>> +    private transient BackendListenerContext context = null;
> > >>>> +
> > >>>> +    private static final int DEFAULT_QUEUE_SIZE = 5000;
> > >>>> +
> > >>>> +    private transient BlockingQueue<SampleResult> queue; //
> created by
> > >>>> server in readResolve method
> > >>>> +
> > >>>> +    private transient long queueWaits; // how many times we had to
> wait
> > >>>> to queue a sample
> > >>>> +
> > >>>> +    private transient long queueWaitTime; // how long we had to
> wait
> > >>>> (nanoSeconds)
> > >>>> +
> > >>>> +    // Create unique object as marker for end of queue
> > >>>> +    private transient static final SampleResult FINAL_EVENT = new
> > >>>> SampleResult();
> > >>>> +
> > >>>> +    /**
> > >>>> +     * Create a BackendListener.
> > >>>> +     */
> > >>>> +    public BackendListener() {
> > >>>> +        setArguments(new Arguments());
> > >>>> +    }
> > >>>> +
> > >>>> +    /*
> > >>>> +     * Ensure that the required class variables are cloned,
> > >>>> +     * as this is not currently done by the super-implementation.
> > >>>> +     */
> > >>>> +    @Override
> > >>>> +    public Object clone() {
> > >>>> +        BackendListener clone = (BackendListener) super.clone();
> > >>>> +        clone.javaClass = this.javaClass;
> > >>>> +        clone.isToBeRegistered = this.isToBeRegistered;
> > >>>> +        return clone;
> > >>>> +    }
> > >>>> +
> > >>>> +    private void initClass() {
> > >>>> +        String name = getClassname().trim();
> > >>>> +        try {
> > >>>> +            javaClass = Class.forName(name, false,
> > >>>> Thread.currentThread().getContextClassLoader());
> > >>>> +            Method method = javaClass.getMethod("teardownTest", new
> > >>>> Class[]{BackendListenerContext.class});
> > >>>> +            isToBeRegistered = !method.getDeclaringClass().equals(
> > >>>> AbstractBackendListenerClient.class);
> > >>>> +            log.info("Created class: " + name + ". Uses
> teardownTest:
> > >>>> "
> > >>>> + isToBeRegistered);
> > >>>> +        } catch (Exception e) {
> > >>>> +            log.error(whoAmI() + "\tException initialising: " +
> name,
> > >>>> e);
> > >>>> +        }
> > >>>> +    }
> > >>>> +
> > >>>> +    /**
> > >>>> +     * Retrieves reference to BackendListenerClient.
> > >>>> +     *
> > >>>> +     * Convience method used to check for null reference without
> > >>>> actually
> > >>>> +     * creating a BackendListenerClient
> > >>>> +     *
> > >>>> +     * @return reference to BackendListenerClient NOTUSED private
> > >>>> BackendListenerClient
> > >>>> +     *         retrieveJavaClient() { return javaClient; }
> > >>>> +     */
> > >>>>
> > >>>>  Javadoc for non-existant method?
> > >>>
> > >>>  +
> > >>>> +    /**
> > >>>> +     * Generate a String identifier of this instance for debugging
> > >>>> purposes.
> > >>>> +     *
> > >>>> +     * @return a String identifier for this sampler instance
> > >>>> +     */
> > >>>> +    private String whoAmI() {
> > >>>> +        StringBuilder sb = new StringBuilder();
> > >>>> +        sb.append(Thread.currentThread().getName());
> > >>>> +        sb.append("@");
> > >>>> +        sb.append(Integer.toHexString(hashCode()));
> > >>>> +        sb.append("-");
> > >>>> +        sb.append(getName());
> > >>>> +        return sb.toString();
> > >>>> +    }
> > >>>> +
> > >>>> +    // TestStateListener implementation
> > >>>> +    /* Implements TestStateListener.testStarted() */
> > >>>> +    @Override
> > >>>> +    public void testStarted() {
> > >>>> +        testStarted("");
> > >>>> +    }
> > >>>> +
> > >>>> +    /* Implements TestStateListener.testStarted(String) */
> > >>>> +    @Override
> > >>>> +    public void testStarted(String host) {
> > >>>> +        log.debug(whoAmI() + "\ttestStarted(" + host + ")");
> > >>>>
> > >>>>  Maybe use isDebugEnabled to guard whoAmI() call?
> > >>>
> > >>>  +        queue = new
> ArrayBlockingQueue<SampleResult>(getQueueSize());
> > >>>> +        initClass();
> > >>>> +        queueWaits=0L;
> > >>>> +        queueWaitTime=0L;
> > >>>> +        log.info(getName()+":Starting worker with
> class:"+javaClass +"
> > >>>> and queue capacity:"+getQueueSize());
> > >>>> +
> > >>>> +        backendListenerClient = createBackendListenerClientImp
> > >>>> l(javaClass);
> > >>>> +        context = new BackendListenerContext((
> > >>>> Arguments)getArguments().
> > >>>> clone());
> > >>>> +        if(isToBeRegistered) {
> > >>>>
> > >>>>  space after if and before (?
> > >>>
> > >>>  +            TEAR_DOWN_SET.add(this);
> > >>>> +        }
> > >>>> +        try {
> > >>>> +            backendListenerClient.setupTest(context);
> > >>>> +        } catch (Exception e) {
> > >>>> +            throw new java.lang.IllegalStateException("Failed
> calling
> > >>>> setupTest", e);
> > >>>> +        }
> > >>>> +
> > >>>> +        Worker worker = new Worker(javaClass,
> backendListenerClient,
> > >>>> (Arguments) getArguments().clone(), queue);
> > >>>> +        worker.setDaemon(true);
> > >>>> +        worker.start();
> > >>>>
> > >>>>  Don't we want to stop worker after we're done with one test?
> > >>>
> > >>>  +        log.info(getName()+":Started  worker with
> class:"+javaClass);
> > >>>>
> > >>>>  Spaces after :?
> > >>>
> > >>>  +
> > >>>> +    }
> > >>>> +
> > >>>> +    /* (non-Javadoc)
> > >>>> +     * @see
> org.apache.jmeter.samplers.SampleListener#sampleOccurred(
> > >>>> org.apache.jmeter.samplers.SampleEvent)
> > >>>> +     */
> > >>>> +    @Override
> > >>>> +    public void sampleOccurred(SampleEvent e) {
> > >>>>
> > >>>>  Longer name then 'e'? I expect e to be an exception, not an event.
> > >>>
> > >>>  +        Arguments args = getArguments();
> > >>>> +        context = new BackendListenerContext(args);
> > >>>> +
> > >>>> +        SampleResult sr = backendListenerClient.
> > >>>> createSampleResult(context,
> > >>>> e.getResult());
> > >>>> +        try {
> > >>>> +            if (!queue.offer(sr)){ // we failed to add the element
> > >>>> first
> > >>>> time
> > >>>> +                queueWaits++;
> > >>>> +                long t1 = System.nanoTime();
> > >>>> +                queue.put(sr);
> > >>>> +                long t2 = System.nanoTime();
> > >>>> +                queueWaitTime += t2-t1;
> > >>>>
> > >>>>  Will sampleOccurred be called concurrently? If so, than
> queueWaitTime
> > >>> +=
> > >>> will not be correct.
> > >>>
> > >>>  +            }
> > >>>> +        } catch (Exception err) {
> > >>>> +            log.error("sampleOccurred, failed to queue the sample",
> > >>>> err);
> > >>>> +        }
> > >>>> +    }
> > >>>> +
> > >>>> +    private static final class Worker extends Thread {
> > >>>> +
> > >>>> +        private final BlockingQueue<SampleResult> queue;
> > >>>> +        private final BackendListenerContext context;
> > >>>> +        private final BackendListenerClient backendListenerClient;
> > >>>> +        private Worker(Class<?> javaClass, BackendListenerClient
> > >>>> backendListenerClient, Arguments arguments,
> BlockingQueue<SampleResult>
> > >>>> q){
> > >>>>
> > >>>>  Same naming argument as above. clientclass instead of javaClass?
> > >>>
> > >>>  +            queue = q;
> > >>>> +            // Allow BackendListenerClient implementations to get
> > >>>> access
> > >>>> to test element name
> > >>>> +            arguments.addArgument(TestElement.NAME, getName());
> > >>>> +            context = new BackendListenerContext(arguments);
> > >>>> +            this.backendListenerClient = backendListenerClient;
> > >>>> +        }
> > >>>> +
> > >>>> +
> > >>>> +        @Override
> > >>>> +        public void run() {
> > >>>> +            boolean isDebugEnabled = log.isDebugEnabled();
> > >>>> +            List<SampleResult> l = new
> ArrayList<SampleResult>(queue.
> > >>>> size());
> > >>>>
> > >>>>  samples instead of l?
> > >>>
> > >>>  +            try {
> > >>>> +                boolean eof = false;
> > >>>>
> > >>>>  endOfLoop?
> > >>>
> > >>>  +                while (!eof) {
> > >>>> +                    if(isDebugEnabled) {
> > >>>> +                        log.debug("Thread:"+Thread.
> > >>>> currentThread().getName()+"
> > >>>> taking SampleResult from queue:"+queue.size());
> > >>>> +                    }
> > >>>> +                    SampleResult e = queue.take();
> > >>>>
> > >>>>  Could be named result, or sample instead of e
> > >>>
> > >>>  +                    if(isDebugEnabled) {
> > >>>> +                        log.debug("Thread:"+Thread.
> > >>>> currentThread().getName()+"
> > >>>> took SampleResult:"+e+", isFinal:" + (e==FINAL_EVENT));
> > >>>> +                    }
> > >>>> +                    while (!(eof = (e == FINAL_EVENT)) && e !=
> null ) {
> > >>>> // try to process as many as possible
> > >>>> +                        l.add(e);
> > >>>> +                        if(isDebugEnabled) {
> > >>>> +                            log.debug("Thread:"+Thread.
> > >>>> currentThread().getName()+"
> > >>>> polling from queue:"+queue.size());
> > >>>> +                        }
> > >>>> +                        e = queue.poll(); // returns null if
> nothing on
> > >>>> queue currently
> > >>>> +                        if(isDebugEnabled) {
> > >>>> +                            log.debug("Thread:"+Thread.
> > >>>> currentThread().getName()+"
> > >>>> took from queue:"+e+", isFinal:" + (e==FINAL_EVENT));
> > >>>> +                        }
> > >>>> +                    }
> > >>>> +                    if(isDebugEnabled) {
> > >>>> +                        log.debug("Thread:"+Thread.
> > >>>> currentThread().getName()+
> > >>>> +                                " exiting with FINAL EVENT:"+(e ==
> > >>>> FINAL_EVENT)
> > >>>> +                                +", null:" + (e==null));
> > >>>> +                    }
> > >>>> +                    int size = l.size();
> > >>>>
> > >>>>  No need for a temporary variable.
> > >>>
> > >>>  +                    if (size > 0) {
> > >>>> +
> backendListenerClient.handleSampleResults(l,
> > >>>> context);
> > >>>> +                        l.clear();
> > >>>> +                    }
> > >>>> +                    if(!eof) {
> > >>>> +                        LockSupport.parkNanos(100);
> > >>>> +                    }
> > >>>> +                }
> > >>>> +            } catch (InterruptedException e) {
> > >>>> +                // NOOP
> > >>>> +            }
> > >>>> +            // We may have been interrupted
> > >>>> +            int size = l.size();
> > >>>> +            if (size > 0) {
> > >>>> +                backendListenerClient.handleSampleResults(l,
> context);
> > >>>> +                l.clear();
> > >>>> +            }
> > >>>>
> > >>>>  Same code as a few lines above, could be factored out into a method
> > >>> handleSamples(l, context)
> > >>>
> > >>>  +            log.info("Worker ended");
> > >>>> +        }
> > >>>> +    }
> > >>>> +
> > >>>> +
> > >>>> +    /**
> > >>>> +     * Returns reference to <code>BackendListenerClient</code>.
> > >>>>
> > >>>>  Could use a {@link...}
> > >>>
> > >>>  +     *
> > >>>> +     *
> > >>>> +     * @return BackendListenerClient reference.
> > >>>> +     */
> > >>>> +    static BackendListenerClient createBackendListenerClientImp
> > >>>> l(Class<?>
> > >>>> javaClass) {
> > >>>> +        if (javaClass == null) { // failed to initialise the class
> > >>>> +            return new ErrorBackendListenerClient();
> > >>>> +        }
> > >>>> +        BackendListenerClient client;
> > >>>> +        try {
> > >>>> +            client = (BackendListenerClient)
> javaClass.newInstance();
> > >>>> +        } catch (Exception e) {
> > >>>> +            log.error("Exception creating: " + javaClass, e);
> > >>>> +            client = new ErrorBackendListenerClient();
> > >>>> +        }
> > >>>> +        return client;
> > >>>>
> > >>>>  I would return newInstance() in try Block and return new Error.. in
> > >>> catch
> > >>> Block. javaClass -> clientClass
> > >>>
> > >>>  +    }
> > >>>> +
> > >>>> +    /**
> > >>>> +     * Method called at the end of the test. This is called only
> on one
> > >>>> instance
> > >>>> +     * of BackendListener. This method will loop through all of the
> > >>>> other
> > >>>> +     * BackendListenerClients which have been registered
> (automatically
> > >>>> in the
> > >>>> +     * constructor) and notify them that the test has ended,
> allowing
> > >>>> the
> > >>>> +     * BackendListenerClients to cleanup.
> > >>>> +     */
> > >>>> +    @Override
> > >>>> +    public void testEnded() {
> > >>>> +        try {
> > >>>> +            queue.put(FINAL_EVENT);
> > >>>> +        } catch (Exception ex) {
> > >>>> +            log.warn("testEnded() with exception:"+ex.getMessage(),
> > >>>> ex);
> > >>>> +        }
> > >>>> +        if (queueWaits > 0) {
> > >>>> +            log.warn("QueueWaits: "+queueWaits+"; QueueWaitTime:
> > >>>> "+queueWaitTime+" (nanoseconds), you may need to increase queue
> > >>>> capacity,
> > >>>> see property 'backend_queue_capacity'");
> > >>>> +        }
> > >>>> +        synchronized (TEAR_DOWN_SET) {
> > >>>> +            for (BackendListener backendListener : TEAR_DOWN_SET) {
> > >>>> +                BackendListenerClient client = backendListener.
> > >>>> backendListenerClient;
> > >>>> +                if (client != null) {
> > >>>> +                    try {
> > >>>> +
> client.teardownTest(backendListener.context);
> > >>>> +                    } catch (Exception e) {
> > >>>> +                        throw new java.lang.
> > >>>> IllegalStateException("Failed
> > >>>> calling teardownTest", e);
> > >>>>
> > >>>>  If we throw an exception here, we will not try every client.
> > >>>
> > >>>  +                    }
> > >>>> +                }
> > >>>> +            }
> > >>>> +            TEAR_DOWN_SET.clear();
> > >>>> +        }
> > >>>> +    }
> > >>>> +
> > >>>> +    /* Implements TestStateListener.testEnded(String) */
> > >>>> +    @Override
> > >>>> +    public void testEnded(String host) {
> > >>>> +        testEnded();
> > >>>> +    }
> > >>>> +
> > >>>> +    /**
> > >>>> +     * A {@link BackendListenerClient} implementation used for
> error
> > >>>> handling. If an
> > >>>> +     * error occurs while creating the real BackendListenerClient
> > >>>> object, it is
> > >>>> +     * replaced with an instance of this class. Each time a sample
> > >>>> occurs with
> > >>>> +     * this class, the result is marked as a failure so the user
> can
> > >>>> see
> > >>>> that
> > >>>> +     * the test failed.
> > >>>> +     */
> > >>>> +    static class ErrorBackendListenerClient extends
> > >>>> AbstractBackendListenerClient {
> > >>>> +        /**
> > >>>> +         * Return SampleResult with data on error.
> > >>>> +         *
> > >>>> +         * @see BackendListenerClient#runTest(JavaSamplerContext)
> > >>>> +         */
> > >>>> +        @Override
> > >>>> +        public void handleSampleResults(List<SampleResult>
> > >>>> sampleResults, BackendListenerContext context) {
> > >>>> +            log.warn("ErrorBackendListenerClient#handleSampleResult
> > >>>> called, noop");
> > >>>> +            Thread.yield();
> > >>>> +        }
> > >>>> +    }
> > >>>> +
> > >>>> +    /* (non-Javadoc)
> > >>>> +     * @see
> org.apache.jmeter.samplers.SampleListener#sampleStarted(
> > >>>> org.apache.jmeter.samplers.SampleEvent)
> > >>>> +     */
> > >>>> +    @Override
> > >>>> +    public void sampleStarted(SampleEvent e) {
> > >>>> +        // NOOP
> > >>>> +
> > >>>> +    }
> > >>>> +
> > >>>> +    /* (non-Javadoc)
> > >>>> +     * @see
> org.apache.jmeter.samplers.SampleListener#sampleStopped(
> > >>>> org.apache.jmeter.samplers.SampleEvent)
> > >>>> +     */
> > >>>> +    @Override
> > >>>> +    public void sampleStopped(SampleEvent e) {
> > >>>> +        // NOOP
> > >>>> +
> > >>>> +    }
> > >>>> +
> > >>>> +    /**
> > >>>> +     * Set the arguments (parameters) for the
> BackendListenerClient to
> > >>>> be executed
> > >>>> +     * with.
> > >>>> +     *
> > >>>> +     * @param args
> > >>>> +     *            the new arguments. These replace any existing
> > >>>> arguments.
> > >>>> +     */
> > >>>> +    public void setArguments(Arguments args) {
> > >>>> +        setProperty(new TestElementProperty(ARGUMENTS, args));
> > >>>> +    }
> > >>>> +
> > >>>> +    /**
> > >>>> +     * Get the arguments (parameters) for the
> BackendListenerClient to
> > >>>> be executed
> > >>>> +     * with.
> > >>>> +     *
> > >>>> +     * @return the arguments
> > >>>> +     */
> > >>>> +    public Arguments getArguments() {
> > >>>> +        return (Arguments) getProperty(ARGUMENTS).getObjectValue();
> > >>>> +    }
> > >>>> +
> > >>>> +    /**
> > >>>> +     * Sets the Classname of the BackendListenerClient object
> > >>>> +     *
> > >>>> +     * @param classname
> > >>>> +     *            the new Classname value
> > >>>> +     */
> > >>>> +    public void setClassname(String classname) {
> > >>>> +        setProperty(CLASSNAME, classname);
> > >>>> +    }
> > >>>> +
> > >>>> +    /**
> > >>>> +     * Gets the Classname of the BackendListenerClient object
> > >>>> +     *
> > >>>> +     * @return the Classname value
> > >>>> +     */
> > >>>> +    public String getClassname() {
> > >>>> +        return getPropertyAsString(CLASSNAME);
> > >>>> +    }
> > >>>> +
> > >>>> +    /**
> > >>>> +     * Sets the queue size
> > >>>> +     *
> > >>>> +     * @param queueSize
> > >>>> +     *
> > >>>> +     */
> > >>>> +    public void setQueueSize(int queueSize) {
> > >>>> +        setProperty(QUEUE_SIZE, queueSize, DEFAULT_QUEUE_SIZE);
> > >>>> +    }
> > >>>> +
> > >>>> +    /**
> > >>>> +     * Gets the queue size
> > >>>> +     *
> > >>>> +     * @return int queueSize
> > >>>> +     */
> > >>>> +    public int getQueueSize() {
> > >>>> +        return getPropertyAsInt(QUEUE_SIZE, DEFAULT_QUEUE_SIZE);
> > >>>> +    }
> > >>>> +}
> > >>>>
> > >>>> Propchange:
> jmeter/trunk/src/components/org/apache/jmeter/visualizers/
> > >>>> backend/BackendListener.java
> > >>>> ------------------------------------------------------------
> > >>>> ------------------
> > >>>>       svn:mime-type = text/plain
> > >>>>
> > >>>> Added: jmeter/trunk/src/components/org/apache/jmeter/visualizers/
> > >>>> backend/BackendListenerClient.java
> > >>>> URL: http://svn.apache.org/viewvc/jmeter/trunk/src/components/
> > >>>> org/apache/jmeter/visualizers/backend/BackendListenerClient.
> > >>>> java?rev=1641081&view=auto
> > >>>> ============================================================
> > >>>> ==================
> > >>>> --- jmeter/trunk/src/components/org/apache/jmeter/visualizers/
> > >>>> backend/BackendListenerClient.java (added)
> > >>>> +++ jmeter/trunk/src/components/org/apache/jmeter/visualizers/
> > >>>> backend/BackendListenerClient.java Sat Nov 22 15:36:37 2014
> > >>>> @@ -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.jmeter.visualizers.backend;
> > >>>> +
> > >>>> +import java.util.List;
> > >>>> +
> > >>>> +import org.apache.jmeter.config.Arguments;
> > >>>> +import org.apache.jmeter.samplers.SampleResult;
> > >>>> +
> > >>>> +/**
> > >>>> + * This interface defines the interactions between the
> BackendListener
> > >>>> and external
> > >>>> + * Java programs which can be executed by JMeter. Any Java class
> which
> > >>>> wants to
> > >>>> + * be executed as a JMeter test must implement this interface
> (either
> > >>>> directly
> > >>>> + * or indirectly through AbstractBackendListenerClient).
> > >>>> + * <p>
> > >>>> + * JMeter will create one instance of a BackendListenerClient
> > >>>> implementation for
> > >>>> + * each user/thread in the test. Additional instances may be
> created
> > >>>> for
> > >>>> + * internal use by JMeter (for example, to find out what
> parameters are
> > >>>> + * supported by the client).
> > >>>> + * <p>
> > >>>> + * When the test is started, setupTest() will be called on each
> > >>>> thread's
> > >>>> + * BackendListenerClient instance to initialize the client. Then
> > >>>> handleSampleResult() will be
> > >>>> + * called for each SampleResult notification. Finally,
> teardownTest()
> > >>>> will be called
> > >>>> + * to allow the client to do any necessary clean-up.
> > >>>> + * <p>
> > >>>> + * The JMeter BackendListener GUI allows a list of parameters to be
> > >>>> defined for the
> > >>>> + * test. These are passed to the various test methods through the
> > >>>> + * {@link BackendListenerContext}. A list of default parameters
> can be
> > >>>> defined
> > >>>> + * through the getDefaultParameters() method. These parameters and
> any
> > >>>> default
> > >>>> + * values associated with them will be shown in the GUI. Users can
> add
> > >>>> other
> > >>>> + * parameters as well.
> > >>>> + * <p>
> > >>>> + * When possible, Listeners should extend {@link
> > >>>> AbstractBackendListenerClient
> > >>>> + * AbstractBackendListenerClient} rather than implementing
> > >>>> BackendListenerClient
> > >>>> + * directly. This should protect your tests from future changes to
> the
> > >>>> + * interface. While it may be necessary to make changes to the
> > >>>> BackendListenerClient
> > >>>> + * interface from time to time (therefore requiring changes to any
> > >>>> + * implementations of this interface), we intend to make this
> abstract
> > >>>> class
> > >>>> + * provide reasonable default implementations of any new methods so
> > >>>> that
> > >>>> + * subclasses do not necessarily need to be updated for new
> versions.
> > >>>> + * Implementing BackendListenerClient directly will continue to be
> > >>>> supported for
> > >>>> + * cases where extending this class is not possible (for example,
> when
> > >>>> the
> > >>>> + * client class is already a subclass of some other class).
> > >>>> + *
> > >>>> + * @since 2.13
> > >>>> + */
> > >>>> +public interface BackendListenerClient {
> > >>>> +    /**
> > >>>> +     * Do any initialization required by this client. It is
> generally
> > >>>> +     * recommended to do any initialization such as getting
> parameter
> > >>>> values in
> > >>>> +     * the setupTest method rather than the runTest method in
> order to
> > >>>> add as
> > >>>> +     * little overhead as possible to the test.
> > >>>> +     *
> > >>>> +     * @param context
> > >>>> +     *            the context to run with. This provides access to
> > >>>> +     *            initialization parameters.
> > >>>> +     */
> > >>>> +    void setupTest(BackendListenerContext context) throws
> Exception;
> > >>>> +
> > >>>> +    /**
> > >>>> +     * Perform a single sample for each iteration. This method
> returns
> > >>>> a
> > >>>> +     * <code>SampleResult</code> object. <code>SampleResult</code>
> has
> > >>>> many
> > >>>> +     * fields which can be used. At a minimum, the test should use
> > >>>> +     * <code>SampleResult.sampleStart</code> and
> > >>>> +     * <code>SampleResult.sampleEnd</code>to set the time that the
> > >>>> test
> > >>>>
> > >>>>  use {@link..} instead of <code>..?
> > >>>
> > >>>  +     * required to execute. It is also a good idea to set the
> > >>>> sampleLabel and
> > >>>> +     * the successful flag.
> > >>>> +     *
> > >>>> +     * @see org.apache.jmeter.samplers.SampleResult#sampleStart()
> > >>>> +     * @see org.apache.jmeter.samplers.SampleResult#sampleEnd()
> > >>>> +     * @see org.apache.jmeter.samplers.SampleResult#setSuccessful(
> > >>>> boolean)
> > >>>> +     * @see org.apache.jmeter.samplers.SampleResult#setSampleLabel(
> > >>>> String)
> > >>>> +     *
> > >>>> +     * @param context
> > >>>> +     *            the context to run with. This provides access to
> > >>>> +     *            initialization parameters.
> > >>>> +     *
> > >>>> +     */
> > >>>> +    void handleSampleResults(List<SampleResult> sampleResults,
> > >>>> BackendListenerContext context);
> > >>>> +
> > >>>> +    /**
> > >>>> +     * Do any clean-up required by this test at the end of a test
> run.
> > >>>> +     *
> > >>>> +     * @param context
> > >>>> +     *            the context to run with. This provides access to
> > >>>> +     *            initialization parameters.
> > >>>> +     */
> > >>>> +    void teardownTest(BackendListenerContext context) throws
> > >>>> Exception;
> > >>>> +
> > >>>> +    /**
> > >>>> +     * Provide a list of parameters which this test supports. Any
> > >>>> parameter
> > >>>> +     * names and associated values returned by this method will
> appear
> > >>>> in the
> > >>>> +     * GUI by default so the user doesn't have to remember the
> exact
> > >>>> names. The
> > >>>> +     * user can add other parameters which are not listed here. If
> this
> > >>>> method
> > >>>> +     * returns null then no parameters will be listed. If the
> value for
> > >>>> some
> > >>>> +     * parameter is null then that parameter will be listed in the
> GUI
> > >>>> with an
> > >>>> +     * empty value.
> > >>>> +     *
> > >>>> +     * @return a specification of the parameters used by this test
> > >>>> which
> > >>>> should
> > >>>> +     *         be listed in the GUI, or null if no parameters
> should be
> > >>>> listed.
> > >>>> +     */
> > >>>> +    Arguments getDefaultParameters();
> > >>>> +
> > >>>> +    /**
> > >>>> +     *
> > >>>> +     * @param context
> > >>>> +     * @param result
> > >>>> +     * @return
> > >>>> +     */
> > >>>> +    SampleResult createSampleResult(
> > >>>> +            BackendListenerContext context, SampleResult result);
> > >>>> +}
> > >>>>
> > >>>> Propchange:
> jmeter/trunk/src/components/org/apache/jmeter/visualizers/
> > >>>> backend/BackendListenerClient.java
> > >>>> ------------------------------------------------------------
> > >>>> ------------------
> > >>>>       svn:mime-type = text/plain
> > >>>>
> > >>>> Added: jmeter/trunk/src/components/org/apache/jmeter/visualizers/
> > >>>> backend/
> > >>>> BackendListenerContext.java
> > >>>> URL: http://svn.apache.org/viewvc/jmeter/trunk/src/components/
> > >>>> org/apache/jmeter/visualizers/backend/BackendListenerContext.java?
> > >>>> rev=1641081&view=auto
> > >>>> ============================================================
> > >>>> ==================
> > >>>> ---
> jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/
> > >>>> BackendListenerContext.java
> > >>>> (added)
> > >>>> +++
> jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/
> > >>>> BackendListenerContext.java
> > >>>> Sat Nov 22 15:36:37 2014
> > >>>> @@ -0,0 +1,237 @@
> > >>>> +/*
> > >>>> +
> > >>>> + * 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.jmeter.visualizers.backend;
> > >>>> +
> > >>>> +import java.util.Iterator;
> > >>>> +import java.util.Map;
> > >>>> +
> > >>>> +import org.apache.jmeter.config.Arguments;
> > >>>> +import org.apache.jorphan.logging.LoggingManager;
> > >>>> +import org.apache.log.Logger;
> > >>>> +
> > >>>> +/**
> > >>>> + * BackendListenerContext is used to provide context information
> to a
> > >>>> + * BackendListenerClient implementation. This currently consists
> of the
> > >>>> + * initialization parameters which were specified in the GUI.
> > >>>> + * @since 2.13
> > >>>> + */
> > >>>> +public class BackendListenerContext {
> > >>>> +    /*
> > >>>> +     * Implementation notes:
> > >>>> +     *
> > >>>> +     * All of the methods in this class are currently read-only. If
> > >>>> update
> > >>>> +     * methods are included in the future, they should be defined
> so
> > >>>> that a
> > >>>> +     * single instance of BackendListenerContext can be associated
> with
> > >>>> each thread.
> > >>>> +     * Therefore, no synchronization should be needed. The same
> > >>>> instance
> > >>>> should
> > >>>> +     * be used for the call to setupTest, all calls to runTest,
> and the
> > >>>> call to
> > >>>> +     * teardownTest.
> > >>>> +     */
> > >>>> +
> > >>>> +    /** Logging */
> > >>>> +    private static final Logger log = LoggingManager.
> > >>>> getLoggerForClass();
> > >>>>
> > >>>>  See naming comments for logger above
> > >>>
> > >>>  +
> > >>>> +    /**
> > >>>> +     * Map containing the initialization parameters for the
> > >>>> BackendListenerClient.
> > >>>> +     */
> > >>>> +    private final Map<String, String> params;
> > >>>> +
> > >>>> +    /**
> > >>>> +     *
> > >>>> +     * @param args
> > >>>> +     *            the initialization parameters.
> > >>>> +     */
> > >>>> +    public BackendListenerContext(Arguments args) {
> > >>>> +        this.params = args.getArgumentsAsMap();
> > >>>> +    }
> > >>>> +
> > >>>> +    /**
> > >>>> +     * Determine whether or not a value has been specified for the
> > >>>> parameter
> > >>>> +     * with this name.
> > >>>> +     *
> > >>>> +     * @param name
> > >>>> +     *            the name of the parameter to test
> > >>>> +     * @return true if the parameter value has been specified,
> false
> > >>>> otherwise.
> > >>>> +     */
> > >>>> +    public boolean containsParameter(String name) {
> > >>>>
> > >>>>  hasParameter instead of containsParameter?
> > >>>
> > >>>  +        return params.containsKey(name);
> > >>>> +    }
> > >>>> +
> > >>>> +    /**
> > >>>> +     * Get an iterator of the parameter names. Each entry in the
> > >>>> Iterator is a
> > >>>> +     * String.
> > >>>> +     *
> > >>>> +     * @return an Iterator of Strings listing the names of the
> > >>>> parameters which
> > >>>> +     *         have been specified for this test.
> > >>>> +     */
> > >>>> +    public Iterator<String> getParameterNamesIterator() {
> > >>>> +        return params.keySet().iterator();
> > >>>> +    }
> > >>>> +
> > >>>> +    /**
> > >>>> +     * Get the value of a specific parameter as a String, or null
> if
> > >>>> the
> > >>>> value
> > >>>> +     * was not specified.
> > >>>> +     *
> > >>>> +     * @param name
> > >>>> +     *            the name of the parameter whose value should be
> > >>>> retrieved
> > >>>> +     * @return the value of the parameter, or null if the value
> was not
> > >>>> +     *         specified
> > >>>> +     */
> > >>>> +    public String getParameter(String name) {
> > >>>> +        return getParameter(name, null);
> > >>>> +    }
> > >>>> +
> > >>>> +    /**
> > >>>> +     * Get the value of a specified parameter as a String, or
> return
> > >>>> the
> > >>>> +     * specified default value if the value was not specified.
> > >>>> +     *
> > >>>> +     * @param name
> > >>>> +     *            the name of the parameter whose value should be
> > >>>> retrieved
> > >>>> +     * @param defaultValue
> > >>>> +     *            the default value to return if the value of this
> > >>>> parameter was
> > >>>> +     *            not specified
> > >>>> +     * @return the value of the parameter, or the default value if
> the
> > >>>> parameter
> > >>>> +     *         was not specified
> > >>>> +     */
> > >>>> +    public String getParameter(String name, String defaultValue) {
> > >>>> +        if (params == null || !params.containsKey(name)) {
> > >>>> +            return defaultValue;
> > >>>> +        }
> > >>>> +        return params.get(name);
> > >>>> +    }
> > >>>> +
> > >>>> +    /**
> > >>>> +     * Get the value of a specified parameter as an integer. An
> > >>>> exception will
> > >>>> +     * be thrown if the parameter is not specified or if it is not
> an
> > >>>> integer.
> > >>>> +     * The value may be specified in decimal, hexadecimal, or
> octal, as
> > >>>> defined
> > >>>> +     * by Integer.decode().
> > >>>> +     *
> > >>>> +     * @param name
> > >>>> +     *            the name of the parameter whose value should be
> > >>>> retrieved
> > >>>> +     * @return the value of the parameter
> > >>>> +     *
> > >>>> +     * @throws NumberFormatException
> > >>>> +     *             if the parameter is not specified or is not an
> > >>>> integer
> > >>>> +     *
> > >>>> +     * @see java.lang.Integer#decode(java.lang.String)
> > >>>> +     */
> > >>>> +    public int getIntParameter(String name) throws
> > >>>> NumberFormatException
> > >>>> {
> > >>>> +        if (params == null || !params.containsKey(name)) {
> > >>>> +            throw new NumberFormatException("No value for parameter
> > >>>> named '" + name + "'.");
> > >>>>
> > >>>>  I would expect an IllegalArgumentException, if no parameter of that
> > >>> name
> > >>> is found
> > >>>
> > >>>  +        }
> > >>>> +
> > >>>> +        return Integer.decode(params.get(name)).intValue();
> > >>>> +    }
> > >>>> +
> > >>>> +    /**
> > >>>> +     * Get the value of a specified parameter as an integer, or
> return
> > >>>> the
> > >>>> +     * specified default value if the value was not specified or
> is not
> > >>>> an
> > >>>> +     * integer. A warning will be logged if the value is not an
> > >>>> integer.
> > >>>> The
> > >>>> +     * value may be specified in decimal, hexadecimal, or octal, as
> > >>>> defined by
> > >>>> +     * Integer.decode().
> > >>>> +     *
> > >>>> +     * @param name
> > >>>> +     *            the name of the parameter whose value should be
> > >>>> retrieved
> > >>>> +     * @param defaultValue
> > >>>> +     *            the default value to return if the value of this
> > >>>> parameter was
> > >>>> +     *            not specified
> > >>>> +     * @return the value of the parameter, or the default value if
> the
> > >>>> parameter
> > >>>> +     *         was not specified
> > >>>> +     *
> > >>>> +     * @see java.lang.Integer#decode(java.lang.String)
> > >>>> +     */
> > >>>> +    public int getIntParameter(String name, int defaultValue) {
> > >>>> +        if (params == null || !params.containsKey(name)) {
> > >>>> +            return defaultValue;
> > >>>> +        }
> > >>>> +
> > >>>> +        try {
> > >>>> +            return Integer.decode(params.get(name)).intValue();
> > >>>> +        } catch (NumberFormatException e) {
> > >>>> +            log.warn("Value for parameter '" + name + "' not an
> > >>>> integer:
> > >>>> '" + params.get(name) + "'.  Using default: '"
> > >>>> +                    + defaultValue + "'.", e);
> > >>>> +            return defaultValue;
> > >>>> +        }
> > >>>> +    }
> > >>>> +
> > >>>> +    /**
> > >>>> +     * Get the value of a specified parameter as a long. An
> exception
> > >>>> will be
> > >>>> +     * thrown if the parameter is not specified or if it is not a
> long.
> > >>>> The
> > >>>> +     * value may be specified in decimal, hexadecimal, or octal, as
> > >>>> defined by
> > >>>> +     * Long.decode().
> > >>>> +     *
> > >>>> +     * @param name
> > >>>> +     *            the name of the parameter whose value should be
> > >>>> retrieved
> > >>>> +     * @return the value of the parameter
> > >>>> +     *
> > >>>> +     * @throws NumberFormatException
> > >>>> +     *             if the parameter is not specified or is not a
> long
> > >>>> +     *
> > >>>> +     * @see Long#decode(String)
> > >>>> +     */
> > >>>> +    public long getLongParameter(String name) throws
> > >>>> NumberFormatException {
> > >>>> +        if (params == null || !params.containsKey(name)) {
> > >>>> +            throw new NumberFormatException("No value for parameter
> > >>>> named '" + name + "'.");
> > >>>> +        }
> > >>>> +
> > >>>> +        return Long.decode(params.get(name)).longValue();
> > >>>> +    }
> > >>>> +
> > >>>> +    /**
> > >>>> +     * Get the value of a specified parameter as along, or return
> the
> > >>>> specified
> > >>>> +     * default value if the value was not specified or is not a
> long. A
> > >>>> warning
> > >>>> +     * will be logged if the value is not a long. The value may be
> > >>>> specified in
> > >>>> +     * decimal, hexadecimal, or octal, as defined by Long.decode().
> > >>>> +     *
> > >>>> +     * @param name
> > >>>> +     *            the name of the parameter whose value should be
> > >>>> retrieved
> > >>>> +     * @param defaultValue
> > >>>> +     *            the default value to return if the value of this
> > >>>> parameter was
> > >>>> +     *            not specified
> > >>>> +     * @return the value of the parameter, or the default value if
> the
> > >>>> parameter
> > >>>> +     *         was not specified
> > >>>> +     *
> > >>>> +     * @see Long#decode(String)
> > >>>> +     */
> > >>>> +    public long getLongParameter(String name, long defaultValue) {
> > >>>> +        if (params == null || !params.containsKey(name)) {
> > >>>> +            return defaultValue;
> > >>>> +        }
> > >>>> +        try {
> > >>>> +            return Long.decode(params.get(name)).longValue();
> > >>>> +        } catch (NumberFormatException e) {
> > >>>> +            log.warn("Value for parameter '" + name + "' not a
> long: '"
> > >>>> + params.get(name) + "'.  Using default: '"
> > >>>> +                    + defaultValue + "'.", e);
> > >>>> +            return defaultValue;
> > >>>> +        }
> > >>>> +    }
> > >>>> +
> > >>>> +    /**
> > >>>> +     *
> > >>>> +     * @param name
> > >>>> +     * @param defaultValue
> > >>>> +     * @return
> > >>>>
> > >>>>  No javadoc? Again three warnings more :)
> > >>>
> > >>>  +     */
> > >>>> +    public boolean getBooleanParameter(String name, boolean
> > >>>> defaultValue) {
> > >>>> +        if (params == null || !params.containsKey(name)) {
> > >>>> +            return defaultValue;
> > >>>> +        }
> > >>>> +        return Boolean.valueOf(params.get(name));
> > >>>> +    }
> > >>>> +}
> > >>>>
> > >>>> Propchange:
> jmeter/trunk/src/components/org/apache/jmeter/visualizers/
> > >>>> backend/BackendListenerContext.java
> > >>>> ------------------------------------------------------------
> > >>>> ------------------
> > >>>>       svn:mime-type = text/plain
> > >>>>
> > >>>> Added: jmeter/trunk/src/components/org/apache/jmeter/visualizers/
> > >>>> backend/BackendListenerGui.java
> > >>>> URL: http://svn.apache.org/viewvc/jmeter/trunk/src/components/
> > >>>> org/apache/jmeter/visualizers/backend/BackendListenerGui.
> > >>>> java?rev=1641081&view=auto
> > >>>> ============================================================
> > >>>> ==================
> > >>>> --- jmeter/trunk/src/components/org/apache/jmeter/visualizers/
> > >>>> backend/BackendListenerGui.java (added)
> > >>>> +++ jmeter/trunk/src/components/org/apache/jmeter/visualizers/
> > >>>> backend/BackendListenerGui.java Sat Nov 22 15:36:37 2014
> > >>>> @@ -0,0 +1,282 @@
> > >>>> +/*
> > >>>> + * 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.jmeter.visualizers.backend;
> > >>>> +
> > >>>> +import java.awt.BorderLayout;
> > >>>> +import java.awt.event.ActionEvent;
> > >>>> +import java.awt.event.ActionListener;
> > >>>> +import java.util.ArrayList;
> > >>>> +import java.util.HashSet;
> > >>>> +import java.util.List;
> > >>>> +import java.util.Map;
> > >>>> +import java.util.Set;
> > >>>> +
> > >>>> +import javax.swing.ComboBoxModel;
> > >>>> +import javax.swing.JComboBox;
> > >>>> +import javax.swing.JLabel;
> > >>>> +import javax.swing.JPanel;
> > >>>> +import javax.swing.JTextField;
> > >>>> +
> > >>>> +import org.apache.jmeter.config.Argument;
> > >>>> +import org.apache.jmeter.config.Arguments;
> > >>>> +import org.apache.jmeter.config.gui.ArgumentsPanel;
> > >>>> +import org.apache.jmeter.gui.util.HorizontalPanel;
> > >>>> +import org.apache.jmeter.testelement.TestElement;
> > >>>> +import org.apache.jmeter.testelement.property.PropertyIterator;
> > >>>> +import org.apache.jmeter.util.JMeterUtils;
> > >>>> +import org.apache.jmeter.visualizers.gui.AbstractListenerGui;
> > >>>> +import org.apache.jorphan.logging.LoggingManager;
> > >>>> +import org.apache.jorphan.reflect.ClassFinder;
> > >>>> +import org.apache.log.Logger;
> > >>>> +
> > >>>> +/**
> > >>>> + * The <code>BackendListenerGui</code> class provides the user
> > >>>> interface for the
> > >>>> + * {@link BackendListener} object.
> > >>>> + * @since 2.13
> > >>>> + */
> > >>>> +public class BackendListenerGui extends AbstractListenerGui
> implements
> > >>>> ActionListener {
> > >>>> +
> > >>>> +    /**
> > >>>> +     *
> > >>>> +     */
> > >>>> +    private static final long serialVersionUID =
> 4331668988576438604L;
> > >>>> +
> > >>>> +    /** Logging */
> > >>>> +    private static final Logger log = LoggingManager.
> > >>>> getLoggerForClass();
> > >>>> +
> > >>>> +    /** A combo box allowing the user to choose a backend class. */
> > >>>> +    private JComboBox classnameCombo;
> > >>>> +
> > >>>> +    /**
> > >>>> +     * A field allowing the user to specify the size of Queue
> > >>>> +     */
> > >>>> +    private JTextField queueSize;
> > >>>> +
> > >>>> +    /** A panel allowing the user to set arguments for this test.
> */
> > >>>> +    private ArgumentsPanel argsPanel;
> > >>>> +
> > >>>> +    /**
> > >>>> +     * Create a new BackendListenerGui as a standalone component.
> > >>>> +     */
> > >>>> +    public BackendListenerGui() {
> > >>>> +        super();
> > >>>> +        init();
> > >>>> +    }
> > >>>> +
> > >>>> +
> > >>>> +    /** {@inheritDoc} */
> > >>>> +    @Override
> > >>>> +    public String getLabelResource() {
> > >>>> +        return "backend_listener"; // $NON-NLS-1$
> > >>>> +    }
> > >>>> +
> > >>>> +    /**
> > >>>> +     * Initialize the GUI components and layout.
> > >>>> +     */
> > >>>> +    private void init() {// called from ctor, so must not be
> > >>>> overridable
> > >>>> +        setLayout(new BorderLayout(0, 5));
> > >>>> +
> > >>>> +        setBorder(makeBorder());
> > >>>> +        add(makeTitlePanel(), BorderLayout.NORTH);
> > >>>> +
> > >>>> +        JPanel classnameRequestPanel = new JPanel(new
> BorderLayout(0,
> > >>>> 5));
> > >>>> +        classnameRequestPanel.add(createClassnamePanel(),
> > >>>> BorderLayout.NORTH);
> > >>>> +        classnameRequestPanel.add(createParameterPanel(),
> > >>>> BorderLayout.CENTER);
> > >>>> +
> > >>>> +        add(classnameRequestPanel, BorderLayout.CENTER);
> > >>>> +    }
> > >>>> +
> > >>>> +    /**
> > >>>> +     * Create a panel with GUI components allowing the user to
> select a
> > >>>> test
> > >>>> +     * class.
> > >>>> +     *
> > >>>> +     * @return a panel containing the relevant components
> > >>>> +     */
> > >>>> +    private JPanel createClassnamePanel() {
> > >>>> +        List<String> possibleClasses = new ArrayList<String>();
> > >>>> +
> > >>>> +        try {
> > >>>> +            // Find all the classes which implement the
> > >>>> BackendListenerClient
> > >>>> +            // interface.
> > >>>> +            possibleClasses = ClassFinder.findClassesThatExtend(
> > >>>> JMeterUtils.getSearchPaths(),
> > >>>> +                    new Class[] { BackendListenerClient.class });
> > >>>> +
> > >>>> +            // Remove the BackendListener class from the list
> since it
> > >>>> only
> > >>>>
> > >>>>  ErrorBackendListener
> > >>>
> > >>>  +            // implements the interface for error conditions.
> > >>>> +
> > >>>> +            possibleClasses.remove(BackendListener.class.getName()
> +
> > >>>> "$ErrorBackendListenerClient");
> > >>>> +        } catch (Exception e) {
> > >>>> +            log.debug("Exception getting interfaces.", e);
> > >>>> +        }
> > >>>> +
> > >>>> +        JLabel label = new
> JLabel(JMeterUtils.getResString("backend_
> > >>>> listener_classname"));
> > >>>> // $NON-NLS-1$
> > >>>> +
> > >>>> +        classnameCombo = new JComboBox(possibleClasses.toArray());
> > >>>> +        classnameCombo.addActionListener(this);
> > >>>> +        classnameCombo.setEditable(false);
> > >>>> +        label.setLabelFor(classnameCombo);
> > >>>> +
> > >>>> +        HorizontalPanel classNamePanel = new HorizontalPanel();
> > >>>> +        classNamePanel.add(label);
> > >>>> +        classNamePanel.add(classnameCombo);
> > >>>> +
> > >>>> +        queueSize = new JTextField("", 5);
> > >>>> +        queueSize.setName("Queue Size"); //$NON-NLS-1$
> > >>>> +        JLabel queueSizeLabel = new JLabel(JMeterUtils.
> > >>>> getResString("backend_listener_queue_size")); // $NON-NLS-1$
> > >>>> +        queueSizeLabel.setLabelFor(queueSize);
> > >>>> +        HorizontalPanel queueSizePanel = new HorizontalPanel();
> > >>>> +        queueSizePanel.add(queueSizeLabel, BorderLayout.WEST);
> > >>>> +        queueSizePanel.add(queueSize);
> > >>>> +
> > >>>> +        JPanel panel = new JPanel(new BorderLayout(0, 5));
> > >>>> +        panel.add(classNamePanel, BorderLayout.NORTH);
> > >>>> +        panel.add(queueSizePanel, BorderLayout.CENTER);
> > >>>> +        return panel;
> > >>>> +    }
> > >>>> +
> > >>>> +    /**
> > >>>> +     * Handle action events for this component. This method
> currently
> > >>>> handles
> > >>>> +     * events for the classname combo box.
> > >>>> +     *
> > >>>> +     * @param evt
> > >>>>
> > >>>>  I would spend the few extra characters to make it event instead of
> evt
> > >>>
> > >>>  +     *            the ActionEvent to be handled
> > >>>> +     */
> > >>>> +    @Override
> > >>>> +    public void actionPerformed(ActionEvent evt) {
> > >>>> +        if (evt.getSource() == classnameCombo) {
> > >>>> +            String className = ((String) classnameCombo.
> > >>>> getSelectedItem()).trim();
> > >>>> +            try {
> > >>>> +                BackendListenerClient client =
> (BackendListenerClient)
> > >>>> Class.forName(className, true,
> > >>>> +                        Thread.currentThread().
> > >>>> getContextClassLoader()).
> > >>>> newInstance();
> > >>>> +
> > >>>> +                Arguments currArgs = new Arguments();
> > >>>> +                argsPanel.modifyTestElement(currArgs);
> > >>>> +                Map<String, String> currArgsMap =
> > >>>> currArgs.getArgumentsAsMap();
> > >>>> +
> > >>>> +                Arguments newArgs = new Arguments();
> > >>>> +                Arguments testParams = null;
> > >>>> +                try {
> > >>>> +                    testParams = client.getDefaultParameters();
> > >>>> +                } catch (AbstractMethodError e) {
> > >>>> +                    log.warn("BackendListenerClient doesn't
> implement
> > >>>> "
> > >>>> +                            + "getDefaultParameters.  Default
> > >>>> parameters
> > >>>> won't "
> > >>>> +                            + "be shown.  Please update your client
> > >>>> class: " + className);
> > >>>> +                }
> > >>>> +
> > >>>> +                if (testParams != null) {
> > >>>> +                    PropertyIterator i = testParams.getArguments().
> > >>>> iterator();
> > >>>>
> > >>>>  I would try a for loop instead of explicitly using an iterator
> > >>>
> > >>>  +                    while (i.hasNext()) {
> > >>>> +                        Argument arg = (Argument)
> > >>>> i.next().getObjectValue();
> > >>>> +                        String name = arg.getName();
> > >>>> +                        String value = arg.getValue();
> > >>>> +
> > >>>> +                        // If a user has set parameters in one
> test,
> > >>>> and
> > >>>> then
> > >>>> +                        // selects a different test which supports
> the
> > >>>> same
> > >>>> +                        // parameters, those parameters should
> have the
> > >>>> same
> > >>>> +                        // values that they did in the original
> test.
> > >>>> +                        if (currArgsMap.containsKey(name)) {
> > >>>> +                            String newVal = currArgsMap.get(name);
> > >>>> +                            if (newVal != null && newVal.length()
> > 0)
> > >>>> {
> > >>>> +                                value = newVal;
> > >>>> +                            }
> > >>>> +                        }
> > >>>> +                        newArgs.addArgument(name, value);
> > >>>> +                    }
> > >>>> +                }
> > >>>> +
> > >>>> +                argsPanel.configure(newArgs);
> > >>>> +            } catch (Exception e) {
> > >>>> +                log.error("Error getting argument list for " +
> > >>>> className, e);
> > >>>> +            }
> > >>>> +        }
> > >>>> +    }
> > >>>> +
> > >>>> +    /**
> > >>>> +     * Create a panel containing components allowing the user to
> > >>>> provide
> > >>>> +     * arguments to be passed to the test class instance.
> > >>>> +     *
> > >>>> +     * @return a panel containing the relevant components
> > >>>> +     */
> > >>>> +    private JPanel createParameterPanel() {
> > >>>> +        argsPanel = new ArgumentsPanel(JMeterUtils.
> > >>>> getResString("backend_listener_paramtable")); // $NON-NLS-1$
> > >>>> +        return argsPanel;
> > >>>> +    }
> > >>>> +
> > >>>> +    /** {@inheritDoc} */
> > >>>> +    @Override
> > >>>> +    public void configure(TestElement config) {
> > >>>> +        super.configure(config);
> > >>>> +
> > >>>> +        argsPanel.configure((Arguments) config.getProperty(
> > >>>> BackendListener.ARGUMENTS).getObjectValue());
> > >>>> +
> > >>>> +        String className = config.getPropertyAsString(
> > >>>> BackendListener.CLASSNAME);
> > >>>> +        if(checkContainsClassName(classnameCombo.getModel(),
> > >>>> className)) {
> > >>>> +            classnameCombo.setSelectedItem(className);
> > >>>> +        } else {
> > >>>> +            log.error("Error setting class:'"+className+"' in
> > >>>> BackendListener: "+getName()+
> > >>>> +                    ", check for a missing jar in your jmeter
> > >>>> 'search_paths' and 'plugin_dependency_paths' properties");
> > >>>> +        }
> > >>>> +        queueSize.setText(Integer.toString(((BackendListener)
> > >>>> config).getQueueSize()));
> > >>>> +    }
> > >>>> +
> > >>>> +    /**
> > >>>> +     * Check combo contains className
> > >>>> +     * @param model ComboBoxModel
> > >>>> +     * @param className String class name
> > >>>> +     * @return boolean
> > >>>>
> > >>>>  explain "boolean" or the other params a bit more?
> > >>>
> > >>>  +     */
> > >>>> +    private static final boolean
> checkContainsClassName(ComboBoxModel
> > >>>> model, String className) {
> > >>>> +        int size = model.getSize();
> > >>>> +        Set<String> set = new HashSet<String>(size);
> > >>>> +        for (int i = 0; i < size; i++) {
> > >>>> +            set.add((String)model.getElementAt(i));
> > >>>> +        }
> > >>>> +        return set.contains(className);
> > >>>> +    }
> > >>>> +
> > >>>> +    /** {@inheritDoc} */
> > >>>> +    @Override
> > >>>> +    public TestElement createTestElement() {
> > >>>> +        BackendListener config = new BackendListener();
> > >>>> +        modifyTestElement(config);
> > >>>> +        return config;
> > >>>> +    }
> > >>>> +
> > >>>> +    /** {@inheritDoc} */
> > >>>> +    @Override
> > >>>> +    public void modifyTestElement(TestElement config) {
> > >>>> +        configureTestElement(config);
> > >>>> +        BackendListener backendListener = (BackendListener) config;
> > >>>> +        backendListener.setArguments((Arguments)
> > >>>> argsPanel.createTestElement());
> > >>>> +        backendListener.setClassname(String.valueOf(classnameCombo.
> > >>>> getSelectedItem()));
> > >>>> +        backendListener.setQueueSize(Integer.parseInt(queueSize.
> > >>>> getText()));
> > >>>> +
> > >>>> +    }
> > >>>> +
> > >>>>
> > >>>
> >
>
>
>


-- 
Cordialement.
Philippe Mouawad.

Re: svn commit: r1641081 - in /jmeter/trunk: ./ bin/ res/maven/ src/components/org/apache/jmeter/visualizers/backend/ src/core/org/apache/jmeter/resources/ src/core/org/apache/jmeter/samplers/ src/core/org/apache/jmeter/save/ xdocs/ xdocs/usermanual/

Posted by Felix Schumacher <fe...@internetallee.de>.
Hello Philippe,

Am Sonntag, den 23.11.2014, 12:22 +0100 schrieb Philippe Mouawad:
> Thanks a lot for your review which pointed to a synchronisation issue that
> I fixed, good catch!
> 
> I think I took all your notes into account, let me know if I forgot
> something.
in SamplerMetric you have used a sliding window for the statistics.
* Should we make the length of the window configurable?
* Should min/max and minThreads/maxThreads be limited to the sliding
window, also? At least min and max would be simple to do.

Regards
 Felix
> 
> Regards
> Philippe
> 
> On Sunday, November 23, 2014, Felix Schumacher <
> felix.schumacher@internetallee.de> wrote:
> 
> > Hi Phillipe,
> > Am 22.11.2014 um 19:29 schrieb Philippe Mouawad:
> >
> >> Hi Felix,
> >> As I said in thread, I commited code and will improve, feel free to fix
> >> javadocs issues on your side.
> >> I will review your comment.
> >>
> >> I have spent many hours if not days on this code and I am aware it is not
> >> yet fully completed (although tests are promising) but my aim when
> >> commiting it was to have feedback and help to finish it.
> >>
> > I did not mean to offend you. I can clearly see, that you put a lot of
> > effort
> > in this listener and I will surely try to integrate jmeter into our
> > collectd server.
> >
> > Regards
> >  Felix
> >
> >>
> >> Regards
> >> Philippe
> >>
> >> On Sat, Nov 22, 2014 at 7:21 PM, Felix Schumacher <
> >> felix.schumacher@internetallee.de> wrote:
> >>
> >>  Hello Philippe,
> >>>
> >>> I have hidden a few comments inside the cited code.
> >>> They are mostly around javadoc and naming things.
> >>>
> >>> Am 22.11.2014 um 16:36 schrieb pmouawad@apache.org:
> >>>
> >>>  Author: pmouawad
> >>>> Date: Sat Nov 22 15:36:37 2014
> >>>> New Revision: 1641081
> >>>>
> >>>> URL: http://svn.apache.org/r1641081
> >>>> Log:
> >>>> Bug 55932 - Create a Async BackendListener to allow easy plug of new
> >>>> listener (Graphite, JDBC, Console,...)
> >>>> Bugzilla Id: 55932
> >>>>
> >>>> Added:
> >>>>       jmeter/trunk/src/components/org/apache/jmeter/visualizers/
> >>>> backend/
> >>>>       jmeter/trunk/src/components/org/apache/jmeter/visualizers/
> >>>> backend/
> >>>> AbstractBackendListenerClient.java   (with props)
> >>>>       jmeter/trunk/src/components/org/apache/jmeter/visualizers/
> >>>> backend/BackendListener.java
> >>>>   (with props)
> >>>>       jmeter/trunk/src/components/org/apache/jmeter/visualizers/
> >>>> backend/BackendListenerClient.java   (with props)
> >>>>       jmeter/trunk/src/components/org/apache/jmeter/visualizers/
> >>>> backend/BackendListenerContext.java
> >>>>   (with props)
> >>>>       jmeter/trunk/src/components/org/apache/jmeter/visualizers/
> >>>> backend/BackendListenerGui.java   (with props)
> >>>>       jmeter/trunk/src/components/org/apache/jmeter/visualizers/
> >>>> backend/SamplerMetric.java
> >>>>   (with props)
> >>>> Modified:
> >>>>       jmeter/trunk/bin/saveservice.properties
> >>>>       jmeter/trunk/build.properties
> >>>>       jmeter/trunk/build.xml
> >>>>       jmeter/trunk/eclipse.classpath
> >>>>       jmeter/trunk/res/maven/ApacheJMeter_parent.pom
> >>>>       jmeter/trunk/src/core/org/apache/jmeter/resources/
> >>>> messages.properties
> >>>>       jmeter/trunk/src/core/org/apache/jmeter/resources/
> >>>> messages_fr.properties
> >>>>       jmeter/trunk/src/core/org/apache/jmeter/samplers/
> >>>> SampleResult.java
> >>>>       jmeter/trunk/src/core/org/apache/jmeter/save/SaveService.java
> >>>>       jmeter/trunk/xdocs/changes.xml
> >>>>       jmeter/trunk/xdocs/usermanual/component_reference.xml
> >>>>
> >>>> Modified: jmeter/trunk/bin/saveservice.properties
> >>>> URL: http://svn.apache.org/viewvc/jmeter/trunk/bin/saveservice.
> >>>> properties?rev=1641081&r1=1641080&r2=1641081&view=diff
> >>>> ============================================================
> >>>> ==================
> >>>> --- jmeter/trunk/bin/saveservice.properties (original)
> >>>> +++ jmeter/trunk/bin/saveservice.properties Sat Nov 22 15:36:37 2014
> >>>> @@ -53,7 +53,8 @@ _file_version=$Revision$
> >>>>    # 2.5 = 2.10
> >>>>    # 2.6 = 2.11
> >>>>    # 2.7 = 2.12
> >>>> -_version=2.7
> >>>> +# 2.8 = 2.13
> >>>> +_version=2.8
> >>>>    #
> >>>>    #
> >>>>    # Character set encoding used to read and write JMeter XML files and
> >>>> CSV results
> >>>> @@ -78,6 +79,8 @@ AssertionVisualizer=org.apache.jmeter.vi
> >>>>    AuthManager=org.apache.jmeter.protocol.http.control.AuthManager
> >>>>    Authorization=org.apache.jmeter.protocol.http.control.Authorization
> >>>>    AuthPanel=org.apache.jmeter.protocol.http.gui.AuthPanel
> >>>> +BackendListener=org.apache.jmeter.visualizers.backend.BackendListener
> >>>> +BackendListenerGui=org.apache.jmeter.visualizers.
> >>>> backend.BackendListenerGui
> >>>>    BarChart=org.apache.jmeter.testelement.BarChart
> >>>>    BarChartGui=org.apache.jmeter.report.gui.BarChartGui
> >>>>    BeanShellAssertion=org.apache.jmeter.assertions.BeanShellAssertion
> >>>>
> >>>> Modified: jmeter/trunk/build.properties
> >>>> URL: http://svn.apache.org/viewvc/jmeter/trunk/build.properties?
> >>>> rev=1641081&r1=1641080&r2=1641081&view=diff
> >>>> ============================================================
> >>>> ==================
> >>>> --- jmeter/trunk/build.properties (original)
> >>>> +++ jmeter/trunk/build.properties Sat Nov 22 15:36:37 2014
> >>>> @@ -118,11 +118,21 @@ commons-logging.loc         = ${maven2.r
> >>>>    #commons-logging.md5         = E2C390FE739B2550A218262B28F290CE
> >>>>    commons-logging.md5         = 040b4b4d8eac886f6b4a2a3bd2f31b00
> >>>>    +commons-math3.version         = 3.3
> >>>> +commons-math3.jar             = commons-math3-${commons-math3.
> >>>> version}.jar
> >>>> +commons-math3.loc             = ${maven2.repo}/org/apache/
> >>>> commons/commons-math3/${commons-math3.version}
> >>>> +commons-math3.md5             = 87346cf2772dc2becf106c45e0f63863
> >>>> +
> >>>>    commons-net.version         = 3.3
> >>>>    commons-net.jar             = commons-net-${commons-net.version}.jar
> >>>>    commons-net.loc             = ${maven2.repo}/commons-net/
> >>>> commons-net/${commons-net.version}
> >>>>    commons-net.md5             = c077ca61598e9c21f43f8b6488fbbee9
> >>>>    +commons-pool2.version         = 2.2
> >>>> +commons-pool2.jar             = commons-pool2-${commons-pool2.
> >>>> version}.jar
> >>>> +commons-pool2.loc             = ${maven2.repo}/org/apache/
> >>>> commons/commons-pool2/${commons-pool2.version}
> >>>> +commons-pool2.md5             = 51b56c92883812c56fbeb339866ce2df
> >>>> +
> >>>>    # dnsjava for DNSCacheManager
> >>>>    dnsjava.version             = 2.1.6
> >>>>    dnsjava.jar                 = dnsjava-${dnsjava.version}.jar
> >>>>
> >>>> Modified: jmeter/trunk/build.xml
> >>>> URL: http://svn.apache.org/viewvc/jmeter/trunk/build.xml?rev=
> >>>> 1641081&r1=1641080&r2=1641081&view=diff
> >>>> ============================================================
> >>>> ==================
> >>>> --- jmeter/trunk/build.xml (original)
> >>>> +++ jmeter/trunk/build.xml Sat Nov 22 15:36:37 2014
> >>>> @@ -365,7 +365,9 @@
> >>>>        <include name="${lib.dir}/${commons-jexl2.jar}"/>
> >>>>        <include name="${lib.dir}/${commons-lang3.jar}"/>
> >>>>        <include name="${lib.dir}/${commons-logging.jar}"/>
> >>>> +    <include name="${lib.dir}/${commons-math3}"/>
> >>>>        <include name="${lib.dir}/${commons-net.jar}"/>
> >>>> +    <include name="${lib.dir}/${commons-pool2.jar}"/>
> >>>>        <include name="${lib.dir}/${dnsjava.jar}"/>
> >>>>        <include name="${lib.dir}/${excalibur-datasource.jar}"/>
> >>>>        <include name="${lib.dir}/${excalibur-instrument.jar}"/>
> >>>> @@ -438,8 +440,10 @@
> >>>>        <pathelement location="${lib.dir}/${commons-jexl2.jar}"/>
> >>>>        <pathelement location="${lib.dir}/${commons-lang3.jar}"/>
> >>>>        <pathelement location="${lib.dir}/${commons-logging.jar}"/>
> >>>> +    <pathelement location="${lib.dir}/${commons-math3.jar}"/>
> >>>>        <pathelement location="${lib.dir}/${commons-net.jar}"/>
> >>>> -    <pathelement location="${lib.dir}/${dnsjava.jar}"/>
> >>>> +       <pathelement location="${lib.dir}/${commons-pool2.jar}"/>
> >>>> +       <pathelement location="${lib.dir}/${dnsjava.jar}"/>
> >>>>        <pathelement location="${lib.dir}/${excalibur-datasource.jar}"/>
> >>>>        <pathelement location="${lib.dir}/${excalibur-instrument.jar}"/>
> >>>>        <pathelement location="${lib.dir}/${excalibur-logger.jar}"/>
> >>>> @@ -2909,7 +2913,9 @@ run JMeter unless all the JMeter jars ar
> >>>>            <process_jarfile jarname="commons-jexl2"/>
> >>>>            <process_jarfile jarname="commons-lang3"/>
> >>>>            <process_jarfile jarname="commons-logging"/>
> >>>> +        <process_jarfile jarname="commons-math3"/>
> >>>>            <process_jarfile jarname="commons-net"/>
> >>>> +       <process_jarfile jarname="commons-pool2"/>
> >>>>            <process_jarfile jarname="dnsjava"/>
> >>>>            <process_jarfile jarname="excalibur-datasource"/>
> >>>>            <process_jarfile jarname="excalibur-instrument"/>
> >>>>
> >>>> Modified: jmeter/trunk/eclipse.classpath
> >>>> URL: http://svn.apache.org/viewvc/jmeter/trunk/eclipse.
> >>>> classpath?rev=1641081&r1=1641080&r2=1641081&view=diff
> >>>> ============================================================
> >>>> ==================
> >>>> --- jmeter/trunk/eclipse.classpath (original)
> >>>> +++ jmeter/trunk/eclipse.classpath Sat Nov 22 15:36:37 2014
> >>>> @@ -55,7 +55,9 @@
> >>>>          <classpathentry kind="lib" path="lib/commons-jexl-2.1.1.jar"/>
> >>>>          <classpathentry kind="lib" path="lib/commons-lang3-3.3.2.
> >>>> jar"/>
> >>>>          <classpathentry kind="lib" path="lib/commons-logging-1.2.
> >>>> jar"/>
> >>>> +    <classpathentry kind="lib" path="lib/commons-math3-3.3.jar"/>
> >>>>          <classpathentry kind="lib" path="lib/commons-net-3.3.jar"/>
> >>>> +    <classpathentry kind="lib" path="lib/commons-pool2-2.2.jar"/>
> >>>>          <classpathentry kind="lib" path="lib/dnsjava-2.1.6.jar"/>
> >>>>          <classpathentry kind="lib" path="lib/excalibur-
> >>>> datasource-2.1.jar"/>
> >>>>          <classpathentry kind="lib" path="lib/excalibur-
> >>>> instrument-1.0.jar"/>
> >>>>
> >>>> Modified: jmeter/trunk/res/maven/ApacheJMeter_parent.pom
> >>>> URL: http://svn.apache.org/viewvc/jmeter/trunk/res/maven/
> >>>> ApacheJMeter_parent.pom?rev=1641081&r1=1641080&r2=1641081&view=diff
> >>>> ============================================================
> >>>> ==================
> >>>> --- jmeter/trunk/res/maven/ApacheJMeter_parent.pom (original)
> >>>> +++ jmeter/trunk/res/maven/ApacheJMeter_parent.pom Sat Nov 22 15:36:37
> >>>> 2014
> >>>> @@ -66,7 +66,9 @@ under the License.
> >>>>          <commons-jexl2.version>2.1.1</commons-jexl2.version>
> >>>>          <commons-lang3.version>3.3.2</commons-lang3.version>
> >>>>          <commons-logging.version>1.2</commons-logging.version>
> >>>> +      <commons-math3.version>3.3</commons-math3.version>
> >>>>          <commons-net.version>3.3</commons-net.version>
> >>>> +      <commons-pool2.version>2.2</commons-pool2.version>
> >>>>          <dnsjava.version>2.1.6</dnsjava.version>
> >>>>          <excalibur-datasource.version>2.1</excalibur-datasource.
> >>>> version>
> >>>>          <excalibur-instrument.version>1.0</excalibur-instrument.
> >>>> version>
> >>>> @@ -181,11 +183,21 @@ under the License.
> >>>>            <version>${commons-logging.version}</version>
> >>>>          </dependency>
> >>>>          <dependency>
> >>>> +        <groupId>commons-math3</groupId>
> >>>> +        <artifactId>commons-math3</artifactId>
> >>>> +        <version>${commons-math3.version}</version>
> >>>> +      </dependency>
> >>>> +      <dependency>
> >>>>            <groupId>commons-net</groupId>
> >>>>            <artifactId>commons-net</artifactId>
> >>>>            <version>${commons-net.version}</version>
> >>>>          </dependency>
> >>>>          <dependency>
> >>>> +        <groupId>commons-pool2</groupId>
> >>>> +        <artifactId>commons-pool2</artifactId>
> >>>> +        <version>${commons-pool2.version}</version>
> >>>> +      </dependency>
> >>>> +      <dependency>
> >>>>              <groupId>dnsjava</groupId>
> >>>>              <artifactId>dnsjava</artifactId>
> >>>>              <version>${dnsjava.version}</version>
> >>>>
> >>>> Added: jmeter/trunk/src/components/org/apache/jmeter/visualizers/
> >>>> backend/
> >>>> AbstractBackendListenerClient.java
> >>>> URL: http://svn.apache.org/viewvc/jmeter/trunk/src/components/
> >>>> org/apache/jmeter/visualizers/backend/AbstractBackendListenerClient.
> >>>> java?rev=1641081&view=auto
> >>>> ============================================================
> >>>> ==================
> >>>> --- jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/
> >>>> AbstractBackendListenerClient.java (added)
> >>>> +++ jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/
> >>>> AbstractBackendListenerClient.java Sat Nov 22 15:36:37 2014
> >>>> @@ -0,0 +1,121 @@
> >>>> +/*
> >>>> + * 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.jmeter.visualizers.backend;
> >>>> +
> >>>> +import java.util.Map;
> >>>> +import java.util.concurrent.ConcurrentHashMap;
> >>>> +
> >>>> +import org.apache.jmeter.config.Arguments;
> >>>> +import org.apache.jmeter.samplers.SampleResult;
> >>>> +import org.apache.jorphan.logging.LoggingManager;
> >>>> +import org.apache.log.Logger;
> >>>> +
> >>>> +/**
> >>>> + * An abstract implementation of the BackendListenerClient interface.
> >>>> This
> >>>> + * implementation provides default implementations of most of the
> >>>> methods in the
> >>>> + * interface, as well as some convenience methods, in order to simplify
> >>>> + * development of BackendListenerClient implementations.
> >>>> + *
> >>>> + * While it may be necessary to make changes to the
> >>>> BackendListenerClient interface
> >>>> + * from time to time (therefore requiring changes to any
> >>>> implementations
> >>>> of this
> >>>> + * interface), we intend to make this abstract class provide reasonable
> >>>> + * implementations of any new methods so that subclasses do not
> >>>> necessarily need
> >>>> + * to be updated for new versions. Therefore, when creating a new
> >>>> + * BackendListenerClient implementation, developers are encouraged to
> >>>> subclass this
> >>>> + * abstract class rather than implementing the BackendListenerClient
> >>>> interface
> >>>> + * directly. Implementing BackendListenerClient directly will continue
> >>>> to be
> >>>> + * supported for cases where extending this class is not possible (for
> >>>> example,
> >>>> + * when the client class is already a subclass of some other class).
> >>>> + * <p>
> >>>> + * The handleSampleResult() method of BackendListenerClient does not
> >>>> have a default
> >>>> + * implementation here, so subclasses must define at least this method.
> >>>> It may
> >>>> + * be useful to override other methods as well.
> >>>> + *
> >>>> + * @see BackendListener#sampleOccurred(org.apache.
> >>>> jmeter.samplers.SampleEvent)
> >>>> + * @since 2.13
> >>>> + */
> >>>> +public abstract class AbstractBackendListenerClient implements
> >>>> BackendListenerClient {
> >>>> +
> >>>> +    private static final Logger log = LoggingManager.
> >>>> getLoggerForClass();
> >>>>
> >>>>  In classes further down the logger is stored in variables named LOG and
> >>> LOGGER, should we use one name?
> >>> In this class we have a getter for the logger in other classes not. Why?
> >>>
> >>>  +
> >>>> +    private ConcurrentHashMap<String, SamplerMetric> metricsPerSampler
> >>>> =
> >>>> new ConcurrentHashMap<String, SamplerMetric>();
> >>>> +
> >>>> +    /* Implements BackendListenerClient.setupTest(JavaSamplerContext)
> >>>> */
> >>>> +    @Override
> >>>> +    public void setupTest(BackendListenerContext context) throws
> >>>> Exception {
> >>>> +        log.debug(getClass().getName() + ": setupTest");
> >>>> +    }
> >>>> +
> >>>> +    /* Implements BackendListenerClient.teardownTest(
> >>>> JavaSamplerContext)
> >>>> */
> >>>> +    @Override
> >>>> +    public void teardownTest(BackendListenerContext context) throws
> >>>> Exception {
> >>>> +        log.debug(getClass().getName() + ": teardownTest");
> >>>> +        metricsPerSampler.clear();
> >>>> +    }
> >>>> +
> >>>> +    /* Implements BackendListenerClient.getDefaultParameters() */
> >>>> +    @Override
> >>>> +    public Arguments getDefaultParameters() {
> >>>> +        return null;
> >>>> +    }
> >>>> +
> >>>> +    /**
> >>>> +     * Get a Logger instance which can be used by subclasses to log
> >>>> information.
> >>>> +     *
> >>>> +     * @return a Logger instance which can be used for logging
> >>>> +     */
> >>>> +    protected Logger getLogger() {
> >>>> +        return log;
> >>>> +    }
> >>>> +
> >>>> +    /* (non-Javadoc)
> >>>> +     * @see org.apache.jmeter.visualizers.
> >>>> backend.BackendListenerClient#
> >>>> createSampleResult(org.apache.jmeter.samplers.SampleResult)
> >>>> +     */
> >>>> +    @Override
> >>>> +    public SampleResult createSampleResult(BackendListenerContext
> >>>> context, SampleResult result) {
> >>>> +        SampleResult sampleResult = (SampleResult) result.clone();
> >>>> +        return sampleResult;
> >>>> +    }
> >>>> +
> >>>> +    /**
> >>>> +     *
> >>>> +     * @param sampleLabel
> >>>> +     * @return SamplerMetric
> >>>>
> >>>>  No description of the method and the parameters?
> >>>
> >>>  +     */
> >>>> +    protected SamplerMetric getSamplerMetric(String sampleLabel) {
> >>>> +        SamplerMetric samplerMetric = metricsPerSampler.get(
> >>>> sampleLabel);
> >>>> +        if(samplerMetric == null) {
> >>>> +            samplerMetric = new SamplerMetric();
> >>>> +            SamplerMetric oldValue = metricsPerSampler.putIfAbsent(
> >>>> sampleLabel,
> >>>> samplerMetric);
> >>>> +            if(oldValue != null ){
> >>>> +                samplerMetric = oldValue;
> >>>> +            }
> >>>> +        }
> >>>> +        return samplerMetric;
> >>>> +    }
> >>>> +
> >>>> +    /**
> >>>> +     *
> >>>> +     * @return Map<String, SamplerMetric>
> >>>>
> >>>>  No description of the method and usage of forbidden characters :) there
> >>> are still more than 800 warnings in the javadoc to prune, so don't
> >>> introduce new ones, please.
> >>>
> >>>  +     */
> >>>> +    protected Map<String, SamplerMetric> getMetricsPerSampler() {
> >>>> +        return metricsPerSampler;
> >>>> +    }
> >>>> +
> >>>> +}
> >>>>
> >>>> Propchange: jmeter/trunk/src/components/org/apache/jmeter/visualizers/
> >>>> backend/AbstractBackendListenerClient.java
> >>>> ------------------------------------------------------------
> >>>> ------------------
> >>>>       svn:mime-type = text/plain
> >>>>
> >>>> Added: jmeter/trunk/src/components/org/apache/jmeter/visualizers/
> >>>> backend/BackendListener.java
> >>>> URL: http://svn.apache.org/viewvc/jmeter/trunk/src/components/
> >>>> org/apache/jmeter/visualizers/backend/BackendListener.java?
> >>>> rev=1641081&view=auto
> >>>> ============================================================
> >>>> ==================
> >>>> --- jmeter/trunk/src/components/org/apache/jmeter/visualizers/
> >>>> backend/BackendListener.java
> >>>> (added)
> >>>> +++ jmeter/trunk/src/components/org/apache/jmeter/visualizers/
> >>>> backend/BackendListener.java
> >>>> Sat Nov 22 15:36:37 2014
> >>>> @@ -0,0 +1,448 @@
> >>>> +/*
> >>>> + * 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.jmeter.visualizers.backend;
> >>>> +
> >>>> +import java.io.Serializable;
> >>>> +import java.lang.reflect.Method;
> >>>> +import java.util.ArrayList;
> >>>> +import java.util.HashSet;
> >>>> +import java.util.List;
> >>>> +import java.util.Set;
> >>>> +import java.util.concurrent.ArrayBlockingQueue;
> >>>> +import java.util.concurrent.BlockingQueue;
> >>>> +import java.util.concurrent.locks.LockSupport;
> >>>> +
> >>>> +import org.apache.jmeter.config.Arguments;
> >>>> +import org.apache.jmeter.engine.util.NoThreadClone;
> >>>> +import org.apache.jmeter.protocol.java.sampler.JavaSamplerContext;
> >>>> +import org.apache.jmeter.samplers.Remoteable;
> >>>> +import org.apache.jmeter.samplers.SampleEvent;
> >>>> +import org.apache.jmeter.samplers.SampleListener;
> >>>> +import org.apache.jmeter.samplers.SampleResult;
> >>>> +import org.apache.jmeter.testelement.AbstractTestElement;
> >>>> +import org.apache.jmeter.testelement.TestElement;
> >>>> +import org.apache.jmeter.testelement.TestStateListener;
> >>>> +import org.apache.jmeter.testelement.property.TestElementProperty;
> >>>> +import org.apache.jorphan.logging.LoggingManager;
> >>>> +import org.apache.log.Logger;
> >>>> +
> >>>> +/**
> >>>> + * Async Listener that delegates SampleResult handling to
> >>>> implementations of {@link BackendListenerClient}
> >>>> + * @since 2.13
> >>>> + */
> >>>> +public class BackendListener extends AbstractTestElement
> >>>> +    implements Serializable, SampleListener, TestStateListener,
> >>>> NoThreadClone, Remoteable  {
> >>>> +
> >>>> +    /**
> >>>> +     *
> >>>> +     */
> >>>> +    private static final long serialVersionUID = 8184103677832024335L;
> >>>> +
> >>>> +    private static final Logger log = LoggingManager.
> >>>> getLoggerForClass();
> >>>>
> >>>>  See naming comment of log from above
> >>>
> >>>  +
> >>>> +    /**
> >>>> +     * Set used to register instances which implement teardownTest.
> >>>> +     * This is used so that the BackendListenerClient can be notified
> >>>> when the test ends.
> >>>> +     */
> >>>> +    private static final Set<BackendListener> TEAR_DOWN_SET = new
> >>>> HashSet<BackendListener>();
> >>>> +
> >>>> +    /**
> >>>> +     * Property key representing the classname of the
> >>>> BackendListenerClient to user.
> >>>> +     */
> >>>> +    public static final String CLASSNAME = "classname";
> >>>> +
> >>>> +    /**
> >>>> +     * Queue size
> >>>> +     */
> >>>> +    public static final String QUEUE_SIZE = "QUEUE_SIZE";
> >>>> +
> >>>> +    /**
> >>>> +     * Property key representing the arguments for the
> >>>> BackendListenerClient.
> >>>> +     */
> >>>> +    public static final String ARGUMENTS = "arguments";
> >>>> +
> >>>> +    /**
> >>>> +     * The BackendListenerClient class used by this sampler.
> >>>> +     * Created by testStarted; copied to cloned instances.
> >>>> +     */
> >>>> +    private Class<?> javaClass;
> >>>>
> >>>>  Could probably named clientClass instead of javaClass, since we already
> >>> know it is a java class.
> >>>
> >>>  +
> >>>> +    /**
> >>>> +     * If true, the BackendListenerClient class implements
> >>>> teardownTest.
> >>>> +     * Created by testStarted; copied to cloned instances.
> >>>> +     */
> >>>> +    private boolean isToBeRegistered;
> >>>> +
> >>>> +    /**
> >>>> +     * The BackendListenerClient instance
> >>>> +     */
> >>>> +    private transient BackendListenerClient backendListenerClient =
> >>>> null;
> >>>> +
> >>>> +    /**
> >>>> +     * The JavaSamplerContext instance used by this sampler to hold
> >>>> information
> >>>>
> >>>>  BackendListenerContext?
> >>>
> >>>  +     * related to the test run, such as the parameters specified for
> >>>> the
> >>>> sampler
> >>>> +     * client.
> >>>> +     */
> >>>> +    private transient BackendListenerContext context = null;
> >>>> +
> >>>> +    private static final int DEFAULT_QUEUE_SIZE = 5000;
> >>>> +
> >>>> +    private transient BlockingQueue<SampleResult> queue; // created by
> >>>> server in readResolve method
> >>>> +
> >>>> +    private transient long queueWaits; // how many times we had to wait
> >>>> to queue a sample
> >>>> +
> >>>> +    private transient long queueWaitTime; // how long we had to wait
> >>>> (nanoSeconds)
> >>>> +
> >>>> +    // Create unique object as marker for end of queue
> >>>> +    private transient static final SampleResult FINAL_EVENT = new
> >>>> SampleResult();
> >>>> +
> >>>> +    /**
> >>>> +     * Create a BackendListener.
> >>>> +     */
> >>>> +    public BackendListener() {
> >>>> +        setArguments(new Arguments());
> >>>> +    }
> >>>> +
> >>>> +    /*
> >>>> +     * Ensure that the required class variables are cloned,
> >>>> +     * as this is not currently done by the super-implementation.
> >>>> +     */
> >>>> +    @Override
> >>>> +    public Object clone() {
> >>>> +        BackendListener clone = (BackendListener) super.clone();
> >>>> +        clone.javaClass = this.javaClass;
> >>>> +        clone.isToBeRegistered = this.isToBeRegistered;
> >>>> +        return clone;
> >>>> +    }
> >>>> +
> >>>> +    private void initClass() {
> >>>> +        String name = getClassname().trim();
> >>>> +        try {
> >>>> +            javaClass = Class.forName(name, false,
> >>>> Thread.currentThread().getContextClassLoader());
> >>>> +            Method method = javaClass.getMethod("teardownTest", new
> >>>> Class[]{BackendListenerContext.class});
> >>>> +            isToBeRegistered = !method.getDeclaringClass().equals(
> >>>> AbstractBackendListenerClient.class);
> >>>> +            log.info("Created class: " + name + ". Uses teardownTest:
> >>>> "
> >>>> + isToBeRegistered);
> >>>> +        } catch (Exception e) {
> >>>> +            log.error(whoAmI() + "\tException initialising: " + name,
> >>>> e);
> >>>> +        }
> >>>> +    }
> >>>> +
> >>>> +    /**
> >>>> +     * Retrieves reference to BackendListenerClient.
> >>>> +     *
> >>>> +     * Convience method used to check for null reference without
> >>>> actually
> >>>> +     * creating a BackendListenerClient
> >>>> +     *
> >>>> +     * @return reference to BackendListenerClient NOTUSED private
> >>>> BackendListenerClient
> >>>> +     *         retrieveJavaClient() { return javaClient; }
> >>>> +     */
> >>>>
> >>>>  Javadoc for non-existant method?
> >>>
> >>>  +
> >>>> +    /**
> >>>> +     * Generate a String identifier of this instance for debugging
> >>>> purposes.
> >>>> +     *
> >>>> +     * @return a String identifier for this sampler instance
> >>>> +     */
> >>>> +    private String whoAmI() {
> >>>> +        StringBuilder sb = new StringBuilder();
> >>>> +        sb.append(Thread.currentThread().getName());
> >>>> +        sb.append("@");
> >>>> +        sb.append(Integer.toHexString(hashCode()));
> >>>> +        sb.append("-");
> >>>> +        sb.append(getName());
> >>>> +        return sb.toString();
> >>>> +    }
> >>>> +
> >>>> +    // TestStateListener implementation
> >>>> +    /* Implements TestStateListener.testStarted() */
> >>>> +    @Override
> >>>> +    public void testStarted() {
> >>>> +        testStarted("");
> >>>> +    }
> >>>> +
> >>>> +    /* Implements TestStateListener.testStarted(String) */
> >>>> +    @Override
> >>>> +    public void testStarted(String host) {
> >>>> +        log.debug(whoAmI() + "\ttestStarted(" + host + ")");
> >>>>
> >>>>  Maybe use isDebugEnabled to guard whoAmI() call?
> >>>
> >>>  +        queue = new ArrayBlockingQueue<SampleResult>(getQueueSize());
> >>>> +        initClass();
> >>>> +        queueWaits=0L;
> >>>> +        queueWaitTime=0L;
> >>>> +        log.info(getName()+":Starting worker with class:"+javaClass +"
> >>>> and queue capacity:"+getQueueSize());
> >>>> +
> >>>> +        backendListenerClient = createBackendListenerClientImp
> >>>> l(javaClass);
> >>>> +        context = new BackendListenerContext((
> >>>> Arguments)getArguments().
> >>>> clone());
> >>>> +        if(isToBeRegistered) {
> >>>>
> >>>>  space after if and before (?
> >>>
> >>>  +            TEAR_DOWN_SET.add(this);
> >>>> +        }
> >>>> +        try {
> >>>> +            backendListenerClient.setupTest(context);
> >>>> +        } catch (Exception e) {
> >>>> +            throw new java.lang.IllegalStateException("Failed calling
> >>>> setupTest", e);
> >>>> +        }
> >>>> +
> >>>> +        Worker worker = new Worker(javaClass, backendListenerClient,
> >>>> (Arguments) getArguments().clone(), queue);
> >>>> +        worker.setDaemon(true);
> >>>> +        worker.start();
> >>>>
> >>>>  Don't we want to stop worker after we're done with one test?
> >>>
> >>>  +        log.info(getName()+":Started  worker with class:"+javaClass);
> >>>>
> >>>>  Spaces after :?
> >>>
> >>>  +
> >>>> +    }
> >>>> +
> >>>> +    /* (non-Javadoc)
> >>>> +     * @see org.apache.jmeter.samplers.SampleListener#sampleOccurred(
> >>>> org.apache.jmeter.samplers.SampleEvent)
> >>>> +     */
> >>>> +    @Override
> >>>> +    public void sampleOccurred(SampleEvent e) {
> >>>>
> >>>>  Longer name then 'e'? I expect e to be an exception, not an event.
> >>>
> >>>  +        Arguments args = getArguments();
> >>>> +        context = new BackendListenerContext(args);
> >>>> +
> >>>> +        SampleResult sr = backendListenerClient.
> >>>> createSampleResult(context,
> >>>> e.getResult());
> >>>> +        try {
> >>>> +            if (!queue.offer(sr)){ // we failed to add the element
> >>>> first
> >>>> time
> >>>> +                queueWaits++;
> >>>> +                long t1 = System.nanoTime();
> >>>> +                queue.put(sr);
> >>>> +                long t2 = System.nanoTime();
> >>>> +                queueWaitTime += t2-t1;
> >>>>
> >>>>  Will sampleOccurred be called concurrently? If so, than queueWaitTime
> >>> +=
> >>> will not be correct.
> >>>
> >>>  +            }
> >>>> +        } catch (Exception err) {
> >>>> +            log.error("sampleOccurred, failed to queue the sample",
> >>>> err);
> >>>> +        }
> >>>> +    }
> >>>> +
> >>>> +    private static final class Worker extends Thread {
> >>>> +
> >>>> +        private final BlockingQueue<SampleResult> queue;
> >>>> +        private final BackendListenerContext context;
> >>>> +        private final BackendListenerClient backendListenerClient;
> >>>> +        private Worker(Class<?> javaClass, BackendListenerClient
> >>>> backendListenerClient, Arguments arguments, BlockingQueue<SampleResult>
> >>>> q){
> >>>>
> >>>>  Same naming argument as above. clientclass instead of javaClass?
> >>>
> >>>  +            queue = q;
> >>>> +            // Allow BackendListenerClient implementations to get
> >>>> access
> >>>> to test element name
> >>>> +            arguments.addArgument(TestElement.NAME, getName());
> >>>> +            context = new BackendListenerContext(arguments);
> >>>> +            this.backendListenerClient = backendListenerClient;
> >>>> +        }
> >>>> +
> >>>> +
> >>>> +        @Override
> >>>> +        public void run() {
> >>>> +            boolean isDebugEnabled = log.isDebugEnabled();
> >>>> +            List<SampleResult> l = new ArrayList<SampleResult>(queue.
> >>>> size());
> >>>>
> >>>>  samples instead of l?
> >>>
> >>>  +            try {
> >>>> +                boolean eof = false;
> >>>>
> >>>>  endOfLoop?
> >>>
> >>>  +                while (!eof) {
> >>>> +                    if(isDebugEnabled) {
> >>>> +                        log.debug("Thread:"+Thread.
> >>>> currentThread().getName()+"
> >>>> taking SampleResult from queue:"+queue.size());
> >>>> +                    }
> >>>> +                    SampleResult e = queue.take();
> >>>>
> >>>>  Could be named result, or sample instead of e
> >>>
> >>>  +                    if(isDebugEnabled) {
> >>>> +                        log.debug("Thread:"+Thread.
> >>>> currentThread().getName()+"
> >>>> took SampleResult:"+e+", isFinal:" + (e==FINAL_EVENT));
> >>>> +                    }
> >>>> +                    while (!(eof = (e == FINAL_EVENT)) && e != null ) {
> >>>> // try to process as many as possible
> >>>> +                        l.add(e);
> >>>> +                        if(isDebugEnabled) {
> >>>> +                            log.debug("Thread:"+Thread.
> >>>> currentThread().getName()+"
> >>>> polling from queue:"+queue.size());
> >>>> +                        }
> >>>> +                        e = queue.poll(); // returns null if nothing on
> >>>> queue currently
> >>>> +                        if(isDebugEnabled) {
> >>>> +                            log.debug("Thread:"+Thread.
> >>>> currentThread().getName()+"
> >>>> took from queue:"+e+", isFinal:" + (e==FINAL_EVENT));
> >>>> +                        }
> >>>> +                    }
> >>>> +                    if(isDebugEnabled) {
> >>>> +                        log.debug("Thread:"+Thread.
> >>>> currentThread().getName()+
> >>>> +                                " exiting with FINAL EVENT:"+(e ==
> >>>> FINAL_EVENT)
> >>>> +                                +", null:" + (e==null));
> >>>> +                    }
> >>>> +                    int size = l.size();
> >>>>
> >>>>  No need for a temporary variable.
> >>>
> >>>  +                    if (size > 0) {
> >>>> +                        backendListenerClient.handleSampleResults(l,
> >>>> context);
> >>>> +                        l.clear();
> >>>> +                    }
> >>>> +                    if(!eof) {
> >>>> +                        LockSupport.parkNanos(100);
> >>>> +                    }
> >>>> +                }
> >>>> +            } catch (InterruptedException e) {
> >>>> +                // NOOP
> >>>> +            }
> >>>> +            // We may have been interrupted
> >>>> +            int size = l.size();
> >>>> +            if (size > 0) {
> >>>> +                backendListenerClient.handleSampleResults(l, context);
> >>>> +                l.clear();
> >>>> +            }
> >>>>
> >>>>  Same code as a few lines above, could be factored out into a method
> >>> handleSamples(l, context)
> >>>
> >>>  +            log.info("Worker ended");
> >>>> +        }
> >>>> +    }
> >>>> +
> >>>> +
> >>>> +    /**
> >>>> +     * Returns reference to <code>BackendListenerClient</code>.
> >>>>
> >>>>  Could use a {@link...}
> >>>
> >>>  +     *
> >>>> +     *
> >>>> +     * @return BackendListenerClient reference.
> >>>> +     */
> >>>> +    static BackendListenerClient createBackendListenerClientImp
> >>>> l(Class<?>
> >>>> javaClass) {
> >>>> +        if (javaClass == null) { // failed to initialise the class
> >>>> +            return new ErrorBackendListenerClient();
> >>>> +        }
> >>>> +        BackendListenerClient client;
> >>>> +        try {
> >>>> +            client = (BackendListenerClient) javaClass.newInstance();
> >>>> +        } catch (Exception e) {
> >>>> +            log.error("Exception creating: " + javaClass, e);
> >>>> +            client = new ErrorBackendListenerClient();
> >>>> +        }
> >>>> +        return client;
> >>>>
> >>>>  I would return newInstance() in try Block and return new Error.. in
> >>> catch
> >>> Block. javaClass -> clientClass
> >>>
> >>>  +    }
> >>>> +
> >>>> +    /**
> >>>> +     * Method called at the end of the test. This is called only on one
> >>>> instance
> >>>> +     * of BackendListener. This method will loop through all of the
> >>>> other
> >>>> +     * BackendListenerClients which have been registered (automatically
> >>>> in the
> >>>> +     * constructor) and notify them that the test has ended, allowing
> >>>> the
> >>>> +     * BackendListenerClients to cleanup.
> >>>> +     */
> >>>> +    @Override
> >>>> +    public void testEnded() {
> >>>> +        try {
> >>>> +            queue.put(FINAL_EVENT);
> >>>> +        } catch (Exception ex) {
> >>>> +            log.warn("testEnded() with exception:"+ex.getMessage(),
> >>>> ex);
> >>>> +        }
> >>>> +        if (queueWaits > 0) {
> >>>> +            log.warn("QueueWaits: "+queueWaits+"; QueueWaitTime:
> >>>> "+queueWaitTime+" (nanoseconds), you may need to increase queue
> >>>> capacity,
> >>>> see property 'backend_queue_capacity'");
> >>>> +        }
> >>>> +        synchronized (TEAR_DOWN_SET) {
> >>>> +            for (BackendListener backendListener : TEAR_DOWN_SET) {
> >>>> +                BackendListenerClient client = backendListener.
> >>>> backendListenerClient;
> >>>> +                if (client != null) {
> >>>> +                    try {
> >>>> +                        client.teardownTest(backendListener.context);
> >>>> +                    } catch (Exception e) {
> >>>> +                        throw new java.lang.
> >>>> IllegalStateException("Failed
> >>>> calling teardownTest", e);
> >>>>
> >>>>  If we throw an exception here, we will not try every client.
> >>>
> >>>  +                    }
> >>>> +                }
> >>>> +            }
> >>>> +            TEAR_DOWN_SET.clear();
> >>>> +        }
> >>>> +    }
> >>>> +
> >>>> +    /* Implements TestStateListener.testEnded(String) */
> >>>> +    @Override
> >>>> +    public void testEnded(String host) {
> >>>> +        testEnded();
> >>>> +    }
> >>>> +
> >>>> +    /**
> >>>> +     * A {@link BackendListenerClient} implementation used for error
> >>>> handling. If an
> >>>> +     * error occurs while creating the real BackendListenerClient
> >>>> object, it is
> >>>> +     * replaced with an instance of this class. Each time a sample
> >>>> occurs with
> >>>> +     * this class, the result is marked as a failure so the user can
> >>>> see
> >>>> that
> >>>> +     * the test failed.
> >>>> +     */
> >>>> +    static class ErrorBackendListenerClient extends
> >>>> AbstractBackendListenerClient {
> >>>> +        /**
> >>>> +         * Return SampleResult with data on error.
> >>>> +         *
> >>>> +         * @see BackendListenerClient#runTest(JavaSamplerContext)
> >>>> +         */
> >>>> +        @Override
> >>>> +        public void handleSampleResults(List<SampleResult>
> >>>> sampleResults, BackendListenerContext context) {
> >>>> +            log.warn("ErrorBackendListenerClient#handleSampleResult
> >>>> called, noop");
> >>>> +            Thread.yield();
> >>>> +        }
> >>>> +    }
> >>>> +
> >>>> +    /* (non-Javadoc)
> >>>> +     * @see org.apache.jmeter.samplers.SampleListener#sampleStarted(
> >>>> org.apache.jmeter.samplers.SampleEvent)
> >>>> +     */
> >>>> +    @Override
> >>>> +    public void sampleStarted(SampleEvent e) {
> >>>> +        // NOOP
> >>>> +
> >>>> +    }
> >>>> +
> >>>> +    /* (non-Javadoc)
> >>>> +     * @see org.apache.jmeter.samplers.SampleListener#sampleStopped(
> >>>> org.apache.jmeter.samplers.SampleEvent)
> >>>> +     */
> >>>> +    @Override
> >>>> +    public void sampleStopped(SampleEvent e) {
> >>>> +        // NOOP
> >>>> +
> >>>> +    }
> >>>> +
> >>>> +    /**
> >>>> +     * Set the arguments (parameters) for the BackendListenerClient to
> >>>> be executed
> >>>> +     * with.
> >>>> +     *
> >>>> +     * @param args
> >>>> +     *            the new arguments. These replace any existing
> >>>> arguments.
> >>>> +     */
> >>>> +    public void setArguments(Arguments args) {
> >>>> +        setProperty(new TestElementProperty(ARGUMENTS, args));
> >>>> +    }
> >>>> +
> >>>> +    /**
> >>>> +     * Get the arguments (parameters) for the BackendListenerClient to
> >>>> be executed
> >>>> +     * with.
> >>>> +     *
> >>>> +     * @return the arguments
> >>>> +     */
> >>>> +    public Arguments getArguments() {
> >>>> +        return (Arguments) getProperty(ARGUMENTS).getObjectValue();
> >>>> +    }
> >>>> +
> >>>> +    /**
> >>>> +     * Sets the Classname of the BackendListenerClient object
> >>>> +     *
> >>>> +     * @param classname
> >>>> +     *            the new Classname value
> >>>> +     */
> >>>> +    public void setClassname(String classname) {
> >>>> +        setProperty(CLASSNAME, classname);
> >>>> +    }
> >>>> +
> >>>> +    /**
> >>>> +     * Gets the Classname of the BackendListenerClient object
> >>>> +     *
> >>>> +     * @return the Classname value
> >>>> +     */
> >>>> +    public String getClassname() {
> >>>> +        return getPropertyAsString(CLASSNAME);
> >>>> +    }
> >>>> +
> >>>> +    /**
> >>>> +     * Sets the queue size
> >>>> +     *
> >>>> +     * @param queueSize
> >>>> +     *
> >>>> +     */
> >>>> +    public void setQueueSize(int queueSize) {
> >>>> +        setProperty(QUEUE_SIZE, queueSize, DEFAULT_QUEUE_SIZE);
> >>>> +    }
> >>>> +
> >>>> +    /**
> >>>> +     * Gets the queue size
> >>>> +     *
> >>>> +     * @return int queueSize
> >>>> +     */
> >>>> +    public int getQueueSize() {
> >>>> +        return getPropertyAsInt(QUEUE_SIZE, DEFAULT_QUEUE_SIZE);
> >>>> +    }
> >>>> +}
> >>>>
> >>>> Propchange: jmeter/trunk/src/components/org/apache/jmeter/visualizers/
> >>>> backend/BackendListener.java
> >>>> ------------------------------------------------------------
> >>>> ------------------
> >>>>       svn:mime-type = text/plain
> >>>>
> >>>> Added: jmeter/trunk/src/components/org/apache/jmeter/visualizers/
> >>>> backend/BackendListenerClient.java
> >>>> URL: http://svn.apache.org/viewvc/jmeter/trunk/src/components/
> >>>> org/apache/jmeter/visualizers/backend/BackendListenerClient.
> >>>> java?rev=1641081&view=auto
> >>>> ============================================================
> >>>> ==================
> >>>> --- jmeter/trunk/src/components/org/apache/jmeter/visualizers/
> >>>> backend/BackendListenerClient.java (added)
> >>>> +++ jmeter/trunk/src/components/org/apache/jmeter/visualizers/
> >>>> backend/BackendListenerClient.java Sat Nov 22 15:36:37 2014
> >>>> @@ -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.jmeter.visualizers.backend;
> >>>> +
> >>>> +import java.util.List;
> >>>> +
> >>>> +import org.apache.jmeter.config.Arguments;
> >>>> +import org.apache.jmeter.samplers.SampleResult;
> >>>> +
> >>>> +/**
> >>>> + * This interface defines the interactions between the BackendListener
> >>>> and external
> >>>> + * Java programs which can be executed by JMeter. Any Java class which
> >>>> wants to
> >>>> + * be executed as a JMeter test must implement this interface (either
> >>>> directly
> >>>> + * or indirectly through AbstractBackendListenerClient).
> >>>> + * <p>
> >>>> + * JMeter will create one instance of a BackendListenerClient
> >>>> implementation for
> >>>> + * each user/thread in the test. Additional instances may be created
> >>>> for
> >>>> + * internal use by JMeter (for example, to find out what parameters are
> >>>> + * supported by the client).
> >>>> + * <p>
> >>>> + * When the test is started, setupTest() will be called on each
> >>>> thread's
> >>>> + * BackendListenerClient instance to initialize the client. Then
> >>>> handleSampleResult() will be
> >>>> + * called for each SampleResult notification. Finally, teardownTest()
> >>>> will be called
> >>>> + * to allow the client to do any necessary clean-up.
> >>>> + * <p>
> >>>> + * The JMeter BackendListener GUI allows a list of parameters to be
> >>>> defined for the
> >>>> + * test. These are passed to the various test methods through the
> >>>> + * {@link BackendListenerContext}. A list of default parameters can be
> >>>> defined
> >>>> + * through the getDefaultParameters() method. These parameters and any
> >>>> default
> >>>> + * values associated with them will be shown in the GUI. Users can add
> >>>> other
> >>>> + * parameters as well.
> >>>> + * <p>
> >>>> + * When possible, Listeners should extend {@link
> >>>> AbstractBackendListenerClient
> >>>> + * AbstractBackendListenerClient} rather than implementing
> >>>> BackendListenerClient
> >>>> + * directly. This should protect your tests from future changes to the
> >>>> + * interface. While it may be necessary to make changes to the
> >>>> BackendListenerClient
> >>>> + * interface from time to time (therefore requiring changes to any
> >>>> + * implementations of this interface), we intend to make this abstract
> >>>> class
> >>>> + * provide reasonable default implementations of any new methods so
> >>>> that
> >>>> + * subclasses do not necessarily need to be updated for new versions.
> >>>> + * Implementing BackendListenerClient directly will continue to be
> >>>> supported for
> >>>> + * cases where extending this class is not possible (for example, when
> >>>> the
> >>>> + * client class is already a subclass of some other class).
> >>>> + *
> >>>> + * @since 2.13
> >>>> + */
> >>>> +public interface BackendListenerClient {
> >>>> +    /**
> >>>> +     * Do any initialization required by this client. It is generally
> >>>> +     * recommended to do any initialization such as getting parameter
> >>>> values in
> >>>> +     * the setupTest method rather than the runTest method in order to
> >>>> add as
> >>>> +     * little overhead as possible to the test.
> >>>> +     *
> >>>> +     * @param context
> >>>> +     *            the context to run with. This provides access to
> >>>> +     *            initialization parameters.
> >>>> +     */
> >>>> +    void setupTest(BackendListenerContext context) throws Exception;
> >>>> +
> >>>> +    /**
> >>>> +     * Perform a single sample for each iteration. This method returns
> >>>> a
> >>>> +     * <code>SampleResult</code> object. <code>SampleResult</code> has
> >>>> many
> >>>> +     * fields which can be used. At a minimum, the test should use
> >>>> +     * <code>SampleResult.sampleStart</code> and
> >>>> +     * <code>SampleResult.sampleEnd</code>to set the time that the
> >>>> test
> >>>>
> >>>>  use {@link..} instead of <code>..?
> >>>
> >>>  +     * required to execute. It is also a good idea to set the
> >>>> sampleLabel and
> >>>> +     * the successful flag.
> >>>> +     *
> >>>> +     * @see org.apache.jmeter.samplers.SampleResult#sampleStart()
> >>>> +     * @see org.apache.jmeter.samplers.SampleResult#sampleEnd()
> >>>> +     * @see org.apache.jmeter.samplers.SampleResult#setSuccessful(
> >>>> boolean)
> >>>> +     * @see org.apache.jmeter.samplers.SampleResult#setSampleLabel(
> >>>> String)
> >>>> +     *
> >>>> +     * @param context
> >>>> +     *            the context to run with. This provides access to
> >>>> +     *            initialization parameters.
> >>>> +     *
> >>>> +     */
> >>>> +    void handleSampleResults(List<SampleResult> sampleResults,
> >>>> BackendListenerContext context);
> >>>> +
> >>>> +    /**
> >>>> +     * Do any clean-up required by this test at the end of a test run.
> >>>> +     *
> >>>> +     * @param context
> >>>> +     *            the context to run with. This provides access to
> >>>> +     *            initialization parameters.
> >>>> +     */
> >>>> +    void teardownTest(BackendListenerContext context) throws
> >>>> Exception;
> >>>> +
> >>>> +    /**
> >>>> +     * Provide a list of parameters which this test supports. Any
> >>>> parameter
> >>>> +     * names and associated values returned by this method will appear
> >>>> in the
> >>>> +     * GUI by default so the user doesn't have to remember the exact
> >>>> names. The
> >>>> +     * user can add other parameters which are not listed here. If this
> >>>> method
> >>>> +     * returns null then no parameters will be listed. If the value for
> >>>> some
> >>>> +     * parameter is null then that parameter will be listed in the GUI
> >>>> with an
> >>>> +     * empty value.
> >>>> +     *
> >>>> +     * @return a specification of the parameters used by this test
> >>>> which
> >>>> should
> >>>> +     *         be listed in the GUI, or null if no parameters should be
> >>>> listed.
> >>>> +     */
> >>>> +    Arguments getDefaultParameters();
> >>>> +
> >>>> +    /**
> >>>> +     *
> >>>> +     * @param context
> >>>> +     * @param result
> >>>> +     * @return
> >>>> +     */
> >>>> +    SampleResult createSampleResult(
> >>>> +            BackendListenerContext context, SampleResult result);
> >>>> +}
> >>>>
> >>>> Propchange: jmeter/trunk/src/components/org/apache/jmeter/visualizers/
> >>>> backend/BackendListenerClient.java
> >>>> ------------------------------------------------------------
> >>>> ------------------
> >>>>       svn:mime-type = text/plain
> >>>>
> >>>> Added: jmeter/trunk/src/components/org/apache/jmeter/visualizers/
> >>>> backend/
> >>>> BackendListenerContext.java
> >>>> URL: http://svn.apache.org/viewvc/jmeter/trunk/src/components/
> >>>> org/apache/jmeter/visualizers/backend/BackendListenerContext.java?
> >>>> rev=1641081&view=auto
> >>>> ============================================================
> >>>> ==================
> >>>> --- jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/
> >>>> BackendListenerContext.java
> >>>> (added)
> >>>> +++ jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/
> >>>> BackendListenerContext.java
> >>>> Sat Nov 22 15:36:37 2014
> >>>> @@ -0,0 +1,237 @@
> >>>> +/*
> >>>> +
> >>>> + * 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.jmeter.visualizers.backend;
> >>>> +
> >>>> +import java.util.Iterator;
> >>>> +import java.util.Map;
> >>>> +
> >>>> +import org.apache.jmeter.config.Arguments;
> >>>> +import org.apache.jorphan.logging.LoggingManager;
> >>>> +import org.apache.log.Logger;
> >>>> +
> >>>> +/**
> >>>> + * BackendListenerContext is used to provide context information to a
> >>>> + * BackendListenerClient implementation. This currently consists of the
> >>>> + * initialization parameters which were specified in the GUI.
> >>>> + * @since 2.13
> >>>> + */
> >>>> +public class BackendListenerContext {
> >>>> +    /*
> >>>> +     * Implementation notes:
> >>>> +     *
> >>>> +     * All of the methods in this class are currently read-only. If
> >>>> update
> >>>> +     * methods are included in the future, they should be defined so
> >>>> that a
> >>>> +     * single instance of BackendListenerContext can be associated with
> >>>> each thread.
> >>>> +     * Therefore, no synchronization should be needed. The same
> >>>> instance
> >>>> should
> >>>> +     * be used for the call to setupTest, all calls to runTest, and the
> >>>> call to
> >>>> +     * teardownTest.
> >>>> +     */
> >>>> +
> >>>> +    /** Logging */
> >>>> +    private static final Logger log = LoggingManager.
> >>>> getLoggerForClass();
> >>>>
> >>>>  See naming comments for logger above
> >>>
> >>>  +
> >>>> +    /**
> >>>> +     * Map containing the initialization parameters for the
> >>>> BackendListenerClient.
> >>>> +     */
> >>>> +    private final Map<String, String> params;
> >>>> +
> >>>> +    /**
> >>>> +     *
> >>>> +     * @param args
> >>>> +     *            the initialization parameters.
> >>>> +     */
> >>>> +    public BackendListenerContext(Arguments args) {
> >>>> +        this.params = args.getArgumentsAsMap();
> >>>> +    }
> >>>> +
> >>>> +    /**
> >>>> +     * Determine whether or not a value has been specified for the
> >>>> parameter
> >>>> +     * with this name.
> >>>> +     *
> >>>> +     * @param name
> >>>> +     *            the name of the parameter to test
> >>>> +     * @return true if the parameter value has been specified, false
> >>>> otherwise.
> >>>> +     */
> >>>> +    public boolean containsParameter(String name) {
> >>>>
> >>>>  hasParameter instead of containsParameter?
> >>>
> >>>  +        return params.containsKey(name);
> >>>> +    }
> >>>> +
> >>>> +    /**
> >>>> +     * Get an iterator of the parameter names. Each entry in the
> >>>> Iterator is a
> >>>> +     * String.
> >>>> +     *
> >>>> +     * @return an Iterator of Strings listing the names of the
> >>>> parameters which
> >>>> +     *         have been specified for this test.
> >>>> +     */
> >>>> +    public Iterator<String> getParameterNamesIterator() {
> >>>> +        return params.keySet().iterator();
> >>>> +    }
> >>>> +
> >>>> +    /**
> >>>> +     * Get the value of a specific parameter as a String, or null if
> >>>> the
> >>>> value
> >>>> +     * was not specified.
> >>>> +     *
> >>>> +     * @param name
> >>>> +     *            the name of the parameter whose value should be
> >>>> retrieved
> >>>> +     * @return the value of the parameter, or null if the value was not
> >>>> +     *         specified
> >>>> +     */
> >>>> +    public String getParameter(String name) {
> >>>> +        return getParameter(name, null);
> >>>> +    }
> >>>> +
> >>>> +    /**
> >>>> +     * Get the value of a specified parameter as a String, or return
> >>>> the
> >>>> +     * specified default value if the value was not specified.
> >>>> +     *
> >>>> +     * @param name
> >>>> +     *            the name of the parameter whose value should be
> >>>> retrieved
> >>>> +     * @param defaultValue
> >>>> +     *            the default value to return if the value of this
> >>>> parameter was
> >>>> +     *            not specified
> >>>> +     * @return the value of the parameter, or the default value if the
> >>>> parameter
> >>>> +     *         was not specified
> >>>> +     */
> >>>> +    public String getParameter(String name, String defaultValue) {
> >>>> +        if (params == null || !params.containsKey(name)) {
> >>>> +            return defaultValue;
> >>>> +        }
> >>>> +        return params.get(name);
> >>>> +    }
> >>>> +
> >>>> +    /**
> >>>> +     * Get the value of a specified parameter as an integer. An
> >>>> exception will
> >>>> +     * be thrown if the parameter is not specified or if it is not an
> >>>> integer.
> >>>> +     * The value may be specified in decimal, hexadecimal, or octal, as
> >>>> defined
> >>>> +     * by Integer.decode().
> >>>> +     *
> >>>> +     * @param name
> >>>> +     *            the name of the parameter whose value should be
> >>>> retrieved
> >>>> +     * @return the value of the parameter
> >>>> +     *
> >>>> +     * @throws NumberFormatException
> >>>> +     *             if the parameter is not specified or is not an
> >>>> integer
> >>>> +     *
> >>>> +     * @see java.lang.Integer#decode(java.lang.String)
> >>>> +     */
> >>>> +    public int getIntParameter(String name) throws
> >>>> NumberFormatException
> >>>> {
> >>>> +        if (params == null || !params.containsKey(name)) {
> >>>> +            throw new NumberFormatException("No value for parameter
> >>>> named '" + name + "'.");
> >>>>
> >>>>  I would expect an IllegalArgumentException, if no parameter of that
> >>> name
> >>> is found
> >>>
> >>>  +        }
> >>>> +
> >>>> +        return Integer.decode(params.get(name)).intValue();
> >>>> +    }
> >>>> +
> >>>> +    /**
> >>>> +     * Get the value of a specified parameter as an integer, or return
> >>>> the
> >>>> +     * specified default value if the value was not specified or is not
> >>>> an
> >>>> +     * integer. A warning will be logged if the value is not an
> >>>> integer.
> >>>> The
> >>>> +     * value may be specified in decimal, hexadecimal, or octal, as
> >>>> defined by
> >>>> +     * Integer.decode().
> >>>> +     *
> >>>> +     * @param name
> >>>> +     *            the name of the parameter whose value should be
> >>>> retrieved
> >>>> +     * @param defaultValue
> >>>> +     *            the default value to return if the value of this
> >>>> parameter was
> >>>> +     *            not specified
> >>>> +     * @return the value of the parameter, or the default value if the
> >>>> parameter
> >>>> +     *         was not specified
> >>>> +     *
> >>>> +     * @see java.lang.Integer#decode(java.lang.String)
> >>>> +     */
> >>>> +    public int getIntParameter(String name, int defaultValue) {
> >>>> +        if (params == null || !params.containsKey(name)) {
> >>>> +            return defaultValue;
> >>>> +        }
> >>>> +
> >>>> +        try {
> >>>> +            return Integer.decode(params.get(name)).intValue();
> >>>> +        } catch (NumberFormatException e) {
> >>>> +            log.warn("Value for parameter '" + name + "' not an
> >>>> integer:
> >>>> '" + params.get(name) + "'.  Using default: '"
> >>>> +                    + defaultValue + "'.", e);
> >>>> +            return defaultValue;
> >>>> +        }
> >>>> +    }
> >>>> +
> >>>> +    /**
> >>>> +     * Get the value of a specified parameter as a long. An exception
> >>>> will be
> >>>> +     * thrown if the parameter is not specified or if it is not a long.
> >>>> The
> >>>> +     * value may be specified in decimal, hexadecimal, or octal, as
> >>>> defined by
> >>>> +     * Long.decode().
> >>>> +     *
> >>>> +     * @param name
> >>>> +     *            the name of the parameter whose value should be
> >>>> retrieved
> >>>> +     * @return the value of the parameter
> >>>> +     *
> >>>> +     * @throws NumberFormatException
> >>>> +     *             if the parameter is not specified or is not a long
> >>>> +     *
> >>>> +     * @see Long#decode(String)
> >>>> +     */
> >>>> +    public long getLongParameter(String name) throws
> >>>> NumberFormatException {
> >>>> +        if (params == null || !params.containsKey(name)) {
> >>>> +            throw new NumberFormatException("No value for parameter
> >>>> named '" + name + "'.");
> >>>> +        }
> >>>> +
> >>>> +        return Long.decode(params.get(name)).longValue();
> >>>> +    }
> >>>> +
> >>>> +    /**
> >>>> +     * Get the value of a specified parameter as along, or return the
> >>>> specified
> >>>> +     * default value if the value was not specified or is not a long. A
> >>>> warning
> >>>> +     * will be logged if the value is not a long. The value may be
> >>>> specified in
> >>>> +     * decimal, hexadecimal, or octal, as defined by Long.decode().
> >>>> +     *
> >>>> +     * @param name
> >>>> +     *            the name of the parameter whose value should be
> >>>> retrieved
> >>>> +     * @param defaultValue
> >>>> +     *            the default value to return if the value of this
> >>>> parameter was
> >>>> +     *            not specified
> >>>> +     * @return the value of the parameter, or the default value if the
> >>>> parameter
> >>>> +     *         was not specified
> >>>> +     *
> >>>> +     * @see Long#decode(String)
> >>>> +     */
> >>>> +    public long getLongParameter(String name, long defaultValue) {
> >>>> +        if (params == null || !params.containsKey(name)) {
> >>>> +            return defaultValue;
> >>>> +        }
> >>>> +        try {
> >>>> +            return Long.decode(params.get(name)).longValue();
> >>>> +        } catch (NumberFormatException e) {
> >>>> +            log.warn("Value for parameter '" + name + "' not a long: '"
> >>>> + params.get(name) + "'.  Using default: '"
> >>>> +                    + defaultValue + "'.", e);
> >>>> +            return defaultValue;
> >>>> +        }
> >>>> +    }
> >>>> +
> >>>> +    /**
> >>>> +     *
> >>>> +     * @param name
> >>>> +     * @param defaultValue
> >>>> +     * @return
> >>>>
> >>>>  No javadoc? Again three warnings more :)
> >>>
> >>>  +     */
> >>>> +    public boolean getBooleanParameter(String name, boolean
> >>>> defaultValue) {
> >>>> +        if (params == null || !params.containsKey(name)) {
> >>>> +            return defaultValue;
> >>>> +        }
> >>>> +        return Boolean.valueOf(params.get(name));
> >>>> +    }
> >>>> +}
> >>>>
> >>>> Propchange: jmeter/trunk/src/components/org/apache/jmeter/visualizers/
> >>>> backend/BackendListenerContext.java
> >>>> ------------------------------------------------------------
> >>>> ------------------
> >>>>       svn:mime-type = text/plain
> >>>>
> >>>> Added: jmeter/trunk/src/components/org/apache/jmeter/visualizers/
> >>>> backend/BackendListenerGui.java
> >>>> URL: http://svn.apache.org/viewvc/jmeter/trunk/src/components/
> >>>> org/apache/jmeter/visualizers/backend/BackendListenerGui.
> >>>> java?rev=1641081&view=auto
> >>>> ============================================================
> >>>> ==================
> >>>> --- jmeter/trunk/src/components/org/apache/jmeter/visualizers/
> >>>> backend/BackendListenerGui.java (added)
> >>>> +++ jmeter/trunk/src/components/org/apache/jmeter/visualizers/
> >>>> backend/BackendListenerGui.java Sat Nov 22 15:36:37 2014
> >>>> @@ -0,0 +1,282 @@
> >>>> +/*
> >>>> + * 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.jmeter.visualizers.backend;
> >>>> +
> >>>> +import java.awt.BorderLayout;
> >>>> +import java.awt.event.ActionEvent;
> >>>> +import java.awt.event.ActionListener;
> >>>> +import java.util.ArrayList;
> >>>> +import java.util.HashSet;
> >>>> +import java.util.List;
> >>>> +import java.util.Map;
> >>>> +import java.util.Set;
> >>>> +
> >>>> +import javax.swing.ComboBoxModel;
> >>>> +import javax.swing.JComboBox;
> >>>> +import javax.swing.JLabel;
> >>>> +import javax.swing.JPanel;
> >>>> +import javax.swing.JTextField;
> >>>> +
> >>>> +import org.apache.jmeter.config.Argument;
> >>>> +import org.apache.jmeter.config.Arguments;
> >>>> +import org.apache.jmeter.config.gui.ArgumentsPanel;
> >>>> +import org.apache.jmeter.gui.util.HorizontalPanel;
> >>>> +import org.apache.jmeter.testelement.TestElement;
> >>>> +import org.apache.jmeter.testelement.property.PropertyIterator;
> >>>> +import org.apache.jmeter.util.JMeterUtils;
> >>>> +import org.apache.jmeter.visualizers.gui.AbstractListenerGui;
> >>>> +import org.apache.jorphan.logging.LoggingManager;
> >>>> +import org.apache.jorphan.reflect.ClassFinder;
> >>>> +import org.apache.log.Logger;
> >>>> +
> >>>> +/**
> >>>> + * The <code>BackendListenerGui</code> class provides the user
> >>>> interface for the
> >>>> + * {@link BackendListener} object.
> >>>> + * @since 2.13
> >>>> + */
> >>>> +public class BackendListenerGui extends AbstractListenerGui implements
> >>>> ActionListener {
> >>>> +
> >>>> +    /**
> >>>> +     *
> >>>> +     */
> >>>> +    private static final long serialVersionUID = 4331668988576438604L;
> >>>> +
> >>>> +    /** Logging */
> >>>> +    private static final Logger log = LoggingManager.
> >>>> getLoggerForClass();
> >>>> +
> >>>> +    /** A combo box allowing the user to choose a backend class. */
> >>>> +    private JComboBox classnameCombo;
> >>>> +
> >>>> +    /**
> >>>> +     * A field allowing the user to specify the size of Queue
> >>>> +     */
> >>>> +    private JTextField queueSize;
> >>>> +
> >>>> +    /** A panel allowing the user to set arguments for this test. */
> >>>> +    private ArgumentsPanel argsPanel;
> >>>> +
> >>>> +    /**
> >>>> +     * Create a new BackendListenerGui as a standalone component.
> >>>> +     */
> >>>> +    public BackendListenerGui() {
> >>>> +        super();
> >>>> +        init();
> >>>> +    }
> >>>> +
> >>>> +
> >>>> +    /** {@inheritDoc} */
> >>>> +    @Override
> >>>> +    public String getLabelResource() {
> >>>> +        return "backend_listener"; // $NON-NLS-1$
> >>>> +    }
> >>>> +
> >>>> +    /**
> >>>> +     * Initialize the GUI components and layout.
> >>>> +     */
> >>>> +    private void init() {// called from ctor, so must not be
> >>>> overridable
> >>>> +        setLayout(new BorderLayout(0, 5));
> >>>> +
> >>>> +        setBorder(makeBorder());
> >>>> +        add(makeTitlePanel(), BorderLayout.NORTH);
> >>>> +
> >>>> +        JPanel classnameRequestPanel = new JPanel(new BorderLayout(0,
> >>>> 5));
> >>>> +        classnameRequestPanel.add(createClassnamePanel(),
> >>>> BorderLayout.NORTH);
> >>>> +        classnameRequestPanel.add(createParameterPanel(),
> >>>> BorderLayout.CENTER);
> >>>> +
> >>>> +        add(classnameRequestPanel, BorderLayout.CENTER);
> >>>> +    }
> >>>> +
> >>>> +    /**
> >>>> +     * Create a panel with GUI components allowing the user to select a
> >>>> test
> >>>> +     * class.
> >>>> +     *
> >>>> +     * @return a panel containing the relevant components
> >>>> +     */
> >>>> +    private JPanel createClassnamePanel() {
> >>>> +        List<String> possibleClasses = new ArrayList<String>();
> >>>> +
> >>>> +        try {
> >>>> +            // Find all the classes which implement the
> >>>> BackendListenerClient
> >>>> +            // interface.
> >>>> +            possibleClasses = ClassFinder.findClassesThatExtend(
> >>>> JMeterUtils.getSearchPaths(),
> >>>> +                    new Class[] { BackendListenerClient.class });
> >>>> +
> >>>> +            // Remove the BackendListener class from the list since it
> >>>> only
> >>>>
> >>>>  ErrorBackendListener
> >>>
> >>>  +            // implements the interface for error conditions.
> >>>> +
> >>>> +            possibleClasses.remove(BackendListener.class.getName() +
> >>>> "$ErrorBackendListenerClient");
> >>>> +        } catch (Exception e) {
> >>>> +            log.debug("Exception getting interfaces.", e);
> >>>> +        }
> >>>> +
> >>>> +        JLabel label = new JLabel(JMeterUtils.getResString("backend_
> >>>> listener_classname"));
> >>>> // $NON-NLS-1$
> >>>> +
> >>>> +        classnameCombo = new JComboBox(possibleClasses.toArray());
> >>>> +        classnameCombo.addActionListener(this);
> >>>> +        classnameCombo.setEditable(false);
> >>>> +        label.setLabelFor(classnameCombo);
> >>>> +
> >>>> +        HorizontalPanel classNamePanel = new HorizontalPanel();
> >>>> +        classNamePanel.add(label);
> >>>> +        classNamePanel.add(classnameCombo);
> >>>> +
> >>>> +        queueSize = new JTextField("", 5);
> >>>> +        queueSize.setName("Queue Size"); //$NON-NLS-1$
> >>>> +        JLabel queueSizeLabel = new JLabel(JMeterUtils.
> >>>> getResString("backend_listener_queue_size")); // $NON-NLS-1$
> >>>> +        queueSizeLabel.setLabelFor(queueSize);
> >>>> +        HorizontalPanel queueSizePanel = new HorizontalPanel();
> >>>> +        queueSizePanel.add(queueSizeLabel, BorderLayout.WEST);
> >>>> +        queueSizePanel.add(queueSize);
> >>>> +
> >>>> +        JPanel panel = new JPanel(new BorderLayout(0, 5));
> >>>> +        panel.add(classNamePanel, BorderLayout.NORTH);
> >>>> +        panel.add(queueSizePanel, BorderLayout.CENTER);
> >>>> +        return panel;
> >>>> +    }
> >>>> +
> >>>> +    /**
> >>>> +     * Handle action events for this component. This method currently
> >>>> handles
> >>>> +     * events for the classname combo box.
> >>>> +     *
> >>>> +     * @param evt
> >>>>
> >>>>  I would spend the few extra characters to make it event instead of evt
> >>>
> >>>  +     *            the ActionEvent to be handled
> >>>> +     */
> >>>> +    @Override
> >>>> +    public void actionPerformed(ActionEvent evt) {
> >>>> +        if (evt.getSource() == classnameCombo) {
> >>>> +            String className = ((String) classnameCombo.
> >>>> getSelectedItem()).trim();
> >>>> +            try {
> >>>> +                BackendListenerClient client = (BackendListenerClient)
> >>>> Class.forName(className, true,
> >>>> +                        Thread.currentThread().
> >>>> getContextClassLoader()).
> >>>> newInstance();
> >>>> +
> >>>> +                Arguments currArgs = new Arguments();
> >>>> +                argsPanel.modifyTestElement(currArgs);
> >>>> +                Map<String, String> currArgsMap =
> >>>> currArgs.getArgumentsAsMap();
> >>>> +
> >>>> +                Arguments newArgs = new Arguments();
> >>>> +                Arguments testParams = null;
> >>>> +                try {
> >>>> +                    testParams = client.getDefaultParameters();
> >>>> +                } catch (AbstractMethodError e) {
> >>>> +                    log.warn("BackendListenerClient doesn't implement
> >>>> "
> >>>> +                            + "getDefaultParameters.  Default
> >>>> parameters
> >>>> won't "
> >>>> +                            + "be shown.  Please update your client
> >>>> class: " + className);
> >>>> +                }
> >>>> +
> >>>> +                if (testParams != null) {
> >>>> +                    PropertyIterator i = testParams.getArguments().
> >>>> iterator();
> >>>>
> >>>>  I would try a for loop instead of explicitly using an iterator
> >>>
> >>>  +                    while (i.hasNext()) {
> >>>> +                        Argument arg = (Argument)
> >>>> i.next().getObjectValue();
> >>>> +                        String name = arg.getName();
> >>>> +                        String value = arg.getValue();
> >>>> +
> >>>> +                        // If a user has set parameters in one test,
> >>>> and
> >>>> then
> >>>> +                        // selects a different test which supports the
> >>>> same
> >>>> +                        // parameters, those parameters should have the
> >>>> same
> >>>> +                        // values that they did in the original test.
> >>>> +                        if (currArgsMap.containsKey(name)) {
> >>>> +                            String newVal = currArgsMap.get(name);
> >>>> +                            if (newVal != null && newVal.length() > 0)
> >>>> {
> >>>> +                                value = newVal;
> >>>> +                            }
> >>>> +                        }
> >>>> +                        newArgs.addArgument(name, value);
> >>>> +                    }
> >>>> +                }
> >>>> +
> >>>> +                argsPanel.configure(newArgs);
> >>>> +            } catch (Exception e) {
> >>>> +                log.error("Error getting argument list for " +
> >>>> className, e);
> >>>> +            }
> >>>> +        }
> >>>> +    }
> >>>> +
> >>>> +    /**
> >>>> +     * Create a panel containing components allowing the user to
> >>>> provide
> >>>> +     * arguments to be passed to the test class instance.
> >>>> +     *
> >>>> +     * @return a panel containing the relevant components
> >>>> +     */
> >>>> +    private JPanel createParameterPanel() {
> >>>> +        argsPanel = new ArgumentsPanel(JMeterUtils.
> >>>> getResString("backend_listener_paramtable")); // $NON-NLS-1$
> >>>> +        return argsPanel;
> >>>> +    }
> >>>> +
> >>>> +    /** {@inheritDoc} */
> >>>> +    @Override
> >>>> +    public void configure(TestElement config) {
> >>>> +        super.configure(config);
> >>>> +
> >>>> +        argsPanel.configure((Arguments) config.getProperty(
> >>>> BackendListener.ARGUMENTS).getObjectValue());
> >>>> +
> >>>> +        String className = config.getPropertyAsString(
> >>>> BackendListener.CLASSNAME);
> >>>> +        if(checkContainsClassName(classnameCombo.getModel(),
> >>>> className)) {
> >>>> +            classnameCombo.setSelectedItem(className);
> >>>> +        } else {
> >>>> +            log.error("Error setting class:'"+className+"' in
> >>>> BackendListener: "+getName()+
> >>>> +                    ", check for a missing jar in your jmeter
> >>>> 'search_paths' and 'plugin_dependency_paths' properties");
> >>>> +        }
> >>>> +        queueSize.setText(Integer.toString(((BackendListener)
> >>>> config).getQueueSize()));
> >>>> +    }
> >>>> +
> >>>> +    /**
> >>>> +     * Check combo contains className
> >>>> +     * @param model ComboBoxModel
> >>>> +     * @param className String class name
> >>>> +     * @return boolean
> >>>>
> >>>>  explain "boolean" or the other params a bit more?
> >>>
> >>>  +     */
> >>>> +    private static final boolean checkContainsClassName(ComboBoxModel
> >>>> model, String className) {
> >>>> +        int size = model.getSize();
> >>>> +        Set<String> set = new HashSet<String>(size);
> >>>> +        for (int i = 0; i < size; i++) {
> >>>> +            set.add((String)model.getElementAt(i));
> >>>> +        }
> >>>> +        return set.contains(className);
> >>>> +    }
> >>>> +
> >>>> +    /** {@inheritDoc} */
> >>>> +    @Override
> >>>> +    public TestElement createTestElement() {
> >>>> +        BackendListener config = new BackendListener();
> >>>> +        modifyTestElement(config);
> >>>> +        return config;
> >>>> +    }
> >>>> +
> >>>> +    /** {@inheritDoc} */
> >>>> +    @Override
> >>>> +    public void modifyTestElement(TestElement config) {
> >>>> +        configureTestElement(config);
> >>>> +        BackendListener backendListener = (BackendListener) config;
> >>>> +        backendListener.setArguments((Arguments)
> >>>> argsPanel.createTestElement());
> >>>> +        backendListener.setClassname(String.valueOf(classnameCombo.
> >>>> getSelectedItem()));
> >>>> +        backendListener.setQueueSize(Integer.parseInt(queueSize.
> >>>> getText()));
> >>>> +
> >>>> +    }
> >>>> +
> >>>>
> >>>
> 



Re: svn commit: r1641081 - in /jmeter/trunk: ./ bin/ res/maven/ src/components/org/apache/jmeter/visualizers/backend/ src/core/org/apache/jmeter/resources/ src/core/org/apache/jmeter/samplers/ src/core/org/apache/jmeter/save/ xdocs/ xdocs/usermanual/

Posted by Felix Schumacher <fe...@internetallee.de>.
Am 23.11.2014 um 12:22 schrieb Philippe Mouawad:
> Thanks a lot for your review which pointed to a synchronisation issue that
> I fixed, good catch!
>
> I think I took all your notes into account, let me know if I forgot
> something.
Well, I have forgotten to mention at least two things:

In PickleGraphiteMetricsSender.java on line 125 you emit a debug 
message, while a few lines below the same message has a criticality of 
warn. Seems a bit strange to me.

In GraphiteBackendListenerClient you have defined samplersToFilter to be 
transient. Why? Is the ListenerClient going to be serialized? If so it 
should be marked as serializable.

Regards
  Felix
>
> Regards
> Philippe
>
> On Sunday, November 23, 2014, Felix Schumacher <
> felix.schumacher@internetallee.de> wrote:
>
>> Hi Phillipe,
>> Am 22.11.2014 um 19:29 schrieb Philippe Mouawad:
>>
>>> Hi Felix,
>>> As I said in thread, I commited code and will improve, feel free to fix
>>> javadocs issues on your side.
>>> I will review your comment.
>>>
>>> I have spent many hours if not days on this code and I am aware it is not
>>> yet fully completed (although tests are promising) but my aim when
>>> commiting it was to have feedback and help to finish it.
>>>
>> I did not mean to offend you. I can clearly see, that you put a lot of
>> effort
>> in this listener and I will surely try to integrate jmeter into our
>> collectd server.
>>
>> Regards
>>   Felix
>>
>>> Regards
>>> Philippe
>>>
>>> On Sat, Nov 22, 2014 at 7:21 PM, Felix Schumacher <
>>> felix.schumacher@internetallee.de> wrote:
>>>
>>>   Hello Philippe,
>>>> I have hidden a few comments inside the cited code.
>>>> They are mostly around javadoc and naming things.
>>>>
>>>> Am 22.11.2014 um 16:36 schrieb pmouawad@apache.org:
>>>>
>>>>   Author: pmouawad
>>>>> Date: Sat Nov 22 15:36:37 2014
>>>>> New Revision: 1641081
>>>>>
>>>>> URL: http://svn.apache.org/r1641081
>>>>> Log:
>>>>> Bug 55932 - Create a Async BackendListener to allow easy plug of new
>>>>> listener (Graphite, JDBC, Console,...)
>>>>> Bugzilla Id: 55932
>>>>>
>>>>> Added:
>>>>>        jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>>>>> backend/
>>>>>        jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>>>>> backend/
>>>>> AbstractBackendListenerClient.java   (with props)
>>>>>        jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>>>>> backend/BackendListener.java
>>>>>    (with props)
>>>>>        jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>>>>> backend/BackendListenerClient.java   (with props)
>>>>>        jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>>>>> backend/BackendListenerContext.java
>>>>>    (with props)
>>>>>        jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>>>>> backend/BackendListenerGui.java   (with props)
>>>>>        jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>>>>> backend/SamplerMetric.java
>>>>>    (with props)
>>>>> Modified:
>>>>>        jmeter/trunk/bin/saveservice.properties
>>>>>        jmeter/trunk/build.properties
>>>>>        jmeter/trunk/build.xml
>>>>>        jmeter/trunk/eclipse.classpath
>>>>>        jmeter/trunk/res/maven/ApacheJMeter_parent.pom
>>>>>        jmeter/trunk/src/core/org/apache/jmeter/resources/
>>>>> messages.properties
>>>>>        jmeter/trunk/src/core/org/apache/jmeter/resources/
>>>>> messages_fr.properties
>>>>>        jmeter/trunk/src/core/org/apache/jmeter/samplers/
>>>>> SampleResult.java
>>>>>        jmeter/trunk/src/core/org/apache/jmeter/save/SaveService.java
>>>>>        jmeter/trunk/xdocs/changes.xml
>>>>>        jmeter/trunk/xdocs/usermanual/component_reference.xml
>>>>>
>>>>> Modified: jmeter/trunk/bin/saveservice.properties
>>>>> URL: http://svn.apache.org/viewvc/jmeter/trunk/bin/saveservice.
>>>>> properties?rev=1641081&r1=1641080&r2=1641081&view=diff
>>>>> ============================================================
>>>>> ==================
>>>>> --- jmeter/trunk/bin/saveservice.properties (original)
>>>>> +++ jmeter/trunk/bin/saveservice.properties Sat Nov 22 15:36:37 2014
>>>>> @@ -53,7 +53,8 @@ _file_version=$Revision$
>>>>>     # 2.5 = 2.10
>>>>>     # 2.6 = 2.11
>>>>>     # 2.7 = 2.12
>>>>> -_version=2.7
>>>>> +# 2.8 = 2.13
>>>>> +_version=2.8
>>>>>     #
>>>>>     #
>>>>>     # Character set encoding used to read and write JMeter XML files and
>>>>> CSV results
>>>>> @@ -78,6 +79,8 @@ AssertionVisualizer=org.apache.jmeter.vi
>>>>>     AuthManager=org.apache.jmeter.protocol.http.control.AuthManager
>>>>>     Authorization=org.apache.jmeter.protocol.http.control.Authorization
>>>>>     AuthPanel=org.apache.jmeter.protocol.http.gui.AuthPanel
>>>>> +BackendListener=org.apache.jmeter.visualizers.backend.BackendListener
>>>>> +BackendListenerGui=org.apache.jmeter.visualizers.
>>>>> backend.BackendListenerGui
>>>>>     BarChart=org.apache.jmeter.testelement.BarChart
>>>>>     BarChartGui=org.apache.jmeter.report.gui.BarChartGui
>>>>>     BeanShellAssertion=org.apache.jmeter.assertions.BeanShellAssertion
>>>>>
>>>>> Modified: jmeter/trunk/build.properties
>>>>> URL: http://svn.apache.org/viewvc/jmeter/trunk/build.properties?
>>>>> rev=1641081&r1=1641080&r2=1641081&view=diff
>>>>> ============================================================
>>>>> ==================
>>>>> --- jmeter/trunk/build.properties (original)
>>>>> +++ jmeter/trunk/build.properties Sat Nov 22 15:36:37 2014
>>>>> @@ -118,11 +118,21 @@ commons-logging.loc         = ${maven2.r
>>>>>     #commons-logging.md5         = E2C390FE739B2550A218262B28F290CE
>>>>>     commons-logging.md5         = 040b4b4d8eac886f6b4a2a3bd2f31b00
>>>>>     +commons-math3.version         = 3.3
>>>>> +commons-math3.jar             = commons-math3-${commons-math3.
>>>>> version}.jar
>>>>> +commons-math3.loc             = ${maven2.repo}/org/apache/
>>>>> commons/commons-math3/${commons-math3.version}
>>>>> +commons-math3.md5             = 87346cf2772dc2becf106c45e0f63863
>>>>> +
>>>>>     commons-net.version         = 3.3
>>>>>     commons-net.jar             = commons-net-${commons-net.version}.jar
>>>>>     commons-net.loc             = ${maven2.repo}/commons-net/
>>>>> commons-net/${commons-net.version}
>>>>>     commons-net.md5             = c077ca61598e9c21f43f8b6488fbbee9
>>>>>     +commons-pool2.version         = 2.2
>>>>> +commons-pool2.jar             = commons-pool2-${commons-pool2.
>>>>> version}.jar
>>>>> +commons-pool2.loc             = ${maven2.repo}/org/apache/
>>>>> commons/commons-pool2/${commons-pool2.version}
>>>>> +commons-pool2.md5             = 51b56c92883812c56fbeb339866ce2df
>>>>> +
>>>>>     # dnsjava for DNSCacheManager
>>>>>     dnsjava.version             = 2.1.6
>>>>>     dnsjava.jar                 = dnsjava-${dnsjava.version}.jar
>>>>>
>>>>> Modified: jmeter/trunk/build.xml
>>>>> URL: http://svn.apache.org/viewvc/jmeter/trunk/build.xml?rev=
>>>>> 1641081&r1=1641080&r2=1641081&view=diff
>>>>> ============================================================
>>>>> ==================
>>>>> --- jmeter/trunk/build.xml (original)
>>>>> +++ jmeter/trunk/build.xml Sat Nov 22 15:36:37 2014
>>>>> @@ -365,7 +365,9 @@
>>>>>         <include name="${lib.dir}/${commons-jexl2.jar}"/>
>>>>>         <include name="${lib.dir}/${commons-lang3.jar}"/>
>>>>>         <include name="${lib.dir}/${commons-logging.jar}"/>
>>>>> +    <include name="${lib.dir}/${commons-math3}"/>
>>>>>         <include name="${lib.dir}/${commons-net.jar}"/>
>>>>> +    <include name="${lib.dir}/${commons-pool2.jar}"/>
>>>>>         <include name="${lib.dir}/${dnsjava.jar}"/>
>>>>>         <include name="${lib.dir}/${excalibur-datasource.jar}"/>
>>>>>         <include name="${lib.dir}/${excalibur-instrument.jar}"/>
>>>>> @@ -438,8 +440,10 @@
>>>>>         <pathelement location="${lib.dir}/${commons-jexl2.jar}"/>
>>>>>         <pathelement location="${lib.dir}/${commons-lang3.jar}"/>
>>>>>         <pathelement location="${lib.dir}/${commons-logging.jar}"/>
>>>>> +    <pathelement location="${lib.dir}/${commons-math3.jar}"/>
>>>>>         <pathelement location="${lib.dir}/${commons-net.jar}"/>
>>>>> -    <pathelement location="${lib.dir}/${dnsjava.jar}"/>
>>>>> +       <pathelement location="${lib.dir}/${commons-pool2.jar}"/>
>>>>> +       <pathelement location="${lib.dir}/${dnsjava.jar}"/>
>>>>>         <pathelement location="${lib.dir}/${excalibur-datasource.jar}"/>
>>>>>         <pathelement location="${lib.dir}/${excalibur-instrument.jar}"/>
>>>>>         <pathelement location="${lib.dir}/${excalibur-logger.jar}"/>
>>>>> @@ -2909,7 +2913,9 @@ run JMeter unless all the JMeter jars ar
>>>>>             <process_jarfile jarname="commons-jexl2"/>
>>>>>             <process_jarfile jarname="commons-lang3"/>
>>>>>             <process_jarfile jarname="commons-logging"/>
>>>>> +        <process_jarfile jarname="commons-math3"/>
>>>>>             <process_jarfile jarname="commons-net"/>
>>>>> +       <process_jarfile jarname="commons-pool2"/>
>>>>>             <process_jarfile jarname="dnsjava"/>
>>>>>             <process_jarfile jarname="excalibur-datasource"/>
>>>>>             <process_jarfile jarname="excalibur-instrument"/>
>>>>>
>>>>> Modified: jmeter/trunk/eclipse.classpath
>>>>> URL: http://svn.apache.org/viewvc/jmeter/trunk/eclipse.
>>>>> classpath?rev=1641081&r1=1641080&r2=1641081&view=diff
>>>>> ============================================================
>>>>> ==================
>>>>> --- jmeter/trunk/eclipse.classpath (original)
>>>>> +++ jmeter/trunk/eclipse.classpath Sat Nov 22 15:36:37 2014
>>>>> @@ -55,7 +55,9 @@
>>>>>           <classpathentry kind="lib" path="lib/commons-jexl-2.1.1.jar"/>
>>>>>           <classpathentry kind="lib" path="lib/commons-lang3-3.3.2.
>>>>> jar"/>
>>>>>           <classpathentry kind="lib" path="lib/commons-logging-1.2.
>>>>> jar"/>
>>>>> +    <classpathentry kind="lib" path="lib/commons-math3-3.3.jar"/>
>>>>>           <classpathentry kind="lib" path="lib/commons-net-3.3.jar"/>
>>>>> +    <classpathentry kind="lib" path="lib/commons-pool2-2.2.jar"/>
>>>>>           <classpathentry kind="lib" path="lib/dnsjava-2.1.6.jar"/>
>>>>>           <classpathentry kind="lib" path="lib/excalibur-
>>>>> datasource-2.1.jar"/>
>>>>>           <classpathentry kind="lib" path="lib/excalibur-
>>>>> instrument-1.0.jar"/>
>>>>>
>>>>> Modified: jmeter/trunk/res/maven/ApacheJMeter_parent.pom
>>>>> URL: http://svn.apache.org/viewvc/jmeter/trunk/res/maven/
>>>>> ApacheJMeter_parent.pom?rev=1641081&r1=1641080&r2=1641081&view=diff
>>>>> ============================================================
>>>>> ==================
>>>>> --- jmeter/trunk/res/maven/ApacheJMeter_parent.pom (original)
>>>>> +++ jmeter/trunk/res/maven/ApacheJMeter_parent.pom Sat Nov 22 15:36:37
>>>>> 2014
>>>>> @@ -66,7 +66,9 @@ under the License.
>>>>>           <commons-jexl2.version>2.1.1</commons-jexl2.version>
>>>>>           <commons-lang3.version>3.3.2</commons-lang3.version>
>>>>>           <commons-logging.version>1.2</commons-logging.version>
>>>>> +      <commons-math3.version>3.3</commons-math3.version>
>>>>>           <commons-net.version>3.3</commons-net.version>
>>>>> +      <commons-pool2.version>2.2</commons-pool2.version>
>>>>>           <dnsjava.version>2.1.6</dnsjava.version>
>>>>>           <excalibur-datasource.version>2.1</excalibur-datasource.
>>>>> version>
>>>>>           <excalibur-instrument.version>1.0</excalibur-instrument.
>>>>> version>
>>>>> @@ -181,11 +183,21 @@ under the License.
>>>>>             <version>${commons-logging.version}</version>
>>>>>           </dependency>
>>>>>           <dependency>
>>>>> +        <groupId>commons-math3</groupId>
>>>>> +        <artifactId>commons-math3</artifactId>
>>>>> +        <version>${commons-math3.version}</version>
>>>>> +      </dependency>
>>>>> +      <dependency>
>>>>>             <groupId>commons-net</groupId>
>>>>>             <artifactId>commons-net</artifactId>
>>>>>             <version>${commons-net.version}</version>
>>>>>           </dependency>
>>>>>           <dependency>
>>>>> +        <groupId>commons-pool2</groupId>
>>>>> +        <artifactId>commons-pool2</artifactId>
>>>>> +        <version>${commons-pool2.version}</version>
>>>>> +      </dependency>
>>>>> +      <dependency>
>>>>>               <groupId>dnsjava</groupId>
>>>>>               <artifactId>dnsjava</artifactId>
>>>>>               <version>${dnsjava.version}</version>
>>>>>
>>>>> Added: jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>>>>> backend/
>>>>> AbstractBackendListenerClient.java
>>>>> URL: http://svn.apache.org/viewvc/jmeter/trunk/src/components/
>>>>> org/apache/jmeter/visualizers/backend/AbstractBackendListenerClient.
>>>>> java?rev=1641081&view=auto
>>>>> ============================================================
>>>>> ==================
>>>>> --- jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/
>>>>> AbstractBackendListenerClient.java (added)
>>>>> +++ jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/
>>>>> AbstractBackendListenerClient.java Sat Nov 22 15:36:37 2014
>>>>> @@ -0,0 +1,121 @@
>>>>> +/*
>>>>> + * 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.jmeter.visualizers.backend;
>>>>> +
>>>>> +import java.util.Map;
>>>>> +import java.util.concurrent.ConcurrentHashMap;
>>>>> +
>>>>> +import org.apache.jmeter.config.Arguments;
>>>>> +import org.apache.jmeter.samplers.SampleResult;
>>>>> +import org.apache.jorphan.logging.LoggingManager;
>>>>> +import org.apache.log.Logger;
>>>>> +
>>>>> +/**
>>>>> + * An abstract implementation of the BackendListenerClient interface.
>>>>> This
>>>>> + * implementation provides default implementations of most of the
>>>>> methods in the
>>>>> + * interface, as well as some convenience methods, in order to simplify
>>>>> + * development of BackendListenerClient implementations.
>>>>> + *
>>>>> + * While it may be necessary to make changes to the
>>>>> BackendListenerClient interface
>>>>> + * from time to time (therefore requiring changes to any
>>>>> implementations
>>>>> of this
>>>>> + * interface), we intend to make this abstract class provide reasonable
>>>>> + * implementations of any new methods so that subclasses do not
>>>>> necessarily need
>>>>> + * to be updated for new versions. Therefore, when creating a new
>>>>> + * BackendListenerClient implementation, developers are encouraged to
>>>>> subclass this
>>>>> + * abstract class rather than implementing the BackendListenerClient
>>>>> interface
>>>>> + * directly. Implementing BackendListenerClient directly will continue
>>>>> to be
>>>>> + * supported for cases where extending this class is not possible (for
>>>>> example,
>>>>> + * when the client class is already a subclass of some other class).
>>>>> + * <p>
>>>>> + * The handleSampleResult() method of BackendListenerClient does not
>>>>> have a default
>>>>> + * implementation here, so subclasses must define at least this method.
>>>>> It may
>>>>> + * be useful to override other methods as well.
>>>>> + *
>>>>> + * @see BackendListener#sampleOccurred(org.apache.
>>>>> jmeter.samplers.SampleEvent)
>>>>> + * @since 2.13
>>>>> + */
>>>>> +public abstract class AbstractBackendListenerClient implements
>>>>> BackendListenerClient {
>>>>> +
>>>>> +    private static final Logger log = LoggingManager.
>>>>> getLoggerForClass();
>>>>>
>>>>>   In classes further down the logger is stored in variables named LOG and
>>>> LOGGER, should we use one name?
>>>> In this class we have a getter for the logger in other classes not. Why?
>>>>
>>>>   +
>>>>> +    private ConcurrentHashMap<String, SamplerMetric> metricsPerSampler
>>>>> =
>>>>> new ConcurrentHashMap<String, SamplerMetric>();
>>>>> +
>>>>> +    /* Implements BackendListenerClient.setupTest(JavaSamplerContext)
>>>>> */
>>>>> +    @Override
>>>>> +    public void setupTest(BackendListenerContext context) throws
>>>>> Exception {
>>>>> +        log.debug(getClass().getName() + ": setupTest");
>>>>> +    }
>>>>> +
>>>>> +    /* Implements BackendListenerClient.teardownTest(
>>>>> JavaSamplerContext)
>>>>> */
>>>>> +    @Override
>>>>> +    public void teardownTest(BackendListenerContext context) throws
>>>>> Exception {
>>>>> +        log.debug(getClass().getName() + ": teardownTest");
>>>>> +        metricsPerSampler.clear();
>>>>> +    }
>>>>> +
>>>>> +    /* Implements BackendListenerClient.getDefaultParameters() */
>>>>> +    @Override
>>>>> +    public Arguments getDefaultParameters() {
>>>>> +        return null;
>>>>> +    }
>>>>> +
>>>>> +    /**
>>>>> +     * Get a Logger instance which can be used by subclasses to log
>>>>> information.
>>>>> +     *
>>>>> +     * @return a Logger instance which can be used for logging
>>>>> +     */
>>>>> +    protected Logger getLogger() {
>>>>> +        return log;
>>>>> +    }
>>>>> +
>>>>> +    /* (non-Javadoc)
>>>>> +     * @see org.apache.jmeter.visualizers.
>>>>> backend.BackendListenerClient#
>>>>> createSampleResult(org.apache.jmeter.samplers.SampleResult)
>>>>> +     */
>>>>> +    @Override
>>>>> +    public SampleResult createSampleResult(BackendListenerContext
>>>>> context, SampleResult result) {
>>>>> +        SampleResult sampleResult = (SampleResult) result.clone();
>>>>> +        return sampleResult;
>>>>> +    }
>>>>> +
>>>>> +    /**
>>>>> +     *
>>>>> +     * @param sampleLabel
>>>>> +     * @return SamplerMetric
>>>>>
>>>>>   No description of the method and the parameters?
>>>>   +     */
>>>>> +    protected SamplerMetric getSamplerMetric(String sampleLabel) {
>>>>> +        SamplerMetric samplerMetric = metricsPerSampler.get(
>>>>> sampleLabel);
>>>>> +        if(samplerMetric == null) {
>>>>> +            samplerMetric = new SamplerMetric();
>>>>> +            SamplerMetric oldValue = metricsPerSampler.putIfAbsent(
>>>>> sampleLabel,
>>>>> samplerMetric);
>>>>> +            if(oldValue != null ){
>>>>> +                samplerMetric = oldValue;
>>>>> +            }
>>>>> +        }
>>>>> +        return samplerMetric;
>>>>> +    }
>>>>> +
>>>>> +    /**
>>>>> +     *
>>>>> +     * @return Map<String, SamplerMetric>
>>>>>
>>>>>   No description of the method and usage of forbidden characters :) there
>>>> are still more than 800 warnings in the javadoc to prune, so don't
>>>> introduce new ones, please.
>>>>
>>>>   +     */
>>>>> +    protected Map<String, SamplerMetric> getMetricsPerSampler() {
>>>>> +        return metricsPerSampler;
>>>>> +    }
>>>>> +
>>>>> +}
>>>>>
>>>>> Propchange: jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>>>>> backend/AbstractBackendListenerClient.java
>>>>> ------------------------------------------------------------
>>>>> ------------------
>>>>>        svn:mime-type = text/plain
>>>>>
>>>>> Added: jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>>>>> backend/BackendListener.java
>>>>> URL: http://svn.apache.org/viewvc/jmeter/trunk/src/components/
>>>>> org/apache/jmeter/visualizers/backend/BackendListener.java?
>>>>> rev=1641081&view=auto
>>>>> ============================================================
>>>>> ==================
>>>>> --- jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>>>>> backend/BackendListener.java
>>>>> (added)
>>>>> +++ jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>>>>> backend/BackendListener.java
>>>>> Sat Nov 22 15:36:37 2014
>>>>> @@ -0,0 +1,448 @@
>>>>> +/*
>>>>> + * 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.jmeter.visualizers.backend;
>>>>> +
>>>>> +import java.io.Serializable;
>>>>> +import java.lang.reflect.Method;
>>>>> +import java.util.ArrayList;
>>>>> +import java.util.HashSet;
>>>>> +import java.util.List;
>>>>> +import java.util.Set;
>>>>> +import java.util.concurrent.ArrayBlockingQueue;
>>>>> +import java.util.concurrent.BlockingQueue;
>>>>> +import java.util.concurrent.locks.LockSupport;
>>>>> +
>>>>> +import org.apache.jmeter.config.Arguments;
>>>>> +import org.apache.jmeter.engine.util.NoThreadClone;
>>>>> +import org.apache.jmeter.protocol.java.sampler.JavaSamplerContext;
>>>>> +import org.apache.jmeter.samplers.Remoteable;
>>>>> +import org.apache.jmeter.samplers.SampleEvent;
>>>>> +import org.apache.jmeter.samplers.SampleListener;
>>>>> +import org.apache.jmeter.samplers.SampleResult;
>>>>> +import org.apache.jmeter.testelement.AbstractTestElement;
>>>>> +import org.apache.jmeter.testelement.TestElement;
>>>>> +import org.apache.jmeter.testelement.TestStateListener;
>>>>> +import org.apache.jmeter.testelement.property.TestElementProperty;
>>>>> +import org.apache.jorphan.logging.LoggingManager;
>>>>> +import org.apache.log.Logger;
>>>>> +
>>>>> +/**
>>>>> + * Async Listener that delegates SampleResult handling to
>>>>> implementations of {@link BackendListenerClient}
>>>>> + * @since 2.13
>>>>> + */
>>>>> +public class BackendListener extends AbstractTestElement
>>>>> +    implements Serializable, SampleListener, TestStateListener,
>>>>> NoThreadClone, Remoteable  {
>>>>> +
>>>>> +    /**
>>>>> +     *
>>>>> +     */
>>>>> +    private static final long serialVersionUID = 8184103677832024335L;
>>>>> +
>>>>> +    private static final Logger log = LoggingManager.
>>>>> getLoggerForClass();
>>>>>
>>>>>   See naming comment of log from above
>>>>   +
>>>>> +    /**
>>>>> +     * Set used to register instances which implement teardownTest.
>>>>> +     * This is used so that the BackendListenerClient can be notified
>>>>> when the test ends.
>>>>> +     */
>>>>> +    private static final Set<BackendListener> TEAR_DOWN_SET = new
>>>>> HashSet<BackendListener>();
>>>>> +
>>>>> +    /**
>>>>> +     * Property key representing the classname of the
>>>>> BackendListenerClient to user.
>>>>> +     */
>>>>> +    public static final String CLASSNAME = "classname";
>>>>> +
>>>>> +    /**
>>>>> +     * Queue size
>>>>> +     */
>>>>> +    public static final String QUEUE_SIZE = "QUEUE_SIZE";
>>>>> +
>>>>> +    /**
>>>>> +     * Property key representing the arguments for the
>>>>> BackendListenerClient.
>>>>> +     */
>>>>> +    public static final String ARGUMENTS = "arguments";
>>>>> +
>>>>> +    /**
>>>>> +     * The BackendListenerClient class used by this sampler.
>>>>> +     * Created by testStarted; copied to cloned instances.
>>>>> +     */
>>>>> +    private Class<?> javaClass;
>>>>>
>>>>>   Could probably named clientClass instead of javaClass, since we already
>>>> know it is a java class.
>>>>
>>>>   +
>>>>> +    /**
>>>>> +     * If true, the BackendListenerClient class implements
>>>>> teardownTest.
>>>>> +     * Created by testStarted; copied to cloned instances.
>>>>> +     */
>>>>> +    private boolean isToBeRegistered;
>>>>> +
>>>>> +    /**
>>>>> +     * The BackendListenerClient instance
>>>>> +     */
>>>>> +    private transient BackendListenerClient backendListenerClient =
>>>>> null;
>>>>> +
>>>>> +    /**
>>>>> +     * The JavaSamplerContext instance used by this sampler to hold
>>>>> information
>>>>>
>>>>>   BackendListenerContext?
>>>>   +     * related to the test run, such as the parameters specified for
>>>>> the
>>>>> sampler
>>>>> +     * client.
>>>>> +     */
>>>>> +    private transient BackendListenerContext context = null;
>>>>> +
>>>>> +    private static final int DEFAULT_QUEUE_SIZE = 5000;
>>>>> +
>>>>> +    private transient BlockingQueue<SampleResult> queue; // created by
>>>>> server in readResolve method
>>>>> +
>>>>> +    private transient long queueWaits; // how many times we had to wait
>>>>> to queue a sample
>>>>> +
>>>>> +    private transient long queueWaitTime; // how long we had to wait
>>>>> (nanoSeconds)
>>>>> +
>>>>> +    // Create unique object as marker for end of queue
>>>>> +    private transient static final SampleResult FINAL_EVENT = new
>>>>> SampleResult();
>>>>> +
>>>>> +    /**
>>>>> +     * Create a BackendListener.
>>>>> +     */
>>>>> +    public BackendListener() {
>>>>> +        setArguments(new Arguments());
>>>>> +    }
>>>>> +
>>>>> +    /*
>>>>> +     * Ensure that the required class variables are cloned,
>>>>> +     * as this is not currently done by the super-implementation.
>>>>> +     */
>>>>> +    @Override
>>>>> +    public Object clone() {
>>>>> +        BackendListener clone = (BackendListener) super.clone();
>>>>> +        clone.javaClass = this.javaClass;
>>>>> +        clone.isToBeRegistered = this.isToBeRegistered;
>>>>> +        return clone;
>>>>> +    }
>>>>> +
>>>>> +    private void initClass() {
>>>>> +        String name = getClassname().trim();
>>>>> +        try {
>>>>> +            javaClass = Class.forName(name, false,
>>>>> Thread.currentThread().getContextClassLoader());
>>>>> +            Method method = javaClass.getMethod("teardownTest", new
>>>>> Class[]{BackendListenerContext.class});
>>>>> +            isToBeRegistered = !method.getDeclaringClass().equals(
>>>>> AbstractBackendListenerClient.class);
>>>>> +            log.info("Created class: " + name + ". Uses teardownTest:
>>>>> "
>>>>> + isToBeRegistered);
>>>>> +        } catch (Exception e) {
>>>>> +            log.error(whoAmI() + "\tException initialising: " + name,
>>>>> e);
>>>>> +        }
>>>>> +    }
>>>>> +
>>>>> +    /**
>>>>> +     * Retrieves reference to BackendListenerClient.
>>>>> +     *
>>>>> +     * Convience method used to check for null reference without
>>>>> actually
>>>>> +     * creating a BackendListenerClient
>>>>> +     *
>>>>> +     * @return reference to BackendListenerClient NOTUSED private
>>>>> BackendListenerClient
>>>>> +     *         retrieveJavaClient() { return javaClient; }
>>>>> +     */
>>>>>
>>>>>   Javadoc for non-existant method?
>>>>   +
>>>>> +    /**
>>>>> +     * Generate a String identifier of this instance for debugging
>>>>> purposes.
>>>>> +     *
>>>>> +     * @return a String identifier for this sampler instance
>>>>> +     */
>>>>> +    private String whoAmI() {
>>>>> +        StringBuilder sb = new StringBuilder();
>>>>> +        sb.append(Thread.currentThread().getName());
>>>>> +        sb.append("@");
>>>>> +        sb.append(Integer.toHexString(hashCode()));
>>>>> +        sb.append("-");
>>>>> +        sb.append(getName());
>>>>> +        return sb.toString();
>>>>> +    }
>>>>> +
>>>>> +    // TestStateListener implementation
>>>>> +    /* Implements TestStateListener.testStarted() */
>>>>> +    @Override
>>>>> +    public void testStarted() {
>>>>> +        testStarted("");
>>>>> +    }
>>>>> +
>>>>> +    /* Implements TestStateListener.testStarted(String) */
>>>>> +    @Override
>>>>> +    public void testStarted(String host) {
>>>>> +        log.debug(whoAmI() + "\ttestStarted(" + host + ")");
>>>>>
>>>>>   Maybe use isDebugEnabled to guard whoAmI() call?
>>>>   +        queue = new ArrayBlockingQueue<SampleResult>(getQueueSize());
>>>>> +        initClass();
>>>>> +        queueWaits=0L;
>>>>> +        queueWaitTime=0L;
>>>>> +        log.info(getName()+":Starting worker with class:"+javaClass +"
>>>>> and queue capacity:"+getQueueSize());
>>>>> +
>>>>> +        backendListenerClient = createBackendListenerClientImp
>>>>> l(javaClass);
>>>>> +        context = new BackendListenerContext((
>>>>> Arguments)getArguments().
>>>>> clone());
>>>>> +        if(isToBeRegistered) {
>>>>>
>>>>>   space after if and before (?
>>>>   +            TEAR_DOWN_SET.add(this);
>>>>> +        }
>>>>> +        try {
>>>>> +            backendListenerClient.setupTest(context);
>>>>> +        } catch (Exception e) {
>>>>> +            throw new java.lang.IllegalStateException("Failed calling
>>>>> setupTest", e);
>>>>> +        }
>>>>> +
>>>>> +        Worker worker = new Worker(javaClass, backendListenerClient,
>>>>> (Arguments) getArguments().clone(), queue);
>>>>> +        worker.setDaemon(true);
>>>>> +        worker.start();
>>>>>
>>>>>   Don't we want to stop worker after we're done with one test?
>>>>   +        log.info(getName()+":Started  worker with class:"+javaClass);
>>>>>   Spaces after :?
>>>>   +
>>>>> +    }
>>>>> +
>>>>> +    /* (non-Javadoc)
>>>>> +     * @see org.apache.jmeter.samplers.SampleListener#sampleOccurred(
>>>>> org.apache.jmeter.samplers.SampleEvent)
>>>>> +     */
>>>>> +    @Override
>>>>> +    public void sampleOccurred(SampleEvent e) {
>>>>>
>>>>>   Longer name then 'e'? I expect e to be an exception, not an event.
>>>>   +        Arguments args = getArguments();
>>>>> +        context = new BackendListenerContext(args);
>>>>> +
>>>>> +        SampleResult sr = backendListenerClient.
>>>>> createSampleResult(context,
>>>>> e.getResult());
>>>>> +        try {
>>>>> +            if (!queue.offer(sr)){ // we failed to add the element
>>>>> first
>>>>> time
>>>>> +                queueWaits++;
>>>>> +                long t1 = System.nanoTime();
>>>>> +                queue.put(sr);
>>>>> +                long t2 = System.nanoTime();
>>>>> +                queueWaitTime += t2-t1;
>>>>>
>>>>>   Will sampleOccurred be called concurrently? If so, than queueWaitTime
>>>> +=
>>>> will not be correct.
>>>>
>>>>   +            }
>>>>> +        } catch (Exception err) {
>>>>> +            log.error("sampleOccurred, failed to queue the sample",
>>>>> err);
>>>>> +        }
>>>>> +    }
>>>>> +
>>>>> +    private static final class Worker extends Thread {
>>>>> +
>>>>> +        private final BlockingQueue<SampleResult> queue;
>>>>> +        private final BackendListenerContext context;
>>>>> +        private final BackendListenerClient backendListenerClient;
>>>>> +        private Worker(Class<?> javaClass, BackendListenerClient
>>>>> backendListenerClient, Arguments arguments, BlockingQueue<SampleResult>
>>>>> q){
>>>>>
>>>>>   Same naming argument as above. clientclass instead of javaClass?
>>>>   +            queue = q;
>>>>> +            // Allow BackendListenerClient implementations to get
>>>>> access
>>>>> to test element name
>>>>> +            arguments.addArgument(TestElement.NAME, getName());
>>>>> +            context = new BackendListenerContext(arguments);
>>>>> +            this.backendListenerClient = backendListenerClient;
>>>>> +        }
>>>>> +
>>>>> +
>>>>> +        @Override
>>>>> +        public void run() {
>>>>> +            boolean isDebugEnabled = log.isDebugEnabled();
>>>>> +            List<SampleResult> l = new ArrayList<SampleResult>(queue.
>>>>> size());
>>>>>
>>>>>   samples instead of l?
>>>>   +            try {
>>>>> +                boolean eof = false;
>>>>>
>>>>>   endOfLoop?
>>>>   +                while (!eof) {
>>>>> +                    if(isDebugEnabled) {
>>>>> +                        log.debug("Thread:"+Thread.
>>>>> currentThread().getName()+"
>>>>> taking SampleResult from queue:"+queue.size());
>>>>> +                    }
>>>>> +                    SampleResult e = queue.take();
>>>>>
>>>>>   Could be named result, or sample instead of e
>>>>   +                    if(isDebugEnabled) {
>>>>> +                        log.debug("Thread:"+Thread.
>>>>> currentThread().getName()+"
>>>>> took SampleResult:"+e+", isFinal:" + (e==FINAL_EVENT));
>>>>> +                    }
>>>>> +                    while (!(eof = (e == FINAL_EVENT)) && e != null ) {
>>>>> // try to process as many as possible
>>>>> +                        l.add(e);
>>>>> +                        if(isDebugEnabled) {
>>>>> +                            log.debug("Thread:"+Thread.
>>>>> currentThread().getName()+"
>>>>> polling from queue:"+queue.size());
>>>>> +                        }
>>>>> +                        e = queue.poll(); // returns null if nothing on
>>>>> queue currently
>>>>> +                        if(isDebugEnabled) {
>>>>> +                            log.debug("Thread:"+Thread.
>>>>> currentThread().getName()+"
>>>>> took from queue:"+e+", isFinal:" + (e==FINAL_EVENT));
>>>>> +                        }
>>>>> +                    }
>>>>> +                    if(isDebugEnabled) {
>>>>> +                        log.debug("Thread:"+Thread.
>>>>> currentThread().getName()+
>>>>> +                                " exiting with FINAL EVENT:"+(e ==
>>>>> FINAL_EVENT)
>>>>> +                                +", null:" + (e==null));
>>>>> +                    }
>>>>> +                    int size = l.size();
>>>>>
>>>>>   No need for a temporary variable.
>>>>   +                    if (size > 0) {
>>>>> +                        backendListenerClient.handleSampleResults(l,
>>>>> context);
>>>>> +                        l.clear();
>>>>> +                    }
>>>>> +                    if(!eof) {
>>>>> +                        LockSupport.parkNanos(100);
>>>>> +                    }
>>>>> +                }
>>>>> +            } catch (InterruptedException e) {
>>>>> +                // NOOP
>>>>> +            }
>>>>> +            // We may have been interrupted
>>>>> +            int size = l.size();
>>>>> +            if (size > 0) {
>>>>> +                backendListenerClient.handleSampleResults(l, context);
>>>>> +                l.clear();
>>>>> +            }
>>>>>
>>>>>   Same code as a few lines above, could be factored out into a method
>>>> handleSamples(l, context)
>>>>
>>>>   +            log.info("Worker ended");
>>>>> +        }
>>>>> +    }
>>>>> +
>>>>> +
>>>>> +    /**
>>>>> +     * Returns reference to <code>BackendListenerClient</code>.
>>>>>
>>>>>   Could use a {@link...}
>>>>   +     *
>>>>> +     *
>>>>> +     * @return BackendListenerClient reference.
>>>>> +     */
>>>>> +    static BackendListenerClient createBackendListenerClientImp
>>>>> l(Class<?>
>>>>> javaClass) {
>>>>> +        if (javaClass == null) { // failed to initialise the class
>>>>> +            return new ErrorBackendListenerClient();
>>>>> +        }
>>>>> +        BackendListenerClient client;
>>>>> +        try {
>>>>> +            client = (BackendListenerClient) javaClass.newInstance();
>>>>> +        } catch (Exception e) {
>>>>> +            log.error("Exception creating: " + javaClass, e);
>>>>> +            client = new ErrorBackendListenerClient();
>>>>> +        }
>>>>> +        return client;
>>>>>
>>>>>   I would return newInstance() in try Block and return new Error.. in
>>>> catch
>>>> Block. javaClass -> clientClass
>>>>
>>>>   +    }
>>>>> +
>>>>> +    /**
>>>>> +     * Method called at the end of the test. This is called only on one
>>>>> instance
>>>>> +     * of BackendListener. This method will loop through all of the
>>>>> other
>>>>> +     * BackendListenerClients which have been registered (automatically
>>>>> in the
>>>>> +     * constructor) and notify them that the test has ended, allowing
>>>>> the
>>>>> +     * BackendListenerClients to cleanup.
>>>>> +     */
>>>>> +    @Override
>>>>> +    public void testEnded() {
>>>>> +        try {
>>>>> +            queue.put(FINAL_EVENT);
>>>>> +        } catch (Exception ex) {
>>>>> +            log.warn("testEnded() with exception:"+ex.getMessage(),
>>>>> ex);
>>>>> +        }
>>>>> +        if (queueWaits > 0) {
>>>>> +            log.warn("QueueWaits: "+queueWaits+"; QueueWaitTime:
>>>>> "+queueWaitTime+" (nanoseconds), you may need to increase queue
>>>>> capacity,
>>>>> see property 'backend_queue_capacity'");
>>>>> +        }
>>>>> +        synchronized (TEAR_DOWN_SET) {
>>>>> +            for (BackendListener backendListener : TEAR_DOWN_SET) {
>>>>> +                BackendListenerClient client = backendListener.
>>>>> backendListenerClient;
>>>>> +                if (client != null) {
>>>>> +                    try {
>>>>> +                        client.teardownTest(backendListener.context);
>>>>> +                    } catch (Exception e) {
>>>>> +                        throw new java.lang.
>>>>> IllegalStateException("Failed
>>>>> calling teardownTest", e);
>>>>>
>>>>>   If we throw an exception here, we will not try every client.
>>>>   +                    }
>>>>> +                }
>>>>> +            }
>>>>> +            TEAR_DOWN_SET.clear();
>>>>> +        }
>>>>> +    }
>>>>> +
>>>>> +    /* Implements TestStateListener.testEnded(String) */
>>>>> +    @Override
>>>>> +    public void testEnded(String host) {
>>>>> +        testEnded();
>>>>> +    }
>>>>> +
>>>>> +    /**
>>>>> +     * A {@link BackendListenerClient} implementation used for error
>>>>> handling. If an
>>>>> +     * error occurs while creating the real BackendListenerClient
>>>>> object, it is
>>>>> +     * replaced with an instance of this class. Each time a sample
>>>>> occurs with
>>>>> +     * this class, the result is marked as a failure so the user can
>>>>> see
>>>>> that
>>>>> +     * the test failed.
>>>>> +     */
>>>>> +    static class ErrorBackendListenerClient extends
>>>>> AbstractBackendListenerClient {
>>>>> +        /**
>>>>> +         * Return SampleResult with data on error.
>>>>> +         *
>>>>> +         * @see BackendListenerClient#runTest(JavaSamplerContext)
>>>>> +         */
>>>>> +        @Override
>>>>> +        public void handleSampleResults(List<SampleResult>
>>>>> sampleResults, BackendListenerContext context) {
>>>>> +            log.warn("ErrorBackendListenerClient#handleSampleResult
>>>>> called, noop");
>>>>> +            Thread.yield();
>>>>> +        }
>>>>> +    }
>>>>> +
>>>>> +    /* (non-Javadoc)
>>>>> +     * @see org.apache.jmeter.samplers.SampleListener#sampleStarted(
>>>>> org.apache.jmeter.samplers.SampleEvent)
>>>>> +     */
>>>>> +    @Override
>>>>> +    public void sampleStarted(SampleEvent e) {
>>>>> +        // NOOP
>>>>> +
>>>>> +    }
>>>>> +
>>>>> +    /* (non-Javadoc)
>>>>> +     * @see org.apache.jmeter.samplers.SampleListener#sampleStopped(
>>>>> org.apache.jmeter.samplers.SampleEvent)
>>>>> +     */
>>>>> +    @Override
>>>>> +    public void sampleStopped(SampleEvent e) {
>>>>> +        // NOOP
>>>>> +
>>>>> +    }
>>>>> +
>>>>> +    /**
>>>>> +     * Set the arguments (parameters) for the BackendListenerClient to
>>>>> be executed
>>>>> +     * with.
>>>>> +     *
>>>>> +     * @param args
>>>>> +     *            the new arguments. These replace any existing
>>>>> arguments.
>>>>> +     */
>>>>> +    public void setArguments(Arguments args) {
>>>>> +        setProperty(new TestElementProperty(ARGUMENTS, args));
>>>>> +    }
>>>>> +
>>>>> +    /**
>>>>> +     * Get the arguments (parameters) for the BackendListenerClient to
>>>>> be executed
>>>>> +     * with.
>>>>> +     *
>>>>> +     * @return the arguments
>>>>> +     */
>>>>> +    public Arguments getArguments() {
>>>>> +        return (Arguments) getProperty(ARGUMENTS).getObjectValue();
>>>>> +    }
>>>>> +
>>>>> +    /**
>>>>> +     * Sets the Classname of the BackendListenerClient object
>>>>> +     *
>>>>> +     * @param classname
>>>>> +     *            the new Classname value
>>>>> +     */
>>>>> +    public void setClassname(String classname) {
>>>>> +        setProperty(CLASSNAME, classname);
>>>>> +    }
>>>>> +
>>>>> +    /**
>>>>> +     * Gets the Classname of the BackendListenerClient object
>>>>> +     *
>>>>> +     * @return the Classname value
>>>>> +     */
>>>>> +    public String getClassname() {
>>>>> +        return getPropertyAsString(CLASSNAME);
>>>>> +    }
>>>>> +
>>>>> +    /**
>>>>> +     * Sets the queue size
>>>>> +     *
>>>>> +     * @param queueSize
>>>>> +     *
>>>>> +     */
>>>>> +    public void setQueueSize(int queueSize) {
>>>>> +        setProperty(QUEUE_SIZE, queueSize, DEFAULT_QUEUE_SIZE);
>>>>> +    }
>>>>> +
>>>>> +    /**
>>>>> +     * Gets the queue size
>>>>> +     *
>>>>> +     * @return int queueSize
>>>>> +     */
>>>>> +    public int getQueueSize() {
>>>>> +        return getPropertyAsInt(QUEUE_SIZE, DEFAULT_QUEUE_SIZE);
>>>>> +    }
>>>>> +}
>>>>>
>>>>> Propchange: jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>>>>> backend/BackendListener.java
>>>>> ------------------------------------------------------------
>>>>> ------------------
>>>>>        svn:mime-type = text/plain
>>>>>
>>>>> Added: jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>>>>> backend/BackendListenerClient.java
>>>>> URL: http://svn.apache.org/viewvc/jmeter/trunk/src/components/
>>>>> org/apache/jmeter/visualizers/backend/BackendListenerClient.
>>>>> java?rev=1641081&view=auto
>>>>> ============================================================
>>>>> ==================
>>>>> --- jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>>>>> backend/BackendListenerClient.java (added)
>>>>> +++ jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>>>>> backend/BackendListenerClient.java Sat Nov 22 15:36:37 2014
>>>>> @@ -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.jmeter.visualizers.backend;
>>>>> +
>>>>> +import java.util.List;
>>>>> +
>>>>> +import org.apache.jmeter.config.Arguments;
>>>>> +import org.apache.jmeter.samplers.SampleResult;
>>>>> +
>>>>> +/**
>>>>> + * This interface defines the interactions between the BackendListener
>>>>> and external
>>>>> + * Java programs which can be executed by JMeter. Any Java class which
>>>>> wants to
>>>>> + * be executed as a JMeter test must implement this interface (either
>>>>> directly
>>>>> + * or indirectly through AbstractBackendListenerClient).
>>>>> + * <p>
>>>>> + * JMeter will create one instance of a BackendListenerClient
>>>>> implementation for
>>>>> + * each user/thread in the test. Additional instances may be created
>>>>> for
>>>>> + * internal use by JMeter (for example, to find out what parameters are
>>>>> + * supported by the client).
>>>>> + * <p>
>>>>> + * When the test is started, setupTest() will be called on each
>>>>> thread's
>>>>> + * BackendListenerClient instance to initialize the client. Then
>>>>> handleSampleResult() will be
>>>>> + * called for each SampleResult notification. Finally, teardownTest()
>>>>> will be called
>>>>> + * to allow the client to do any necessary clean-up.
>>>>> + * <p>
>>>>> + * The JMeter BackendListener GUI allows a list of parameters to be
>>>>> defined for the
>>>>> + * test. These are passed to the various test methods through the
>>>>> + * {@link BackendListenerContext}. A list of default parameters can be
>>>>> defined
>>>>> + * through the getDefaultParameters() method. These parameters and any
>>>>> default
>>>>> + * values associated with them will be shown in the GUI. Users can add
>>>>> other
>>>>> + * parameters as well.
>>>>> + * <p>
>>>>> + * When possible, Listeners should extend {@link
>>>>> AbstractBackendListenerClient
>>>>> + * AbstractBackendListenerClient} rather than implementing
>>>>> BackendListenerClient
>>>>> + * directly. This should protect your tests from future changes to the
>>>>> + * interface. While it may be necessary to make changes to the
>>>>> BackendListenerClient
>>>>> + * interface from time to time (therefore requiring changes to any
>>>>> + * implementations of this interface), we intend to make this abstract
>>>>> class
>>>>> + * provide reasonable default implementations of any new methods so
>>>>> that
>>>>> + * subclasses do not necessarily need to be updated for new versions.
>>>>> + * Implementing BackendListenerClient directly will continue to be
>>>>> supported for
>>>>> + * cases where extending this class is not possible (for example, when
>>>>> the
>>>>> + * client class is already a subclass of some other class).
>>>>> + *
>>>>> + * @since 2.13
>>>>> + */
>>>>> +public interface BackendListenerClient {
>>>>> +    /**
>>>>> +     * Do any initialization required by this client. It is generally
>>>>> +     * recommended to do any initialization such as getting parameter
>>>>> values in
>>>>> +     * the setupTest method rather than the runTest method in order to
>>>>> add as
>>>>> +     * little overhead as possible to the test.
>>>>> +     *
>>>>> +     * @param context
>>>>> +     *            the context to run with. This provides access to
>>>>> +     *            initialization parameters.
>>>>> +     */
>>>>> +    void setupTest(BackendListenerContext context) throws Exception;
>>>>> +
>>>>> +    /**
>>>>> +     * Perform a single sample for each iteration. This method returns
>>>>> a
>>>>> +     * <code>SampleResult</code> object. <code>SampleResult</code> has
>>>>> many
>>>>> +     * fields which can be used. At a minimum, the test should use
>>>>> +     * <code>SampleResult.sampleStart</code> and
>>>>> +     * <code>SampleResult.sampleEnd</code>to set the time that the
>>>>> test
>>>>>
>>>>>   use {@link..} instead of <code>..?
>>>>   +     * required to execute. It is also a good idea to set the
>>>>> sampleLabel and
>>>>> +     * the successful flag.
>>>>> +     *
>>>>> +     * @see org.apache.jmeter.samplers.SampleResult#sampleStart()
>>>>> +     * @see org.apache.jmeter.samplers.SampleResult#sampleEnd()
>>>>> +     * @see org.apache.jmeter.samplers.SampleResult#setSuccessful(
>>>>> boolean)
>>>>> +     * @see org.apache.jmeter.samplers.SampleResult#setSampleLabel(
>>>>> String)
>>>>> +     *
>>>>> +     * @param context
>>>>> +     *            the context to run with. This provides access to
>>>>> +     *            initialization parameters.
>>>>> +     *
>>>>> +     */
>>>>> +    void handleSampleResults(List<SampleResult> sampleResults,
>>>>> BackendListenerContext context);
>>>>> +
>>>>> +    /**
>>>>> +     * Do any clean-up required by this test at the end of a test run.
>>>>> +     *
>>>>> +     * @param context
>>>>> +     *            the context to run with. This provides access to
>>>>> +     *            initialization parameters.
>>>>> +     */
>>>>> +    void teardownTest(BackendListenerContext context) throws
>>>>> Exception;
>>>>> +
>>>>> +    /**
>>>>> +     * Provide a list of parameters which this test supports. Any
>>>>> parameter
>>>>> +     * names and associated values returned by this method will appear
>>>>> in the
>>>>> +     * GUI by default so the user doesn't have to remember the exact
>>>>> names. The
>>>>> +     * user can add other parameters which are not listed here. If this
>>>>> method
>>>>> +     * returns null then no parameters will be listed. If the value for
>>>>> some
>>>>> +     * parameter is null then that parameter will be listed in the GUI
>>>>> with an
>>>>> +     * empty value.
>>>>> +     *
>>>>> +     * @return a specification of the parameters used by this test
>>>>> which
>>>>> should
>>>>> +     *         be listed in the GUI, or null if no parameters should be
>>>>> listed.
>>>>> +     */
>>>>> +    Arguments getDefaultParameters();
>>>>> +
>>>>> +    /**
>>>>> +     *
>>>>> +     * @param context
>>>>> +     * @param result
>>>>> +     * @return
>>>>> +     */
>>>>> +    SampleResult createSampleResult(
>>>>> +            BackendListenerContext context, SampleResult result);
>>>>> +}
>>>>>
>>>>> Propchange: jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>>>>> backend/BackendListenerClient.java
>>>>> ------------------------------------------------------------
>>>>> ------------------
>>>>>        svn:mime-type = text/plain
>>>>>
>>>>> Added: jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>>>>> backend/
>>>>> BackendListenerContext.java
>>>>> URL: http://svn.apache.org/viewvc/jmeter/trunk/src/components/
>>>>> org/apache/jmeter/visualizers/backend/BackendListenerContext.java?
>>>>> rev=1641081&view=auto
>>>>> ============================================================
>>>>> ==================
>>>>> --- jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/
>>>>> BackendListenerContext.java
>>>>> (added)
>>>>> +++ jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/
>>>>> BackendListenerContext.java
>>>>> Sat Nov 22 15:36:37 2014
>>>>> @@ -0,0 +1,237 @@
>>>>> +/*
>>>>> +
>>>>> + * 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.jmeter.visualizers.backend;
>>>>> +
>>>>> +import java.util.Iterator;
>>>>> +import java.util.Map;
>>>>> +
>>>>> +import org.apache.jmeter.config.Arguments;
>>>>> +import org.apache.jorphan.logging.LoggingManager;
>>>>> +import org.apache.log.Logger;
>>>>> +
>>>>> +/**
>>>>> + * BackendListenerContext is used to provide context information to a
>>>>> + * BackendListenerClient implementation. This currently consists of the
>>>>> + * initialization parameters which were specified in the GUI.
>>>>> + * @since 2.13
>>>>> + */
>>>>> +public class BackendListenerContext {
>>>>> +    /*
>>>>> +     * Implementation notes:
>>>>> +     *
>>>>> +     * All of the methods in this class are currently read-only. If
>>>>> update
>>>>> +     * methods are included in the future, they should be defined so
>>>>> that a
>>>>> +     * single instance of BackendListenerContext can be associated with
>>>>> each thread.
>>>>> +     * Therefore, no synchronization should be needed. The same
>>>>> instance
>>>>> should
>>>>> +     * be used for the call to setupTest, all calls to runTest, and the
>>>>> call to
>>>>> +     * teardownTest.
>>>>> +     */
>>>>> +
>>>>> +    /** Logging */
>>>>> +    private static final Logger log = LoggingManager.
>>>>> getLoggerForClass();
>>>>>
>>>>>   See naming comments for logger above
>>>>   +
>>>>> +    /**
>>>>> +     * Map containing the initialization parameters for the
>>>>> BackendListenerClient.
>>>>> +     */
>>>>> +    private final Map<String, String> params;
>>>>> +
>>>>> +    /**
>>>>> +     *
>>>>> +     * @param args
>>>>> +     *            the initialization parameters.
>>>>> +     */
>>>>> +    public BackendListenerContext(Arguments args) {
>>>>> +        this.params = args.getArgumentsAsMap();
>>>>> +    }
>>>>> +
>>>>> +    /**
>>>>> +     * Determine whether or not a value has been specified for the
>>>>> parameter
>>>>> +     * with this name.
>>>>> +     *
>>>>> +     * @param name
>>>>> +     *            the name of the parameter to test
>>>>> +     * @return true if the parameter value has been specified, false
>>>>> otherwise.
>>>>> +     */
>>>>> +    public boolean containsParameter(String name) {
>>>>>
>>>>>   hasParameter instead of containsParameter?
>>>>   +        return params.containsKey(name);
>>>>> +    }
>>>>> +
>>>>> +    /**
>>>>> +     * Get an iterator of the parameter names. Each entry in the
>>>>> Iterator is a
>>>>> +     * String.
>>>>> +     *
>>>>> +     * @return an Iterator of Strings listing the names of the
>>>>> parameters which
>>>>> +     *         have been specified for this test.
>>>>> +     */
>>>>> +    public Iterator<String> getParameterNamesIterator() {
>>>>> +        return params.keySet().iterator();
>>>>> +    }
>>>>> +
>>>>> +    /**
>>>>> +     * Get the value of a specific parameter as a String, or null if
>>>>> the
>>>>> value
>>>>> +     * was not specified.
>>>>> +     *
>>>>> +     * @param name
>>>>> +     *            the name of the parameter whose value should be
>>>>> retrieved
>>>>> +     * @return the value of the parameter, or null if the value was not
>>>>> +     *         specified
>>>>> +     */
>>>>> +    public String getParameter(String name) {
>>>>> +        return getParameter(name, null);
>>>>> +    }
>>>>> +
>>>>> +    /**
>>>>> +     * Get the value of a specified parameter as a String, or return
>>>>> the
>>>>> +     * specified default value if the value was not specified.
>>>>> +     *
>>>>> +     * @param name
>>>>> +     *            the name of the parameter whose value should be
>>>>> retrieved
>>>>> +     * @param defaultValue
>>>>> +     *            the default value to return if the value of this
>>>>> parameter was
>>>>> +     *            not specified
>>>>> +     * @return the value of the parameter, or the default value if the
>>>>> parameter
>>>>> +     *         was not specified
>>>>> +     */
>>>>> +    public String getParameter(String name, String defaultValue) {
>>>>> +        if (params == null || !params.containsKey(name)) {
>>>>> +            return defaultValue;
>>>>> +        }
>>>>> +        return params.get(name);
>>>>> +    }
>>>>> +
>>>>> +    /**
>>>>> +     * Get the value of a specified parameter as an integer. An
>>>>> exception will
>>>>> +     * be thrown if the parameter is not specified or if it is not an
>>>>> integer.
>>>>> +     * The value may be specified in decimal, hexadecimal, or octal, as
>>>>> defined
>>>>> +     * by Integer.decode().
>>>>> +     *
>>>>> +     * @param name
>>>>> +     *            the name of the parameter whose value should be
>>>>> retrieved
>>>>> +     * @return the value of the parameter
>>>>> +     *
>>>>> +     * @throws NumberFormatException
>>>>> +     *             if the parameter is not specified or is not an
>>>>> integer
>>>>> +     *
>>>>> +     * @see java.lang.Integer#decode(java.lang.String)
>>>>> +     */
>>>>> +    public int getIntParameter(String name) throws
>>>>> NumberFormatException
>>>>> {
>>>>> +        if (params == null || !params.containsKey(name)) {
>>>>> +            throw new NumberFormatException("No value for parameter
>>>>> named '" + name + "'.");
>>>>>
>>>>>   I would expect an IllegalArgumentException, if no parameter of that
>>>> name
>>>> is found
>>>>
>>>>   +        }
>>>>> +
>>>>> +        return Integer.decode(params.get(name)).intValue();
>>>>> +    }
>>>>> +
>>>>> +    /**
>>>>> +     * Get the value of a specified parameter as an integer, or return
>>>>> the
>>>>> +     * specified default value if the value was not specified or is not
>>>>> an
>>>>> +     * integer. A warning will be logged if the value is not an
>>>>> integer.
>>>>> The
>>>>> +     * value may be specified in decimal, hexadecimal, or octal, as
>>>>> defined by
>>>>> +     * Integer.decode().
>>>>> +     *
>>>>> +     * @param name
>>>>> +     *            the name of the parameter whose value should be
>>>>> retrieved
>>>>> +     * @param defaultValue
>>>>> +     *            the default value to return if the value of this
>>>>> parameter was
>>>>> +     *            not specified
>>>>> +     * @return the value of the parameter, or the default value if the
>>>>> parameter
>>>>> +     *         was not specified
>>>>> +     *
>>>>> +     * @see java.lang.Integer#decode(java.lang.String)
>>>>> +     */
>>>>> +    public int getIntParameter(String name, int defaultValue) {
>>>>> +        if (params == null || !params.containsKey(name)) {
>>>>> +            return defaultValue;
>>>>> +        }
>>>>> +
>>>>> +        try {
>>>>> +            return Integer.decode(params.get(name)).intValue();
>>>>> +        } catch (NumberFormatException e) {
>>>>> +            log.warn("Value for parameter '" + name + "' not an
>>>>> integer:
>>>>> '" + params.get(name) + "'.  Using default: '"
>>>>> +                    + defaultValue + "'.", e);
>>>>> +            return defaultValue;
>>>>> +        }
>>>>> +    }
>>>>> +
>>>>> +    /**
>>>>> +     * Get the value of a specified parameter as a long. An exception
>>>>> will be
>>>>> +     * thrown if the parameter is not specified or if it is not a long.
>>>>> The
>>>>> +     * value may be specified in decimal, hexadecimal, or octal, as
>>>>> defined by
>>>>> +     * Long.decode().
>>>>> +     *
>>>>> +     * @param name
>>>>> +     *            the name of the parameter whose value should be
>>>>> retrieved
>>>>> +     * @return the value of the parameter
>>>>> +     *
>>>>> +     * @throws NumberFormatException
>>>>> +     *             if the parameter is not specified or is not a long
>>>>> +     *
>>>>> +     * @see Long#decode(String)
>>>>> +     */
>>>>> +    public long getLongParameter(String name) throws
>>>>> NumberFormatException {
>>>>> +        if (params == null || !params.containsKey(name)) {
>>>>> +            throw new NumberFormatException("No value for parameter
>>>>> named '" + name + "'.");
>>>>> +        }
>>>>> +
>>>>> +        return Long.decode(params.get(name)).longValue();
>>>>> +    }
>>>>> +
>>>>> +    /**
>>>>> +     * Get the value of a specified parameter as along, or return the
>>>>> specified
>>>>> +     * default value if the value was not specified or is not a long. A
>>>>> warning
>>>>> +     * will be logged if the value is not a long. The value may be
>>>>> specified in
>>>>> +     * decimal, hexadecimal, or octal, as defined by Long.decode().
>>>>> +     *
>>>>> +     * @param name
>>>>> +     *            the name of the parameter whose value should be
>>>>> retrieved
>>>>> +     * @param defaultValue
>>>>> +     *            the default value to return if the value of this
>>>>> parameter was
>>>>> +     *            not specified
>>>>> +     * @return the value of the parameter, or the default value if the
>>>>> parameter
>>>>> +     *         was not specified
>>>>> +     *
>>>>> +     * @see Long#decode(String)
>>>>> +     */
>>>>> +    public long getLongParameter(String name, long defaultValue) {
>>>>> +        if (params == null || !params.containsKey(name)) {
>>>>> +            return defaultValue;
>>>>> +        }
>>>>> +        try {
>>>>> +            return Long.decode(params.get(name)).longValue();
>>>>> +        } catch (NumberFormatException e) {
>>>>> +            log.warn("Value for parameter '" + name + "' not a long: '"
>>>>> + params.get(name) + "'.  Using default: '"
>>>>> +                    + defaultValue + "'.", e);
>>>>> +            return defaultValue;
>>>>> +        }
>>>>> +    }
>>>>> +
>>>>> +    /**
>>>>> +     *
>>>>> +     * @param name
>>>>> +     * @param defaultValue
>>>>> +     * @return
>>>>>
>>>>>   No javadoc? Again three warnings more :)
>>>>   +     */
>>>>> +    public boolean getBooleanParameter(String name, boolean
>>>>> defaultValue) {
>>>>> +        if (params == null || !params.containsKey(name)) {
>>>>> +            return defaultValue;
>>>>> +        }
>>>>> +        return Boolean.valueOf(params.get(name));
>>>>> +    }
>>>>> +}
>>>>>
>>>>> Propchange: jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>>>>> backend/BackendListenerContext.java
>>>>> ------------------------------------------------------------
>>>>> ------------------
>>>>>        svn:mime-type = text/plain
>>>>>
>>>>> Added: jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>>>>> backend/BackendListenerGui.java
>>>>> URL: http://svn.apache.org/viewvc/jmeter/trunk/src/components/
>>>>> org/apache/jmeter/visualizers/backend/BackendListenerGui.
>>>>> java?rev=1641081&view=auto
>>>>> ============================================================
>>>>> ==================
>>>>> --- jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>>>>> backend/BackendListenerGui.java (added)
>>>>> +++ jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>>>>> backend/BackendListenerGui.java Sat Nov 22 15:36:37 2014
>>>>> @@ -0,0 +1,282 @@
>>>>> +/*
>>>>> + * 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.jmeter.visualizers.backend;
>>>>> +
>>>>> +import java.awt.BorderLayout;
>>>>> +import java.awt.event.ActionEvent;
>>>>> +import java.awt.event.ActionListener;
>>>>> +import java.util.ArrayList;
>>>>> +import java.util.HashSet;
>>>>> +import java.util.List;
>>>>> +import java.util.Map;
>>>>> +import java.util.Set;
>>>>> +
>>>>> +import javax.swing.ComboBoxModel;
>>>>> +import javax.swing.JComboBox;
>>>>> +import javax.swing.JLabel;
>>>>> +import javax.swing.JPanel;
>>>>> +import javax.swing.JTextField;
>>>>> +
>>>>> +import org.apache.jmeter.config.Argument;
>>>>> +import org.apache.jmeter.config.Arguments;
>>>>> +import org.apache.jmeter.config.gui.ArgumentsPanel;
>>>>> +import org.apache.jmeter.gui.util.HorizontalPanel;
>>>>> +import org.apache.jmeter.testelement.TestElement;
>>>>> +import org.apache.jmeter.testelement.property.PropertyIterator;
>>>>> +import org.apache.jmeter.util.JMeterUtils;
>>>>> +import org.apache.jmeter.visualizers.gui.AbstractListenerGui;
>>>>> +import org.apache.jorphan.logging.LoggingManager;
>>>>> +import org.apache.jorphan.reflect.ClassFinder;
>>>>> +import org.apache.log.Logger;
>>>>> +
>>>>> +/**
>>>>> + * The <code>BackendListenerGui</code> class provides the user
>>>>> interface for the
>>>>> + * {@link BackendListener} object.
>>>>> + * @since 2.13
>>>>> + */
>>>>> +public class BackendListenerGui extends AbstractListenerGui implements
>>>>> ActionListener {
>>>>> +
>>>>> +    /**
>>>>> +     *
>>>>> +     */
>>>>> +    private static final long serialVersionUID = 4331668988576438604L;
>>>>> +
>>>>> +    /** Logging */
>>>>> +    private static final Logger log = LoggingManager.
>>>>> getLoggerForClass();
>>>>> +
>>>>> +    /** A combo box allowing the user to choose a backend class. */
>>>>> +    private JComboBox classnameCombo;
>>>>> +
>>>>> +    /**
>>>>> +     * A field allowing the user to specify the size of Queue
>>>>> +     */
>>>>> +    private JTextField queueSize;
>>>>> +
>>>>> +    /** A panel allowing the user to set arguments for this test. */
>>>>> +    private ArgumentsPanel argsPanel;
>>>>> +
>>>>> +    /**
>>>>> +     * Create a new BackendListenerGui as a standalone component.
>>>>> +     */
>>>>> +    public BackendListenerGui() {
>>>>> +        super();
>>>>> +        init();
>>>>> +    }
>>>>> +
>>>>> +
>>>>> +    /** {@inheritDoc} */
>>>>> +    @Override
>>>>> +    public String getLabelResource() {
>>>>> +        return "backend_listener"; // $NON-NLS-1$
>>>>> +    }
>>>>> +
>>>>> +    /**
>>>>> +     * Initialize the GUI components and layout.
>>>>> +     */
>>>>> +    private void init() {// called from ctor, so must not be
>>>>> overridable
>>>>> +        setLayout(new BorderLayout(0, 5));
>>>>> +
>>>>> +        setBorder(makeBorder());
>>>>> +        add(makeTitlePanel(), BorderLayout.NORTH);
>>>>> +
>>>>> +        JPanel classnameRequestPanel = new JPanel(new BorderLayout(0,
>>>>> 5));
>>>>> +        classnameRequestPanel.add(createClassnamePanel(),
>>>>> BorderLayout.NORTH);
>>>>> +        classnameRequestPanel.add(createParameterPanel(),
>>>>> BorderLayout.CENTER);
>>>>> +
>>>>> +        add(classnameRequestPanel, BorderLayout.CENTER);
>>>>> +    }
>>>>> +
>>>>> +    /**
>>>>> +     * Create a panel with GUI components allowing the user to select a
>>>>> test
>>>>> +     * class.
>>>>> +     *
>>>>> +     * @return a panel containing the relevant components
>>>>> +     */
>>>>> +    private JPanel createClassnamePanel() {
>>>>> +        List<String> possibleClasses = new ArrayList<String>();
>>>>> +
>>>>> +        try {
>>>>> +            // Find all the classes which implement the
>>>>> BackendListenerClient
>>>>> +            // interface.
>>>>> +            possibleClasses = ClassFinder.findClassesThatExtend(
>>>>> JMeterUtils.getSearchPaths(),
>>>>> +                    new Class[] { BackendListenerClient.class });
>>>>> +
>>>>> +            // Remove the BackendListener class from the list since it
>>>>> only
>>>>>
>>>>>   ErrorBackendListener
>>>>   +            // implements the interface for error conditions.
>>>>> +
>>>>> +            possibleClasses.remove(BackendListener.class.getName() +
>>>>> "$ErrorBackendListenerClient");
>>>>> +        } catch (Exception e) {
>>>>> +            log.debug("Exception getting interfaces.", e);
>>>>> +        }
>>>>> +
>>>>> +        JLabel label = new JLabel(JMeterUtils.getResString("backend_
>>>>> listener_classname"));
>>>>> // $NON-NLS-1$
>>>>> +
>>>>> +        classnameCombo = new JComboBox(possibleClasses.toArray());
>>>>> +        classnameCombo.addActionListener(this);
>>>>> +        classnameCombo.setEditable(false);
>>>>> +        label.setLabelFor(classnameCombo);
>>>>> +
>>>>> +        HorizontalPanel classNamePanel = new HorizontalPanel();
>>>>> +        classNamePanel.add(label);
>>>>> +        classNamePanel.add(classnameCombo);
>>>>> +
>>>>> +        queueSize = new JTextField("", 5);
>>>>> +        queueSize.setName("Queue Size"); //$NON-NLS-1$
>>>>> +        JLabel queueSizeLabel = new JLabel(JMeterUtils.
>>>>> getResString("backend_listener_queue_size")); // $NON-NLS-1$
>>>>> +        queueSizeLabel.setLabelFor(queueSize);
>>>>> +        HorizontalPanel queueSizePanel = new HorizontalPanel();
>>>>> +        queueSizePanel.add(queueSizeLabel, BorderLayout.WEST);
>>>>> +        queueSizePanel.add(queueSize);
>>>>> +
>>>>> +        JPanel panel = new JPanel(new BorderLayout(0, 5));
>>>>> +        panel.add(classNamePanel, BorderLayout.NORTH);
>>>>> +        panel.add(queueSizePanel, BorderLayout.CENTER);
>>>>> +        return panel;
>>>>> +    }
>>>>> +
>>>>> +    /**
>>>>> +     * Handle action events for this component. This method currently
>>>>> handles
>>>>> +     * events for the classname combo box.
>>>>> +     *
>>>>> +     * @param evt
>>>>>
>>>>>   I would spend the few extra characters to make it event instead of evt
>>>>   +     *            the ActionEvent to be handled
>>>>> +     */
>>>>> +    @Override
>>>>> +    public void actionPerformed(ActionEvent evt) {
>>>>> +        if (evt.getSource() == classnameCombo) {
>>>>> +            String className = ((String) classnameCombo.
>>>>> getSelectedItem()).trim();
>>>>> +            try {
>>>>> +                BackendListenerClient client = (BackendListenerClient)
>>>>> Class.forName(className, true,
>>>>> +                        Thread.currentThread().
>>>>> getContextClassLoader()).
>>>>> newInstance();
>>>>> +
>>>>> +                Arguments currArgs = new Arguments();
>>>>> +                argsPanel.modifyTestElement(currArgs);
>>>>> +                Map<String, String> currArgsMap =
>>>>> currArgs.getArgumentsAsMap();
>>>>> +
>>>>> +                Arguments newArgs = new Arguments();
>>>>> +                Arguments testParams = null;
>>>>> +                try {
>>>>> +                    testParams = client.getDefaultParameters();
>>>>> +                } catch (AbstractMethodError e) {
>>>>> +                    log.warn("BackendListenerClient doesn't implement
>>>>> "
>>>>> +                            + "getDefaultParameters.  Default
>>>>> parameters
>>>>> won't "
>>>>> +                            + "be shown.  Please update your client
>>>>> class: " + className);
>>>>> +                }
>>>>> +
>>>>> +                if (testParams != null) {
>>>>> +                    PropertyIterator i = testParams.getArguments().
>>>>> iterator();
>>>>>
>>>>>   I would try a for loop instead of explicitly using an iterator
>>>>   +                    while (i.hasNext()) {
>>>>> +                        Argument arg = (Argument)
>>>>> i.next().getObjectValue();
>>>>> +                        String name = arg.getName();
>>>>> +                        String value = arg.getValue();
>>>>> +
>>>>> +                        // If a user has set parameters in one test,
>>>>> and
>>>>> then
>>>>> +                        // selects a different test which supports the
>>>>> same
>>>>> +                        // parameters, those parameters should have the
>>>>> same
>>>>> +                        // values that they did in the original test.
>>>>> +                        if (currArgsMap.containsKey(name)) {
>>>>> +                            String newVal = currArgsMap.get(name);
>>>>> +                            if (newVal != null && newVal.length() > 0)
>>>>> {
>>>>> +                                value = newVal;
>>>>> +                            }
>>>>> +                        }
>>>>> +                        newArgs.addArgument(name, value);
>>>>> +                    }
>>>>> +                }
>>>>> +
>>>>> +                argsPanel.configure(newArgs);
>>>>> +            } catch (Exception e) {
>>>>> +                log.error("Error getting argument list for " +
>>>>> className, e);
>>>>> +            }
>>>>> +        }
>>>>> +    }
>>>>> +
>>>>> +    /**
>>>>> +     * Create a panel containing components allowing the user to
>>>>> provide
>>>>> +     * arguments to be passed to the test class instance.
>>>>> +     *
>>>>> +     * @return a panel containing the relevant components
>>>>> +     */
>>>>> +    private JPanel createParameterPanel() {
>>>>> +        argsPanel = new ArgumentsPanel(JMeterUtils.
>>>>> getResString("backend_listener_paramtable")); // $NON-NLS-1$
>>>>> +        return argsPanel;
>>>>> +    }
>>>>> +
>>>>> +    /** {@inheritDoc} */
>>>>> +    @Override
>>>>> +    public void configure(TestElement config) {
>>>>> +        super.configure(config);
>>>>> +
>>>>> +        argsPanel.configure((Arguments) config.getProperty(
>>>>> BackendListener.ARGUMENTS).getObjectValue());
>>>>> +
>>>>> +        String className = config.getPropertyAsString(
>>>>> BackendListener.CLASSNAME);
>>>>> +        if(checkContainsClassName(classnameCombo.getModel(),
>>>>> className)) {
>>>>> +            classnameCombo.setSelectedItem(className);
>>>>> +        } else {
>>>>> +            log.error("Error setting class:'"+className+"' in
>>>>> BackendListener: "+getName()+
>>>>> +                    ", check for a missing jar in your jmeter
>>>>> 'search_paths' and 'plugin_dependency_paths' properties");
>>>>> +        }
>>>>> +        queueSize.setText(Integer.toString(((BackendListener)
>>>>> config).getQueueSize()));
>>>>> +    }
>>>>> +
>>>>> +    /**
>>>>> +     * Check combo contains className
>>>>> +     * @param model ComboBoxModel
>>>>> +     * @param className String class name
>>>>> +     * @return boolean
>>>>>
>>>>>   explain "boolean" or the other params a bit more?
>>>>   +     */
>>>>> +    private static final boolean checkContainsClassName(ComboBoxModel
>>>>> model, String className) {
>>>>> +        int size = model.getSize();
>>>>> +        Set<String> set = new HashSet<String>(size);
>>>>> +        for (int i = 0; i < size; i++) {
>>>>> +            set.add((String)model.getElementAt(i));
>>>>> +        }
>>>>> +        return set.contains(className);
>>>>> +    }
>>>>> +
>>>>> +    /** {@inheritDoc} */
>>>>> +    @Override
>>>>> +    public TestElement createTestElement() {
>>>>> +        BackendListener config = new BackendListener();
>>>>> +        modifyTestElement(config);
>>>>> +        return config;
>>>>> +    }
>>>>> +
>>>>> +    /** {@inheritDoc} */
>>>>> +    @Override
>>>>> +    public void modifyTestElement(TestElement config) {
>>>>> +        configureTestElement(config);
>>>>> +        BackendListener backendListener = (BackendListener) config;
>>>>> +        backendListener.setArguments((Arguments)
>>>>> argsPanel.createTestElement());
>>>>> +        backendListener.setClassname(String.valueOf(classnameCombo.
>>>>> getSelectedItem()));
>>>>> +        backendListener.setQueueSize(Integer.parseInt(queueSize.
>>>>> getText()));
>>>>> +
>>>>> +    }
>>>>> +
>>>>>


Re: svn commit: r1641081 - in /jmeter/trunk: ./ bin/ res/maven/ src/components/org/apache/jmeter/visualizers/backend/ src/core/org/apache/jmeter/resources/ src/core/org/apache/jmeter/samplers/ src/core/org/apache/jmeter/save/ xdocs/ xdocs/usermanual/

Posted by Philippe Mouawad <ph...@gmail.com>.
Thanks a lot for your review which pointed to a synchronisation issue that
I fixed, good catch!

I think I took all your notes into account, let me know if I forgot
something.

Regards
Philippe

On Sunday, November 23, 2014, Felix Schumacher <
felix.schumacher@internetallee.de> wrote:

> Hi Phillipe,
> Am 22.11.2014 um 19:29 schrieb Philippe Mouawad:
>
>> Hi Felix,
>> As I said in thread, I commited code and will improve, feel free to fix
>> javadocs issues on your side.
>> I will review your comment.
>>
>> I have spent many hours if not days on this code and I am aware it is not
>> yet fully completed (although tests are promising) but my aim when
>> commiting it was to have feedback and help to finish it.
>>
> I did not mean to offend you. I can clearly see, that you put a lot of
> effort
> in this listener and I will surely try to integrate jmeter into our
> collectd server.
>
> Regards
>  Felix
>
>>
>> Regards
>> Philippe
>>
>> On Sat, Nov 22, 2014 at 7:21 PM, Felix Schumacher <
>> felix.schumacher@internetallee.de> wrote:
>>
>>  Hello Philippe,
>>>
>>> I have hidden a few comments inside the cited code.
>>> They are mostly around javadoc and naming things.
>>>
>>> Am 22.11.2014 um 16:36 schrieb pmouawad@apache.org:
>>>
>>>  Author: pmouawad
>>>> Date: Sat Nov 22 15:36:37 2014
>>>> New Revision: 1641081
>>>>
>>>> URL: http://svn.apache.org/r1641081
>>>> Log:
>>>> Bug 55932 - Create a Async BackendListener to allow easy plug of new
>>>> listener (Graphite, JDBC, Console,...)
>>>> Bugzilla Id: 55932
>>>>
>>>> Added:
>>>>       jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>>>> backend/
>>>>       jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>>>> backend/
>>>> AbstractBackendListenerClient.java   (with props)
>>>>       jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>>>> backend/BackendListener.java
>>>>   (with props)
>>>>       jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>>>> backend/BackendListenerClient.java   (with props)
>>>>       jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>>>> backend/BackendListenerContext.java
>>>>   (with props)
>>>>       jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>>>> backend/BackendListenerGui.java   (with props)
>>>>       jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>>>> backend/SamplerMetric.java
>>>>   (with props)
>>>> Modified:
>>>>       jmeter/trunk/bin/saveservice.properties
>>>>       jmeter/trunk/build.properties
>>>>       jmeter/trunk/build.xml
>>>>       jmeter/trunk/eclipse.classpath
>>>>       jmeter/trunk/res/maven/ApacheJMeter_parent.pom
>>>>       jmeter/trunk/src/core/org/apache/jmeter/resources/
>>>> messages.properties
>>>>       jmeter/trunk/src/core/org/apache/jmeter/resources/
>>>> messages_fr.properties
>>>>       jmeter/trunk/src/core/org/apache/jmeter/samplers/
>>>> SampleResult.java
>>>>       jmeter/trunk/src/core/org/apache/jmeter/save/SaveService.java
>>>>       jmeter/trunk/xdocs/changes.xml
>>>>       jmeter/trunk/xdocs/usermanual/component_reference.xml
>>>>
>>>> Modified: jmeter/trunk/bin/saveservice.properties
>>>> URL: http://svn.apache.org/viewvc/jmeter/trunk/bin/saveservice.
>>>> properties?rev=1641081&r1=1641080&r2=1641081&view=diff
>>>> ============================================================
>>>> ==================
>>>> --- jmeter/trunk/bin/saveservice.properties (original)
>>>> +++ jmeter/trunk/bin/saveservice.properties Sat Nov 22 15:36:37 2014
>>>> @@ -53,7 +53,8 @@ _file_version=$Revision$
>>>>    # 2.5 = 2.10
>>>>    # 2.6 = 2.11
>>>>    # 2.7 = 2.12
>>>> -_version=2.7
>>>> +# 2.8 = 2.13
>>>> +_version=2.8
>>>>    #
>>>>    #
>>>>    # Character set encoding used to read and write JMeter XML files and
>>>> CSV results
>>>> @@ -78,6 +79,8 @@ AssertionVisualizer=org.apache.jmeter.vi
>>>>    AuthManager=org.apache.jmeter.protocol.http.control.AuthManager
>>>>    Authorization=org.apache.jmeter.protocol.http.control.Authorization
>>>>    AuthPanel=org.apache.jmeter.protocol.http.gui.AuthPanel
>>>> +BackendListener=org.apache.jmeter.visualizers.backend.BackendListener
>>>> +BackendListenerGui=org.apache.jmeter.visualizers.
>>>> backend.BackendListenerGui
>>>>    BarChart=org.apache.jmeter.testelement.BarChart
>>>>    BarChartGui=org.apache.jmeter.report.gui.BarChartGui
>>>>    BeanShellAssertion=org.apache.jmeter.assertions.BeanShellAssertion
>>>>
>>>> Modified: jmeter/trunk/build.properties
>>>> URL: http://svn.apache.org/viewvc/jmeter/trunk/build.properties?
>>>> rev=1641081&r1=1641080&r2=1641081&view=diff
>>>> ============================================================
>>>> ==================
>>>> --- jmeter/trunk/build.properties (original)
>>>> +++ jmeter/trunk/build.properties Sat Nov 22 15:36:37 2014
>>>> @@ -118,11 +118,21 @@ commons-logging.loc         = ${maven2.r
>>>>    #commons-logging.md5         = E2C390FE739B2550A218262B28F290CE
>>>>    commons-logging.md5         = 040b4b4d8eac886f6b4a2a3bd2f31b00
>>>>    +commons-math3.version         = 3.3
>>>> +commons-math3.jar             = commons-math3-${commons-math3.
>>>> version}.jar
>>>> +commons-math3.loc             = ${maven2.repo}/org/apache/
>>>> commons/commons-math3/${commons-math3.version}
>>>> +commons-math3.md5             = 87346cf2772dc2becf106c45e0f63863
>>>> +
>>>>    commons-net.version         = 3.3
>>>>    commons-net.jar             = commons-net-${commons-net.version}.jar
>>>>    commons-net.loc             = ${maven2.repo}/commons-net/
>>>> commons-net/${commons-net.version}
>>>>    commons-net.md5             = c077ca61598e9c21f43f8b6488fbbee9
>>>>    +commons-pool2.version         = 2.2
>>>> +commons-pool2.jar             = commons-pool2-${commons-pool2.
>>>> version}.jar
>>>> +commons-pool2.loc             = ${maven2.repo}/org/apache/
>>>> commons/commons-pool2/${commons-pool2.version}
>>>> +commons-pool2.md5             = 51b56c92883812c56fbeb339866ce2df
>>>> +
>>>>    # dnsjava for DNSCacheManager
>>>>    dnsjava.version             = 2.1.6
>>>>    dnsjava.jar                 = dnsjava-${dnsjava.version}.jar
>>>>
>>>> Modified: jmeter/trunk/build.xml
>>>> URL: http://svn.apache.org/viewvc/jmeter/trunk/build.xml?rev=
>>>> 1641081&r1=1641080&r2=1641081&view=diff
>>>> ============================================================
>>>> ==================
>>>> --- jmeter/trunk/build.xml (original)
>>>> +++ jmeter/trunk/build.xml Sat Nov 22 15:36:37 2014
>>>> @@ -365,7 +365,9 @@
>>>>        <include name="${lib.dir}/${commons-jexl2.jar}"/>
>>>>        <include name="${lib.dir}/${commons-lang3.jar}"/>
>>>>        <include name="${lib.dir}/${commons-logging.jar}"/>
>>>> +    <include name="${lib.dir}/${commons-math3}"/>
>>>>        <include name="${lib.dir}/${commons-net.jar}"/>
>>>> +    <include name="${lib.dir}/${commons-pool2.jar}"/>
>>>>        <include name="${lib.dir}/${dnsjava.jar}"/>
>>>>        <include name="${lib.dir}/${excalibur-datasource.jar}"/>
>>>>        <include name="${lib.dir}/${excalibur-instrument.jar}"/>
>>>> @@ -438,8 +440,10 @@
>>>>        <pathelement location="${lib.dir}/${commons-jexl2.jar}"/>
>>>>        <pathelement location="${lib.dir}/${commons-lang3.jar}"/>
>>>>        <pathelement location="${lib.dir}/${commons-logging.jar}"/>
>>>> +    <pathelement location="${lib.dir}/${commons-math3.jar}"/>
>>>>        <pathelement location="${lib.dir}/${commons-net.jar}"/>
>>>> -    <pathelement location="${lib.dir}/${dnsjava.jar}"/>
>>>> +       <pathelement location="${lib.dir}/${commons-pool2.jar}"/>
>>>> +       <pathelement location="${lib.dir}/${dnsjava.jar}"/>
>>>>        <pathelement location="${lib.dir}/${excalibur-datasource.jar}"/>
>>>>        <pathelement location="${lib.dir}/${excalibur-instrument.jar}"/>
>>>>        <pathelement location="${lib.dir}/${excalibur-logger.jar}"/>
>>>> @@ -2909,7 +2913,9 @@ run JMeter unless all the JMeter jars ar
>>>>            <process_jarfile jarname="commons-jexl2"/>
>>>>            <process_jarfile jarname="commons-lang3"/>
>>>>            <process_jarfile jarname="commons-logging"/>
>>>> +        <process_jarfile jarname="commons-math3"/>
>>>>            <process_jarfile jarname="commons-net"/>
>>>> +       <process_jarfile jarname="commons-pool2"/>
>>>>            <process_jarfile jarname="dnsjava"/>
>>>>            <process_jarfile jarname="excalibur-datasource"/>
>>>>            <process_jarfile jarname="excalibur-instrument"/>
>>>>
>>>> Modified: jmeter/trunk/eclipse.classpath
>>>> URL: http://svn.apache.org/viewvc/jmeter/trunk/eclipse.
>>>> classpath?rev=1641081&r1=1641080&r2=1641081&view=diff
>>>> ============================================================
>>>> ==================
>>>> --- jmeter/trunk/eclipse.classpath (original)
>>>> +++ jmeter/trunk/eclipse.classpath Sat Nov 22 15:36:37 2014
>>>> @@ -55,7 +55,9 @@
>>>>          <classpathentry kind="lib" path="lib/commons-jexl-2.1.1.jar"/>
>>>>          <classpathentry kind="lib" path="lib/commons-lang3-3.3.2.
>>>> jar"/>
>>>>          <classpathentry kind="lib" path="lib/commons-logging-1.2.
>>>> jar"/>
>>>> +    <classpathentry kind="lib" path="lib/commons-math3-3.3.jar"/>
>>>>          <classpathentry kind="lib" path="lib/commons-net-3.3.jar"/>
>>>> +    <classpathentry kind="lib" path="lib/commons-pool2-2.2.jar"/>
>>>>          <classpathentry kind="lib" path="lib/dnsjava-2.1.6.jar"/>
>>>>          <classpathentry kind="lib" path="lib/excalibur-
>>>> datasource-2.1.jar"/>
>>>>          <classpathentry kind="lib" path="lib/excalibur-
>>>> instrument-1.0.jar"/>
>>>>
>>>> Modified: jmeter/trunk/res/maven/ApacheJMeter_parent.pom
>>>> URL: http://svn.apache.org/viewvc/jmeter/trunk/res/maven/
>>>> ApacheJMeter_parent.pom?rev=1641081&r1=1641080&r2=1641081&view=diff
>>>> ============================================================
>>>> ==================
>>>> --- jmeter/trunk/res/maven/ApacheJMeter_parent.pom (original)
>>>> +++ jmeter/trunk/res/maven/ApacheJMeter_parent.pom Sat Nov 22 15:36:37
>>>> 2014
>>>> @@ -66,7 +66,9 @@ under the License.
>>>>          <commons-jexl2.version>2.1.1</commons-jexl2.version>
>>>>          <commons-lang3.version>3.3.2</commons-lang3.version>
>>>>          <commons-logging.version>1.2</commons-logging.version>
>>>> +      <commons-math3.version>3.3</commons-math3.version>
>>>>          <commons-net.version>3.3</commons-net.version>
>>>> +      <commons-pool2.version>2.2</commons-pool2.version>
>>>>          <dnsjava.version>2.1.6</dnsjava.version>
>>>>          <excalibur-datasource.version>2.1</excalibur-datasource.
>>>> version>
>>>>          <excalibur-instrument.version>1.0</excalibur-instrument.
>>>> version>
>>>> @@ -181,11 +183,21 @@ under the License.
>>>>            <version>${commons-logging.version}</version>
>>>>          </dependency>
>>>>          <dependency>
>>>> +        <groupId>commons-math3</groupId>
>>>> +        <artifactId>commons-math3</artifactId>
>>>> +        <version>${commons-math3.version}</version>
>>>> +      </dependency>
>>>> +      <dependency>
>>>>            <groupId>commons-net</groupId>
>>>>            <artifactId>commons-net</artifactId>
>>>>            <version>${commons-net.version}</version>
>>>>          </dependency>
>>>>          <dependency>
>>>> +        <groupId>commons-pool2</groupId>
>>>> +        <artifactId>commons-pool2</artifactId>
>>>> +        <version>${commons-pool2.version}</version>
>>>> +      </dependency>
>>>> +      <dependency>
>>>>              <groupId>dnsjava</groupId>
>>>>              <artifactId>dnsjava</artifactId>
>>>>              <version>${dnsjava.version}</version>
>>>>
>>>> Added: jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>>>> backend/
>>>> AbstractBackendListenerClient.java
>>>> URL: http://svn.apache.org/viewvc/jmeter/trunk/src/components/
>>>> org/apache/jmeter/visualizers/backend/AbstractBackendListenerClient.
>>>> java?rev=1641081&view=auto
>>>> ============================================================
>>>> ==================
>>>> --- jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/
>>>> AbstractBackendListenerClient.java (added)
>>>> +++ jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/
>>>> AbstractBackendListenerClient.java Sat Nov 22 15:36:37 2014
>>>> @@ -0,0 +1,121 @@
>>>> +/*
>>>> + * 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.jmeter.visualizers.backend;
>>>> +
>>>> +import java.util.Map;
>>>> +import java.util.concurrent.ConcurrentHashMap;
>>>> +
>>>> +import org.apache.jmeter.config.Arguments;
>>>> +import org.apache.jmeter.samplers.SampleResult;
>>>> +import org.apache.jorphan.logging.LoggingManager;
>>>> +import org.apache.log.Logger;
>>>> +
>>>> +/**
>>>> + * An abstract implementation of the BackendListenerClient interface.
>>>> This
>>>> + * implementation provides default implementations of most of the
>>>> methods in the
>>>> + * interface, as well as some convenience methods, in order to simplify
>>>> + * development of BackendListenerClient implementations.
>>>> + *
>>>> + * While it may be necessary to make changes to the
>>>> BackendListenerClient interface
>>>> + * from time to time (therefore requiring changes to any
>>>> implementations
>>>> of this
>>>> + * interface), we intend to make this abstract class provide reasonable
>>>> + * implementations of any new methods so that subclasses do not
>>>> necessarily need
>>>> + * to be updated for new versions. Therefore, when creating a new
>>>> + * BackendListenerClient implementation, developers are encouraged to
>>>> subclass this
>>>> + * abstract class rather than implementing the BackendListenerClient
>>>> interface
>>>> + * directly. Implementing BackendListenerClient directly will continue
>>>> to be
>>>> + * supported for cases where extending this class is not possible (for
>>>> example,
>>>> + * when the client class is already a subclass of some other class).
>>>> + * <p>
>>>> + * The handleSampleResult() method of BackendListenerClient does not
>>>> have a default
>>>> + * implementation here, so subclasses must define at least this method.
>>>> It may
>>>> + * be useful to override other methods as well.
>>>> + *
>>>> + * @see BackendListener#sampleOccurred(org.apache.
>>>> jmeter.samplers.SampleEvent)
>>>> + * @since 2.13
>>>> + */
>>>> +public abstract class AbstractBackendListenerClient implements
>>>> BackendListenerClient {
>>>> +
>>>> +    private static final Logger log = LoggingManager.
>>>> getLoggerForClass();
>>>>
>>>>  In classes further down the logger is stored in variables named LOG and
>>> LOGGER, should we use one name?
>>> In this class we have a getter for the logger in other classes not. Why?
>>>
>>>  +
>>>> +    private ConcurrentHashMap<String, SamplerMetric> metricsPerSampler
>>>> =
>>>> new ConcurrentHashMap<String, SamplerMetric>();
>>>> +
>>>> +    /* Implements BackendListenerClient.setupTest(JavaSamplerContext)
>>>> */
>>>> +    @Override
>>>> +    public void setupTest(BackendListenerContext context) throws
>>>> Exception {
>>>> +        log.debug(getClass().getName() + ": setupTest");
>>>> +    }
>>>> +
>>>> +    /* Implements BackendListenerClient.teardownTest(
>>>> JavaSamplerContext)
>>>> */
>>>> +    @Override
>>>> +    public void teardownTest(BackendListenerContext context) throws
>>>> Exception {
>>>> +        log.debug(getClass().getName() + ": teardownTest");
>>>> +        metricsPerSampler.clear();
>>>> +    }
>>>> +
>>>> +    /* Implements BackendListenerClient.getDefaultParameters() */
>>>> +    @Override
>>>> +    public Arguments getDefaultParameters() {
>>>> +        return null;
>>>> +    }
>>>> +
>>>> +    /**
>>>> +     * Get a Logger instance which can be used by subclasses to log
>>>> information.
>>>> +     *
>>>> +     * @return a Logger instance which can be used for logging
>>>> +     */
>>>> +    protected Logger getLogger() {
>>>> +        return log;
>>>> +    }
>>>> +
>>>> +    /* (non-Javadoc)
>>>> +     * @see org.apache.jmeter.visualizers.
>>>> backend.BackendListenerClient#
>>>> createSampleResult(org.apache.jmeter.samplers.SampleResult)
>>>> +     */
>>>> +    @Override
>>>> +    public SampleResult createSampleResult(BackendListenerContext
>>>> context, SampleResult result) {
>>>> +        SampleResult sampleResult = (SampleResult) result.clone();
>>>> +        return sampleResult;
>>>> +    }
>>>> +
>>>> +    /**
>>>> +     *
>>>> +     * @param sampleLabel
>>>> +     * @return SamplerMetric
>>>>
>>>>  No description of the method and the parameters?
>>>
>>>  +     */
>>>> +    protected SamplerMetric getSamplerMetric(String sampleLabel) {
>>>> +        SamplerMetric samplerMetric = metricsPerSampler.get(
>>>> sampleLabel);
>>>> +        if(samplerMetric == null) {
>>>> +            samplerMetric = new SamplerMetric();
>>>> +            SamplerMetric oldValue = metricsPerSampler.putIfAbsent(
>>>> sampleLabel,
>>>> samplerMetric);
>>>> +            if(oldValue != null ){
>>>> +                samplerMetric = oldValue;
>>>> +            }
>>>> +        }
>>>> +        return samplerMetric;
>>>> +    }
>>>> +
>>>> +    /**
>>>> +     *
>>>> +     * @return Map<String, SamplerMetric>
>>>>
>>>>  No description of the method and usage of forbidden characters :) there
>>> are still more than 800 warnings in the javadoc to prune, so don't
>>> introduce new ones, please.
>>>
>>>  +     */
>>>> +    protected Map<String, SamplerMetric> getMetricsPerSampler() {
>>>> +        return metricsPerSampler;
>>>> +    }
>>>> +
>>>> +}
>>>>
>>>> Propchange: jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>>>> backend/AbstractBackendListenerClient.java
>>>> ------------------------------------------------------------
>>>> ------------------
>>>>       svn:mime-type = text/plain
>>>>
>>>> Added: jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>>>> backend/BackendListener.java
>>>> URL: http://svn.apache.org/viewvc/jmeter/trunk/src/components/
>>>> org/apache/jmeter/visualizers/backend/BackendListener.java?
>>>> rev=1641081&view=auto
>>>> ============================================================
>>>> ==================
>>>> --- jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>>>> backend/BackendListener.java
>>>> (added)
>>>> +++ jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>>>> backend/BackendListener.java
>>>> Sat Nov 22 15:36:37 2014
>>>> @@ -0,0 +1,448 @@
>>>> +/*
>>>> + * 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.jmeter.visualizers.backend;
>>>> +
>>>> +import java.io.Serializable;
>>>> +import java.lang.reflect.Method;
>>>> +import java.util.ArrayList;
>>>> +import java.util.HashSet;
>>>> +import java.util.List;
>>>> +import java.util.Set;
>>>> +import java.util.concurrent.ArrayBlockingQueue;
>>>> +import java.util.concurrent.BlockingQueue;
>>>> +import java.util.concurrent.locks.LockSupport;
>>>> +
>>>> +import org.apache.jmeter.config.Arguments;
>>>> +import org.apache.jmeter.engine.util.NoThreadClone;
>>>> +import org.apache.jmeter.protocol.java.sampler.JavaSamplerContext;
>>>> +import org.apache.jmeter.samplers.Remoteable;
>>>> +import org.apache.jmeter.samplers.SampleEvent;
>>>> +import org.apache.jmeter.samplers.SampleListener;
>>>> +import org.apache.jmeter.samplers.SampleResult;
>>>> +import org.apache.jmeter.testelement.AbstractTestElement;
>>>> +import org.apache.jmeter.testelement.TestElement;
>>>> +import org.apache.jmeter.testelement.TestStateListener;
>>>> +import org.apache.jmeter.testelement.property.TestElementProperty;
>>>> +import org.apache.jorphan.logging.LoggingManager;
>>>> +import org.apache.log.Logger;
>>>> +
>>>> +/**
>>>> + * Async Listener that delegates SampleResult handling to
>>>> implementations of {@link BackendListenerClient}
>>>> + * @since 2.13
>>>> + */
>>>> +public class BackendListener extends AbstractTestElement
>>>> +    implements Serializable, SampleListener, TestStateListener,
>>>> NoThreadClone, Remoteable  {
>>>> +
>>>> +    /**
>>>> +     *
>>>> +     */
>>>> +    private static final long serialVersionUID = 8184103677832024335L;
>>>> +
>>>> +    private static final Logger log = LoggingManager.
>>>> getLoggerForClass();
>>>>
>>>>  See naming comment of log from above
>>>
>>>  +
>>>> +    /**
>>>> +     * Set used to register instances which implement teardownTest.
>>>> +     * This is used so that the BackendListenerClient can be notified
>>>> when the test ends.
>>>> +     */
>>>> +    private static final Set<BackendListener> TEAR_DOWN_SET = new
>>>> HashSet<BackendListener>();
>>>> +
>>>> +    /**
>>>> +     * Property key representing the classname of the
>>>> BackendListenerClient to user.
>>>> +     */
>>>> +    public static final String CLASSNAME = "classname";
>>>> +
>>>> +    /**
>>>> +     * Queue size
>>>> +     */
>>>> +    public static final String QUEUE_SIZE = "QUEUE_SIZE";
>>>> +
>>>> +    /**
>>>> +     * Property key representing the arguments for the
>>>> BackendListenerClient.
>>>> +     */
>>>> +    public static final String ARGUMENTS = "arguments";
>>>> +
>>>> +    /**
>>>> +     * The BackendListenerClient class used by this sampler.
>>>> +     * Created by testStarted; copied to cloned instances.
>>>> +     */
>>>> +    private Class<?> javaClass;
>>>>
>>>>  Could probably named clientClass instead of javaClass, since we already
>>> know it is a java class.
>>>
>>>  +
>>>> +    /**
>>>> +     * If true, the BackendListenerClient class implements
>>>> teardownTest.
>>>> +     * Created by testStarted; copied to cloned instances.
>>>> +     */
>>>> +    private boolean isToBeRegistered;
>>>> +
>>>> +    /**
>>>> +     * The BackendListenerClient instance
>>>> +     */
>>>> +    private transient BackendListenerClient backendListenerClient =
>>>> null;
>>>> +
>>>> +    /**
>>>> +     * The JavaSamplerContext instance used by this sampler to hold
>>>> information
>>>>
>>>>  BackendListenerContext?
>>>
>>>  +     * related to the test run, such as the parameters specified for
>>>> the
>>>> sampler
>>>> +     * client.
>>>> +     */
>>>> +    private transient BackendListenerContext context = null;
>>>> +
>>>> +    private static final int DEFAULT_QUEUE_SIZE = 5000;
>>>> +
>>>> +    private transient BlockingQueue<SampleResult> queue; // created by
>>>> server in readResolve method
>>>> +
>>>> +    private transient long queueWaits; // how many times we had to wait
>>>> to queue a sample
>>>> +
>>>> +    private transient long queueWaitTime; // how long we had to wait
>>>> (nanoSeconds)
>>>> +
>>>> +    // Create unique object as marker for end of queue
>>>> +    private transient static final SampleResult FINAL_EVENT = new
>>>> SampleResult();
>>>> +
>>>> +    /**
>>>> +     * Create a BackendListener.
>>>> +     */
>>>> +    public BackendListener() {
>>>> +        setArguments(new Arguments());
>>>> +    }
>>>> +
>>>> +    /*
>>>> +     * Ensure that the required class variables are cloned,
>>>> +     * as this is not currently done by the super-implementation.
>>>> +     */
>>>> +    @Override
>>>> +    public Object clone() {
>>>> +        BackendListener clone = (BackendListener) super.clone();
>>>> +        clone.javaClass = this.javaClass;
>>>> +        clone.isToBeRegistered = this.isToBeRegistered;
>>>> +        return clone;
>>>> +    }
>>>> +
>>>> +    private void initClass() {
>>>> +        String name = getClassname().trim();
>>>> +        try {
>>>> +            javaClass = Class.forName(name, false,
>>>> Thread.currentThread().getContextClassLoader());
>>>> +            Method method = javaClass.getMethod("teardownTest", new
>>>> Class[]{BackendListenerContext.class});
>>>> +            isToBeRegistered = !method.getDeclaringClass().equals(
>>>> AbstractBackendListenerClient.class);
>>>> +            log.info("Created class: " + name + ". Uses teardownTest:
>>>> "
>>>> + isToBeRegistered);
>>>> +        } catch (Exception e) {
>>>> +            log.error(whoAmI() + "\tException initialising: " + name,
>>>> e);
>>>> +        }
>>>> +    }
>>>> +
>>>> +    /**
>>>> +     * Retrieves reference to BackendListenerClient.
>>>> +     *
>>>> +     * Convience method used to check for null reference without
>>>> actually
>>>> +     * creating a BackendListenerClient
>>>> +     *
>>>> +     * @return reference to BackendListenerClient NOTUSED private
>>>> BackendListenerClient
>>>> +     *         retrieveJavaClient() { return javaClient; }
>>>> +     */
>>>>
>>>>  Javadoc for non-existant method?
>>>
>>>  +
>>>> +    /**
>>>> +     * Generate a String identifier of this instance for debugging
>>>> purposes.
>>>> +     *
>>>> +     * @return a String identifier for this sampler instance
>>>> +     */
>>>> +    private String whoAmI() {
>>>> +        StringBuilder sb = new StringBuilder();
>>>> +        sb.append(Thread.currentThread().getName());
>>>> +        sb.append("@");
>>>> +        sb.append(Integer.toHexString(hashCode()));
>>>> +        sb.append("-");
>>>> +        sb.append(getName());
>>>> +        return sb.toString();
>>>> +    }
>>>> +
>>>> +    // TestStateListener implementation
>>>> +    /* Implements TestStateListener.testStarted() */
>>>> +    @Override
>>>> +    public void testStarted() {
>>>> +        testStarted("");
>>>> +    }
>>>> +
>>>> +    /* Implements TestStateListener.testStarted(String) */
>>>> +    @Override
>>>> +    public void testStarted(String host) {
>>>> +        log.debug(whoAmI() + "\ttestStarted(" + host + ")");
>>>>
>>>>  Maybe use isDebugEnabled to guard whoAmI() call?
>>>
>>>  +        queue = new ArrayBlockingQueue<SampleResult>(getQueueSize());
>>>> +        initClass();
>>>> +        queueWaits=0L;
>>>> +        queueWaitTime=0L;
>>>> +        log.info(getName()+":Starting worker with class:"+javaClass +"
>>>> and queue capacity:"+getQueueSize());
>>>> +
>>>> +        backendListenerClient = createBackendListenerClientImp
>>>> l(javaClass);
>>>> +        context = new BackendListenerContext((
>>>> Arguments)getArguments().
>>>> clone());
>>>> +        if(isToBeRegistered) {
>>>>
>>>>  space after if and before (?
>>>
>>>  +            TEAR_DOWN_SET.add(this);
>>>> +        }
>>>> +        try {
>>>> +            backendListenerClient.setupTest(context);
>>>> +        } catch (Exception e) {
>>>> +            throw new java.lang.IllegalStateException("Failed calling
>>>> setupTest", e);
>>>> +        }
>>>> +
>>>> +        Worker worker = new Worker(javaClass, backendListenerClient,
>>>> (Arguments) getArguments().clone(), queue);
>>>> +        worker.setDaemon(true);
>>>> +        worker.start();
>>>>
>>>>  Don't we want to stop worker after we're done with one test?
>>>
>>>  +        log.info(getName()+":Started  worker with class:"+javaClass);
>>>>
>>>>  Spaces after :?
>>>
>>>  +
>>>> +    }
>>>> +
>>>> +    /* (non-Javadoc)
>>>> +     * @see org.apache.jmeter.samplers.SampleListener#sampleOccurred(
>>>> org.apache.jmeter.samplers.SampleEvent)
>>>> +     */
>>>> +    @Override
>>>> +    public void sampleOccurred(SampleEvent e) {
>>>>
>>>>  Longer name then 'e'? I expect e to be an exception, not an event.
>>>
>>>  +        Arguments args = getArguments();
>>>> +        context = new BackendListenerContext(args);
>>>> +
>>>> +        SampleResult sr = backendListenerClient.
>>>> createSampleResult(context,
>>>> e.getResult());
>>>> +        try {
>>>> +            if (!queue.offer(sr)){ // we failed to add the element
>>>> first
>>>> time
>>>> +                queueWaits++;
>>>> +                long t1 = System.nanoTime();
>>>> +                queue.put(sr);
>>>> +                long t2 = System.nanoTime();
>>>> +                queueWaitTime += t2-t1;
>>>>
>>>>  Will sampleOccurred be called concurrently? If so, than queueWaitTime
>>> +=
>>> will not be correct.
>>>
>>>  +            }
>>>> +        } catch (Exception err) {
>>>> +            log.error("sampleOccurred, failed to queue the sample",
>>>> err);
>>>> +        }
>>>> +    }
>>>> +
>>>> +    private static final class Worker extends Thread {
>>>> +
>>>> +        private final BlockingQueue<SampleResult> queue;
>>>> +        private final BackendListenerContext context;
>>>> +        private final BackendListenerClient backendListenerClient;
>>>> +        private Worker(Class<?> javaClass, BackendListenerClient
>>>> backendListenerClient, Arguments arguments, BlockingQueue<SampleResult>
>>>> q){
>>>>
>>>>  Same naming argument as above. clientclass instead of javaClass?
>>>
>>>  +            queue = q;
>>>> +            // Allow BackendListenerClient implementations to get
>>>> access
>>>> to test element name
>>>> +            arguments.addArgument(TestElement.NAME, getName());
>>>> +            context = new BackendListenerContext(arguments);
>>>> +            this.backendListenerClient = backendListenerClient;
>>>> +        }
>>>> +
>>>> +
>>>> +        @Override
>>>> +        public void run() {
>>>> +            boolean isDebugEnabled = log.isDebugEnabled();
>>>> +            List<SampleResult> l = new ArrayList<SampleResult>(queue.
>>>> size());
>>>>
>>>>  samples instead of l?
>>>
>>>  +            try {
>>>> +                boolean eof = false;
>>>>
>>>>  endOfLoop?
>>>
>>>  +                while (!eof) {
>>>> +                    if(isDebugEnabled) {
>>>> +                        log.debug("Thread:"+Thread.
>>>> currentThread().getName()+"
>>>> taking SampleResult from queue:"+queue.size());
>>>> +                    }
>>>> +                    SampleResult e = queue.take();
>>>>
>>>>  Could be named result, or sample instead of e
>>>
>>>  +                    if(isDebugEnabled) {
>>>> +                        log.debug("Thread:"+Thread.
>>>> currentThread().getName()+"
>>>> took SampleResult:"+e+", isFinal:" + (e==FINAL_EVENT));
>>>> +                    }
>>>> +                    while (!(eof = (e == FINAL_EVENT)) && e != null ) {
>>>> // try to process as many as possible
>>>> +                        l.add(e);
>>>> +                        if(isDebugEnabled) {
>>>> +                            log.debug("Thread:"+Thread.
>>>> currentThread().getName()+"
>>>> polling from queue:"+queue.size());
>>>> +                        }
>>>> +                        e = queue.poll(); // returns null if nothing on
>>>> queue currently
>>>> +                        if(isDebugEnabled) {
>>>> +                            log.debug("Thread:"+Thread.
>>>> currentThread().getName()+"
>>>> took from queue:"+e+", isFinal:" + (e==FINAL_EVENT));
>>>> +                        }
>>>> +                    }
>>>> +                    if(isDebugEnabled) {
>>>> +                        log.debug("Thread:"+Thread.
>>>> currentThread().getName()+
>>>> +                                " exiting with FINAL EVENT:"+(e ==
>>>> FINAL_EVENT)
>>>> +                                +", null:" + (e==null));
>>>> +                    }
>>>> +                    int size = l.size();
>>>>
>>>>  No need for a temporary variable.
>>>
>>>  +                    if (size > 0) {
>>>> +                        backendListenerClient.handleSampleResults(l,
>>>> context);
>>>> +                        l.clear();
>>>> +                    }
>>>> +                    if(!eof) {
>>>> +                        LockSupport.parkNanos(100);
>>>> +                    }
>>>> +                }
>>>> +            } catch (InterruptedException e) {
>>>> +                // NOOP
>>>> +            }
>>>> +            // We may have been interrupted
>>>> +            int size = l.size();
>>>> +            if (size > 0) {
>>>> +                backendListenerClient.handleSampleResults(l, context);
>>>> +                l.clear();
>>>> +            }
>>>>
>>>>  Same code as a few lines above, could be factored out into a method
>>> handleSamples(l, context)
>>>
>>>  +            log.info("Worker ended");
>>>> +        }
>>>> +    }
>>>> +
>>>> +
>>>> +    /**
>>>> +     * Returns reference to <code>BackendListenerClient</code>.
>>>>
>>>>  Could use a {@link...}
>>>
>>>  +     *
>>>> +     *
>>>> +     * @return BackendListenerClient reference.
>>>> +     */
>>>> +    static BackendListenerClient createBackendListenerClientImp
>>>> l(Class<?>
>>>> javaClass) {
>>>> +        if (javaClass == null) { // failed to initialise the class
>>>> +            return new ErrorBackendListenerClient();
>>>> +        }
>>>> +        BackendListenerClient client;
>>>> +        try {
>>>> +            client = (BackendListenerClient) javaClass.newInstance();
>>>> +        } catch (Exception e) {
>>>> +            log.error("Exception creating: " + javaClass, e);
>>>> +            client = new ErrorBackendListenerClient();
>>>> +        }
>>>> +        return client;
>>>>
>>>>  I would return newInstance() in try Block and return new Error.. in
>>> catch
>>> Block. javaClass -> clientClass
>>>
>>>  +    }
>>>> +
>>>> +    /**
>>>> +     * Method called at the end of the test. This is called only on one
>>>> instance
>>>> +     * of BackendListener. This method will loop through all of the
>>>> other
>>>> +     * BackendListenerClients which have been registered (automatically
>>>> in the
>>>> +     * constructor) and notify them that the test has ended, allowing
>>>> the
>>>> +     * BackendListenerClients to cleanup.
>>>> +     */
>>>> +    @Override
>>>> +    public void testEnded() {
>>>> +        try {
>>>> +            queue.put(FINAL_EVENT);
>>>> +        } catch (Exception ex) {
>>>> +            log.warn("testEnded() with exception:"+ex.getMessage(),
>>>> ex);
>>>> +        }
>>>> +        if (queueWaits > 0) {
>>>> +            log.warn("QueueWaits: "+queueWaits+"; QueueWaitTime:
>>>> "+queueWaitTime+" (nanoseconds), you may need to increase queue
>>>> capacity,
>>>> see property 'backend_queue_capacity'");
>>>> +        }
>>>> +        synchronized (TEAR_DOWN_SET) {
>>>> +            for (BackendListener backendListener : TEAR_DOWN_SET) {
>>>> +                BackendListenerClient client = backendListener.
>>>> backendListenerClient;
>>>> +                if (client != null) {
>>>> +                    try {
>>>> +                        client.teardownTest(backendListener.context);
>>>> +                    } catch (Exception e) {
>>>> +                        throw new java.lang.
>>>> IllegalStateException("Failed
>>>> calling teardownTest", e);
>>>>
>>>>  If we throw an exception here, we will not try every client.
>>>
>>>  +                    }
>>>> +                }
>>>> +            }
>>>> +            TEAR_DOWN_SET.clear();
>>>> +        }
>>>> +    }
>>>> +
>>>> +    /* Implements TestStateListener.testEnded(String) */
>>>> +    @Override
>>>> +    public void testEnded(String host) {
>>>> +        testEnded();
>>>> +    }
>>>> +
>>>> +    /**
>>>> +     * A {@link BackendListenerClient} implementation used for error
>>>> handling. If an
>>>> +     * error occurs while creating the real BackendListenerClient
>>>> object, it is
>>>> +     * replaced with an instance of this class. Each time a sample
>>>> occurs with
>>>> +     * this class, the result is marked as a failure so the user can
>>>> see
>>>> that
>>>> +     * the test failed.
>>>> +     */
>>>> +    static class ErrorBackendListenerClient extends
>>>> AbstractBackendListenerClient {
>>>> +        /**
>>>> +         * Return SampleResult with data on error.
>>>> +         *
>>>> +         * @see BackendListenerClient#runTest(JavaSamplerContext)
>>>> +         */
>>>> +        @Override
>>>> +        public void handleSampleResults(List<SampleResult>
>>>> sampleResults, BackendListenerContext context) {
>>>> +            log.warn("ErrorBackendListenerClient#handleSampleResult
>>>> called, noop");
>>>> +            Thread.yield();
>>>> +        }
>>>> +    }
>>>> +
>>>> +    /* (non-Javadoc)
>>>> +     * @see org.apache.jmeter.samplers.SampleListener#sampleStarted(
>>>> org.apache.jmeter.samplers.SampleEvent)
>>>> +     */
>>>> +    @Override
>>>> +    public void sampleStarted(SampleEvent e) {
>>>> +        // NOOP
>>>> +
>>>> +    }
>>>> +
>>>> +    /* (non-Javadoc)
>>>> +     * @see org.apache.jmeter.samplers.SampleListener#sampleStopped(
>>>> org.apache.jmeter.samplers.SampleEvent)
>>>> +     */
>>>> +    @Override
>>>> +    public void sampleStopped(SampleEvent e) {
>>>> +        // NOOP
>>>> +
>>>> +    }
>>>> +
>>>> +    /**
>>>> +     * Set the arguments (parameters) for the BackendListenerClient to
>>>> be executed
>>>> +     * with.
>>>> +     *
>>>> +     * @param args
>>>> +     *            the new arguments. These replace any existing
>>>> arguments.
>>>> +     */
>>>> +    public void setArguments(Arguments args) {
>>>> +        setProperty(new TestElementProperty(ARGUMENTS, args));
>>>> +    }
>>>> +
>>>> +    /**
>>>> +     * Get the arguments (parameters) for the BackendListenerClient to
>>>> be executed
>>>> +     * with.
>>>> +     *
>>>> +     * @return the arguments
>>>> +     */
>>>> +    public Arguments getArguments() {
>>>> +        return (Arguments) getProperty(ARGUMENTS).getObjectValue();
>>>> +    }
>>>> +
>>>> +    /**
>>>> +     * Sets the Classname of the BackendListenerClient object
>>>> +     *
>>>> +     * @param classname
>>>> +     *            the new Classname value
>>>> +     */
>>>> +    public void setClassname(String classname) {
>>>> +        setProperty(CLASSNAME, classname);
>>>> +    }
>>>> +
>>>> +    /**
>>>> +     * Gets the Classname of the BackendListenerClient object
>>>> +     *
>>>> +     * @return the Classname value
>>>> +     */
>>>> +    public String getClassname() {
>>>> +        return getPropertyAsString(CLASSNAME);
>>>> +    }
>>>> +
>>>> +    /**
>>>> +     * Sets the queue size
>>>> +     *
>>>> +     * @param queueSize
>>>> +     *
>>>> +     */
>>>> +    public void setQueueSize(int queueSize) {
>>>> +        setProperty(QUEUE_SIZE, queueSize, DEFAULT_QUEUE_SIZE);
>>>> +    }
>>>> +
>>>> +    /**
>>>> +     * Gets the queue size
>>>> +     *
>>>> +     * @return int queueSize
>>>> +     */
>>>> +    public int getQueueSize() {
>>>> +        return getPropertyAsInt(QUEUE_SIZE, DEFAULT_QUEUE_SIZE);
>>>> +    }
>>>> +}
>>>>
>>>> Propchange: jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>>>> backend/BackendListener.java
>>>> ------------------------------------------------------------
>>>> ------------------
>>>>       svn:mime-type = text/plain
>>>>
>>>> Added: jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>>>> backend/BackendListenerClient.java
>>>> URL: http://svn.apache.org/viewvc/jmeter/trunk/src/components/
>>>> org/apache/jmeter/visualizers/backend/BackendListenerClient.
>>>> java?rev=1641081&view=auto
>>>> ============================================================
>>>> ==================
>>>> --- jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>>>> backend/BackendListenerClient.java (added)
>>>> +++ jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>>>> backend/BackendListenerClient.java Sat Nov 22 15:36:37 2014
>>>> @@ -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.jmeter.visualizers.backend;
>>>> +
>>>> +import java.util.List;
>>>> +
>>>> +import org.apache.jmeter.config.Arguments;
>>>> +import org.apache.jmeter.samplers.SampleResult;
>>>> +
>>>> +/**
>>>> + * This interface defines the interactions between the BackendListener
>>>> and external
>>>> + * Java programs which can be executed by JMeter. Any Java class which
>>>> wants to
>>>> + * be executed as a JMeter test must implement this interface (either
>>>> directly
>>>> + * or indirectly through AbstractBackendListenerClient).
>>>> + * <p>
>>>> + * JMeter will create one instance of a BackendListenerClient
>>>> implementation for
>>>> + * each user/thread in the test. Additional instances may be created
>>>> for
>>>> + * internal use by JMeter (for example, to find out what parameters are
>>>> + * supported by the client).
>>>> + * <p>
>>>> + * When the test is started, setupTest() will be called on each
>>>> thread's
>>>> + * BackendListenerClient instance to initialize the client. Then
>>>> handleSampleResult() will be
>>>> + * called for each SampleResult notification. Finally, teardownTest()
>>>> will be called
>>>> + * to allow the client to do any necessary clean-up.
>>>> + * <p>
>>>> + * The JMeter BackendListener GUI allows a list of parameters to be
>>>> defined for the
>>>> + * test. These are passed to the various test methods through the
>>>> + * {@link BackendListenerContext}. A list of default parameters can be
>>>> defined
>>>> + * through the getDefaultParameters() method. These parameters and any
>>>> default
>>>> + * values associated with them will be shown in the GUI. Users can add
>>>> other
>>>> + * parameters as well.
>>>> + * <p>
>>>> + * When possible, Listeners should extend {@link
>>>> AbstractBackendListenerClient
>>>> + * AbstractBackendListenerClient} rather than implementing
>>>> BackendListenerClient
>>>> + * directly. This should protect your tests from future changes to the
>>>> + * interface. While it may be necessary to make changes to the
>>>> BackendListenerClient
>>>> + * interface from time to time (therefore requiring changes to any
>>>> + * implementations of this interface), we intend to make this abstract
>>>> class
>>>> + * provide reasonable default implementations of any new methods so
>>>> that
>>>> + * subclasses do not necessarily need to be updated for new versions.
>>>> + * Implementing BackendListenerClient directly will continue to be
>>>> supported for
>>>> + * cases where extending this class is not possible (for example, when
>>>> the
>>>> + * client class is already a subclass of some other class).
>>>> + *
>>>> + * @since 2.13
>>>> + */
>>>> +public interface BackendListenerClient {
>>>> +    /**
>>>> +     * Do any initialization required by this client. It is generally
>>>> +     * recommended to do any initialization such as getting parameter
>>>> values in
>>>> +     * the setupTest method rather than the runTest method in order to
>>>> add as
>>>> +     * little overhead as possible to the test.
>>>> +     *
>>>> +     * @param context
>>>> +     *            the context to run with. This provides access to
>>>> +     *            initialization parameters.
>>>> +     */
>>>> +    void setupTest(BackendListenerContext context) throws Exception;
>>>> +
>>>> +    /**
>>>> +     * Perform a single sample for each iteration. This method returns
>>>> a
>>>> +     * <code>SampleResult</code> object. <code>SampleResult</code> has
>>>> many
>>>> +     * fields which can be used. At a minimum, the test should use
>>>> +     * <code>SampleResult.sampleStart</code> and
>>>> +     * <code>SampleResult.sampleEnd</code>to set the time that the
>>>> test
>>>>
>>>>  use {@link..} instead of <code>..?
>>>
>>>  +     * required to execute. It is also a good idea to set the
>>>> sampleLabel and
>>>> +     * the successful flag.
>>>> +     *
>>>> +     * @see org.apache.jmeter.samplers.SampleResult#sampleStart()
>>>> +     * @see org.apache.jmeter.samplers.SampleResult#sampleEnd()
>>>> +     * @see org.apache.jmeter.samplers.SampleResult#setSuccessful(
>>>> boolean)
>>>> +     * @see org.apache.jmeter.samplers.SampleResult#setSampleLabel(
>>>> String)
>>>> +     *
>>>> +     * @param context
>>>> +     *            the context to run with. This provides access to
>>>> +     *            initialization parameters.
>>>> +     *
>>>> +     */
>>>> +    void handleSampleResults(List<SampleResult> sampleResults,
>>>> BackendListenerContext context);
>>>> +
>>>> +    /**
>>>> +     * Do any clean-up required by this test at the end of a test run.
>>>> +     *
>>>> +     * @param context
>>>> +     *            the context to run with. This provides access to
>>>> +     *            initialization parameters.
>>>> +     */
>>>> +    void teardownTest(BackendListenerContext context) throws
>>>> Exception;
>>>> +
>>>> +    /**
>>>> +     * Provide a list of parameters which this test supports. Any
>>>> parameter
>>>> +     * names and associated values returned by this method will appear
>>>> in the
>>>> +     * GUI by default so the user doesn't have to remember the exact
>>>> names. The
>>>> +     * user can add other parameters which are not listed here. If this
>>>> method
>>>> +     * returns null then no parameters will be listed. If the value for
>>>> some
>>>> +     * parameter is null then that parameter will be listed in the GUI
>>>> with an
>>>> +     * empty value.
>>>> +     *
>>>> +     * @return a specification of the parameters used by this test
>>>> which
>>>> should
>>>> +     *         be listed in the GUI, or null if no parameters should be
>>>> listed.
>>>> +     */
>>>> +    Arguments getDefaultParameters();
>>>> +
>>>> +    /**
>>>> +     *
>>>> +     * @param context
>>>> +     * @param result
>>>> +     * @return
>>>> +     */
>>>> +    SampleResult createSampleResult(
>>>> +            BackendListenerContext context, SampleResult result);
>>>> +}
>>>>
>>>> Propchange: jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>>>> backend/BackendListenerClient.java
>>>> ------------------------------------------------------------
>>>> ------------------
>>>>       svn:mime-type = text/plain
>>>>
>>>> Added: jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>>>> backend/
>>>> BackendListenerContext.java
>>>> URL: http://svn.apache.org/viewvc/jmeter/trunk/src/components/
>>>> org/apache/jmeter/visualizers/backend/BackendListenerContext.java?
>>>> rev=1641081&view=auto
>>>> ============================================================
>>>> ==================
>>>> --- jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/
>>>> BackendListenerContext.java
>>>> (added)
>>>> +++ jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/
>>>> BackendListenerContext.java
>>>> Sat Nov 22 15:36:37 2014
>>>> @@ -0,0 +1,237 @@
>>>> +/*
>>>> +
>>>> + * 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.jmeter.visualizers.backend;
>>>> +
>>>> +import java.util.Iterator;
>>>> +import java.util.Map;
>>>> +
>>>> +import org.apache.jmeter.config.Arguments;
>>>> +import org.apache.jorphan.logging.LoggingManager;
>>>> +import org.apache.log.Logger;
>>>> +
>>>> +/**
>>>> + * BackendListenerContext is used to provide context information to a
>>>> + * BackendListenerClient implementation. This currently consists of the
>>>> + * initialization parameters which were specified in the GUI.
>>>> + * @since 2.13
>>>> + */
>>>> +public class BackendListenerContext {
>>>> +    /*
>>>> +     * Implementation notes:
>>>> +     *
>>>> +     * All of the methods in this class are currently read-only. If
>>>> update
>>>> +     * methods are included in the future, they should be defined so
>>>> that a
>>>> +     * single instance of BackendListenerContext can be associated with
>>>> each thread.
>>>> +     * Therefore, no synchronization should be needed. The same
>>>> instance
>>>> should
>>>> +     * be used for the call to setupTest, all calls to runTest, and the
>>>> call to
>>>> +     * teardownTest.
>>>> +     */
>>>> +
>>>> +    /** Logging */
>>>> +    private static final Logger log = LoggingManager.
>>>> getLoggerForClass();
>>>>
>>>>  See naming comments for logger above
>>>
>>>  +
>>>> +    /**
>>>> +     * Map containing the initialization parameters for the
>>>> BackendListenerClient.
>>>> +     */
>>>> +    private final Map<String, String> params;
>>>> +
>>>> +    /**
>>>> +     *
>>>> +     * @param args
>>>> +     *            the initialization parameters.
>>>> +     */
>>>> +    public BackendListenerContext(Arguments args) {
>>>> +        this.params = args.getArgumentsAsMap();
>>>> +    }
>>>> +
>>>> +    /**
>>>> +     * Determine whether or not a value has been specified for the
>>>> parameter
>>>> +     * with this name.
>>>> +     *
>>>> +     * @param name
>>>> +     *            the name of the parameter to test
>>>> +     * @return true if the parameter value has been specified, false
>>>> otherwise.
>>>> +     */
>>>> +    public boolean containsParameter(String name) {
>>>>
>>>>  hasParameter instead of containsParameter?
>>>
>>>  +        return params.containsKey(name);
>>>> +    }
>>>> +
>>>> +    /**
>>>> +     * Get an iterator of the parameter names. Each entry in the
>>>> Iterator is a
>>>> +     * String.
>>>> +     *
>>>> +     * @return an Iterator of Strings listing the names of the
>>>> parameters which
>>>> +     *         have been specified for this test.
>>>> +     */
>>>> +    public Iterator<String> getParameterNamesIterator() {
>>>> +        return params.keySet().iterator();
>>>> +    }
>>>> +
>>>> +    /**
>>>> +     * Get the value of a specific parameter as a String, or null if
>>>> the
>>>> value
>>>> +     * was not specified.
>>>> +     *
>>>> +     * @param name
>>>> +     *            the name of the parameter whose value should be
>>>> retrieved
>>>> +     * @return the value of the parameter, or null if the value was not
>>>> +     *         specified
>>>> +     */
>>>> +    public String getParameter(String name) {
>>>> +        return getParameter(name, null);
>>>> +    }
>>>> +
>>>> +    /**
>>>> +     * Get the value of a specified parameter as a String, or return
>>>> the
>>>> +     * specified default value if the value was not specified.
>>>> +     *
>>>> +     * @param name
>>>> +     *            the name of the parameter whose value should be
>>>> retrieved
>>>> +     * @param defaultValue
>>>> +     *            the default value to return if the value of this
>>>> parameter was
>>>> +     *            not specified
>>>> +     * @return the value of the parameter, or the default value if the
>>>> parameter
>>>> +     *         was not specified
>>>> +     */
>>>> +    public String getParameter(String name, String defaultValue) {
>>>> +        if (params == null || !params.containsKey(name)) {
>>>> +            return defaultValue;
>>>> +        }
>>>> +        return params.get(name);
>>>> +    }
>>>> +
>>>> +    /**
>>>> +     * Get the value of a specified parameter as an integer. An
>>>> exception will
>>>> +     * be thrown if the parameter is not specified or if it is not an
>>>> integer.
>>>> +     * The value may be specified in decimal, hexadecimal, or octal, as
>>>> defined
>>>> +     * by Integer.decode().
>>>> +     *
>>>> +     * @param name
>>>> +     *            the name of the parameter whose value should be
>>>> retrieved
>>>> +     * @return the value of the parameter
>>>> +     *
>>>> +     * @throws NumberFormatException
>>>> +     *             if the parameter is not specified or is not an
>>>> integer
>>>> +     *
>>>> +     * @see java.lang.Integer#decode(java.lang.String)
>>>> +     */
>>>> +    public int getIntParameter(String name) throws
>>>> NumberFormatException
>>>> {
>>>> +        if (params == null || !params.containsKey(name)) {
>>>> +            throw new NumberFormatException("No value for parameter
>>>> named '" + name + "'.");
>>>>
>>>>  I would expect an IllegalArgumentException, if no parameter of that
>>> name
>>> is found
>>>
>>>  +        }
>>>> +
>>>> +        return Integer.decode(params.get(name)).intValue();
>>>> +    }
>>>> +
>>>> +    /**
>>>> +     * Get the value of a specified parameter as an integer, or return
>>>> the
>>>> +     * specified default value if the value was not specified or is not
>>>> an
>>>> +     * integer. A warning will be logged if the value is not an
>>>> integer.
>>>> The
>>>> +     * value may be specified in decimal, hexadecimal, or octal, as
>>>> defined by
>>>> +     * Integer.decode().
>>>> +     *
>>>> +     * @param name
>>>> +     *            the name of the parameter whose value should be
>>>> retrieved
>>>> +     * @param defaultValue
>>>> +     *            the default value to return if the value of this
>>>> parameter was
>>>> +     *            not specified
>>>> +     * @return the value of the parameter, or the default value if the
>>>> parameter
>>>> +     *         was not specified
>>>> +     *
>>>> +     * @see java.lang.Integer#decode(java.lang.String)
>>>> +     */
>>>> +    public int getIntParameter(String name, int defaultValue) {
>>>> +        if (params == null || !params.containsKey(name)) {
>>>> +            return defaultValue;
>>>> +        }
>>>> +
>>>> +        try {
>>>> +            return Integer.decode(params.get(name)).intValue();
>>>> +        } catch (NumberFormatException e) {
>>>> +            log.warn("Value for parameter '" + name + "' not an
>>>> integer:
>>>> '" + params.get(name) + "'.  Using default: '"
>>>> +                    + defaultValue + "'.", e);
>>>> +            return defaultValue;
>>>> +        }
>>>> +    }
>>>> +
>>>> +    /**
>>>> +     * Get the value of a specified parameter as a long. An exception
>>>> will be
>>>> +     * thrown if the parameter is not specified or if it is not a long.
>>>> The
>>>> +     * value may be specified in decimal, hexadecimal, or octal, as
>>>> defined by
>>>> +     * Long.decode().
>>>> +     *
>>>> +     * @param name
>>>> +     *            the name of the parameter whose value should be
>>>> retrieved
>>>> +     * @return the value of the parameter
>>>> +     *
>>>> +     * @throws NumberFormatException
>>>> +     *             if the parameter is not specified or is not a long
>>>> +     *
>>>> +     * @see Long#decode(String)
>>>> +     */
>>>> +    public long getLongParameter(String name) throws
>>>> NumberFormatException {
>>>> +        if (params == null || !params.containsKey(name)) {
>>>> +            throw new NumberFormatException("No value for parameter
>>>> named '" + name + "'.");
>>>> +        }
>>>> +
>>>> +        return Long.decode(params.get(name)).longValue();
>>>> +    }
>>>> +
>>>> +    /**
>>>> +     * Get the value of a specified parameter as along, or return the
>>>> specified
>>>> +     * default value if the value was not specified or is not a long. A
>>>> warning
>>>> +     * will be logged if the value is not a long. The value may be
>>>> specified in
>>>> +     * decimal, hexadecimal, or octal, as defined by Long.decode().
>>>> +     *
>>>> +     * @param name
>>>> +     *            the name of the parameter whose value should be
>>>> retrieved
>>>> +     * @param defaultValue
>>>> +     *            the default value to return if the value of this
>>>> parameter was
>>>> +     *            not specified
>>>> +     * @return the value of the parameter, or the default value if the
>>>> parameter
>>>> +     *         was not specified
>>>> +     *
>>>> +     * @see Long#decode(String)
>>>> +     */
>>>> +    public long getLongParameter(String name, long defaultValue) {
>>>> +        if (params == null || !params.containsKey(name)) {
>>>> +            return defaultValue;
>>>> +        }
>>>> +        try {
>>>> +            return Long.decode(params.get(name)).longValue();
>>>> +        } catch (NumberFormatException e) {
>>>> +            log.warn("Value for parameter '" + name + "' not a long: '"
>>>> + params.get(name) + "'.  Using default: '"
>>>> +                    + defaultValue + "'.", e);
>>>> +            return defaultValue;
>>>> +        }
>>>> +    }
>>>> +
>>>> +    /**
>>>> +     *
>>>> +     * @param name
>>>> +     * @param defaultValue
>>>> +     * @return
>>>>
>>>>  No javadoc? Again three warnings more :)
>>>
>>>  +     */
>>>> +    public boolean getBooleanParameter(String name, boolean
>>>> defaultValue) {
>>>> +        if (params == null || !params.containsKey(name)) {
>>>> +            return defaultValue;
>>>> +        }
>>>> +        return Boolean.valueOf(params.get(name));
>>>> +    }
>>>> +}
>>>>
>>>> Propchange: jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>>>> backend/BackendListenerContext.java
>>>> ------------------------------------------------------------
>>>> ------------------
>>>>       svn:mime-type = text/plain
>>>>
>>>> Added: jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>>>> backend/BackendListenerGui.java
>>>> URL: http://svn.apache.org/viewvc/jmeter/trunk/src/components/
>>>> org/apache/jmeter/visualizers/backend/BackendListenerGui.
>>>> java?rev=1641081&view=auto
>>>> ============================================================
>>>> ==================
>>>> --- jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>>>> backend/BackendListenerGui.java (added)
>>>> +++ jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>>>> backend/BackendListenerGui.java Sat Nov 22 15:36:37 2014
>>>> @@ -0,0 +1,282 @@
>>>> +/*
>>>> + * 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.jmeter.visualizers.backend;
>>>> +
>>>> +import java.awt.BorderLayout;
>>>> +import java.awt.event.ActionEvent;
>>>> +import java.awt.event.ActionListener;
>>>> +import java.util.ArrayList;
>>>> +import java.util.HashSet;
>>>> +import java.util.List;
>>>> +import java.util.Map;
>>>> +import java.util.Set;
>>>> +
>>>> +import javax.swing.ComboBoxModel;
>>>> +import javax.swing.JComboBox;
>>>> +import javax.swing.JLabel;
>>>> +import javax.swing.JPanel;
>>>> +import javax.swing.JTextField;
>>>> +
>>>> +import org.apache.jmeter.config.Argument;
>>>> +import org.apache.jmeter.config.Arguments;
>>>> +import org.apache.jmeter.config.gui.ArgumentsPanel;
>>>> +import org.apache.jmeter.gui.util.HorizontalPanel;
>>>> +import org.apache.jmeter.testelement.TestElement;
>>>> +import org.apache.jmeter.testelement.property.PropertyIterator;
>>>> +import org.apache.jmeter.util.JMeterUtils;
>>>> +import org.apache.jmeter.visualizers.gui.AbstractListenerGui;
>>>> +import org.apache.jorphan.logging.LoggingManager;
>>>> +import org.apache.jorphan.reflect.ClassFinder;
>>>> +import org.apache.log.Logger;
>>>> +
>>>> +/**
>>>> + * The <code>BackendListenerGui</code> class provides the user
>>>> interface for the
>>>> + * {@link BackendListener} object.
>>>> + * @since 2.13
>>>> + */
>>>> +public class BackendListenerGui extends AbstractListenerGui implements
>>>> ActionListener {
>>>> +
>>>> +    /**
>>>> +     *
>>>> +     */
>>>> +    private static final long serialVersionUID = 4331668988576438604L;
>>>> +
>>>> +    /** Logging */
>>>> +    private static final Logger log = LoggingManager.
>>>> getLoggerForClass();
>>>> +
>>>> +    /** A combo box allowing the user to choose a backend class. */
>>>> +    private JComboBox classnameCombo;
>>>> +
>>>> +    /**
>>>> +     * A field allowing the user to specify the size of Queue
>>>> +     */
>>>> +    private JTextField queueSize;
>>>> +
>>>> +    /** A panel allowing the user to set arguments for this test. */
>>>> +    private ArgumentsPanel argsPanel;
>>>> +
>>>> +    /**
>>>> +     * Create a new BackendListenerGui as a standalone component.
>>>> +     */
>>>> +    public BackendListenerGui() {
>>>> +        super();
>>>> +        init();
>>>> +    }
>>>> +
>>>> +
>>>> +    /** {@inheritDoc} */
>>>> +    @Override
>>>> +    public String getLabelResource() {
>>>> +        return "backend_listener"; // $NON-NLS-1$
>>>> +    }
>>>> +
>>>> +    /**
>>>> +     * Initialize the GUI components and layout.
>>>> +     */
>>>> +    private void init() {// called from ctor, so must not be
>>>> overridable
>>>> +        setLayout(new BorderLayout(0, 5));
>>>> +
>>>> +        setBorder(makeBorder());
>>>> +        add(makeTitlePanel(), BorderLayout.NORTH);
>>>> +
>>>> +        JPanel classnameRequestPanel = new JPanel(new BorderLayout(0,
>>>> 5));
>>>> +        classnameRequestPanel.add(createClassnamePanel(),
>>>> BorderLayout.NORTH);
>>>> +        classnameRequestPanel.add(createParameterPanel(),
>>>> BorderLayout.CENTER);
>>>> +
>>>> +        add(classnameRequestPanel, BorderLayout.CENTER);
>>>> +    }
>>>> +
>>>> +    /**
>>>> +     * Create a panel with GUI components allowing the user to select a
>>>> test
>>>> +     * class.
>>>> +     *
>>>> +     * @return a panel containing the relevant components
>>>> +     */
>>>> +    private JPanel createClassnamePanel() {
>>>> +        List<String> possibleClasses = new ArrayList<String>();
>>>> +
>>>> +        try {
>>>> +            // Find all the classes which implement the
>>>> BackendListenerClient
>>>> +            // interface.
>>>> +            possibleClasses = ClassFinder.findClassesThatExtend(
>>>> JMeterUtils.getSearchPaths(),
>>>> +                    new Class[] { BackendListenerClient.class });
>>>> +
>>>> +            // Remove the BackendListener class from the list since it
>>>> only
>>>>
>>>>  ErrorBackendListener
>>>
>>>  +            // implements the interface for error conditions.
>>>> +
>>>> +            possibleClasses.remove(BackendListener.class.getName() +
>>>> "$ErrorBackendListenerClient");
>>>> +        } catch (Exception e) {
>>>> +            log.debug("Exception getting interfaces.", e);
>>>> +        }
>>>> +
>>>> +        JLabel label = new JLabel(JMeterUtils.getResString("backend_
>>>> listener_classname"));
>>>> // $NON-NLS-1$
>>>> +
>>>> +        classnameCombo = new JComboBox(possibleClasses.toArray());
>>>> +        classnameCombo.addActionListener(this);
>>>> +        classnameCombo.setEditable(false);
>>>> +        label.setLabelFor(classnameCombo);
>>>> +
>>>> +        HorizontalPanel classNamePanel = new HorizontalPanel();
>>>> +        classNamePanel.add(label);
>>>> +        classNamePanel.add(classnameCombo);
>>>> +
>>>> +        queueSize = new JTextField("", 5);
>>>> +        queueSize.setName("Queue Size"); //$NON-NLS-1$
>>>> +        JLabel queueSizeLabel = new JLabel(JMeterUtils.
>>>> getResString("backend_listener_queue_size")); // $NON-NLS-1$
>>>> +        queueSizeLabel.setLabelFor(queueSize);
>>>> +        HorizontalPanel queueSizePanel = new HorizontalPanel();
>>>> +        queueSizePanel.add(queueSizeLabel, BorderLayout.WEST);
>>>> +        queueSizePanel.add(queueSize);
>>>> +
>>>> +        JPanel panel = new JPanel(new BorderLayout(0, 5));
>>>> +        panel.add(classNamePanel, BorderLayout.NORTH);
>>>> +        panel.add(queueSizePanel, BorderLayout.CENTER);
>>>> +        return panel;
>>>> +    }
>>>> +
>>>> +    /**
>>>> +     * Handle action events for this component. This method currently
>>>> handles
>>>> +     * events for the classname combo box.
>>>> +     *
>>>> +     * @param evt
>>>>
>>>>  I would spend the few extra characters to make it event instead of evt
>>>
>>>  +     *            the ActionEvent to be handled
>>>> +     */
>>>> +    @Override
>>>> +    public void actionPerformed(ActionEvent evt) {
>>>> +        if (evt.getSource() == classnameCombo) {
>>>> +            String className = ((String) classnameCombo.
>>>> getSelectedItem()).trim();
>>>> +            try {
>>>> +                BackendListenerClient client = (BackendListenerClient)
>>>> Class.forName(className, true,
>>>> +                        Thread.currentThread().
>>>> getContextClassLoader()).
>>>> newInstance();
>>>> +
>>>> +                Arguments currArgs = new Arguments();
>>>> +                argsPanel.modifyTestElement(currArgs);
>>>> +                Map<String, String> currArgsMap =
>>>> currArgs.getArgumentsAsMap();
>>>> +
>>>> +                Arguments newArgs = new Arguments();
>>>> +                Arguments testParams = null;
>>>> +                try {
>>>> +                    testParams = client.getDefaultParameters();
>>>> +                } catch (AbstractMethodError e) {
>>>> +                    log.warn("BackendListenerClient doesn't implement
>>>> "
>>>> +                            + "getDefaultParameters.  Default
>>>> parameters
>>>> won't "
>>>> +                            + "be shown.  Please update your client
>>>> class: " + className);
>>>> +                }
>>>> +
>>>> +                if (testParams != null) {
>>>> +                    PropertyIterator i = testParams.getArguments().
>>>> iterator();
>>>>
>>>>  I would try a for loop instead of explicitly using an iterator
>>>
>>>  +                    while (i.hasNext()) {
>>>> +                        Argument arg = (Argument)
>>>> i.next().getObjectValue();
>>>> +                        String name = arg.getName();
>>>> +                        String value = arg.getValue();
>>>> +
>>>> +                        // If a user has set parameters in one test,
>>>> and
>>>> then
>>>> +                        // selects a different test which supports the
>>>> same
>>>> +                        // parameters, those parameters should have the
>>>> same
>>>> +                        // values that they did in the original test.
>>>> +                        if (currArgsMap.containsKey(name)) {
>>>> +                            String newVal = currArgsMap.get(name);
>>>> +                            if (newVal != null && newVal.length() > 0)
>>>> {
>>>> +                                value = newVal;
>>>> +                            }
>>>> +                        }
>>>> +                        newArgs.addArgument(name, value);
>>>> +                    }
>>>> +                }
>>>> +
>>>> +                argsPanel.configure(newArgs);
>>>> +            } catch (Exception e) {
>>>> +                log.error("Error getting argument list for " +
>>>> className, e);
>>>> +            }
>>>> +        }
>>>> +    }
>>>> +
>>>> +    /**
>>>> +     * Create a panel containing components allowing the user to
>>>> provide
>>>> +     * arguments to be passed to the test class instance.
>>>> +     *
>>>> +     * @return a panel containing the relevant components
>>>> +     */
>>>> +    private JPanel createParameterPanel() {
>>>> +        argsPanel = new ArgumentsPanel(JMeterUtils.
>>>> getResString("backend_listener_paramtable")); // $NON-NLS-1$
>>>> +        return argsPanel;
>>>> +    }
>>>> +
>>>> +    /** {@inheritDoc} */
>>>> +    @Override
>>>> +    public void configure(TestElement config) {
>>>> +        super.configure(config);
>>>> +
>>>> +        argsPanel.configure((Arguments) config.getProperty(
>>>> BackendListener.ARGUMENTS).getObjectValue());
>>>> +
>>>> +        String className = config.getPropertyAsString(
>>>> BackendListener.CLASSNAME);
>>>> +        if(checkContainsClassName(classnameCombo.getModel(),
>>>> className)) {
>>>> +            classnameCombo.setSelectedItem(className);
>>>> +        } else {
>>>> +            log.error("Error setting class:'"+className+"' in
>>>> BackendListener: "+getName()+
>>>> +                    ", check for a missing jar in your jmeter
>>>> 'search_paths' and 'plugin_dependency_paths' properties");
>>>> +        }
>>>> +        queueSize.setText(Integer.toString(((BackendListener)
>>>> config).getQueueSize()));
>>>> +    }
>>>> +
>>>> +    /**
>>>> +     * Check combo contains className
>>>> +     * @param model ComboBoxModel
>>>> +     * @param className String class name
>>>> +     * @return boolean
>>>>
>>>>  explain "boolean" or the other params a bit more?
>>>
>>>  +     */
>>>> +    private static final boolean checkContainsClassName(ComboBoxModel
>>>> model, String className) {
>>>> +        int size = model.getSize();
>>>> +        Set<String> set = new HashSet<String>(size);
>>>> +        for (int i = 0; i < size; i++) {
>>>> +            set.add((String)model.getElementAt(i));
>>>> +        }
>>>> +        return set.contains(className);
>>>> +    }
>>>> +
>>>> +    /** {@inheritDoc} */
>>>> +    @Override
>>>> +    public TestElement createTestElement() {
>>>> +        BackendListener config = new BackendListener();
>>>> +        modifyTestElement(config);
>>>> +        return config;
>>>> +    }
>>>> +
>>>> +    /** {@inheritDoc} */
>>>> +    @Override
>>>> +    public void modifyTestElement(TestElement config) {
>>>> +        configureTestElement(config);
>>>> +        BackendListener backendListener = (BackendListener) config;
>>>> +        backendListener.setArguments((Arguments)
>>>> argsPanel.createTestElement());
>>>> +        backendListener.setClassname(String.valueOf(classnameCombo.
>>>> getSelectedItem()));
>>>> +        backendListener.setQueueSize(Integer.parseInt(queueSize.
>>>> getText()));
>>>> +
>>>> +    }
>>>> +
>>>>
>>>

-- 
Cordialement.
Philippe Mouawad.

Re: svn commit: r1641081 - in /jmeter/trunk: ./ bin/ res/maven/ src/components/org/apache/jmeter/visualizers/backend/ src/core/org/apache/jmeter/resources/ src/core/org/apache/jmeter/samplers/ src/core/org/apache/jmeter/save/ xdocs/ xdocs/usermanual/

Posted by Felix Schumacher <fe...@internetallee.de>.
Hi Phillipe,
Am 22.11.2014 um 19:29 schrieb Philippe Mouawad:
> Hi Felix,
> As I said in thread, I commited code and will improve, feel free to fix
> javadocs issues on your side.
> I will review your comment.
>
> I have spent many hours if not days on this code and I am aware it is not
> yet fully completed (although tests are promising) but my aim when
> commiting it was to have feedback and help to finish it.
I did not mean to offend you. I can clearly see, that you put a lot of 
effort
in this listener and I will surely try to integrate jmeter into our 
collectd server.

Regards
  Felix
>
> Regards
> Philippe
>
> On Sat, Nov 22, 2014 at 7:21 PM, Felix Schumacher <
> felix.schumacher@internetallee.de> wrote:
>
>> Hello Philippe,
>>
>> I have hidden a few comments inside the cited code.
>> They are mostly around javadoc and naming things.
>>
>> Am 22.11.2014 um 16:36 schrieb pmouawad@apache.org:
>>
>>> Author: pmouawad
>>> Date: Sat Nov 22 15:36:37 2014
>>> New Revision: 1641081
>>>
>>> URL: http://svn.apache.org/r1641081
>>> Log:
>>> Bug 55932 - Create a Async BackendListener to allow easy plug of new
>>> listener (Graphite, JDBC, Console,...)
>>> Bugzilla Id: 55932
>>>
>>> Added:
>>>       jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/
>>>       jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/
>>> AbstractBackendListenerClient.java   (with props)
>>>       jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/BackendListener.java
>>>   (with props)
>>>       jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>>> backend/BackendListenerClient.java   (with props)
>>>       jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/BackendListenerContext.java
>>>   (with props)
>>>       jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>>> backend/BackendListenerGui.java   (with props)
>>>       jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/SamplerMetric.java
>>>   (with props)
>>> Modified:
>>>       jmeter/trunk/bin/saveservice.properties
>>>       jmeter/trunk/build.properties
>>>       jmeter/trunk/build.xml
>>>       jmeter/trunk/eclipse.classpath
>>>       jmeter/trunk/res/maven/ApacheJMeter_parent.pom
>>>       jmeter/trunk/src/core/org/apache/jmeter/resources/
>>> messages.properties
>>>       jmeter/trunk/src/core/org/apache/jmeter/resources/
>>> messages_fr.properties
>>>       jmeter/trunk/src/core/org/apache/jmeter/samplers/SampleResult.java
>>>       jmeter/trunk/src/core/org/apache/jmeter/save/SaveService.java
>>>       jmeter/trunk/xdocs/changes.xml
>>>       jmeter/trunk/xdocs/usermanual/component_reference.xml
>>>
>>> Modified: jmeter/trunk/bin/saveservice.properties
>>> URL: http://svn.apache.org/viewvc/jmeter/trunk/bin/saveservice.
>>> properties?rev=1641081&r1=1641080&r2=1641081&view=diff
>>> ============================================================
>>> ==================
>>> --- jmeter/trunk/bin/saveservice.properties (original)
>>> +++ jmeter/trunk/bin/saveservice.properties Sat Nov 22 15:36:37 2014
>>> @@ -53,7 +53,8 @@ _file_version=$Revision$
>>>    # 2.5 = 2.10
>>>    # 2.6 = 2.11
>>>    # 2.7 = 2.12
>>> -_version=2.7
>>> +# 2.8 = 2.13
>>> +_version=2.8
>>>    #
>>>    #
>>>    # Character set encoding used to read and write JMeter XML files and
>>> CSV results
>>> @@ -78,6 +79,8 @@ AssertionVisualizer=org.apache.jmeter.vi
>>>    AuthManager=org.apache.jmeter.protocol.http.control.AuthManager
>>>    Authorization=org.apache.jmeter.protocol.http.control.Authorization
>>>    AuthPanel=org.apache.jmeter.protocol.http.gui.AuthPanel
>>> +BackendListener=org.apache.jmeter.visualizers.backend.BackendListener
>>> +BackendListenerGui=org.apache.jmeter.visualizers.
>>> backend.BackendListenerGui
>>>    BarChart=org.apache.jmeter.testelement.BarChart
>>>    BarChartGui=org.apache.jmeter.report.gui.BarChartGui
>>>    BeanShellAssertion=org.apache.jmeter.assertions.BeanShellAssertion
>>>
>>> Modified: jmeter/trunk/build.properties
>>> URL: http://svn.apache.org/viewvc/jmeter/trunk/build.properties?
>>> rev=1641081&r1=1641080&r2=1641081&view=diff
>>> ============================================================
>>> ==================
>>> --- jmeter/trunk/build.properties (original)
>>> +++ jmeter/trunk/build.properties Sat Nov 22 15:36:37 2014
>>> @@ -118,11 +118,21 @@ commons-logging.loc         = ${maven2.r
>>>    #commons-logging.md5         = E2C390FE739B2550A218262B28F290CE
>>>    commons-logging.md5         = 040b4b4d8eac886f6b4a2a3bd2f31b00
>>>    +commons-math3.version         = 3.3
>>> +commons-math3.jar             = commons-math3-${commons-math3.
>>> version}.jar
>>> +commons-math3.loc             = ${maven2.repo}/org/apache/
>>> commons/commons-math3/${commons-math3.version}
>>> +commons-math3.md5             = 87346cf2772dc2becf106c45e0f63863
>>> +
>>>    commons-net.version         = 3.3
>>>    commons-net.jar             = commons-net-${commons-net.version}.jar
>>>    commons-net.loc             = ${maven2.repo}/commons-net/
>>> commons-net/${commons-net.version}
>>>    commons-net.md5             = c077ca61598e9c21f43f8b6488fbbee9
>>>    +commons-pool2.version         = 2.2
>>> +commons-pool2.jar             = commons-pool2-${commons-pool2.
>>> version}.jar
>>> +commons-pool2.loc             = ${maven2.repo}/org/apache/
>>> commons/commons-pool2/${commons-pool2.version}
>>> +commons-pool2.md5             = 51b56c92883812c56fbeb339866ce2df
>>> +
>>>    # dnsjava for DNSCacheManager
>>>    dnsjava.version             = 2.1.6
>>>    dnsjava.jar                 = dnsjava-${dnsjava.version}.jar
>>>
>>> Modified: jmeter/trunk/build.xml
>>> URL: http://svn.apache.org/viewvc/jmeter/trunk/build.xml?rev=
>>> 1641081&r1=1641080&r2=1641081&view=diff
>>> ============================================================
>>> ==================
>>> --- jmeter/trunk/build.xml (original)
>>> +++ jmeter/trunk/build.xml Sat Nov 22 15:36:37 2014
>>> @@ -365,7 +365,9 @@
>>>        <include name="${lib.dir}/${commons-jexl2.jar}"/>
>>>        <include name="${lib.dir}/${commons-lang3.jar}"/>
>>>        <include name="${lib.dir}/${commons-logging.jar}"/>
>>> +    <include name="${lib.dir}/${commons-math3}"/>
>>>        <include name="${lib.dir}/${commons-net.jar}"/>
>>> +    <include name="${lib.dir}/${commons-pool2.jar}"/>
>>>        <include name="${lib.dir}/${dnsjava.jar}"/>
>>>        <include name="${lib.dir}/${excalibur-datasource.jar}"/>
>>>        <include name="${lib.dir}/${excalibur-instrument.jar}"/>
>>> @@ -438,8 +440,10 @@
>>>        <pathelement location="${lib.dir}/${commons-jexl2.jar}"/>
>>>        <pathelement location="${lib.dir}/${commons-lang3.jar}"/>
>>>        <pathelement location="${lib.dir}/${commons-logging.jar}"/>
>>> +    <pathelement location="${lib.dir}/${commons-math3.jar}"/>
>>>        <pathelement location="${lib.dir}/${commons-net.jar}"/>
>>> -    <pathelement location="${lib.dir}/${dnsjava.jar}"/>
>>> +       <pathelement location="${lib.dir}/${commons-pool2.jar}"/>
>>> +       <pathelement location="${lib.dir}/${dnsjava.jar}"/>
>>>        <pathelement location="${lib.dir}/${excalibur-datasource.jar}"/>
>>>        <pathelement location="${lib.dir}/${excalibur-instrument.jar}"/>
>>>        <pathelement location="${lib.dir}/${excalibur-logger.jar}"/>
>>> @@ -2909,7 +2913,9 @@ run JMeter unless all the JMeter jars ar
>>>            <process_jarfile jarname="commons-jexl2"/>
>>>            <process_jarfile jarname="commons-lang3"/>
>>>            <process_jarfile jarname="commons-logging"/>
>>> +        <process_jarfile jarname="commons-math3"/>
>>>            <process_jarfile jarname="commons-net"/>
>>> +       <process_jarfile jarname="commons-pool2"/>
>>>            <process_jarfile jarname="dnsjava"/>
>>>            <process_jarfile jarname="excalibur-datasource"/>
>>>            <process_jarfile jarname="excalibur-instrument"/>
>>>
>>> Modified: jmeter/trunk/eclipse.classpath
>>> URL: http://svn.apache.org/viewvc/jmeter/trunk/eclipse.
>>> classpath?rev=1641081&r1=1641080&r2=1641081&view=diff
>>> ============================================================
>>> ==================
>>> --- jmeter/trunk/eclipse.classpath (original)
>>> +++ jmeter/trunk/eclipse.classpath Sat Nov 22 15:36:37 2014
>>> @@ -55,7 +55,9 @@
>>>          <classpathentry kind="lib" path="lib/commons-jexl-2.1.1.jar"/>
>>>          <classpathentry kind="lib" path="lib/commons-lang3-3.3.2.jar"/>
>>>          <classpathentry kind="lib" path="lib/commons-logging-1.2.jar"/>
>>> +    <classpathentry kind="lib" path="lib/commons-math3-3.3.jar"/>
>>>          <classpathentry kind="lib" path="lib/commons-net-3.3.jar"/>
>>> +    <classpathentry kind="lib" path="lib/commons-pool2-2.2.jar"/>
>>>          <classpathentry kind="lib" path="lib/dnsjava-2.1.6.jar"/>
>>>          <classpathentry kind="lib" path="lib/excalibur-
>>> datasource-2.1.jar"/>
>>>          <classpathentry kind="lib" path="lib/excalibur-
>>> instrument-1.0.jar"/>
>>>
>>> Modified: jmeter/trunk/res/maven/ApacheJMeter_parent.pom
>>> URL: http://svn.apache.org/viewvc/jmeter/trunk/res/maven/
>>> ApacheJMeter_parent.pom?rev=1641081&r1=1641080&r2=1641081&view=diff
>>> ============================================================
>>> ==================
>>> --- jmeter/trunk/res/maven/ApacheJMeter_parent.pom (original)
>>> +++ jmeter/trunk/res/maven/ApacheJMeter_parent.pom Sat Nov 22 15:36:37
>>> 2014
>>> @@ -66,7 +66,9 @@ under the License.
>>>          <commons-jexl2.version>2.1.1</commons-jexl2.version>
>>>          <commons-lang3.version>3.3.2</commons-lang3.version>
>>>          <commons-logging.version>1.2</commons-logging.version>
>>> +      <commons-math3.version>3.3</commons-math3.version>
>>>          <commons-net.version>3.3</commons-net.version>
>>> +      <commons-pool2.version>2.2</commons-pool2.version>
>>>          <dnsjava.version>2.1.6</dnsjava.version>
>>>          <excalibur-datasource.version>2.1</excalibur-datasource.version>
>>>          <excalibur-instrument.version>1.0</excalibur-instrument.version>
>>> @@ -181,11 +183,21 @@ under the License.
>>>            <version>${commons-logging.version}</version>
>>>          </dependency>
>>>          <dependency>
>>> +        <groupId>commons-math3</groupId>
>>> +        <artifactId>commons-math3</artifactId>
>>> +        <version>${commons-math3.version}</version>
>>> +      </dependency>
>>> +      <dependency>
>>>            <groupId>commons-net</groupId>
>>>            <artifactId>commons-net</artifactId>
>>>            <version>${commons-net.version}</version>
>>>          </dependency>
>>>          <dependency>
>>> +        <groupId>commons-pool2</groupId>
>>> +        <artifactId>commons-pool2</artifactId>
>>> +        <version>${commons-pool2.version}</version>
>>> +      </dependency>
>>> +      <dependency>
>>>              <groupId>dnsjava</groupId>
>>>              <artifactId>dnsjava</artifactId>
>>>              <version>${dnsjava.version}</version>
>>>
>>> Added: jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/
>>> AbstractBackendListenerClient.java
>>> URL: http://svn.apache.org/viewvc/jmeter/trunk/src/components/
>>> org/apache/jmeter/visualizers/backend/AbstractBackendListenerClient.
>>> java?rev=1641081&view=auto
>>> ============================================================
>>> ==================
>>> --- jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/
>>> AbstractBackendListenerClient.java (added)
>>> +++ jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/
>>> AbstractBackendListenerClient.java Sat Nov 22 15:36:37 2014
>>> @@ -0,0 +1,121 @@
>>> +/*
>>> + * 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.jmeter.visualizers.backend;
>>> +
>>> +import java.util.Map;
>>> +import java.util.concurrent.ConcurrentHashMap;
>>> +
>>> +import org.apache.jmeter.config.Arguments;
>>> +import org.apache.jmeter.samplers.SampleResult;
>>> +import org.apache.jorphan.logging.LoggingManager;
>>> +import org.apache.log.Logger;
>>> +
>>> +/**
>>> + * An abstract implementation of the BackendListenerClient interface.
>>> This
>>> + * implementation provides default implementations of most of the
>>> methods in the
>>> + * interface, as well as some convenience methods, in order to simplify
>>> + * development of BackendListenerClient implementations.
>>> + *
>>> + * While it may be necessary to make changes to the
>>> BackendListenerClient interface
>>> + * from time to time (therefore requiring changes to any implementations
>>> of this
>>> + * interface), we intend to make this abstract class provide reasonable
>>> + * implementations of any new methods so that subclasses do not
>>> necessarily need
>>> + * to be updated for new versions. Therefore, when creating a new
>>> + * BackendListenerClient implementation, developers are encouraged to
>>> subclass this
>>> + * abstract class rather than implementing the BackendListenerClient
>>> interface
>>> + * directly. Implementing BackendListenerClient directly will continue
>>> to be
>>> + * supported for cases where extending this class is not possible (for
>>> example,
>>> + * when the client class is already a subclass of some other class).
>>> + * <p>
>>> + * The handleSampleResult() method of BackendListenerClient does not
>>> have a default
>>> + * implementation here, so subclasses must define at least this method.
>>> It may
>>> + * be useful to override other methods as well.
>>> + *
>>> + * @see BackendListener#sampleOccurred(org.apache.
>>> jmeter.samplers.SampleEvent)
>>> + * @since 2.13
>>> + */
>>> +public abstract class AbstractBackendListenerClient implements
>>> BackendListenerClient {
>>> +
>>> +    private static final Logger log = LoggingManager.
>>> getLoggerForClass();
>>>
>> In classes further down the logger is stored in variables named LOG and
>> LOGGER, should we use one name?
>> In this class we have a getter for the logger in other classes not. Why?
>>
>>> +
>>> +    private ConcurrentHashMap<String, SamplerMetric> metricsPerSampler =
>>> new ConcurrentHashMap<String, SamplerMetric>();
>>> +
>>> +    /* Implements BackendListenerClient.setupTest(JavaSamplerContext) */
>>> +    @Override
>>> +    public void setupTest(BackendListenerContext context) throws
>>> Exception {
>>> +        log.debug(getClass().getName() + ": setupTest");
>>> +    }
>>> +
>>> +    /* Implements BackendListenerClient.teardownTest(JavaSamplerContext)
>>> */
>>> +    @Override
>>> +    public void teardownTest(BackendListenerContext context) throws
>>> Exception {
>>> +        log.debug(getClass().getName() + ": teardownTest");
>>> +        metricsPerSampler.clear();
>>> +    }
>>> +
>>> +    /* Implements BackendListenerClient.getDefaultParameters() */
>>> +    @Override
>>> +    public Arguments getDefaultParameters() {
>>> +        return null;
>>> +    }
>>> +
>>> +    /**
>>> +     * Get a Logger instance which can be used by subclasses to log
>>> information.
>>> +     *
>>> +     * @return a Logger instance which can be used for logging
>>> +     */
>>> +    protected Logger getLogger() {
>>> +        return log;
>>> +    }
>>> +
>>> +    /* (non-Javadoc)
>>> +     * @see org.apache.jmeter.visualizers.backend.BackendListenerClient#
>>> createSampleResult(org.apache.jmeter.samplers.SampleResult)
>>> +     */
>>> +    @Override
>>> +    public SampleResult createSampleResult(BackendListenerContext
>>> context, SampleResult result) {
>>> +        SampleResult sampleResult = (SampleResult) result.clone();
>>> +        return sampleResult;
>>> +    }
>>> +
>>> +    /**
>>> +     *
>>> +     * @param sampleLabel
>>> +     * @return SamplerMetric
>>>
>> No description of the method and the parameters?
>>
>>> +     */
>>> +    protected SamplerMetric getSamplerMetric(String sampleLabel) {
>>> +        SamplerMetric samplerMetric = metricsPerSampler.get(
>>> sampleLabel);
>>> +        if(samplerMetric == null) {
>>> +            samplerMetric = new SamplerMetric();
>>> +            SamplerMetric oldValue = metricsPerSampler.putIfAbsent(sampleLabel,
>>> samplerMetric);
>>> +            if(oldValue != null ){
>>> +                samplerMetric = oldValue;
>>> +            }
>>> +        }
>>> +        return samplerMetric;
>>> +    }
>>> +
>>> +    /**
>>> +     *
>>> +     * @return Map<String, SamplerMetric>
>>>
>> No description of the method and usage of forbidden characters :) there
>> are still more than 800 warnings in the javadoc to prune, so don't
>> introduce new ones, please.
>>
>>> +     */
>>> +    protected Map<String, SamplerMetric> getMetricsPerSampler() {
>>> +        return metricsPerSampler;
>>> +    }
>>> +
>>> +}
>>>
>>> Propchange: jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>>> backend/AbstractBackendListenerClient.java
>>> ------------------------------------------------------------
>>> ------------------
>>>       svn:mime-type = text/plain
>>>
>>> Added: jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>>> backend/BackendListener.java
>>> URL: http://svn.apache.org/viewvc/jmeter/trunk/src/components/
>>> org/apache/jmeter/visualizers/backend/BackendListener.java?
>>> rev=1641081&view=auto
>>> ============================================================
>>> ==================
>>> --- jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/BackendListener.java
>>> (added)
>>> +++ jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/BackendListener.java
>>> Sat Nov 22 15:36:37 2014
>>> @@ -0,0 +1,448 @@
>>> +/*
>>> + * 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.jmeter.visualizers.backend;
>>> +
>>> +import java.io.Serializable;
>>> +import java.lang.reflect.Method;
>>> +import java.util.ArrayList;
>>> +import java.util.HashSet;
>>> +import java.util.List;
>>> +import java.util.Set;
>>> +import java.util.concurrent.ArrayBlockingQueue;
>>> +import java.util.concurrent.BlockingQueue;
>>> +import java.util.concurrent.locks.LockSupport;
>>> +
>>> +import org.apache.jmeter.config.Arguments;
>>> +import org.apache.jmeter.engine.util.NoThreadClone;
>>> +import org.apache.jmeter.protocol.java.sampler.JavaSamplerContext;
>>> +import org.apache.jmeter.samplers.Remoteable;
>>> +import org.apache.jmeter.samplers.SampleEvent;
>>> +import org.apache.jmeter.samplers.SampleListener;
>>> +import org.apache.jmeter.samplers.SampleResult;
>>> +import org.apache.jmeter.testelement.AbstractTestElement;
>>> +import org.apache.jmeter.testelement.TestElement;
>>> +import org.apache.jmeter.testelement.TestStateListener;
>>> +import org.apache.jmeter.testelement.property.TestElementProperty;
>>> +import org.apache.jorphan.logging.LoggingManager;
>>> +import org.apache.log.Logger;
>>> +
>>> +/**
>>> + * Async Listener that delegates SampleResult handling to
>>> implementations of {@link BackendListenerClient}
>>> + * @since 2.13
>>> + */
>>> +public class BackendListener extends AbstractTestElement
>>> +    implements Serializable, SampleListener, TestStateListener,
>>> NoThreadClone, Remoteable  {
>>> +
>>> +    /**
>>> +     *
>>> +     */
>>> +    private static final long serialVersionUID = 8184103677832024335L;
>>> +
>>> +    private static final Logger log = LoggingManager.
>>> getLoggerForClass();
>>>
>> See naming comment of log from above
>>
>>> +
>>> +    /**
>>> +     * Set used to register instances which implement teardownTest.
>>> +     * This is used so that the BackendListenerClient can be notified
>>> when the test ends.
>>> +     */
>>> +    private static final Set<BackendListener> TEAR_DOWN_SET = new
>>> HashSet<BackendListener>();
>>> +
>>> +    /**
>>> +     * Property key representing the classname of the
>>> BackendListenerClient to user.
>>> +     */
>>> +    public static final String CLASSNAME = "classname";
>>> +
>>> +    /**
>>> +     * Queue size
>>> +     */
>>> +    public static final String QUEUE_SIZE = "QUEUE_SIZE";
>>> +
>>> +    /**
>>> +     * Property key representing the arguments for the
>>> BackendListenerClient.
>>> +     */
>>> +    public static final String ARGUMENTS = "arguments";
>>> +
>>> +    /**
>>> +     * The BackendListenerClient class used by this sampler.
>>> +     * Created by testStarted; copied to cloned instances.
>>> +     */
>>> +    private Class<?> javaClass;
>>>
>> Could probably named clientClass instead of javaClass, since we already
>> know it is a java class.
>>
>>> +
>>> +    /**
>>> +     * If true, the BackendListenerClient class implements teardownTest.
>>> +     * Created by testStarted; copied to cloned instances.
>>> +     */
>>> +    private boolean isToBeRegistered;
>>> +
>>> +    /**
>>> +     * The BackendListenerClient instance
>>> +     */
>>> +    private transient BackendListenerClient backendListenerClient = null;
>>> +
>>> +    /**
>>> +     * The JavaSamplerContext instance used by this sampler to hold
>>> information
>>>
>> BackendListenerContext?
>>
>>> +     * related to the test run, such as the parameters specified for the
>>> sampler
>>> +     * client.
>>> +     */
>>> +    private transient BackendListenerContext context = null;
>>> +
>>> +    private static final int DEFAULT_QUEUE_SIZE = 5000;
>>> +
>>> +    private transient BlockingQueue<SampleResult> queue; // created by
>>> server in readResolve method
>>> +
>>> +    private transient long queueWaits; // how many times we had to wait
>>> to queue a sample
>>> +
>>> +    private transient long queueWaitTime; // how long we had to wait
>>> (nanoSeconds)
>>> +
>>> +    // Create unique object as marker for end of queue
>>> +    private transient static final SampleResult FINAL_EVENT = new
>>> SampleResult();
>>> +
>>> +    /**
>>> +     * Create a BackendListener.
>>> +     */
>>> +    public BackendListener() {
>>> +        setArguments(new Arguments());
>>> +    }
>>> +
>>> +    /*
>>> +     * Ensure that the required class variables are cloned,
>>> +     * as this is not currently done by the super-implementation.
>>> +     */
>>> +    @Override
>>> +    public Object clone() {
>>> +        BackendListener clone = (BackendListener) super.clone();
>>> +        clone.javaClass = this.javaClass;
>>> +        clone.isToBeRegistered = this.isToBeRegistered;
>>> +        return clone;
>>> +    }
>>> +
>>> +    private void initClass() {
>>> +        String name = getClassname().trim();
>>> +        try {
>>> +            javaClass = Class.forName(name, false,
>>> Thread.currentThread().getContextClassLoader());
>>> +            Method method = javaClass.getMethod("teardownTest", new
>>> Class[]{BackendListenerContext.class});
>>> +            isToBeRegistered = !method.getDeclaringClass().equals(
>>> AbstractBackendListenerClient.class);
>>> +            log.info("Created class: " + name + ". Uses teardownTest: "
>>> + isToBeRegistered);
>>> +        } catch (Exception e) {
>>> +            log.error(whoAmI() + "\tException initialising: " + name, e);
>>> +        }
>>> +    }
>>> +
>>> +    /**
>>> +     * Retrieves reference to BackendListenerClient.
>>> +     *
>>> +     * Convience method used to check for null reference without actually
>>> +     * creating a BackendListenerClient
>>> +     *
>>> +     * @return reference to BackendListenerClient NOTUSED private
>>> BackendListenerClient
>>> +     *         retrieveJavaClient() { return javaClient; }
>>> +     */
>>>
>> Javadoc for non-existant method?
>>
>>> +
>>> +    /**
>>> +     * Generate a String identifier of this instance for debugging
>>> purposes.
>>> +     *
>>> +     * @return a String identifier for this sampler instance
>>> +     */
>>> +    private String whoAmI() {
>>> +        StringBuilder sb = new StringBuilder();
>>> +        sb.append(Thread.currentThread().getName());
>>> +        sb.append("@");
>>> +        sb.append(Integer.toHexString(hashCode()));
>>> +        sb.append("-");
>>> +        sb.append(getName());
>>> +        return sb.toString();
>>> +    }
>>> +
>>> +    // TestStateListener implementation
>>> +    /* Implements TestStateListener.testStarted() */
>>> +    @Override
>>> +    public void testStarted() {
>>> +        testStarted("");
>>> +    }
>>> +
>>> +    /* Implements TestStateListener.testStarted(String) */
>>> +    @Override
>>> +    public void testStarted(String host) {
>>> +        log.debug(whoAmI() + "\ttestStarted(" + host + ")");
>>>
>> Maybe use isDebugEnabled to guard whoAmI() call?
>>
>>> +        queue = new ArrayBlockingQueue<SampleResult>(getQueueSize());
>>> +        initClass();
>>> +        queueWaits=0L;
>>> +        queueWaitTime=0L;
>>> +        log.info(getName()+":Starting worker with class:"+javaClass +"
>>> and queue capacity:"+getQueueSize());
>>> +
>>> +        backendListenerClient = createBackendListenerClientImp
>>> l(javaClass);
>>> +        context = new BackendListenerContext((Arguments)getArguments().
>>> clone());
>>> +        if(isToBeRegistered) {
>>>
>> space after if and before (?
>>
>>> +            TEAR_DOWN_SET.add(this);
>>> +        }
>>> +        try {
>>> +            backendListenerClient.setupTest(context);
>>> +        } catch (Exception e) {
>>> +            throw new java.lang.IllegalStateException("Failed calling
>>> setupTest", e);
>>> +        }
>>> +
>>> +        Worker worker = new Worker(javaClass, backendListenerClient,
>>> (Arguments) getArguments().clone(), queue);
>>> +        worker.setDaemon(true);
>>> +        worker.start();
>>>
>> Don't we want to stop worker after we're done with one test?
>>
>>> +        log.info(getName()+":Started  worker with class:"+javaClass);
>>>
>> Spaces after :?
>>
>>> +
>>> +    }
>>> +
>>> +    /* (non-Javadoc)
>>> +     * @see org.apache.jmeter.samplers.SampleListener#sampleOccurred(
>>> org.apache.jmeter.samplers.SampleEvent)
>>> +     */
>>> +    @Override
>>> +    public void sampleOccurred(SampleEvent e) {
>>>
>> Longer name then 'e'? I expect e to be an exception, not an event.
>>
>>> +        Arguments args = getArguments();
>>> +        context = new BackendListenerContext(args);
>>> +
>>> +        SampleResult sr = backendListenerClient.createSampleResult(context,
>>> e.getResult());
>>> +        try {
>>> +            if (!queue.offer(sr)){ // we failed to add the element first
>>> time
>>> +                queueWaits++;
>>> +                long t1 = System.nanoTime();
>>> +                queue.put(sr);
>>> +                long t2 = System.nanoTime();
>>> +                queueWaitTime += t2-t1;
>>>
>> Will sampleOccurred be called concurrently? If so, than queueWaitTime +=
>> will not be correct.
>>
>>> +            }
>>> +        } catch (Exception err) {
>>> +            log.error("sampleOccurred, failed to queue the sample", err);
>>> +        }
>>> +    }
>>> +
>>> +    private static final class Worker extends Thread {
>>> +
>>> +        private final BlockingQueue<SampleResult> queue;
>>> +        private final BackendListenerContext context;
>>> +        private final BackendListenerClient backendListenerClient;
>>> +        private Worker(Class<?> javaClass, BackendListenerClient
>>> backendListenerClient, Arguments arguments, BlockingQueue<SampleResult> q){
>>>
>> Same naming argument as above. clientclass instead of javaClass?
>>
>>> +            queue = q;
>>> +            // Allow BackendListenerClient implementations to get access
>>> to test element name
>>> +            arguments.addArgument(TestElement.NAME, getName());
>>> +            context = new BackendListenerContext(arguments);
>>> +            this.backendListenerClient = backendListenerClient;
>>> +        }
>>> +
>>> +
>>> +        @Override
>>> +        public void run() {
>>> +            boolean isDebugEnabled = log.isDebugEnabled();
>>> +            List<SampleResult> l = new ArrayList<SampleResult>(queue.
>>> size());
>>>
>> samples instead of l?
>>
>>> +            try {
>>> +                boolean eof = false;
>>>
>> endOfLoop?
>>
>>> +                while (!eof) {
>>> +                    if(isDebugEnabled) {
>>> +                        log.debug("Thread:"+Thread.currentThread().getName()+"
>>> taking SampleResult from queue:"+queue.size());
>>> +                    }
>>> +                    SampleResult e = queue.take();
>>>
>> Could be named result, or sample instead of e
>>
>>> +                    if(isDebugEnabled) {
>>> +                        log.debug("Thread:"+Thread.currentThread().getName()+"
>>> took SampleResult:"+e+", isFinal:" + (e==FINAL_EVENT));
>>> +                    }
>>> +                    while (!(eof = (e == FINAL_EVENT)) && e != null ) {
>>> // try to process as many as possible
>>> +                        l.add(e);
>>> +                        if(isDebugEnabled) {
>>> +                            log.debug("Thread:"+Thread.currentThread().getName()+"
>>> polling from queue:"+queue.size());
>>> +                        }
>>> +                        e = queue.poll(); // returns null if nothing on
>>> queue currently
>>> +                        if(isDebugEnabled) {
>>> +                            log.debug("Thread:"+Thread.currentThread().getName()+"
>>> took from queue:"+e+", isFinal:" + (e==FINAL_EVENT));
>>> +                        }
>>> +                    }
>>> +                    if(isDebugEnabled) {
>>> +                        log.debug("Thread:"+Thread.
>>> currentThread().getName()+
>>> +                                " exiting with FINAL EVENT:"+(e ==
>>> FINAL_EVENT)
>>> +                                +", null:" + (e==null));
>>> +                    }
>>> +                    int size = l.size();
>>>
>> No need for a temporary variable.
>>
>>> +                    if (size > 0) {
>>> +                        backendListenerClient.handleSampleResults(l,
>>> context);
>>> +                        l.clear();
>>> +                    }
>>> +                    if(!eof) {
>>> +                        LockSupport.parkNanos(100);
>>> +                    }
>>> +                }
>>> +            } catch (InterruptedException e) {
>>> +                // NOOP
>>> +            }
>>> +            // We may have been interrupted
>>> +            int size = l.size();
>>> +            if (size > 0) {
>>> +                backendListenerClient.handleSampleResults(l, context);
>>> +                l.clear();
>>> +            }
>>>
>> Same code as a few lines above, could be factored out into a method
>> handleSamples(l, context)
>>
>>> +            log.info("Worker ended");
>>> +        }
>>> +    }
>>> +
>>> +
>>> +    /**
>>> +     * Returns reference to <code>BackendListenerClient</code>.
>>>
>> Could use a {@link...}
>>
>>> +     *
>>> +     *
>>> +     * @return BackendListenerClient reference.
>>> +     */
>>> +    static BackendListenerClient createBackendListenerClientImpl(Class<?>
>>> javaClass) {
>>> +        if (javaClass == null) { // failed to initialise the class
>>> +            return new ErrorBackendListenerClient();
>>> +        }
>>> +        BackendListenerClient client;
>>> +        try {
>>> +            client = (BackendListenerClient) javaClass.newInstance();
>>> +        } catch (Exception e) {
>>> +            log.error("Exception creating: " + javaClass, e);
>>> +            client = new ErrorBackendListenerClient();
>>> +        }
>>> +        return client;
>>>
>> I would return newInstance() in try Block and return new Error.. in catch
>> Block. javaClass -> clientClass
>>
>>> +    }
>>> +
>>> +    /**
>>> +     * Method called at the end of the test. This is called only on one
>>> instance
>>> +     * of BackendListener. This method will loop through all of the other
>>> +     * BackendListenerClients which have been registered (automatically
>>> in the
>>> +     * constructor) and notify them that the test has ended, allowing the
>>> +     * BackendListenerClients to cleanup.
>>> +     */
>>> +    @Override
>>> +    public void testEnded() {
>>> +        try {
>>> +            queue.put(FINAL_EVENT);
>>> +        } catch (Exception ex) {
>>> +            log.warn("testEnded() with exception:"+ex.getMessage(), ex);
>>> +        }
>>> +        if (queueWaits > 0) {
>>> +            log.warn("QueueWaits: "+queueWaits+"; QueueWaitTime:
>>> "+queueWaitTime+" (nanoseconds), you may need to increase queue capacity,
>>> see property 'backend_queue_capacity'");
>>> +        }
>>> +        synchronized (TEAR_DOWN_SET) {
>>> +            for (BackendListener backendListener : TEAR_DOWN_SET) {
>>> +                BackendListenerClient client = backendListener.
>>> backendListenerClient;
>>> +                if (client != null) {
>>> +                    try {
>>> +                        client.teardownTest(backendListener.context);
>>> +                    } catch (Exception e) {
>>> +                        throw new java.lang.IllegalStateException("Failed
>>> calling teardownTest", e);
>>>
>> If we throw an exception here, we will not try every client.
>>
>>> +                    }
>>> +                }
>>> +            }
>>> +            TEAR_DOWN_SET.clear();
>>> +        }
>>> +    }
>>> +
>>> +    /* Implements TestStateListener.testEnded(String) */
>>> +    @Override
>>> +    public void testEnded(String host) {
>>> +        testEnded();
>>> +    }
>>> +
>>> +    /**
>>> +     * A {@link BackendListenerClient} implementation used for error
>>> handling. If an
>>> +     * error occurs while creating the real BackendListenerClient
>>> object, it is
>>> +     * replaced with an instance of this class. Each time a sample
>>> occurs with
>>> +     * this class, the result is marked as a failure so the user can see
>>> that
>>> +     * the test failed.
>>> +     */
>>> +    static class ErrorBackendListenerClient extends
>>> AbstractBackendListenerClient {
>>> +        /**
>>> +         * Return SampleResult with data on error.
>>> +         *
>>> +         * @see BackendListenerClient#runTest(JavaSamplerContext)
>>> +         */
>>> +        @Override
>>> +        public void handleSampleResults(List<SampleResult>
>>> sampleResults, BackendListenerContext context) {
>>> +            log.warn("ErrorBackendListenerClient#handleSampleResult
>>> called, noop");
>>> +            Thread.yield();
>>> +        }
>>> +    }
>>> +
>>> +    /* (non-Javadoc)
>>> +     * @see org.apache.jmeter.samplers.SampleListener#sampleStarted(
>>> org.apache.jmeter.samplers.SampleEvent)
>>> +     */
>>> +    @Override
>>> +    public void sampleStarted(SampleEvent e) {
>>> +        // NOOP
>>> +
>>> +    }
>>> +
>>> +    /* (non-Javadoc)
>>> +     * @see org.apache.jmeter.samplers.SampleListener#sampleStopped(
>>> org.apache.jmeter.samplers.SampleEvent)
>>> +     */
>>> +    @Override
>>> +    public void sampleStopped(SampleEvent e) {
>>> +        // NOOP
>>> +
>>> +    }
>>> +
>>> +    /**
>>> +     * Set the arguments (parameters) for the BackendListenerClient to
>>> be executed
>>> +     * with.
>>> +     *
>>> +     * @param args
>>> +     *            the new arguments. These replace any existing
>>> arguments.
>>> +     */
>>> +    public void setArguments(Arguments args) {
>>> +        setProperty(new TestElementProperty(ARGUMENTS, args));
>>> +    }
>>> +
>>> +    /**
>>> +     * Get the arguments (parameters) for the BackendListenerClient to
>>> be executed
>>> +     * with.
>>> +     *
>>> +     * @return the arguments
>>> +     */
>>> +    public Arguments getArguments() {
>>> +        return (Arguments) getProperty(ARGUMENTS).getObjectValue();
>>> +    }
>>> +
>>> +    /**
>>> +     * Sets the Classname of the BackendListenerClient object
>>> +     *
>>> +     * @param classname
>>> +     *            the new Classname value
>>> +     */
>>> +    public void setClassname(String classname) {
>>> +        setProperty(CLASSNAME, classname);
>>> +    }
>>> +
>>> +    /**
>>> +     * Gets the Classname of the BackendListenerClient object
>>> +     *
>>> +     * @return the Classname value
>>> +     */
>>> +    public String getClassname() {
>>> +        return getPropertyAsString(CLASSNAME);
>>> +    }
>>> +
>>> +    /**
>>> +     * Sets the queue size
>>> +     *
>>> +     * @param queueSize
>>> +     *
>>> +     */
>>> +    public void setQueueSize(int queueSize) {
>>> +        setProperty(QUEUE_SIZE, queueSize, DEFAULT_QUEUE_SIZE);
>>> +    }
>>> +
>>> +    /**
>>> +     * Gets the queue size
>>> +     *
>>> +     * @return int queueSize
>>> +     */
>>> +    public int getQueueSize() {
>>> +        return getPropertyAsInt(QUEUE_SIZE, DEFAULT_QUEUE_SIZE);
>>> +    }
>>> +}
>>>
>>> Propchange: jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>>> backend/BackendListener.java
>>> ------------------------------------------------------------
>>> ------------------
>>>       svn:mime-type = text/plain
>>>
>>> Added: jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>>> backend/BackendListenerClient.java
>>> URL: http://svn.apache.org/viewvc/jmeter/trunk/src/components/
>>> org/apache/jmeter/visualizers/backend/BackendListenerClient.
>>> java?rev=1641081&view=auto
>>> ============================================================
>>> ==================
>>> --- jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>>> backend/BackendListenerClient.java (added)
>>> +++ jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>>> backend/BackendListenerClient.java Sat Nov 22 15:36:37 2014
>>> @@ -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.jmeter.visualizers.backend;
>>> +
>>> +import java.util.List;
>>> +
>>> +import org.apache.jmeter.config.Arguments;
>>> +import org.apache.jmeter.samplers.SampleResult;
>>> +
>>> +/**
>>> + * This interface defines the interactions between the BackendListener
>>> and external
>>> + * Java programs which can be executed by JMeter. Any Java class which
>>> wants to
>>> + * be executed as a JMeter test must implement this interface (either
>>> directly
>>> + * or indirectly through AbstractBackendListenerClient).
>>> + * <p>
>>> + * JMeter will create one instance of a BackendListenerClient
>>> implementation for
>>> + * each user/thread in the test. Additional instances may be created for
>>> + * internal use by JMeter (for example, to find out what parameters are
>>> + * supported by the client).
>>> + * <p>
>>> + * When the test is started, setupTest() will be called on each thread's
>>> + * BackendListenerClient instance to initialize the client. Then
>>> handleSampleResult() will be
>>> + * called for each SampleResult notification. Finally, teardownTest()
>>> will be called
>>> + * to allow the client to do any necessary clean-up.
>>> + * <p>
>>> + * The JMeter BackendListener GUI allows a list of parameters to be
>>> defined for the
>>> + * test. These are passed to the various test methods through the
>>> + * {@link BackendListenerContext}. A list of default parameters can be
>>> defined
>>> + * through the getDefaultParameters() method. These parameters and any
>>> default
>>> + * values associated with them will be shown in the GUI. Users can add
>>> other
>>> + * parameters as well.
>>> + * <p>
>>> + * When possible, Listeners should extend {@link
>>> AbstractBackendListenerClient
>>> + * AbstractBackendListenerClient} rather than implementing
>>> BackendListenerClient
>>> + * directly. This should protect your tests from future changes to the
>>> + * interface. While it may be necessary to make changes to the
>>> BackendListenerClient
>>> + * interface from time to time (therefore requiring changes to any
>>> + * implementations of this interface), we intend to make this abstract
>>> class
>>> + * provide reasonable default implementations of any new methods so that
>>> + * subclasses do not necessarily need to be updated for new versions.
>>> + * Implementing BackendListenerClient directly will continue to be
>>> supported for
>>> + * cases where extending this class is not possible (for example, when
>>> the
>>> + * client class is already a subclass of some other class).
>>> + *
>>> + * @since 2.13
>>> + */
>>> +public interface BackendListenerClient {
>>> +    /**
>>> +     * Do any initialization required by this client. It is generally
>>> +     * recommended to do any initialization such as getting parameter
>>> values in
>>> +     * the setupTest method rather than the runTest method in order to
>>> add as
>>> +     * little overhead as possible to the test.
>>> +     *
>>> +     * @param context
>>> +     *            the context to run with. This provides access to
>>> +     *            initialization parameters.
>>> +     */
>>> +    void setupTest(BackendListenerContext context) throws Exception;
>>> +
>>> +    /**
>>> +     * Perform a single sample for each iteration. This method returns a
>>> +     * <code>SampleResult</code> object. <code>SampleResult</code> has
>>> many
>>> +     * fields which can be used. At a minimum, the test should use
>>> +     * <code>SampleResult.sampleStart</code> and
>>> +     * <code>SampleResult.sampleEnd</code>to set the time that the test
>>>
>> use {@link..} instead of <code>..?
>>
>>> +     * required to execute. It is also a good idea to set the
>>> sampleLabel and
>>> +     * the successful flag.
>>> +     *
>>> +     * @see org.apache.jmeter.samplers.SampleResult#sampleStart()
>>> +     * @see org.apache.jmeter.samplers.SampleResult#sampleEnd()
>>> +     * @see org.apache.jmeter.samplers.SampleResult#setSuccessful(
>>> boolean)
>>> +     * @see org.apache.jmeter.samplers.SampleResult#setSampleLabel(
>>> String)
>>> +     *
>>> +     * @param context
>>> +     *            the context to run with. This provides access to
>>> +     *            initialization parameters.
>>> +     *
>>> +     */
>>> +    void handleSampleResults(List<SampleResult> sampleResults,
>>> BackendListenerContext context);
>>> +
>>> +    /**
>>> +     * Do any clean-up required by this test at the end of a test run.
>>> +     *
>>> +     * @param context
>>> +     *            the context to run with. This provides access to
>>> +     *            initialization parameters.
>>> +     */
>>> +    void teardownTest(BackendListenerContext context) throws Exception;
>>> +
>>> +    /**
>>> +     * Provide a list of parameters which this test supports. Any
>>> parameter
>>> +     * names and associated values returned by this method will appear
>>> in the
>>> +     * GUI by default so the user doesn't have to remember the exact
>>> names. The
>>> +     * user can add other parameters which are not listed here. If this
>>> method
>>> +     * returns null then no parameters will be listed. If the value for
>>> some
>>> +     * parameter is null then that parameter will be listed in the GUI
>>> with an
>>> +     * empty value.
>>> +     *
>>> +     * @return a specification of the parameters used by this test which
>>> should
>>> +     *         be listed in the GUI, or null if no parameters should be
>>> listed.
>>> +     */
>>> +    Arguments getDefaultParameters();
>>> +
>>> +    /**
>>> +     *
>>> +     * @param context
>>> +     * @param result
>>> +     * @return
>>> +     */
>>> +    SampleResult createSampleResult(
>>> +            BackendListenerContext context, SampleResult result);
>>> +}
>>>
>>> Propchange: jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>>> backend/BackendListenerClient.java
>>> ------------------------------------------------------------
>>> ------------------
>>>       svn:mime-type = text/plain
>>>
>>> Added: jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/
>>> BackendListenerContext.java
>>> URL: http://svn.apache.org/viewvc/jmeter/trunk/src/components/
>>> org/apache/jmeter/visualizers/backend/BackendListenerContext.java?
>>> rev=1641081&view=auto
>>> ============================================================
>>> ==================
>>> --- jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/BackendListenerContext.java
>>> (added)
>>> +++ jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/BackendListenerContext.java
>>> Sat Nov 22 15:36:37 2014
>>> @@ -0,0 +1,237 @@
>>> +/*
>>> +
>>> + * 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.jmeter.visualizers.backend;
>>> +
>>> +import java.util.Iterator;
>>> +import java.util.Map;
>>> +
>>> +import org.apache.jmeter.config.Arguments;
>>> +import org.apache.jorphan.logging.LoggingManager;
>>> +import org.apache.log.Logger;
>>> +
>>> +/**
>>> + * BackendListenerContext is used to provide context information to a
>>> + * BackendListenerClient implementation. This currently consists of the
>>> + * initialization parameters which were specified in the GUI.
>>> + * @since 2.13
>>> + */
>>> +public class BackendListenerContext {
>>> +    /*
>>> +     * Implementation notes:
>>> +     *
>>> +     * All of the methods in this class are currently read-only. If
>>> update
>>> +     * methods are included in the future, they should be defined so
>>> that a
>>> +     * single instance of BackendListenerContext can be associated with
>>> each thread.
>>> +     * Therefore, no synchronization should be needed. The same instance
>>> should
>>> +     * be used for the call to setupTest, all calls to runTest, and the
>>> call to
>>> +     * teardownTest.
>>> +     */
>>> +
>>> +    /** Logging */
>>> +    private static final Logger log = LoggingManager.
>>> getLoggerForClass();
>>>
>> See naming comments for logger above
>>
>>> +
>>> +    /**
>>> +     * Map containing the initialization parameters for the
>>> BackendListenerClient.
>>> +     */
>>> +    private final Map<String, String> params;
>>> +
>>> +    /**
>>> +     *
>>> +     * @param args
>>> +     *            the initialization parameters.
>>> +     */
>>> +    public BackendListenerContext(Arguments args) {
>>> +        this.params = args.getArgumentsAsMap();
>>> +    }
>>> +
>>> +    /**
>>> +     * Determine whether or not a value has been specified for the
>>> parameter
>>> +     * with this name.
>>> +     *
>>> +     * @param name
>>> +     *            the name of the parameter to test
>>> +     * @return true if the parameter value has been specified, false
>>> otherwise.
>>> +     */
>>> +    public boolean containsParameter(String name) {
>>>
>> hasParameter instead of containsParameter?
>>
>>> +        return params.containsKey(name);
>>> +    }
>>> +
>>> +    /**
>>> +     * Get an iterator of the parameter names. Each entry in the
>>> Iterator is a
>>> +     * String.
>>> +     *
>>> +     * @return an Iterator of Strings listing the names of the
>>> parameters which
>>> +     *         have been specified for this test.
>>> +     */
>>> +    public Iterator<String> getParameterNamesIterator() {
>>> +        return params.keySet().iterator();
>>> +    }
>>> +
>>> +    /**
>>> +     * Get the value of a specific parameter as a String, or null if the
>>> value
>>> +     * was not specified.
>>> +     *
>>> +     * @param name
>>> +     *            the name of the parameter whose value should be
>>> retrieved
>>> +     * @return the value of the parameter, or null if the value was not
>>> +     *         specified
>>> +     */
>>> +    public String getParameter(String name) {
>>> +        return getParameter(name, null);
>>> +    }
>>> +
>>> +    /**
>>> +     * Get the value of a specified parameter as a String, or return the
>>> +     * specified default value if the value was not specified.
>>> +     *
>>> +     * @param name
>>> +     *            the name of the parameter whose value should be
>>> retrieved
>>> +     * @param defaultValue
>>> +     *            the default value to return if the value of this
>>> parameter was
>>> +     *            not specified
>>> +     * @return the value of the parameter, or the default value if the
>>> parameter
>>> +     *         was not specified
>>> +     */
>>> +    public String getParameter(String name, String defaultValue) {
>>> +        if (params == null || !params.containsKey(name)) {
>>> +            return defaultValue;
>>> +        }
>>> +        return params.get(name);
>>> +    }
>>> +
>>> +    /**
>>> +     * Get the value of a specified parameter as an integer. An
>>> exception will
>>> +     * be thrown if the parameter is not specified or if it is not an
>>> integer.
>>> +     * The value may be specified in decimal, hexadecimal, or octal, as
>>> defined
>>> +     * by Integer.decode().
>>> +     *
>>> +     * @param name
>>> +     *            the name of the parameter whose value should be
>>> retrieved
>>> +     * @return the value of the parameter
>>> +     *
>>> +     * @throws NumberFormatException
>>> +     *             if the parameter is not specified or is not an integer
>>> +     *
>>> +     * @see java.lang.Integer#decode(java.lang.String)
>>> +     */
>>> +    public int getIntParameter(String name) throws NumberFormatException
>>> {
>>> +        if (params == null || !params.containsKey(name)) {
>>> +            throw new NumberFormatException("No value for parameter
>>> named '" + name + "'.");
>>>
>> I would expect an IllegalArgumentException, if no parameter of that name
>> is found
>>
>>> +        }
>>> +
>>> +        return Integer.decode(params.get(name)).intValue();
>>> +    }
>>> +
>>> +    /**
>>> +     * Get the value of a specified parameter as an integer, or return
>>> the
>>> +     * specified default value if the value was not specified or is not
>>> an
>>> +     * integer. A warning will be logged if the value is not an integer.
>>> The
>>> +     * value may be specified in decimal, hexadecimal, or octal, as
>>> defined by
>>> +     * Integer.decode().
>>> +     *
>>> +     * @param name
>>> +     *            the name of the parameter whose value should be
>>> retrieved
>>> +     * @param defaultValue
>>> +     *            the default value to return if the value of this
>>> parameter was
>>> +     *            not specified
>>> +     * @return the value of the parameter, or the default value if the
>>> parameter
>>> +     *         was not specified
>>> +     *
>>> +     * @see java.lang.Integer#decode(java.lang.String)
>>> +     */
>>> +    public int getIntParameter(String name, int defaultValue) {
>>> +        if (params == null || !params.containsKey(name)) {
>>> +            return defaultValue;
>>> +        }
>>> +
>>> +        try {
>>> +            return Integer.decode(params.get(name)).intValue();
>>> +        } catch (NumberFormatException e) {
>>> +            log.warn("Value for parameter '" + name + "' not an integer:
>>> '" + params.get(name) + "'.  Using default: '"
>>> +                    + defaultValue + "'.", e);
>>> +            return defaultValue;
>>> +        }
>>> +    }
>>> +
>>> +    /**
>>> +     * Get the value of a specified parameter as a long. An exception
>>> will be
>>> +     * thrown if the parameter is not specified or if it is not a long.
>>> The
>>> +     * value may be specified in decimal, hexadecimal, or octal, as
>>> defined by
>>> +     * Long.decode().
>>> +     *
>>> +     * @param name
>>> +     *            the name of the parameter whose value should be
>>> retrieved
>>> +     * @return the value of the parameter
>>> +     *
>>> +     * @throws NumberFormatException
>>> +     *             if the parameter is not specified or is not a long
>>> +     *
>>> +     * @see Long#decode(String)
>>> +     */
>>> +    public long getLongParameter(String name) throws
>>> NumberFormatException {
>>> +        if (params == null || !params.containsKey(name)) {
>>> +            throw new NumberFormatException("No value for parameter
>>> named '" + name + "'.");
>>> +        }
>>> +
>>> +        return Long.decode(params.get(name)).longValue();
>>> +    }
>>> +
>>> +    /**
>>> +     * Get the value of a specified parameter as along, or return the
>>> specified
>>> +     * default value if the value was not specified or is not a long. A
>>> warning
>>> +     * will be logged if the value is not a long. The value may be
>>> specified in
>>> +     * decimal, hexadecimal, or octal, as defined by Long.decode().
>>> +     *
>>> +     * @param name
>>> +     *            the name of the parameter whose value should be
>>> retrieved
>>> +     * @param defaultValue
>>> +     *            the default value to return if the value of this
>>> parameter was
>>> +     *            not specified
>>> +     * @return the value of the parameter, or the default value if the
>>> parameter
>>> +     *         was not specified
>>> +     *
>>> +     * @see Long#decode(String)
>>> +     */
>>> +    public long getLongParameter(String name, long defaultValue) {
>>> +        if (params == null || !params.containsKey(name)) {
>>> +            return defaultValue;
>>> +        }
>>> +        try {
>>> +            return Long.decode(params.get(name)).longValue();
>>> +        } catch (NumberFormatException e) {
>>> +            log.warn("Value for parameter '" + name + "' not a long: '"
>>> + params.get(name) + "'.  Using default: '"
>>> +                    + defaultValue + "'.", e);
>>> +            return defaultValue;
>>> +        }
>>> +    }
>>> +
>>> +    /**
>>> +     *
>>> +     * @param name
>>> +     * @param defaultValue
>>> +     * @return
>>>
>> No javadoc? Again three warnings more :)
>>
>>> +     */
>>> +    public boolean getBooleanParameter(String name, boolean
>>> defaultValue) {
>>> +        if (params == null || !params.containsKey(name)) {
>>> +            return defaultValue;
>>> +        }
>>> +        return Boolean.valueOf(params.get(name));
>>> +    }
>>> +}
>>>
>>> Propchange: jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>>> backend/BackendListenerContext.java
>>> ------------------------------------------------------------
>>> ------------------
>>>       svn:mime-type = text/plain
>>>
>>> Added: jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>>> backend/BackendListenerGui.java
>>> URL: http://svn.apache.org/viewvc/jmeter/trunk/src/components/
>>> org/apache/jmeter/visualizers/backend/BackendListenerGui.
>>> java?rev=1641081&view=auto
>>> ============================================================
>>> ==================
>>> --- jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>>> backend/BackendListenerGui.java (added)
>>> +++ jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>>> backend/BackendListenerGui.java Sat Nov 22 15:36:37 2014
>>> @@ -0,0 +1,282 @@
>>> +/*
>>> + * 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.jmeter.visualizers.backend;
>>> +
>>> +import java.awt.BorderLayout;
>>> +import java.awt.event.ActionEvent;
>>> +import java.awt.event.ActionListener;
>>> +import java.util.ArrayList;
>>> +import java.util.HashSet;
>>> +import java.util.List;
>>> +import java.util.Map;
>>> +import java.util.Set;
>>> +
>>> +import javax.swing.ComboBoxModel;
>>> +import javax.swing.JComboBox;
>>> +import javax.swing.JLabel;
>>> +import javax.swing.JPanel;
>>> +import javax.swing.JTextField;
>>> +
>>> +import org.apache.jmeter.config.Argument;
>>> +import org.apache.jmeter.config.Arguments;
>>> +import org.apache.jmeter.config.gui.ArgumentsPanel;
>>> +import org.apache.jmeter.gui.util.HorizontalPanel;
>>> +import org.apache.jmeter.testelement.TestElement;
>>> +import org.apache.jmeter.testelement.property.PropertyIterator;
>>> +import org.apache.jmeter.util.JMeterUtils;
>>> +import org.apache.jmeter.visualizers.gui.AbstractListenerGui;
>>> +import org.apache.jorphan.logging.LoggingManager;
>>> +import org.apache.jorphan.reflect.ClassFinder;
>>> +import org.apache.log.Logger;
>>> +
>>> +/**
>>> + * The <code>BackendListenerGui</code> class provides the user
>>> interface for the
>>> + * {@link BackendListener} object.
>>> + * @since 2.13
>>> + */
>>> +public class BackendListenerGui extends AbstractListenerGui implements
>>> ActionListener {
>>> +
>>> +    /**
>>> +     *
>>> +     */
>>> +    private static final long serialVersionUID = 4331668988576438604L;
>>> +
>>> +    /** Logging */
>>> +    private static final Logger log = LoggingManager.
>>> getLoggerForClass();
>>> +
>>> +    /** A combo box allowing the user to choose a backend class. */
>>> +    private JComboBox classnameCombo;
>>> +
>>> +    /**
>>> +     * A field allowing the user to specify the size of Queue
>>> +     */
>>> +    private JTextField queueSize;
>>> +
>>> +    /** A panel allowing the user to set arguments for this test. */
>>> +    private ArgumentsPanel argsPanel;
>>> +
>>> +    /**
>>> +     * Create a new BackendListenerGui as a standalone component.
>>> +     */
>>> +    public BackendListenerGui() {
>>> +        super();
>>> +        init();
>>> +    }
>>> +
>>> +
>>> +    /** {@inheritDoc} */
>>> +    @Override
>>> +    public String getLabelResource() {
>>> +        return "backend_listener"; // $NON-NLS-1$
>>> +    }
>>> +
>>> +    /**
>>> +     * Initialize the GUI components and layout.
>>> +     */
>>> +    private void init() {// called from ctor, so must not be overridable
>>> +        setLayout(new BorderLayout(0, 5));
>>> +
>>> +        setBorder(makeBorder());
>>> +        add(makeTitlePanel(), BorderLayout.NORTH);
>>> +
>>> +        JPanel classnameRequestPanel = new JPanel(new BorderLayout(0,
>>> 5));
>>> +        classnameRequestPanel.add(createClassnamePanel(),
>>> BorderLayout.NORTH);
>>> +        classnameRequestPanel.add(createParameterPanel(),
>>> BorderLayout.CENTER);
>>> +
>>> +        add(classnameRequestPanel, BorderLayout.CENTER);
>>> +    }
>>> +
>>> +    /**
>>> +     * Create a panel with GUI components allowing the user to select a
>>> test
>>> +     * class.
>>> +     *
>>> +     * @return a panel containing the relevant components
>>> +     */
>>> +    private JPanel createClassnamePanel() {
>>> +        List<String> possibleClasses = new ArrayList<String>();
>>> +
>>> +        try {
>>> +            // Find all the classes which implement the
>>> BackendListenerClient
>>> +            // interface.
>>> +            possibleClasses = ClassFinder.findClassesThatExtend(
>>> JMeterUtils.getSearchPaths(),
>>> +                    new Class[] { BackendListenerClient.class });
>>> +
>>> +            // Remove the BackendListener class from the list since it
>>> only
>>>
>> ErrorBackendListener
>>
>>> +            // implements the interface for error conditions.
>>> +
>>> +            possibleClasses.remove(BackendListener.class.getName() +
>>> "$ErrorBackendListenerClient");
>>> +        } catch (Exception e) {
>>> +            log.debug("Exception getting interfaces.", e);
>>> +        }
>>> +
>>> +        JLabel label = new JLabel(JMeterUtils.getResString("backend_listener_classname"));
>>> // $NON-NLS-1$
>>> +
>>> +        classnameCombo = new JComboBox(possibleClasses.toArray());
>>> +        classnameCombo.addActionListener(this);
>>> +        classnameCombo.setEditable(false);
>>> +        label.setLabelFor(classnameCombo);
>>> +
>>> +        HorizontalPanel classNamePanel = new HorizontalPanel();
>>> +        classNamePanel.add(label);
>>> +        classNamePanel.add(classnameCombo);
>>> +
>>> +        queueSize = new JTextField("", 5);
>>> +        queueSize.setName("Queue Size"); //$NON-NLS-1$
>>> +        JLabel queueSizeLabel = new JLabel(JMeterUtils.
>>> getResString("backend_listener_queue_size")); // $NON-NLS-1$
>>> +        queueSizeLabel.setLabelFor(queueSize);
>>> +        HorizontalPanel queueSizePanel = new HorizontalPanel();
>>> +        queueSizePanel.add(queueSizeLabel, BorderLayout.WEST);
>>> +        queueSizePanel.add(queueSize);
>>> +
>>> +        JPanel panel = new JPanel(new BorderLayout(0, 5));
>>> +        panel.add(classNamePanel, BorderLayout.NORTH);
>>> +        panel.add(queueSizePanel, BorderLayout.CENTER);
>>> +        return panel;
>>> +    }
>>> +
>>> +    /**
>>> +     * Handle action events for this component. This method currently
>>> handles
>>> +     * events for the classname combo box.
>>> +     *
>>> +     * @param evt
>>>
>> I would spend the few extra characters to make it event instead of evt
>>
>>> +     *            the ActionEvent to be handled
>>> +     */
>>> +    @Override
>>> +    public void actionPerformed(ActionEvent evt) {
>>> +        if (evt.getSource() == classnameCombo) {
>>> +            String className = ((String) classnameCombo.
>>> getSelectedItem()).trim();
>>> +            try {
>>> +                BackendListenerClient client = (BackendListenerClient)
>>> Class.forName(className, true,
>>> +                        Thread.currentThread().getContextClassLoader()).
>>> newInstance();
>>> +
>>> +                Arguments currArgs = new Arguments();
>>> +                argsPanel.modifyTestElement(currArgs);
>>> +                Map<String, String> currArgsMap =
>>> currArgs.getArgumentsAsMap();
>>> +
>>> +                Arguments newArgs = new Arguments();
>>> +                Arguments testParams = null;
>>> +                try {
>>> +                    testParams = client.getDefaultParameters();
>>> +                } catch (AbstractMethodError e) {
>>> +                    log.warn("BackendListenerClient doesn't implement "
>>> +                            + "getDefaultParameters.  Default parameters
>>> won't "
>>> +                            + "be shown.  Please update your client
>>> class: " + className);
>>> +                }
>>> +
>>> +                if (testParams != null) {
>>> +                    PropertyIterator i = testParams.getArguments().
>>> iterator();
>>>
>> I would try a for loop instead of explicitly using an iterator
>>
>>> +                    while (i.hasNext()) {
>>> +                        Argument arg = (Argument)
>>> i.next().getObjectValue();
>>> +                        String name = arg.getName();
>>> +                        String value = arg.getValue();
>>> +
>>> +                        // If a user has set parameters in one test, and
>>> then
>>> +                        // selects a different test which supports the
>>> same
>>> +                        // parameters, those parameters should have the
>>> same
>>> +                        // values that they did in the original test.
>>> +                        if (currArgsMap.containsKey(name)) {
>>> +                            String newVal = currArgsMap.get(name);
>>> +                            if (newVal != null && newVal.length() > 0) {
>>> +                                value = newVal;
>>> +                            }
>>> +                        }
>>> +                        newArgs.addArgument(name, value);
>>> +                    }
>>> +                }
>>> +
>>> +                argsPanel.configure(newArgs);
>>> +            } catch (Exception e) {
>>> +                log.error("Error getting argument list for " +
>>> className, e);
>>> +            }
>>> +        }
>>> +    }
>>> +
>>> +    /**
>>> +     * Create a panel containing components allowing the user to provide
>>> +     * arguments to be passed to the test class instance.
>>> +     *
>>> +     * @return a panel containing the relevant components
>>> +     */
>>> +    private JPanel createParameterPanel() {
>>> +        argsPanel = new ArgumentsPanel(JMeterUtils.
>>> getResString("backend_listener_paramtable")); // $NON-NLS-1$
>>> +        return argsPanel;
>>> +    }
>>> +
>>> +    /** {@inheritDoc} */
>>> +    @Override
>>> +    public void configure(TestElement config) {
>>> +        super.configure(config);
>>> +
>>> +        argsPanel.configure((Arguments) config.getProperty(
>>> BackendListener.ARGUMENTS).getObjectValue());
>>> +
>>> +        String className = config.getPropertyAsString(
>>> BackendListener.CLASSNAME);
>>> +        if(checkContainsClassName(classnameCombo.getModel(),
>>> className)) {
>>> +            classnameCombo.setSelectedItem(className);
>>> +        } else {
>>> +            log.error("Error setting class:'"+className+"' in
>>> BackendListener: "+getName()+
>>> +                    ", check for a missing jar in your jmeter
>>> 'search_paths' and 'plugin_dependency_paths' properties");
>>> +        }
>>> +        queueSize.setText(Integer.toString(((BackendListener)
>>> config).getQueueSize()));
>>> +    }
>>> +
>>> +    /**
>>> +     * Check combo contains className
>>> +     * @param model ComboBoxModel
>>> +     * @param className String class name
>>> +     * @return boolean
>>>
>> explain "boolean" or the other params a bit more?
>>
>>> +     */
>>> +    private static final boolean checkContainsClassName(ComboBoxModel
>>> model, String className) {
>>> +        int size = model.getSize();
>>> +        Set<String> set = new HashSet<String>(size);
>>> +        for (int i = 0; i < size; i++) {
>>> +            set.add((String)model.getElementAt(i));
>>> +        }
>>> +        return set.contains(className);
>>> +    }
>>> +
>>> +    /** {@inheritDoc} */
>>> +    @Override
>>> +    public TestElement createTestElement() {
>>> +        BackendListener config = new BackendListener();
>>> +        modifyTestElement(config);
>>> +        return config;
>>> +    }
>>> +
>>> +    /** {@inheritDoc} */
>>> +    @Override
>>> +    public void modifyTestElement(TestElement config) {
>>> +        configureTestElement(config);
>>> +        BackendListener backendListener = (BackendListener) config;
>>> +        backendListener.setArguments((Arguments)
>>> argsPanel.createTestElement());
>>> +        backendListener.setClassname(String.valueOf(classnameCombo.
>>> getSelectedItem()));
>>> +        backendListener.setQueueSize(Integer.parseInt(queueSize.
>>> getText()));
>>> +
>>> +    }
>>> +
>>> +    /* (non-Javadoc)
>>> +     * @see org.apache.jmeter.gui.AbstractJMeterGuiComponent#clearGui()
>>> +     */
>>> +    @Override
>>> +    public void clearGui() {
>>> +        super.clearGui();
>>> +        argsPanel.clearGui();
>>> +        classnameCombo.setSelectedIndex(0);
>>> +        queueSize.setText("");
>>> +    }
>>> +}
>>>
>>> Propchange: jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>>> backend/BackendListenerGui.java
>>> ------------------------------------------------------------
>>> ------------------
>>>       svn:mime-type = text/plain
>>>
>>> Added: jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>>> backend/SamplerMetric.java
>>> URL: http://svn.apache.org/viewvc/jmeter/trunk/src/components/
>>> org/apache/jmeter/visualizers/backend/SamplerMetric.java?
>>> rev=1641081&view=auto
>>> ============================================================
>>> ==================
>>> --- jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/SamplerMetric.java
>>> (added)
>>> +++ jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/SamplerMetric.java
>>> Sat Nov 22 15:36:37 2014
>>> @@ -0,0 +1,138 @@
>>> +/*
>>> + * 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.jmeter.visualizers.backend;
>>> +
>>> +import org.apache.commons.math3.stat.descriptive.DescriptiveStatistics;
>>> +import org.apache.jmeter.samplers.SampleResult;
>>> +
>>> +/**
>>> + * Sampler metric
>>> + * @since 2.13
>>> + */
>>> +public class SamplerMetric {
>>> +    // Limit to sliding window of 100 values
>>> +    private DescriptiveStatistics stats = new DescriptiveStatistics(100);
>>> +    private int success;
>>
>


Re: svn commit: r1641081 - in /jmeter/trunk: ./ bin/ res/maven/ src/components/org/apache/jmeter/visualizers/backend/ src/core/org/apache/jmeter/resources/ src/core/org/apache/jmeter/samplers/ src/core/org/apache/jmeter/save/ xdocs/ xdocs/usermanual/

Posted by Philippe Mouawad <ph...@gmail.com>.
Hi Felix,
As I said in thread, I commited code and will improve, feel free to fix
javadocs issues on your side.
I will review your comment.

I have spent many hours if not days on this code and I am aware it is not
yet fully completed (although tests are promising) but my aim when
commiting it was to have feedback and help to finish it.

Regards
Philippe

On Sat, Nov 22, 2014 at 7:21 PM, Felix Schumacher <
felix.schumacher@internetallee.de> wrote:

> Hello Philippe,
>
> I have hidden a few comments inside the cited code.
> They are mostly around javadoc and naming things.
>
> Am 22.11.2014 um 16:36 schrieb pmouawad@apache.org:
>
>> Author: pmouawad
>> Date: Sat Nov 22 15:36:37 2014
>> New Revision: 1641081
>>
>> URL: http://svn.apache.org/r1641081
>> Log:
>> Bug 55932 - Create a Async BackendListener to allow easy plug of new
>> listener (Graphite, JDBC, Console,...)
>> Bugzilla Id: 55932
>>
>> Added:
>>      jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/
>>      jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/
>> AbstractBackendListenerClient.java   (with props)
>>      jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/BackendListener.java
>>  (with props)
>>      jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>> backend/BackendListenerClient.java   (with props)
>>      jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/BackendListenerContext.java
>>  (with props)
>>      jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>> backend/BackendListenerGui.java   (with props)
>>      jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/SamplerMetric.java
>>  (with props)
>> Modified:
>>      jmeter/trunk/bin/saveservice.properties
>>      jmeter/trunk/build.properties
>>      jmeter/trunk/build.xml
>>      jmeter/trunk/eclipse.classpath
>>      jmeter/trunk/res/maven/ApacheJMeter_parent.pom
>>      jmeter/trunk/src/core/org/apache/jmeter/resources/
>> messages.properties
>>      jmeter/trunk/src/core/org/apache/jmeter/resources/
>> messages_fr.properties
>>      jmeter/trunk/src/core/org/apache/jmeter/samplers/SampleResult.java
>>      jmeter/trunk/src/core/org/apache/jmeter/save/SaveService.java
>>      jmeter/trunk/xdocs/changes.xml
>>      jmeter/trunk/xdocs/usermanual/component_reference.xml
>>
>> Modified: jmeter/trunk/bin/saveservice.properties
>> URL: http://svn.apache.org/viewvc/jmeter/trunk/bin/saveservice.
>> properties?rev=1641081&r1=1641080&r2=1641081&view=diff
>> ============================================================
>> ==================
>> --- jmeter/trunk/bin/saveservice.properties (original)
>> +++ jmeter/trunk/bin/saveservice.properties Sat Nov 22 15:36:37 2014
>> @@ -53,7 +53,8 @@ _file_version=$Revision$
>>   # 2.5 = 2.10
>>   # 2.6 = 2.11
>>   # 2.7 = 2.12
>> -_version=2.7
>> +# 2.8 = 2.13
>> +_version=2.8
>>   #
>>   #
>>   # Character set encoding used to read and write JMeter XML files and
>> CSV results
>> @@ -78,6 +79,8 @@ AssertionVisualizer=org.apache.jmeter.vi
>>   AuthManager=org.apache.jmeter.protocol.http.control.AuthManager
>>   Authorization=org.apache.jmeter.protocol.http.control.Authorization
>>   AuthPanel=org.apache.jmeter.protocol.http.gui.AuthPanel
>> +BackendListener=org.apache.jmeter.visualizers.backend.BackendListener
>> +BackendListenerGui=org.apache.jmeter.visualizers.
>> backend.BackendListenerGui
>>   BarChart=org.apache.jmeter.testelement.BarChart
>>   BarChartGui=org.apache.jmeter.report.gui.BarChartGui
>>   BeanShellAssertion=org.apache.jmeter.assertions.BeanShellAssertion
>>
>> Modified: jmeter/trunk/build.properties
>> URL: http://svn.apache.org/viewvc/jmeter/trunk/build.properties?
>> rev=1641081&r1=1641080&r2=1641081&view=diff
>> ============================================================
>> ==================
>> --- jmeter/trunk/build.properties (original)
>> +++ jmeter/trunk/build.properties Sat Nov 22 15:36:37 2014
>> @@ -118,11 +118,21 @@ commons-logging.loc         = ${maven2.r
>>   #commons-logging.md5         = E2C390FE739B2550A218262B28F290CE
>>   commons-logging.md5         = 040b4b4d8eac886f6b4a2a3bd2f31b00
>>   +commons-math3.version         = 3.3
>> +commons-math3.jar             = commons-math3-${commons-math3.
>> version}.jar
>> +commons-math3.loc             = ${maven2.repo}/org/apache/
>> commons/commons-math3/${commons-math3.version}
>> +commons-math3.md5             = 87346cf2772dc2becf106c45e0f63863
>> +
>>   commons-net.version         = 3.3
>>   commons-net.jar             = commons-net-${commons-net.version}.jar
>>   commons-net.loc             = ${maven2.repo}/commons-net/
>> commons-net/${commons-net.version}
>>   commons-net.md5             = c077ca61598e9c21f43f8b6488fbbee9
>>   +commons-pool2.version         = 2.2
>> +commons-pool2.jar             = commons-pool2-${commons-pool2.
>> version}.jar
>> +commons-pool2.loc             = ${maven2.repo}/org/apache/
>> commons/commons-pool2/${commons-pool2.version}
>> +commons-pool2.md5             = 51b56c92883812c56fbeb339866ce2df
>> +
>>   # dnsjava for DNSCacheManager
>>   dnsjava.version             = 2.1.6
>>   dnsjava.jar                 = dnsjava-${dnsjava.version}.jar
>>
>> Modified: jmeter/trunk/build.xml
>> URL: http://svn.apache.org/viewvc/jmeter/trunk/build.xml?rev=
>> 1641081&r1=1641080&r2=1641081&view=diff
>> ============================================================
>> ==================
>> --- jmeter/trunk/build.xml (original)
>> +++ jmeter/trunk/build.xml Sat Nov 22 15:36:37 2014
>> @@ -365,7 +365,9 @@
>>       <include name="${lib.dir}/${commons-jexl2.jar}"/>
>>       <include name="${lib.dir}/${commons-lang3.jar}"/>
>>       <include name="${lib.dir}/${commons-logging.jar}"/>
>> +    <include name="${lib.dir}/${commons-math3}"/>
>>       <include name="${lib.dir}/${commons-net.jar}"/>
>> +    <include name="${lib.dir}/${commons-pool2.jar}"/>
>>       <include name="${lib.dir}/${dnsjava.jar}"/>
>>       <include name="${lib.dir}/${excalibur-datasource.jar}"/>
>>       <include name="${lib.dir}/${excalibur-instrument.jar}"/>
>> @@ -438,8 +440,10 @@
>>       <pathelement location="${lib.dir}/${commons-jexl2.jar}"/>
>>       <pathelement location="${lib.dir}/${commons-lang3.jar}"/>
>>       <pathelement location="${lib.dir}/${commons-logging.jar}"/>
>> +    <pathelement location="${lib.dir}/${commons-math3.jar}"/>
>>       <pathelement location="${lib.dir}/${commons-net.jar}"/>
>> -    <pathelement location="${lib.dir}/${dnsjava.jar}"/>
>> +       <pathelement location="${lib.dir}/${commons-pool2.jar}"/>
>> +       <pathelement location="${lib.dir}/${dnsjava.jar}"/>
>>       <pathelement location="${lib.dir}/${excalibur-datasource.jar}"/>
>>       <pathelement location="${lib.dir}/${excalibur-instrument.jar}"/>
>>       <pathelement location="${lib.dir}/${excalibur-logger.jar}"/>
>> @@ -2909,7 +2913,9 @@ run JMeter unless all the JMeter jars ar
>>           <process_jarfile jarname="commons-jexl2"/>
>>           <process_jarfile jarname="commons-lang3"/>
>>           <process_jarfile jarname="commons-logging"/>
>> +        <process_jarfile jarname="commons-math3"/>
>>           <process_jarfile jarname="commons-net"/>
>> +       <process_jarfile jarname="commons-pool2"/>
>>           <process_jarfile jarname="dnsjava"/>
>>           <process_jarfile jarname="excalibur-datasource"/>
>>           <process_jarfile jarname="excalibur-instrument"/>
>>
>> Modified: jmeter/trunk/eclipse.classpath
>> URL: http://svn.apache.org/viewvc/jmeter/trunk/eclipse.
>> classpath?rev=1641081&r1=1641080&r2=1641081&view=diff
>> ============================================================
>> ==================
>> --- jmeter/trunk/eclipse.classpath (original)
>> +++ jmeter/trunk/eclipse.classpath Sat Nov 22 15:36:37 2014
>> @@ -55,7 +55,9 @@
>>         <classpathentry kind="lib" path="lib/commons-jexl-2.1.1.jar"/>
>>         <classpathentry kind="lib" path="lib/commons-lang3-3.3.2.jar"/>
>>         <classpathentry kind="lib" path="lib/commons-logging-1.2.jar"/>
>> +    <classpathentry kind="lib" path="lib/commons-math3-3.3.jar"/>
>>         <classpathentry kind="lib" path="lib/commons-net-3.3.jar"/>
>> +    <classpathentry kind="lib" path="lib/commons-pool2-2.2.jar"/>
>>         <classpathentry kind="lib" path="lib/dnsjava-2.1.6.jar"/>
>>         <classpathentry kind="lib" path="lib/excalibur-
>> datasource-2.1.jar"/>
>>         <classpathentry kind="lib" path="lib/excalibur-
>> instrument-1.0.jar"/>
>>
>> Modified: jmeter/trunk/res/maven/ApacheJMeter_parent.pom
>> URL: http://svn.apache.org/viewvc/jmeter/trunk/res/maven/
>> ApacheJMeter_parent.pom?rev=1641081&r1=1641080&r2=1641081&view=diff
>> ============================================================
>> ==================
>> --- jmeter/trunk/res/maven/ApacheJMeter_parent.pom (original)
>> +++ jmeter/trunk/res/maven/ApacheJMeter_parent.pom Sat Nov 22 15:36:37
>> 2014
>> @@ -66,7 +66,9 @@ under the License.
>>         <commons-jexl2.version>2.1.1</commons-jexl2.version>
>>         <commons-lang3.version>3.3.2</commons-lang3.version>
>>         <commons-logging.version>1.2</commons-logging.version>
>> +      <commons-math3.version>3.3</commons-math3.version>
>>         <commons-net.version>3.3</commons-net.version>
>> +      <commons-pool2.version>2.2</commons-pool2.version>
>>         <dnsjava.version>2.1.6</dnsjava.version>
>>         <excalibur-datasource.version>2.1</excalibur-datasource.version>
>>         <excalibur-instrument.version>1.0</excalibur-instrument.version>
>> @@ -181,11 +183,21 @@ under the License.
>>           <version>${commons-logging.version}</version>
>>         </dependency>
>>         <dependency>
>> +        <groupId>commons-math3</groupId>
>> +        <artifactId>commons-math3</artifactId>
>> +        <version>${commons-math3.version}</version>
>> +      </dependency>
>> +      <dependency>
>>           <groupId>commons-net</groupId>
>>           <artifactId>commons-net</artifactId>
>>           <version>${commons-net.version}</version>
>>         </dependency>
>>         <dependency>
>> +        <groupId>commons-pool2</groupId>
>> +        <artifactId>commons-pool2</artifactId>
>> +        <version>${commons-pool2.version}</version>
>> +      </dependency>
>> +      <dependency>
>>             <groupId>dnsjava</groupId>
>>             <artifactId>dnsjava</artifactId>
>>             <version>${dnsjava.version}</version>
>>
>> Added: jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/
>> AbstractBackendListenerClient.java
>> URL: http://svn.apache.org/viewvc/jmeter/trunk/src/components/
>> org/apache/jmeter/visualizers/backend/AbstractBackendListenerClient.
>> java?rev=1641081&view=auto
>> ============================================================
>> ==================
>> --- jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/
>> AbstractBackendListenerClient.java (added)
>> +++ jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/
>> AbstractBackendListenerClient.java Sat Nov 22 15:36:37 2014
>> @@ -0,0 +1,121 @@
>> +/*
>> + * 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.jmeter.visualizers.backend;
>> +
>> +import java.util.Map;
>> +import java.util.concurrent.ConcurrentHashMap;
>> +
>> +import org.apache.jmeter.config.Arguments;
>> +import org.apache.jmeter.samplers.SampleResult;
>> +import org.apache.jorphan.logging.LoggingManager;
>> +import org.apache.log.Logger;
>> +
>> +/**
>> + * An abstract implementation of the BackendListenerClient interface.
>> This
>> + * implementation provides default implementations of most of the
>> methods in the
>> + * interface, as well as some convenience methods, in order to simplify
>> + * development of BackendListenerClient implementations.
>> + *
>> + * While it may be necessary to make changes to the
>> BackendListenerClient interface
>> + * from time to time (therefore requiring changes to any implementations
>> of this
>> + * interface), we intend to make this abstract class provide reasonable
>> + * implementations of any new methods so that subclasses do not
>> necessarily need
>> + * to be updated for new versions. Therefore, when creating a new
>> + * BackendListenerClient implementation, developers are encouraged to
>> subclass this
>> + * abstract class rather than implementing the BackendListenerClient
>> interface
>> + * directly. Implementing BackendListenerClient directly will continue
>> to be
>> + * supported for cases where extending this class is not possible (for
>> example,
>> + * when the client class is already a subclass of some other class).
>> + * <p>
>> + * The handleSampleResult() method of BackendListenerClient does not
>> have a default
>> + * implementation here, so subclasses must define at least this method.
>> It may
>> + * be useful to override other methods as well.
>> + *
>> + * @see BackendListener#sampleOccurred(org.apache.
>> jmeter.samplers.SampleEvent)
>> + * @since 2.13
>> + */
>> +public abstract class AbstractBackendListenerClient implements
>> BackendListenerClient {
>> +
>> +    private static final Logger log = LoggingManager.
>> getLoggerForClass();
>>
> In classes further down the logger is stored in variables named LOG and
> LOGGER, should we use one name?
> In this class we have a getter for the logger in other classes not. Why?
>
>> +
>> +    private ConcurrentHashMap<String, SamplerMetric> metricsPerSampler =
>> new ConcurrentHashMap<String, SamplerMetric>();
>> +
>> +    /* Implements BackendListenerClient.setupTest(JavaSamplerContext) */
>> +    @Override
>> +    public void setupTest(BackendListenerContext context) throws
>> Exception {
>> +        log.debug(getClass().getName() + ": setupTest");
>> +    }
>> +
>> +    /* Implements BackendListenerClient.teardownTest(JavaSamplerContext)
>> */
>> +    @Override
>> +    public void teardownTest(BackendListenerContext context) throws
>> Exception {
>> +        log.debug(getClass().getName() + ": teardownTest");
>> +        metricsPerSampler.clear();
>> +    }
>> +
>> +    /* Implements BackendListenerClient.getDefaultParameters() */
>> +    @Override
>> +    public Arguments getDefaultParameters() {
>> +        return null;
>> +    }
>> +
>> +    /**
>> +     * Get a Logger instance which can be used by subclasses to log
>> information.
>> +     *
>> +     * @return a Logger instance which can be used for logging
>> +     */
>> +    protected Logger getLogger() {
>> +        return log;
>> +    }
>> +
>> +    /* (non-Javadoc)
>> +     * @see org.apache.jmeter.visualizers.backend.BackendListenerClient#
>> createSampleResult(org.apache.jmeter.samplers.SampleResult)
>> +     */
>> +    @Override
>> +    public SampleResult createSampleResult(BackendListenerContext
>> context, SampleResult result) {
>> +        SampleResult sampleResult = (SampleResult) result.clone();
>> +        return sampleResult;
>> +    }
>> +
>> +    /**
>> +     *
>> +     * @param sampleLabel
>> +     * @return SamplerMetric
>>
> No description of the method and the parameters?
>
>> +     */
>> +    protected SamplerMetric getSamplerMetric(String sampleLabel) {
>> +        SamplerMetric samplerMetric = metricsPerSampler.get(
>> sampleLabel);
>> +        if(samplerMetric == null) {
>> +            samplerMetric = new SamplerMetric();
>> +            SamplerMetric oldValue = metricsPerSampler.putIfAbsent(sampleLabel,
>> samplerMetric);
>> +            if(oldValue != null ){
>> +                samplerMetric = oldValue;
>> +            }
>> +        }
>> +        return samplerMetric;
>> +    }
>> +
>> +    /**
>> +     *
>> +     * @return Map<String, SamplerMetric>
>>
> No description of the method and usage of forbidden characters :) there
> are still more than 800 warnings in the javadoc to prune, so don't
> introduce new ones, please.
>
>> +     */
>> +    protected Map<String, SamplerMetric> getMetricsPerSampler() {
>> +        return metricsPerSampler;
>> +    }
>> +
>> +}
>>
>> Propchange: jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>> backend/AbstractBackendListenerClient.java
>> ------------------------------------------------------------
>> ------------------
>>      svn:mime-type = text/plain
>>
>> Added: jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>> backend/BackendListener.java
>> URL: http://svn.apache.org/viewvc/jmeter/trunk/src/components/
>> org/apache/jmeter/visualizers/backend/BackendListener.java?
>> rev=1641081&view=auto
>> ============================================================
>> ==================
>> --- jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/BackendListener.java
>> (added)
>> +++ jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/BackendListener.java
>> Sat Nov 22 15:36:37 2014
>> @@ -0,0 +1,448 @@
>> +/*
>> + * 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.jmeter.visualizers.backend;
>> +
>> +import java.io.Serializable;
>> +import java.lang.reflect.Method;
>> +import java.util.ArrayList;
>> +import java.util.HashSet;
>> +import java.util.List;
>> +import java.util.Set;
>> +import java.util.concurrent.ArrayBlockingQueue;
>> +import java.util.concurrent.BlockingQueue;
>> +import java.util.concurrent.locks.LockSupport;
>> +
>> +import org.apache.jmeter.config.Arguments;
>> +import org.apache.jmeter.engine.util.NoThreadClone;
>> +import org.apache.jmeter.protocol.java.sampler.JavaSamplerContext;
>> +import org.apache.jmeter.samplers.Remoteable;
>> +import org.apache.jmeter.samplers.SampleEvent;
>> +import org.apache.jmeter.samplers.SampleListener;
>> +import org.apache.jmeter.samplers.SampleResult;
>> +import org.apache.jmeter.testelement.AbstractTestElement;
>> +import org.apache.jmeter.testelement.TestElement;
>> +import org.apache.jmeter.testelement.TestStateListener;
>> +import org.apache.jmeter.testelement.property.TestElementProperty;
>> +import org.apache.jorphan.logging.LoggingManager;
>> +import org.apache.log.Logger;
>> +
>> +/**
>> + * Async Listener that delegates SampleResult handling to
>> implementations of {@link BackendListenerClient}
>> + * @since 2.13
>> + */
>> +public class BackendListener extends AbstractTestElement
>> +    implements Serializable, SampleListener, TestStateListener,
>> NoThreadClone, Remoteable  {
>> +
>> +    /**
>> +     *
>> +     */
>> +    private static final long serialVersionUID = 8184103677832024335L;
>> +
>> +    private static final Logger log = LoggingManager.
>> getLoggerForClass();
>>
> See naming comment of log from above
>
>> +
>> +    /**
>> +     * Set used to register instances which implement teardownTest.
>> +     * This is used so that the BackendListenerClient can be notified
>> when the test ends.
>> +     */
>> +    private static final Set<BackendListener> TEAR_DOWN_SET = new
>> HashSet<BackendListener>();
>> +
>> +    /**
>> +     * Property key representing the classname of the
>> BackendListenerClient to user.
>> +     */
>> +    public static final String CLASSNAME = "classname";
>> +
>> +    /**
>> +     * Queue size
>> +     */
>> +    public static final String QUEUE_SIZE = "QUEUE_SIZE";
>> +
>> +    /**
>> +     * Property key representing the arguments for the
>> BackendListenerClient.
>> +     */
>> +    public static final String ARGUMENTS = "arguments";
>> +
>> +    /**
>> +     * The BackendListenerClient class used by this sampler.
>> +     * Created by testStarted; copied to cloned instances.
>> +     */
>> +    private Class<?> javaClass;
>>
> Could probably named clientClass instead of javaClass, since we already
> know it is a java class.
>
>> +
>> +    /**
>> +     * If true, the BackendListenerClient class implements teardownTest.
>> +     * Created by testStarted; copied to cloned instances.
>> +     */
>> +    private boolean isToBeRegistered;
>> +
>> +    /**
>> +     * The BackendListenerClient instance
>> +     */
>> +    private transient BackendListenerClient backendListenerClient = null;
>> +
>> +    /**
>> +     * The JavaSamplerContext instance used by this sampler to hold
>> information
>>
> BackendListenerContext?
>
>> +     * related to the test run, such as the parameters specified for the
>> sampler
>> +     * client.
>> +     */
>> +    private transient BackendListenerContext context = null;
>> +
>> +    private static final int DEFAULT_QUEUE_SIZE = 5000;
>> +
>> +    private transient BlockingQueue<SampleResult> queue; // created by
>> server in readResolve method
>> +
>> +    private transient long queueWaits; // how many times we had to wait
>> to queue a sample
>> +
>> +    private transient long queueWaitTime; // how long we had to wait
>> (nanoSeconds)
>> +
>> +    // Create unique object as marker for end of queue
>> +    private transient static final SampleResult FINAL_EVENT = new
>> SampleResult();
>> +
>> +    /**
>> +     * Create a BackendListener.
>> +     */
>> +    public BackendListener() {
>> +        setArguments(new Arguments());
>> +    }
>> +
>> +    /*
>> +     * Ensure that the required class variables are cloned,
>> +     * as this is not currently done by the super-implementation.
>> +     */
>> +    @Override
>> +    public Object clone() {
>> +        BackendListener clone = (BackendListener) super.clone();
>> +        clone.javaClass = this.javaClass;
>> +        clone.isToBeRegistered = this.isToBeRegistered;
>> +        return clone;
>> +    }
>> +
>> +    private void initClass() {
>> +        String name = getClassname().trim();
>> +        try {
>> +            javaClass = Class.forName(name, false,
>> Thread.currentThread().getContextClassLoader());
>> +            Method method = javaClass.getMethod("teardownTest", new
>> Class[]{BackendListenerContext.class});
>> +            isToBeRegistered = !method.getDeclaringClass().equals(
>> AbstractBackendListenerClient.class);
>> +            log.info("Created class: " + name + ". Uses teardownTest: "
>> + isToBeRegistered);
>> +        } catch (Exception e) {
>> +            log.error(whoAmI() + "\tException initialising: " + name, e);
>> +        }
>> +    }
>> +
>> +    /**
>> +     * Retrieves reference to BackendListenerClient.
>> +     *
>> +     * Convience method used to check for null reference without actually
>> +     * creating a BackendListenerClient
>> +     *
>> +     * @return reference to BackendListenerClient NOTUSED private
>> BackendListenerClient
>> +     *         retrieveJavaClient() { return javaClient; }
>> +     */
>>
> Javadoc for non-existant method?
>
>> +
>> +    /**
>> +     * Generate a String identifier of this instance for debugging
>> purposes.
>> +     *
>> +     * @return a String identifier for this sampler instance
>> +     */
>> +    private String whoAmI() {
>> +        StringBuilder sb = new StringBuilder();
>> +        sb.append(Thread.currentThread().getName());
>> +        sb.append("@");
>> +        sb.append(Integer.toHexString(hashCode()));
>> +        sb.append("-");
>> +        sb.append(getName());
>> +        return sb.toString();
>> +    }
>> +
>> +    // TestStateListener implementation
>> +    /* Implements TestStateListener.testStarted() */
>> +    @Override
>> +    public void testStarted() {
>> +        testStarted("");
>> +    }
>> +
>> +    /* Implements TestStateListener.testStarted(String) */
>> +    @Override
>> +    public void testStarted(String host) {
>> +        log.debug(whoAmI() + "\ttestStarted(" + host + ")");
>>
> Maybe use isDebugEnabled to guard whoAmI() call?
>
>> +        queue = new ArrayBlockingQueue<SampleResult>(getQueueSize());
>> +        initClass();
>> +        queueWaits=0L;
>> +        queueWaitTime=0L;
>> +        log.info(getName()+":Starting worker with class:"+javaClass +"
>> and queue capacity:"+getQueueSize());
>> +
>> +        backendListenerClient = createBackendListenerClientImp
>> l(javaClass);
>> +        context = new BackendListenerContext((Arguments)getArguments().
>> clone());
>> +        if(isToBeRegistered) {
>>
> space after if and before (?
>
>> +            TEAR_DOWN_SET.add(this);
>> +        }
>> +        try {
>> +            backendListenerClient.setupTest(context);
>> +        } catch (Exception e) {
>> +            throw new java.lang.IllegalStateException("Failed calling
>> setupTest", e);
>> +        }
>> +
>> +        Worker worker = new Worker(javaClass, backendListenerClient,
>> (Arguments) getArguments().clone(), queue);
>> +        worker.setDaemon(true);
>> +        worker.start();
>>
> Don't we want to stop worker after we're done with one test?
>
>> +        log.info(getName()+":Started  worker with class:"+javaClass);
>>
> Spaces after :?
>
>> +
>> +    }
>> +
>> +    /* (non-Javadoc)
>> +     * @see org.apache.jmeter.samplers.SampleListener#sampleOccurred(
>> org.apache.jmeter.samplers.SampleEvent)
>> +     */
>> +    @Override
>> +    public void sampleOccurred(SampleEvent e) {
>>
> Longer name then 'e'? I expect e to be an exception, not an event.
>
>> +        Arguments args = getArguments();
>> +        context = new BackendListenerContext(args);
>> +
>> +        SampleResult sr = backendListenerClient.createSampleResult(context,
>> e.getResult());
>> +        try {
>> +            if (!queue.offer(sr)){ // we failed to add the element first
>> time
>> +                queueWaits++;
>> +                long t1 = System.nanoTime();
>> +                queue.put(sr);
>> +                long t2 = System.nanoTime();
>> +                queueWaitTime += t2-t1;
>>
> Will sampleOccurred be called concurrently? If so, than queueWaitTime +=
> will not be correct.
>
>> +            }
>> +        } catch (Exception err) {
>> +            log.error("sampleOccurred, failed to queue the sample", err);
>> +        }
>> +    }
>> +
>> +    private static final class Worker extends Thread {
>> +
>> +        private final BlockingQueue<SampleResult> queue;
>> +        private final BackendListenerContext context;
>> +        private final BackendListenerClient backendListenerClient;
>> +        private Worker(Class<?> javaClass, BackendListenerClient
>> backendListenerClient, Arguments arguments, BlockingQueue<SampleResult> q){
>>
> Same naming argument as above. clientclass instead of javaClass?
>
>> +            queue = q;
>> +            // Allow BackendListenerClient implementations to get access
>> to test element name
>> +            arguments.addArgument(TestElement.NAME, getName());
>> +            context = new BackendListenerContext(arguments);
>> +            this.backendListenerClient = backendListenerClient;
>> +        }
>> +
>> +
>> +        @Override
>> +        public void run() {
>> +            boolean isDebugEnabled = log.isDebugEnabled();
>> +            List<SampleResult> l = new ArrayList<SampleResult>(queue.
>> size());
>>
> samples instead of l?
>
>> +            try {
>> +                boolean eof = false;
>>
> endOfLoop?
>
>> +                while (!eof) {
>> +                    if(isDebugEnabled) {
>> +                        log.debug("Thread:"+Thread.currentThread().getName()+"
>> taking SampleResult from queue:"+queue.size());
>> +                    }
>> +                    SampleResult e = queue.take();
>>
> Could be named result, or sample instead of e
>
>> +                    if(isDebugEnabled) {
>> +                        log.debug("Thread:"+Thread.currentThread().getName()+"
>> took SampleResult:"+e+", isFinal:" + (e==FINAL_EVENT));
>> +                    }
>> +                    while (!(eof = (e == FINAL_EVENT)) && e != null ) {
>> // try to process as many as possible
>> +                        l.add(e);
>> +                        if(isDebugEnabled) {
>> +                            log.debug("Thread:"+Thread.currentThread().getName()+"
>> polling from queue:"+queue.size());
>> +                        }
>> +                        e = queue.poll(); // returns null if nothing on
>> queue currently
>> +                        if(isDebugEnabled) {
>> +                            log.debug("Thread:"+Thread.currentThread().getName()+"
>> took from queue:"+e+", isFinal:" + (e==FINAL_EVENT));
>> +                        }
>> +                    }
>> +                    if(isDebugEnabled) {
>> +                        log.debug("Thread:"+Thread.
>> currentThread().getName()+
>> +                                " exiting with FINAL EVENT:"+(e ==
>> FINAL_EVENT)
>> +                                +", null:" + (e==null));
>> +                    }
>> +                    int size = l.size();
>>
> No need for a temporary variable.
>
>> +                    if (size > 0) {
>> +                        backendListenerClient.handleSampleResults(l,
>> context);
>> +                        l.clear();
>> +                    }
>> +                    if(!eof) {
>> +                        LockSupport.parkNanos(100);
>> +                    }
>> +                }
>> +            } catch (InterruptedException e) {
>> +                // NOOP
>> +            }
>> +            // We may have been interrupted
>> +            int size = l.size();
>> +            if (size > 0) {
>> +                backendListenerClient.handleSampleResults(l, context);
>> +                l.clear();
>> +            }
>>
> Same code as a few lines above, could be factored out into a method
> handleSamples(l, context)
>
>> +            log.info("Worker ended");
>> +        }
>> +    }
>> +
>> +
>> +    /**
>> +     * Returns reference to <code>BackendListenerClient</code>.
>>
> Could use a {@link...}
>
>> +     *
>> +     *
>> +     * @return BackendListenerClient reference.
>> +     */
>> +    static BackendListenerClient createBackendListenerClientImpl(Class<?>
>> javaClass) {
>> +        if (javaClass == null) { // failed to initialise the class
>> +            return new ErrorBackendListenerClient();
>> +        }
>> +        BackendListenerClient client;
>> +        try {
>> +            client = (BackendListenerClient) javaClass.newInstance();
>> +        } catch (Exception e) {
>> +            log.error("Exception creating: " + javaClass, e);
>> +            client = new ErrorBackendListenerClient();
>> +        }
>> +        return client;
>>
> I would return newInstance() in try Block and return new Error.. in catch
> Block. javaClass -> clientClass
>
>> +    }
>> +
>> +    /**
>> +     * Method called at the end of the test. This is called only on one
>> instance
>> +     * of BackendListener. This method will loop through all of the other
>> +     * BackendListenerClients which have been registered (automatically
>> in the
>> +     * constructor) and notify them that the test has ended, allowing the
>> +     * BackendListenerClients to cleanup.
>> +     */
>> +    @Override
>> +    public void testEnded() {
>> +        try {
>> +            queue.put(FINAL_EVENT);
>> +        } catch (Exception ex) {
>> +            log.warn("testEnded() with exception:"+ex.getMessage(), ex);
>> +        }
>> +        if (queueWaits > 0) {
>> +            log.warn("QueueWaits: "+queueWaits+"; QueueWaitTime:
>> "+queueWaitTime+" (nanoseconds), you may need to increase queue capacity,
>> see property 'backend_queue_capacity'");
>> +        }
>> +        synchronized (TEAR_DOWN_SET) {
>> +            for (BackendListener backendListener : TEAR_DOWN_SET) {
>> +                BackendListenerClient client = backendListener.
>> backendListenerClient;
>> +                if (client != null) {
>> +                    try {
>> +                        client.teardownTest(backendListener.context);
>> +                    } catch (Exception e) {
>> +                        throw new java.lang.IllegalStateException("Failed
>> calling teardownTest", e);
>>
> If we throw an exception here, we will not try every client.
>
>> +                    }
>> +                }
>> +            }
>> +            TEAR_DOWN_SET.clear();
>> +        }
>> +    }
>> +
>> +    /* Implements TestStateListener.testEnded(String) */
>> +    @Override
>> +    public void testEnded(String host) {
>> +        testEnded();
>> +    }
>> +
>> +    /**
>> +     * A {@link BackendListenerClient} implementation used for error
>> handling. If an
>> +     * error occurs while creating the real BackendListenerClient
>> object, it is
>> +     * replaced with an instance of this class. Each time a sample
>> occurs with
>> +     * this class, the result is marked as a failure so the user can see
>> that
>> +     * the test failed.
>> +     */
>> +    static class ErrorBackendListenerClient extends
>> AbstractBackendListenerClient {
>> +        /**
>> +         * Return SampleResult with data on error.
>> +         *
>> +         * @see BackendListenerClient#runTest(JavaSamplerContext)
>> +         */
>> +        @Override
>> +        public void handleSampleResults(List<SampleResult>
>> sampleResults, BackendListenerContext context) {
>> +            log.warn("ErrorBackendListenerClient#handleSampleResult
>> called, noop");
>> +            Thread.yield();
>> +        }
>> +    }
>> +
>> +    /* (non-Javadoc)
>> +     * @see org.apache.jmeter.samplers.SampleListener#sampleStarted(
>> org.apache.jmeter.samplers.SampleEvent)
>> +     */
>> +    @Override
>> +    public void sampleStarted(SampleEvent e) {
>> +        // NOOP
>> +
>> +    }
>> +
>> +    /* (non-Javadoc)
>> +     * @see org.apache.jmeter.samplers.SampleListener#sampleStopped(
>> org.apache.jmeter.samplers.SampleEvent)
>> +     */
>> +    @Override
>> +    public void sampleStopped(SampleEvent e) {
>> +        // NOOP
>> +
>> +    }
>> +
>> +    /**
>> +     * Set the arguments (parameters) for the BackendListenerClient to
>> be executed
>> +     * with.
>> +     *
>> +     * @param args
>> +     *            the new arguments. These replace any existing
>> arguments.
>> +     */
>> +    public void setArguments(Arguments args) {
>> +        setProperty(new TestElementProperty(ARGUMENTS, args));
>> +    }
>> +
>> +    /**
>> +     * Get the arguments (parameters) for the BackendListenerClient to
>> be executed
>> +     * with.
>> +     *
>> +     * @return the arguments
>> +     */
>> +    public Arguments getArguments() {
>> +        return (Arguments) getProperty(ARGUMENTS).getObjectValue();
>> +    }
>> +
>> +    /**
>> +     * Sets the Classname of the BackendListenerClient object
>> +     *
>> +     * @param classname
>> +     *            the new Classname value
>> +     */
>> +    public void setClassname(String classname) {
>> +        setProperty(CLASSNAME, classname);
>> +    }
>> +
>> +    /**
>> +     * Gets the Classname of the BackendListenerClient object
>> +     *
>> +     * @return the Classname value
>> +     */
>> +    public String getClassname() {
>> +        return getPropertyAsString(CLASSNAME);
>> +    }
>> +
>> +    /**
>> +     * Sets the queue size
>> +     *
>> +     * @param queueSize
>> +     *
>> +     */
>> +    public void setQueueSize(int queueSize) {
>> +        setProperty(QUEUE_SIZE, queueSize, DEFAULT_QUEUE_SIZE);
>> +    }
>> +
>> +    /**
>> +     * Gets the queue size
>> +     *
>> +     * @return int queueSize
>> +     */
>> +    public int getQueueSize() {
>> +        return getPropertyAsInt(QUEUE_SIZE, DEFAULT_QUEUE_SIZE);
>> +    }
>> +}
>>
>> Propchange: jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>> backend/BackendListener.java
>> ------------------------------------------------------------
>> ------------------
>>      svn:mime-type = text/plain
>>
>> Added: jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>> backend/BackendListenerClient.java
>> URL: http://svn.apache.org/viewvc/jmeter/trunk/src/components/
>> org/apache/jmeter/visualizers/backend/BackendListenerClient.
>> java?rev=1641081&view=auto
>> ============================================================
>> ==================
>> --- jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>> backend/BackendListenerClient.java (added)
>> +++ jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>> backend/BackendListenerClient.java Sat Nov 22 15:36:37 2014
>> @@ -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.jmeter.visualizers.backend;
>> +
>> +import java.util.List;
>> +
>> +import org.apache.jmeter.config.Arguments;
>> +import org.apache.jmeter.samplers.SampleResult;
>> +
>> +/**
>> + * This interface defines the interactions between the BackendListener
>> and external
>> + * Java programs which can be executed by JMeter. Any Java class which
>> wants to
>> + * be executed as a JMeter test must implement this interface (either
>> directly
>> + * or indirectly through AbstractBackendListenerClient).
>> + * <p>
>> + * JMeter will create one instance of a BackendListenerClient
>> implementation for
>> + * each user/thread in the test. Additional instances may be created for
>> + * internal use by JMeter (for example, to find out what parameters are
>> + * supported by the client).
>> + * <p>
>> + * When the test is started, setupTest() will be called on each thread's
>> + * BackendListenerClient instance to initialize the client. Then
>> handleSampleResult() will be
>> + * called for each SampleResult notification. Finally, teardownTest()
>> will be called
>> + * to allow the client to do any necessary clean-up.
>> + * <p>
>> + * The JMeter BackendListener GUI allows a list of parameters to be
>> defined for the
>> + * test. These are passed to the various test methods through the
>> + * {@link BackendListenerContext}. A list of default parameters can be
>> defined
>> + * through the getDefaultParameters() method. These parameters and any
>> default
>> + * values associated with them will be shown in the GUI. Users can add
>> other
>> + * parameters as well.
>> + * <p>
>> + * When possible, Listeners should extend {@link
>> AbstractBackendListenerClient
>> + * AbstractBackendListenerClient} rather than implementing
>> BackendListenerClient
>> + * directly. This should protect your tests from future changes to the
>> + * interface. While it may be necessary to make changes to the
>> BackendListenerClient
>> + * interface from time to time (therefore requiring changes to any
>> + * implementations of this interface), we intend to make this abstract
>> class
>> + * provide reasonable default implementations of any new methods so that
>> + * subclasses do not necessarily need to be updated for new versions.
>> + * Implementing BackendListenerClient directly will continue to be
>> supported for
>> + * cases where extending this class is not possible (for example, when
>> the
>> + * client class is already a subclass of some other class).
>> + *
>> + * @since 2.13
>> + */
>> +public interface BackendListenerClient {
>> +    /**
>> +     * Do any initialization required by this client. It is generally
>> +     * recommended to do any initialization such as getting parameter
>> values in
>> +     * the setupTest method rather than the runTest method in order to
>> add as
>> +     * little overhead as possible to the test.
>> +     *
>> +     * @param context
>> +     *            the context to run with. This provides access to
>> +     *            initialization parameters.
>> +     */
>> +    void setupTest(BackendListenerContext context) throws Exception;
>> +
>> +    /**
>> +     * Perform a single sample for each iteration. This method returns a
>> +     * <code>SampleResult</code> object. <code>SampleResult</code> has
>> many
>> +     * fields which can be used. At a minimum, the test should use
>> +     * <code>SampleResult.sampleStart</code> and
>> +     * <code>SampleResult.sampleEnd</code>to set the time that the test
>>
> use {@link..} instead of <code>..?
>
>> +     * required to execute. It is also a good idea to set the
>> sampleLabel and
>> +     * the successful flag.
>> +     *
>> +     * @see org.apache.jmeter.samplers.SampleResult#sampleStart()
>> +     * @see org.apache.jmeter.samplers.SampleResult#sampleEnd()
>> +     * @see org.apache.jmeter.samplers.SampleResult#setSuccessful(
>> boolean)
>> +     * @see org.apache.jmeter.samplers.SampleResult#setSampleLabel(
>> String)
>> +     *
>> +     * @param context
>> +     *            the context to run with. This provides access to
>> +     *            initialization parameters.
>> +     *
>> +     */
>> +    void handleSampleResults(List<SampleResult> sampleResults,
>> BackendListenerContext context);
>> +
>> +    /**
>> +     * Do any clean-up required by this test at the end of a test run.
>> +     *
>> +     * @param context
>> +     *            the context to run with. This provides access to
>> +     *            initialization parameters.
>> +     */
>> +    void teardownTest(BackendListenerContext context) throws Exception;
>> +
>> +    /**
>> +     * Provide a list of parameters which this test supports. Any
>> parameter
>> +     * names and associated values returned by this method will appear
>> in the
>> +     * GUI by default so the user doesn't have to remember the exact
>> names. The
>> +     * user can add other parameters which are not listed here. If this
>> method
>> +     * returns null then no parameters will be listed. If the value for
>> some
>> +     * parameter is null then that parameter will be listed in the GUI
>> with an
>> +     * empty value.
>> +     *
>> +     * @return a specification of the parameters used by this test which
>> should
>> +     *         be listed in the GUI, or null if no parameters should be
>> listed.
>> +     */
>> +    Arguments getDefaultParameters();
>> +
>> +    /**
>> +     *
>> +     * @param context
>> +     * @param result
>> +     * @return
>> +     */
>> +    SampleResult createSampleResult(
>> +            BackendListenerContext context, SampleResult result);
>> +}
>>
>> Propchange: jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>> backend/BackendListenerClient.java
>> ------------------------------------------------------------
>> ------------------
>>      svn:mime-type = text/plain
>>
>> Added: jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/
>> BackendListenerContext.java
>> URL: http://svn.apache.org/viewvc/jmeter/trunk/src/components/
>> org/apache/jmeter/visualizers/backend/BackendListenerContext.java?
>> rev=1641081&view=auto
>> ============================================================
>> ==================
>> --- jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/BackendListenerContext.java
>> (added)
>> +++ jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/BackendListenerContext.java
>> Sat Nov 22 15:36:37 2014
>> @@ -0,0 +1,237 @@
>> +/*
>> +
>> + * 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.jmeter.visualizers.backend;
>> +
>> +import java.util.Iterator;
>> +import java.util.Map;
>> +
>> +import org.apache.jmeter.config.Arguments;
>> +import org.apache.jorphan.logging.LoggingManager;
>> +import org.apache.log.Logger;
>> +
>> +/**
>> + * BackendListenerContext is used to provide context information to a
>> + * BackendListenerClient implementation. This currently consists of the
>> + * initialization parameters which were specified in the GUI.
>> + * @since 2.13
>> + */
>> +public class BackendListenerContext {
>> +    /*
>> +     * Implementation notes:
>> +     *
>> +     * All of the methods in this class are currently read-only. If
>> update
>> +     * methods are included in the future, they should be defined so
>> that a
>> +     * single instance of BackendListenerContext can be associated with
>> each thread.
>> +     * Therefore, no synchronization should be needed. The same instance
>> should
>> +     * be used for the call to setupTest, all calls to runTest, and the
>> call to
>> +     * teardownTest.
>> +     */
>> +
>> +    /** Logging */
>> +    private static final Logger log = LoggingManager.
>> getLoggerForClass();
>>
> See naming comments for logger above
>
>> +
>> +    /**
>> +     * Map containing the initialization parameters for the
>> BackendListenerClient.
>> +     */
>> +    private final Map<String, String> params;
>> +
>> +    /**
>> +     *
>> +     * @param args
>> +     *            the initialization parameters.
>> +     */
>> +    public BackendListenerContext(Arguments args) {
>> +        this.params = args.getArgumentsAsMap();
>> +    }
>> +
>> +    /**
>> +     * Determine whether or not a value has been specified for the
>> parameter
>> +     * with this name.
>> +     *
>> +     * @param name
>> +     *            the name of the parameter to test
>> +     * @return true if the parameter value has been specified, false
>> otherwise.
>> +     */
>> +    public boolean containsParameter(String name) {
>>
> hasParameter instead of containsParameter?
>
>> +        return params.containsKey(name);
>> +    }
>> +
>> +    /**
>> +     * Get an iterator of the parameter names. Each entry in the
>> Iterator is a
>> +     * String.
>> +     *
>> +     * @return an Iterator of Strings listing the names of the
>> parameters which
>> +     *         have been specified for this test.
>> +     */
>> +    public Iterator<String> getParameterNamesIterator() {
>> +        return params.keySet().iterator();
>> +    }
>> +
>> +    /**
>> +     * Get the value of a specific parameter as a String, or null if the
>> value
>> +     * was not specified.
>> +     *
>> +     * @param name
>> +     *            the name of the parameter whose value should be
>> retrieved
>> +     * @return the value of the parameter, or null if the value was not
>> +     *         specified
>> +     */
>> +    public String getParameter(String name) {
>> +        return getParameter(name, null);
>> +    }
>> +
>> +    /**
>> +     * Get the value of a specified parameter as a String, or return the
>> +     * specified default value if the value was not specified.
>> +     *
>> +     * @param name
>> +     *            the name of the parameter whose value should be
>> retrieved
>> +     * @param defaultValue
>> +     *            the default value to return if the value of this
>> parameter was
>> +     *            not specified
>> +     * @return the value of the parameter, or the default value if the
>> parameter
>> +     *         was not specified
>> +     */
>> +    public String getParameter(String name, String defaultValue) {
>> +        if (params == null || !params.containsKey(name)) {
>> +            return defaultValue;
>> +        }
>> +        return params.get(name);
>> +    }
>> +
>> +    /**
>> +     * Get the value of a specified parameter as an integer. An
>> exception will
>> +     * be thrown if the parameter is not specified or if it is not an
>> integer.
>> +     * The value may be specified in decimal, hexadecimal, or octal, as
>> defined
>> +     * by Integer.decode().
>> +     *
>> +     * @param name
>> +     *            the name of the parameter whose value should be
>> retrieved
>> +     * @return the value of the parameter
>> +     *
>> +     * @throws NumberFormatException
>> +     *             if the parameter is not specified or is not an integer
>> +     *
>> +     * @see java.lang.Integer#decode(java.lang.String)
>> +     */
>> +    public int getIntParameter(String name) throws NumberFormatException
>> {
>> +        if (params == null || !params.containsKey(name)) {
>> +            throw new NumberFormatException("No value for parameter
>> named '" + name + "'.");
>>
> I would expect an IllegalArgumentException, if no parameter of that name
> is found
>
>> +        }
>> +
>> +        return Integer.decode(params.get(name)).intValue();
>> +    }
>> +
>> +    /**
>> +     * Get the value of a specified parameter as an integer, or return
>> the
>> +     * specified default value if the value was not specified or is not
>> an
>> +     * integer. A warning will be logged if the value is not an integer.
>> The
>> +     * value may be specified in decimal, hexadecimal, or octal, as
>> defined by
>> +     * Integer.decode().
>> +     *
>> +     * @param name
>> +     *            the name of the parameter whose value should be
>> retrieved
>> +     * @param defaultValue
>> +     *            the default value to return if the value of this
>> parameter was
>> +     *            not specified
>> +     * @return the value of the parameter, or the default value if the
>> parameter
>> +     *         was not specified
>> +     *
>> +     * @see java.lang.Integer#decode(java.lang.String)
>> +     */
>> +    public int getIntParameter(String name, int defaultValue) {
>> +        if (params == null || !params.containsKey(name)) {
>> +            return defaultValue;
>> +        }
>> +
>> +        try {
>> +            return Integer.decode(params.get(name)).intValue();
>> +        } catch (NumberFormatException e) {
>> +            log.warn("Value for parameter '" + name + "' not an integer:
>> '" + params.get(name) + "'.  Using default: '"
>> +                    + defaultValue + "'.", e);
>> +            return defaultValue;
>> +        }
>> +    }
>> +
>> +    /**
>> +     * Get the value of a specified parameter as a long. An exception
>> will be
>> +     * thrown if the parameter is not specified or if it is not a long.
>> The
>> +     * value may be specified in decimal, hexadecimal, or octal, as
>> defined by
>> +     * Long.decode().
>> +     *
>> +     * @param name
>> +     *            the name of the parameter whose value should be
>> retrieved
>> +     * @return the value of the parameter
>> +     *
>> +     * @throws NumberFormatException
>> +     *             if the parameter is not specified or is not a long
>> +     *
>> +     * @see Long#decode(String)
>> +     */
>> +    public long getLongParameter(String name) throws
>> NumberFormatException {
>> +        if (params == null || !params.containsKey(name)) {
>> +            throw new NumberFormatException("No value for parameter
>> named '" + name + "'.");
>> +        }
>> +
>> +        return Long.decode(params.get(name)).longValue();
>> +    }
>> +
>> +    /**
>> +     * Get the value of a specified parameter as along, or return the
>> specified
>> +     * default value if the value was not specified or is not a long. A
>> warning
>> +     * will be logged if the value is not a long. The value may be
>> specified in
>> +     * decimal, hexadecimal, or octal, as defined by Long.decode().
>> +     *
>> +     * @param name
>> +     *            the name of the parameter whose value should be
>> retrieved
>> +     * @param defaultValue
>> +     *            the default value to return if the value of this
>> parameter was
>> +     *            not specified
>> +     * @return the value of the parameter, or the default value if the
>> parameter
>> +     *         was not specified
>> +     *
>> +     * @see Long#decode(String)
>> +     */
>> +    public long getLongParameter(String name, long defaultValue) {
>> +        if (params == null || !params.containsKey(name)) {
>> +            return defaultValue;
>> +        }
>> +        try {
>> +            return Long.decode(params.get(name)).longValue();
>> +        } catch (NumberFormatException e) {
>> +            log.warn("Value for parameter '" + name + "' not a long: '"
>> + params.get(name) + "'.  Using default: '"
>> +                    + defaultValue + "'.", e);
>> +            return defaultValue;
>> +        }
>> +    }
>> +
>> +    /**
>> +     *
>> +     * @param name
>> +     * @param defaultValue
>> +     * @return
>>
> No javadoc? Again three warnings more :)
>
>> +     */
>> +    public boolean getBooleanParameter(String name, boolean
>> defaultValue) {
>> +        if (params == null || !params.containsKey(name)) {
>> +            return defaultValue;
>> +        }
>> +        return Boolean.valueOf(params.get(name));
>> +    }
>> +}
>>
>> Propchange: jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>> backend/BackendListenerContext.java
>> ------------------------------------------------------------
>> ------------------
>>      svn:mime-type = text/plain
>>
>> Added: jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>> backend/BackendListenerGui.java
>> URL: http://svn.apache.org/viewvc/jmeter/trunk/src/components/
>> org/apache/jmeter/visualizers/backend/BackendListenerGui.
>> java?rev=1641081&view=auto
>> ============================================================
>> ==================
>> --- jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>> backend/BackendListenerGui.java (added)
>> +++ jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>> backend/BackendListenerGui.java Sat Nov 22 15:36:37 2014
>> @@ -0,0 +1,282 @@
>> +/*
>> + * 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.jmeter.visualizers.backend;
>> +
>> +import java.awt.BorderLayout;
>> +import java.awt.event.ActionEvent;
>> +import java.awt.event.ActionListener;
>> +import java.util.ArrayList;
>> +import java.util.HashSet;
>> +import java.util.List;
>> +import java.util.Map;
>> +import java.util.Set;
>> +
>> +import javax.swing.ComboBoxModel;
>> +import javax.swing.JComboBox;
>> +import javax.swing.JLabel;
>> +import javax.swing.JPanel;
>> +import javax.swing.JTextField;
>> +
>> +import org.apache.jmeter.config.Argument;
>> +import org.apache.jmeter.config.Arguments;
>> +import org.apache.jmeter.config.gui.ArgumentsPanel;
>> +import org.apache.jmeter.gui.util.HorizontalPanel;
>> +import org.apache.jmeter.testelement.TestElement;
>> +import org.apache.jmeter.testelement.property.PropertyIterator;
>> +import org.apache.jmeter.util.JMeterUtils;
>> +import org.apache.jmeter.visualizers.gui.AbstractListenerGui;
>> +import org.apache.jorphan.logging.LoggingManager;
>> +import org.apache.jorphan.reflect.ClassFinder;
>> +import org.apache.log.Logger;
>> +
>> +/**
>> + * The <code>BackendListenerGui</code> class provides the user
>> interface for the
>> + * {@link BackendListener} object.
>> + * @since 2.13
>> + */
>> +public class BackendListenerGui extends AbstractListenerGui implements
>> ActionListener {
>> +
>> +    /**
>> +     *
>> +     */
>> +    private static final long serialVersionUID = 4331668988576438604L;
>> +
>> +    /** Logging */
>> +    private static final Logger log = LoggingManager.
>> getLoggerForClass();
>> +
>> +    /** A combo box allowing the user to choose a backend class. */
>> +    private JComboBox classnameCombo;
>> +
>> +    /**
>> +     * A field allowing the user to specify the size of Queue
>> +     */
>> +    private JTextField queueSize;
>> +
>> +    /** A panel allowing the user to set arguments for this test. */
>> +    private ArgumentsPanel argsPanel;
>> +
>> +    /**
>> +     * Create a new BackendListenerGui as a standalone component.
>> +     */
>> +    public BackendListenerGui() {
>> +        super();
>> +        init();
>> +    }
>> +
>> +
>> +    /** {@inheritDoc} */
>> +    @Override
>> +    public String getLabelResource() {
>> +        return "backend_listener"; // $NON-NLS-1$
>> +    }
>> +
>> +    /**
>> +     * Initialize the GUI components and layout.
>> +     */
>> +    private void init() {// called from ctor, so must not be overridable
>> +        setLayout(new BorderLayout(0, 5));
>> +
>> +        setBorder(makeBorder());
>> +        add(makeTitlePanel(), BorderLayout.NORTH);
>> +
>> +        JPanel classnameRequestPanel = new JPanel(new BorderLayout(0,
>> 5));
>> +        classnameRequestPanel.add(createClassnamePanel(),
>> BorderLayout.NORTH);
>> +        classnameRequestPanel.add(createParameterPanel(),
>> BorderLayout.CENTER);
>> +
>> +        add(classnameRequestPanel, BorderLayout.CENTER);
>> +    }
>> +
>> +    /**
>> +     * Create a panel with GUI components allowing the user to select a
>> test
>> +     * class.
>> +     *
>> +     * @return a panel containing the relevant components
>> +     */
>> +    private JPanel createClassnamePanel() {
>> +        List<String> possibleClasses = new ArrayList<String>();
>> +
>> +        try {
>> +            // Find all the classes which implement the
>> BackendListenerClient
>> +            // interface.
>> +            possibleClasses = ClassFinder.findClassesThatExtend(
>> JMeterUtils.getSearchPaths(),
>> +                    new Class[] { BackendListenerClient.class });
>> +
>> +            // Remove the BackendListener class from the list since it
>> only
>>
> ErrorBackendListener
>
>> +            // implements the interface for error conditions.
>> +
>> +            possibleClasses.remove(BackendListener.class.getName() +
>> "$ErrorBackendListenerClient");
>> +        } catch (Exception e) {
>> +            log.debug("Exception getting interfaces.", e);
>> +        }
>> +
>> +        JLabel label = new JLabel(JMeterUtils.getResString("backend_listener_classname"));
>> // $NON-NLS-1$
>> +
>> +        classnameCombo = new JComboBox(possibleClasses.toArray());
>> +        classnameCombo.addActionListener(this);
>> +        classnameCombo.setEditable(false);
>> +        label.setLabelFor(classnameCombo);
>> +
>> +        HorizontalPanel classNamePanel = new HorizontalPanel();
>> +        classNamePanel.add(label);
>> +        classNamePanel.add(classnameCombo);
>> +
>> +        queueSize = new JTextField("", 5);
>> +        queueSize.setName("Queue Size"); //$NON-NLS-1$
>> +        JLabel queueSizeLabel = new JLabel(JMeterUtils.
>> getResString("backend_listener_queue_size")); // $NON-NLS-1$
>> +        queueSizeLabel.setLabelFor(queueSize);
>> +        HorizontalPanel queueSizePanel = new HorizontalPanel();
>> +        queueSizePanel.add(queueSizeLabel, BorderLayout.WEST);
>> +        queueSizePanel.add(queueSize);
>> +
>> +        JPanel panel = new JPanel(new BorderLayout(0, 5));
>> +        panel.add(classNamePanel, BorderLayout.NORTH);
>> +        panel.add(queueSizePanel, BorderLayout.CENTER);
>> +        return panel;
>> +    }
>> +
>> +    /**
>> +     * Handle action events for this component. This method currently
>> handles
>> +     * events for the classname combo box.
>> +     *
>> +     * @param evt
>>
> I would spend the few extra characters to make it event instead of evt
>
>> +     *            the ActionEvent to be handled
>> +     */
>> +    @Override
>> +    public void actionPerformed(ActionEvent evt) {
>> +        if (evt.getSource() == classnameCombo) {
>> +            String className = ((String) classnameCombo.
>> getSelectedItem()).trim();
>> +            try {
>> +                BackendListenerClient client = (BackendListenerClient)
>> Class.forName(className, true,
>> +                        Thread.currentThread().getContextClassLoader()).
>> newInstance();
>> +
>> +                Arguments currArgs = new Arguments();
>> +                argsPanel.modifyTestElement(currArgs);
>> +                Map<String, String> currArgsMap =
>> currArgs.getArgumentsAsMap();
>> +
>> +                Arguments newArgs = new Arguments();
>> +                Arguments testParams = null;
>> +                try {
>> +                    testParams = client.getDefaultParameters();
>> +                } catch (AbstractMethodError e) {
>> +                    log.warn("BackendListenerClient doesn't implement "
>> +                            + "getDefaultParameters.  Default parameters
>> won't "
>> +                            + "be shown.  Please update your client
>> class: " + className);
>> +                }
>> +
>> +                if (testParams != null) {
>> +                    PropertyIterator i = testParams.getArguments().
>> iterator();
>>
> I would try a for loop instead of explicitly using an iterator
>
>> +                    while (i.hasNext()) {
>> +                        Argument arg = (Argument)
>> i.next().getObjectValue();
>> +                        String name = arg.getName();
>> +                        String value = arg.getValue();
>> +
>> +                        // If a user has set parameters in one test, and
>> then
>> +                        // selects a different test which supports the
>> same
>> +                        // parameters, those parameters should have the
>> same
>> +                        // values that they did in the original test.
>> +                        if (currArgsMap.containsKey(name)) {
>> +                            String newVal = currArgsMap.get(name);
>> +                            if (newVal != null && newVal.length() > 0) {
>> +                                value = newVal;
>> +                            }
>> +                        }
>> +                        newArgs.addArgument(name, value);
>> +                    }
>> +                }
>> +
>> +                argsPanel.configure(newArgs);
>> +            } catch (Exception e) {
>> +                log.error("Error getting argument list for " +
>> className, e);
>> +            }
>> +        }
>> +    }
>> +
>> +    /**
>> +     * Create a panel containing components allowing the user to provide
>> +     * arguments to be passed to the test class instance.
>> +     *
>> +     * @return a panel containing the relevant components
>> +     */
>> +    private JPanel createParameterPanel() {
>> +        argsPanel = new ArgumentsPanel(JMeterUtils.
>> getResString("backend_listener_paramtable")); // $NON-NLS-1$
>> +        return argsPanel;
>> +    }
>> +
>> +    /** {@inheritDoc} */
>> +    @Override
>> +    public void configure(TestElement config) {
>> +        super.configure(config);
>> +
>> +        argsPanel.configure((Arguments) config.getProperty(
>> BackendListener.ARGUMENTS).getObjectValue());
>> +
>> +        String className = config.getPropertyAsString(
>> BackendListener.CLASSNAME);
>> +        if(checkContainsClassName(classnameCombo.getModel(),
>> className)) {
>> +            classnameCombo.setSelectedItem(className);
>> +        } else {
>> +            log.error("Error setting class:'"+className+"' in
>> BackendListener: "+getName()+
>> +                    ", check for a missing jar in your jmeter
>> 'search_paths' and 'plugin_dependency_paths' properties");
>> +        }
>> +        queueSize.setText(Integer.toString(((BackendListener)
>> config).getQueueSize()));
>> +    }
>> +
>> +    /**
>> +     * Check combo contains className
>> +     * @param model ComboBoxModel
>> +     * @param className String class name
>> +     * @return boolean
>>
> explain "boolean" or the other params a bit more?
>
>> +     */
>> +    private static final boolean checkContainsClassName(ComboBoxModel
>> model, String className) {
>> +        int size = model.getSize();
>> +        Set<String> set = new HashSet<String>(size);
>> +        for (int i = 0; i < size; i++) {
>> +            set.add((String)model.getElementAt(i));
>> +        }
>> +        return set.contains(className);
>> +    }
>> +
>> +    /** {@inheritDoc} */
>> +    @Override
>> +    public TestElement createTestElement() {
>> +        BackendListener config = new BackendListener();
>> +        modifyTestElement(config);
>> +        return config;
>> +    }
>> +
>> +    /** {@inheritDoc} */
>> +    @Override
>> +    public void modifyTestElement(TestElement config) {
>> +        configureTestElement(config);
>> +        BackendListener backendListener = (BackendListener) config;
>> +        backendListener.setArguments((Arguments)
>> argsPanel.createTestElement());
>> +        backendListener.setClassname(String.valueOf(classnameCombo.
>> getSelectedItem()));
>> +        backendListener.setQueueSize(Integer.parseInt(queueSize.
>> getText()));
>> +
>> +    }
>> +
>> +    /* (non-Javadoc)
>> +     * @see org.apache.jmeter.gui.AbstractJMeterGuiComponent#clearGui()
>> +     */
>> +    @Override
>> +    public void clearGui() {
>> +        super.clearGui();
>> +        argsPanel.clearGui();
>> +        classnameCombo.setSelectedIndex(0);
>> +        queueSize.setText("");
>> +    }
>> +}
>>
>> Propchange: jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>> backend/BackendListenerGui.java
>> ------------------------------------------------------------
>> ------------------
>>      svn:mime-type = text/plain
>>
>> Added: jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>> backend/SamplerMetric.java
>> URL: http://svn.apache.org/viewvc/jmeter/trunk/src/components/
>> org/apache/jmeter/visualizers/backend/SamplerMetric.java?
>> rev=1641081&view=auto
>> ============================================================
>> ==================
>> --- jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/SamplerMetric.java
>> (added)
>> +++ jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/SamplerMetric.java
>> Sat Nov 22 15:36:37 2014
>> @@ -0,0 +1,138 @@
>> +/*
>> + * 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.jmeter.visualizers.backend;
>> +
>> +import org.apache.commons.math3.stat.descriptive.DescriptiveStatistics;
>> +import org.apache.jmeter.samplers.SampleResult;
>> +
>> +/**
>> + * Sampler metric
>> + * @since 2.13
>> + */
>> +public class SamplerMetric {
>> +    // Limit to sliding window of 100 values
>> +    private DescriptiveStatistics stats = new DescriptiveStatistics(100);
>> +    private int success;
>
>


-- 
Cordialement.
Philippe Mouawad.

Re: svn commit: r1641081 - in /jmeter/trunk: ./ bin/ res/maven/ src/components/org/apache/jmeter/visualizers/backend/ src/core/org/apache/jmeter/resources/ src/core/org/apache/jmeter/samplers/ src/core/org/apache/jmeter/save/ xdocs/ xdocs/usermanual/

Posted by Felix Schumacher <fe...@internetallee.de>.
Hello Philippe,

I have hidden a few comments inside the cited code.
They are mostly around javadoc and naming things.

Am 22.11.2014 um 16:36 schrieb pmouawad@apache.org:
> Author: pmouawad
> Date: Sat Nov 22 15:36:37 2014
> New Revision: 1641081
>
> URL: http://svn.apache.org/r1641081
> Log:
> Bug 55932 - Create a Async BackendListener to allow easy plug of new listener (Graphite, JDBC, Console,...)
> Bugzilla Id: 55932
>
> Added:
>      jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/
>      jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/AbstractBackendListenerClient.java   (with props)
>      jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/BackendListener.java   (with props)
>      jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/BackendListenerClient.java   (with props)
>      jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/BackendListenerContext.java   (with props)
>      jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/BackendListenerGui.java   (with props)
>      jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/SamplerMetric.java   (with props)
> Modified:
>      jmeter/trunk/bin/saveservice.properties
>      jmeter/trunk/build.properties
>      jmeter/trunk/build.xml
>      jmeter/trunk/eclipse.classpath
>      jmeter/trunk/res/maven/ApacheJMeter_parent.pom
>      jmeter/trunk/src/core/org/apache/jmeter/resources/messages.properties
>      jmeter/trunk/src/core/org/apache/jmeter/resources/messages_fr.properties
>      jmeter/trunk/src/core/org/apache/jmeter/samplers/SampleResult.java
>      jmeter/trunk/src/core/org/apache/jmeter/save/SaveService.java
>      jmeter/trunk/xdocs/changes.xml
>      jmeter/trunk/xdocs/usermanual/component_reference.xml
>
> Modified: jmeter/trunk/bin/saveservice.properties
> URL: http://svn.apache.org/viewvc/jmeter/trunk/bin/saveservice.properties?rev=1641081&r1=1641080&r2=1641081&view=diff
> ==============================================================================
> --- jmeter/trunk/bin/saveservice.properties (original)
> +++ jmeter/trunk/bin/saveservice.properties Sat Nov 22 15:36:37 2014
> @@ -53,7 +53,8 @@ _file_version=$Revision$
>   # 2.5 = 2.10
>   # 2.6 = 2.11
>   # 2.7 = 2.12
> -_version=2.7
> +# 2.8 = 2.13
> +_version=2.8
>   #
>   #
>   # Character set encoding used to read and write JMeter XML files and CSV results
> @@ -78,6 +79,8 @@ AssertionVisualizer=org.apache.jmeter.vi
>   AuthManager=org.apache.jmeter.protocol.http.control.AuthManager
>   Authorization=org.apache.jmeter.protocol.http.control.Authorization
>   AuthPanel=org.apache.jmeter.protocol.http.gui.AuthPanel
> +BackendListener=org.apache.jmeter.visualizers.backend.BackendListener
> +BackendListenerGui=org.apache.jmeter.visualizers.backend.BackendListenerGui
>   BarChart=org.apache.jmeter.testelement.BarChart
>   BarChartGui=org.apache.jmeter.report.gui.BarChartGui
>   BeanShellAssertion=org.apache.jmeter.assertions.BeanShellAssertion
>
> Modified: jmeter/trunk/build.properties
> URL: http://svn.apache.org/viewvc/jmeter/trunk/build.properties?rev=1641081&r1=1641080&r2=1641081&view=diff
> ==============================================================================
> --- jmeter/trunk/build.properties (original)
> +++ jmeter/trunk/build.properties Sat Nov 22 15:36:37 2014
> @@ -118,11 +118,21 @@ commons-logging.loc         = ${maven2.r
>   #commons-logging.md5         = E2C390FE739B2550A218262B28F290CE
>   commons-logging.md5         = 040b4b4d8eac886f6b4a2a3bd2f31b00
>   
> +commons-math3.version         = 3.3
> +commons-math3.jar             = commons-math3-${commons-math3.version}.jar
> +commons-math3.loc             = ${maven2.repo}/org/apache/commons/commons-math3/${commons-math3.version}
> +commons-math3.md5             = 87346cf2772dc2becf106c45e0f63863
> +
>   commons-net.version         = 3.3
>   commons-net.jar             = commons-net-${commons-net.version}.jar
>   commons-net.loc             = ${maven2.repo}/commons-net/commons-net/${commons-net.version}
>   commons-net.md5             = c077ca61598e9c21f43f8b6488fbbee9
>   
> +commons-pool2.version         = 2.2
> +commons-pool2.jar             = commons-pool2-${commons-pool2.version}.jar
> +commons-pool2.loc             = ${maven2.repo}/org/apache/commons/commons-pool2/${commons-pool2.version}
> +commons-pool2.md5             = 51b56c92883812c56fbeb339866ce2df
> +
>   # dnsjava for DNSCacheManager
>   dnsjava.version             = 2.1.6
>   dnsjava.jar                 = dnsjava-${dnsjava.version}.jar
>
> Modified: jmeter/trunk/build.xml
> URL: http://svn.apache.org/viewvc/jmeter/trunk/build.xml?rev=1641081&r1=1641080&r2=1641081&view=diff
> ==============================================================================
> --- jmeter/trunk/build.xml (original)
> +++ jmeter/trunk/build.xml Sat Nov 22 15:36:37 2014
> @@ -365,7 +365,9 @@
>       <include name="${lib.dir}/${commons-jexl2.jar}"/>
>       <include name="${lib.dir}/${commons-lang3.jar}"/>
>       <include name="${lib.dir}/${commons-logging.jar}"/>
> +    <include name="${lib.dir}/${commons-math3}"/>
>       <include name="${lib.dir}/${commons-net.jar}"/>
> +    <include name="${lib.dir}/${commons-pool2.jar}"/>
>       <include name="${lib.dir}/${dnsjava.jar}"/>
>       <include name="${lib.dir}/${excalibur-datasource.jar}"/>
>       <include name="${lib.dir}/${excalibur-instrument.jar}"/>
> @@ -438,8 +440,10 @@
>       <pathelement location="${lib.dir}/${commons-jexl2.jar}"/>
>       <pathelement location="${lib.dir}/${commons-lang3.jar}"/>
>       <pathelement location="${lib.dir}/${commons-logging.jar}"/>
> +    <pathelement location="${lib.dir}/${commons-math3.jar}"/>
>       <pathelement location="${lib.dir}/${commons-net.jar}"/>
> -    <pathelement location="${lib.dir}/${dnsjava.jar}"/>
> +  	<pathelement location="${lib.dir}/${commons-pool2.jar}"/>
> +  	<pathelement location="${lib.dir}/${dnsjava.jar}"/>
>       <pathelement location="${lib.dir}/${excalibur-datasource.jar}"/>
>       <pathelement location="${lib.dir}/${excalibur-instrument.jar}"/>
>       <pathelement location="${lib.dir}/${excalibur-logger.jar}"/>
> @@ -2909,7 +2913,9 @@ run JMeter unless all the JMeter jars ar
>           <process_jarfile jarname="commons-jexl2"/>
>           <process_jarfile jarname="commons-lang3"/>
>           <process_jarfile jarname="commons-logging"/>
> +        <process_jarfile jarname="commons-math3"/>
>           <process_jarfile jarname="commons-net"/>
> +    	<process_jarfile jarname="commons-pool2"/>
>           <process_jarfile jarname="dnsjava"/>
>           <process_jarfile jarname="excalibur-datasource"/>
>           <process_jarfile jarname="excalibur-instrument"/>
>
> Modified: jmeter/trunk/eclipse.classpath
> URL: http://svn.apache.org/viewvc/jmeter/trunk/eclipse.classpath?rev=1641081&r1=1641080&r2=1641081&view=diff
> ==============================================================================
> --- jmeter/trunk/eclipse.classpath (original)
> +++ jmeter/trunk/eclipse.classpath Sat Nov 22 15:36:37 2014
> @@ -55,7 +55,9 @@
>   	<classpathentry kind="lib" path="lib/commons-jexl-2.1.1.jar"/>
>   	<classpathentry kind="lib" path="lib/commons-lang3-3.3.2.jar"/>
>   	<classpathentry kind="lib" path="lib/commons-logging-1.2.jar"/>
> +    <classpathentry kind="lib" path="lib/commons-math3-3.3.jar"/>
>   	<classpathentry kind="lib" path="lib/commons-net-3.3.jar"/>
> +    <classpathentry kind="lib" path="lib/commons-pool2-2.2.jar"/>
>   	<classpathentry kind="lib" path="lib/dnsjava-2.1.6.jar"/>
>   	<classpathentry kind="lib" path="lib/excalibur-datasource-2.1.jar"/>
>   	<classpathentry kind="lib" path="lib/excalibur-instrument-1.0.jar"/>
>
> Modified: jmeter/trunk/res/maven/ApacheJMeter_parent.pom
> URL: http://svn.apache.org/viewvc/jmeter/trunk/res/maven/ApacheJMeter_parent.pom?rev=1641081&r1=1641080&r2=1641081&view=diff
> ==============================================================================
> --- jmeter/trunk/res/maven/ApacheJMeter_parent.pom (original)
> +++ jmeter/trunk/res/maven/ApacheJMeter_parent.pom Sat Nov 22 15:36:37 2014
> @@ -66,7 +66,9 @@ under the License.
>         <commons-jexl2.version>2.1.1</commons-jexl2.version>
>         <commons-lang3.version>3.3.2</commons-lang3.version>
>         <commons-logging.version>1.2</commons-logging.version>
> +      <commons-math3.version>3.3</commons-math3.version>
>         <commons-net.version>3.3</commons-net.version>
> +      <commons-pool2.version>2.2</commons-pool2.version>
>         <dnsjava.version>2.1.6</dnsjava.version>
>         <excalibur-datasource.version>2.1</excalibur-datasource.version>
>         <excalibur-instrument.version>1.0</excalibur-instrument.version>
> @@ -181,11 +183,21 @@ under the License.
>           <version>${commons-logging.version}</version>
>         </dependency>
>         <dependency>
> +        <groupId>commons-math3</groupId>
> +        <artifactId>commons-math3</artifactId>
> +        <version>${commons-math3.version}</version>
> +      </dependency>
> +      <dependency>
>           <groupId>commons-net</groupId>
>           <artifactId>commons-net</artifactId>
>           <version>${commons-net.version}</version>
>         </dependency>
>         <dependency>
> +        <groupId>commons-pool2</groupId>
> +        <artifactId>commons-pool2</artifactId>
> +        <version>${commons-pool2.version}</version>
> +      </dependency>
> +      <dependency>
>   	    <groupId>dnsjava</groupId>
>   	    <artifactId>dnsjava</artifactId>
>   	    <version>${dnsjava.version}</version>
>
> Added: jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/AbstractBackendListenerClient.java
> URL: http://svn.apache.org/viewvc/jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/AbstractBackendListenerClient.java?rev=1641081&view=auto
> ==============================================================================
> --- jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/AbstractBackendListenerClient.java (added)
> +++ jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/AbstractBackendListenerClient.java Sat Nov 22 15:36:37 2014
> @@ -0,0 +1,121 @@
> +/*
> + * 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.jmeter.visualizers.backend;
> +
> +import java.util.Map;
> +import java.util.concurrent.ConcurrentHashMap;
> +
> +import org.apache.jmeter.config.Arguments;
> +import org.apache.jmeter.samplers.SampleResult;
> +import org.apache.jorphan.logging.LoggingManager;
> +import org.apache.log.Logger;
> +
> +/**
> + * An abstract implementation of the BackendListenerClient interface. This
> + * implementation provides default implementations of most of the methods in the
> + * interface, as well as some convenience methods, in order to simplify
> + * development of BackendListenerClient implementations.
> + *
> + * While it may be necessary to make changes to the BackendListenerClient interface
> + * from time to time (therefore requiring changes to any implementations of this
> + * interface), we intend to make this abstract class provide reasonable
> + * implementations of any new methods so that subclasses do not necessarily need
> + * to be updated for new versions. Therefore, when creating a new
> + * BackendListenerClient implementation, developers are encouraged to subclass this
> + * abstract class rather than implementing the BackendListenerClient interface
> + * directly. Implementing BackendListenerClient directly will continue to be
> + * supported for cases where extending this class is not possible (for example,
> + * when the client class is already a subclass of some other class).
> + * <p>
> + * The handleSampleResult() method of BackendListenerClient does not have a default
> + * implementation here, so subclasses must define at least this method. It may
> + * be useful to override other methods as well.
> + *
> + * @see BackendListener#sampleOccurred(org.apache.jmeter.samplers.SampleEvent)
> + * @since 2.13
> + */
> +public abstract class AbstractBackendListenerClient implements BackendListenerClient {
> +
> +    private static final Logger log = LoggingManager.getLoggerForClass();
In classes further down the logger is stored in variables named LOG and 
LOGGER, should we use one name?
In this class we have a getter for the logger in other classes not. Why?
> +
> +    private ConcurrentHashMap<String, SamplerMetric> metricsPerSampler = new ConcurrentHashMap<String, SamplerMetric>();
> +
> +    /* Implements BackendListenerClient.setupTest(JavaSamplerContext) */
> +    @Override
> +    public void setupTest(BackendListenerContext context) throws Exception {
> +        log.debug(getClass().getName() + ": setupTest");
> +    }
> +
> +    /* Implements BackendListenerClient.teardownTest(JavaSamplerContext) */
> +    @Override
> +    public void teardownTest(BackendListenerContext context) throws Exception {
> +        log.debug(getClass().getName() + ": teardownTest");
> +        metricsPerSampler.clear();
> +    }
> +
> +    /* Implements BackendListenerClient.getDefaultParameters() */
> +    @Override
> +    public Arguments getDefaultParameters() {
> +        return null;
> +    }
> +
> +    /**
> +     * Get a Logger instance which can be used by subclasses to log information.
> +     *
> +     * @return a Logger instance which can be used for logging
> +     */
> +    protected Logger getLogger() {
> +        return log;
> +    }
> +
> +    /* (non-Javadoc)
> +     * @see org.apache.jmeter.visualizers.backend.BackendListenerClient#createSampleResult(org.apache.jmeter.samplers.SampleResult)
> +     */
> +    @Override
> +    public SampleResult createSampleResult(BackendListenerContext context, SampleResult result) {
> +        SampleResult sampleResult = (SampleResult) result.clone();
> +        return sampleResult;
> +    }
> +
> +    /**
> +     *
> +     * @param sampleLabel
> +     * @return SamplerMetric
No description of the method and the parameters?
> +     */
> +    protected SamplerMetric getSamplerMetric(String sampleLabel) {
> +        SamplerMetric samplerMetric = metricsPerSampler.get(sampleLabel);
> +        if(samplerMetric == null) {
> +            samplerMetric = new SamplerMetric();
> +            SamplerMetric oldValue = metricsPerSampler.putIfAbsent(sampleLabel, samplerMetric);
> +            if(oldValue != null ){
> +                samplerMetric = oldValue;
> +            }
> +        }
> +        return samplerMetric;
> +    }
> +
> +    /**
> +     *
> +     * @return Map<String, SamplerMetric>
No description of the method and usage of forbidden characters :) there 
are still more than 800 warnings in the javadoc to prune, so don't 
introduce new ones, please.
> +     */
> +    protected Map<String, SamplerMetric> getMetricsPerSampler() {
> +        return metricsPerSampler;
> +    }
> +
> +}
>
> Propchange: jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/AbstractBackendListenerClient.java
> ------------------------------------------------------------------------------
>      svn:mime-type = text/plain
>
> Added: jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/BackendListener.java
> URL: http://svn.apache.org/viewvc/jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/BackendListener.java?rev=1641081&view=auto
> ==============================================================================
> --- jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/BackendListener.java (added)
> +++ jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/BackendListener.java Sat Nov 22 15:36:37 2014
> @@ -0,0 +1,448 @@
> +/*
> + * 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.jmeter.visualizers.backend;
> +
> +import java.io.Serializable;
> +import java.lang.reflect.Method;
> +import java.util.ArrayList;
> +import java.util.HashSet;
> +import java.util.List;
> +import java.util.Set;
> +import java.util.concurrent.ArrayBlockingQueue;
> +import java.util.concurrent.BlockingQueue;
> +import java.util.concurrent.locks.LockSupport;
> +
> +import org.apache.jmeter.config.Arguments;
> +import org.apache.jmeter.engine.util.NoThreadClone;
> +import org.apache.jmeter.protocol.java.sampler.JavaSamplerContext;
> +import org.apache.jmeter.samplers.Remoteable;
> +import org.apache.jmeter.samplers.SampleEvent;
> +import org.apache.jmeter.samplers.SampleListener;
> +import org.apache.jmeter.samplers.SampleResult;
> +import org.apache.jmeter.testelement.AbstractTestElement;
> +import org.apache.jmeter.testelement.TestElement;
> +import org.apache.jmeter.testelement.TestStateListener;
> +import org.apache.jmeter.testelement.property.TestElementProperty;
> +import org.apache.jorphan.logging.LoggingManager;
> +import org.apache.log.Logger;
> +
> +/**
> + * Async Listener that delegates SampleResult handling to implementations of {@link BackendListenerClient}
> + * @since 2.13
> + */
> +public class BackendListener extends AbstractTestElement
> +    implements Serializable, SampleListener, TestStateListener, NoThreadClone, Remoteable  {
> +
> +    /**
> +     *
> +     */
> +    private static final long serialVersionUID = 8184103677832024335L;
> +
> +    private static final Logger log = LoggingManager.getLoggerForClass();
See naming comment of log from above
> +
> +    /**
> +     * Set used to register instances which implement teardownTest.
> +     * This is used so that the BackendListenerClient can be notified when the test ends.
> +     */
> +    private static final Set<BackendListener> TEAR_DOWN_SET = new HashSet<BackendListener>();
> +
> +    /**
> +     * Property key representing the classname of the BackendListenerClient to user.
> +     */
> +    public static final String CLASSNAME = "classname";
> +
> +    /**
> +     * Queue size
> +     */
> +    public static final String QUEUE_SIZE = "QUEUE_SIZE";
> +
> +    /**
> +     * Property key representing the arguments for the BackendListenerClient.
> +     */
> +    public static final String ARGUMENTS = "arguments";
> +
> +    /**
> +     * The BackendListenerClient class used by this sampler.
> +     * Created by testStarted; copied to cloned instances.
> +     */
> +    private Class<?> javaClass;
Could probably named clientClass instead of javaClass, since we already 
know it is a java class.
> +
> +    /**
> +     * If true, the BackendListenerClient class implements teardownTest.
> +     * Created by testStarted; copied to cloned instances.
> +     */
> +    private boolean isToBeRegistered;
> +
> +    /**
> +     * The BackendListenerClient instance
> +     */
> +    private transient BackendListenerClient backendListenerClient = null;
> +
> +    /**
> +     * The JavaSamplerContext instance used by this sampler to hold information
BackendListenerContext?
> +     * related to the test run, such as the parameters specified for the sampler
> +     * client.
> +     */
> +    private transient BackendListenerContext context = null;
> +
> +    private static final int DEFAULT_QUEUE_SIZE = 5000;
> +
> +    private transient BlockingQueue<SampleResult> queue; // created by server in readResolve method
> +
> +    private transient long queueWaits; // how many times we had to wait to queue a sample
> +
> +    private transient long queueWaitTime; // how long we had to wait (nanoSeconds)
> +
> +    // Create unique object as marker for end of queue
> +    private transient static final SampleResult FINAL_EVENT = new SampleResult();
> +
> +    /**
> +     * Create a BackendListener.
> +     */
> +    public BackendListener() {
> +        setArguments(new Arguments());
> +    }
> +
> +    /*
> +     * Ensure that the required class variables are cloned,
> +     * as this is not currently done by the super-implementation.
> +     */
> +    @Override
> +    public Object clone() {
> +        BackendListener clone = (BackendListener) super.clone();
> +        clone.javaClass = this.javaClass;
> +        clone.isToBeRegistered = this.isToBeRegistered;
> +        return clone;
> +    }
> +
> +    private void initClass() {
> +        String name = getClassname().trim();
> +        try {
> +            javaClass = Class.forName(name, false, Thread.currentThread().getContextClassLoader());
> +            Method method = javaClass.getMethod("teardownTest", new Class[]{BackendListenerContext.class});
> +            isToBeRegistered = !method.getDeclaringClass().equals(AbstractBackendListenerClient.class);
> +            log.info("Created class: " + name + ". Uses teardownTest: " + isToBeRegistered);
> +        } catch (Exception e) {
> +            log.error(whoAmI() + "\tException initialising: " + name, e);
> +        }
> +    }
> +
> +    /**
> +     * Retrieves reference to BackendListenerClient.
> +     *
> +     * Convience method used to check for null reference without actually
> +     * creating a BackendListenerClient
> +     *
> +     * @return reference to BackendListenerClient NOTUSED private BackendListenerClient
> +     *         retrieveJavaClient() { return javaClient; }
> +     */
Javadoc for non-existant method?
> +
> +    /**
> +     * Generate a String identifier of this instance for debugging purposes.
> +     *
> +     * @return a String identifier for this sampler instance
> +     */
> +    private String whoAmI() {
> +        StringBuilder sb = new StringBuilder();
> +        sb.append(Thread.currentThread().getName());
> +        sb.append("@");
> +        sb.append(Integer.toHexString(hashCode()));
> +        sb.append("-");
> +        sb.append(getName());
> +        return sb.toString();
> +    }
> +
> +    // TestStateListener implementation
> +    /* Implements TestStateListener.testStarted() */
> +    @Override
> +    public void testStarted() {
> +        testStarted("");
> +    }
> +
> +    /* Implements TestStateListener.testStarted(String) */
> +    @Override
> +    public void testStarted(String host) {
> +        log.debug(whoAmI() + "\ttestStarted(" + host + ")");
Maybe use isDebugEnabled to guard whoAmI() call?
> +        queue = new ArrayBlockingQueue<SampleResult>(getQueueSize());
> +        initClass();
> +        queueWaits=0L;
> +        queueWaitTime=0L;
> +        log.info(getName()+":Starting worker with class:"+javaClass +" and queue capacity:"+getQueueSize());
> +
> +        backendListenerClient = createBackendListenerClientImpl(javaClass);
> +        context = new BackendListenerContext((Arguments)getArguments().clone());
> +        if(isToBeRegistered) {
space after if and before (?
> +            TEAR_DOWN_SET.add(this);
> +        }
> +        try {
> +            backendListenerClient.setupTest(context);
> +        } catch (Exception e) {
> +            throw new java.lang.IllegalStateException("Failed calling setupTest", e);
> +        }
> +
> +        Worker worker = new Worker(javaClass, backendListenerClient, (Arguments) getArguments().clone(), queue);
> +        worker.setDaemon(true);
> +        worker.start();
Don't we want to stop worker after we're done with one test?
> +        log.info(getName()+":Started  worker with class:"+javaClass);
Spaces after :?
> +
> +    }
> +
> +    /* (non-Javadoc)
> +     * @see org.apache.jmeter.samplers.SampleListener#sampleOccurred(org.apache.jmeter.samplers.SampleEvent)
> +     */
> +    @Override
> +    public void sampleOccurred(SampleEvent e) {
Longer name then 'e'? I expect e to be an exception, not an event.
> +        Arguments args = getArguments();
> +        context = new BackendListenerContext(args);
> +
> +        SampleResult sr = backendListenerClient.createSampleResult(context, e.getResult());
> +        try {
> +            if (!queue.offer(sr)){ // we failed to add the element first time
> +                queueWaits++;
> +                long t1 = System.nanoTime();
> +                queue.put(sr);
> +                long t2 = System.nanoTime();
> +                queueWaitTime += t2-t1;
Will sampleOccurred be called concurrently? If so, than queueWaitTime += 
will not be correct.
> +            }
> +        } catch (Exception err) {
> +            log.error("sampleOccurred, failed to queue the sample", err);
> +        }
> +    }
> +
> +    private static final class Worker extends Thread {
> +
> +        private final BlockingQueue<SampleResult> queue;
> +        private final BackendListenerContext context;
> +        private final BackendListenerClient backendListenerClient;
> +        private Worker(Class<?> javaClass, BackendListenerClient backendListenerClient, Arguments arguments, BlockingQueue<SampleResult> q){
Same naming argument as above. clientclass instead of javaClass?
> +            queue = q;
> +            // Allow BackendListenerClient implementations to get access to test element name
> +            arguments.addArgument(TestElement.NAME, getName());
> +            context = new BackendListenerContext(arguments);
> +            this.backendListenerClient = backendListenerClient;
> +        }
> +
> +
> +        @Override
> +        public void run() {
> +            boolean isDebugEnabled = log.isDebugEnabled();
> +            List<SampleResult> l = new ArrayList<SampleResult>(queue.size());
samples instead of l?
> +            try {
> +                boolean eof = false;
endOfLoop?
> +                while (!eof) {
> +                    if(isDebugEnabled) {
> +                        log.debug("Thread:"+Thread.currentThread().getName()+" taking SampleResult from queue:"+queue.size());
> +                    }
> +                    SampleResult e = queue.take();
Could be named result, or sample instead of e
> +                    if(isDebugEnabled) {
> +                        log.debug("Thread:"+Thread.currentThread().getName()+" took SampleResult:"+e+", isFinal:" + (e==FINAL_EVENT));
> +                    }
> +                    while (!(eof = (e == FINAL_EVENT)) && e != null ) { // try to process as many as possible
> +                        l.add(e);
> +                        if(isDebugEnabled) {
> +                            log.debug("Thread:"+Thread.currentThread().getName()+" polling from queue:"+queue.size());
> +                        }
> +                        e = queue.poll(); // returns null if nothing on queue currently
> +                        if(isDebugEnabled) {
> +                            log.debug("Thread:"+Thread.currentThread().getName()+" took from queue:"+e+", isFinal:" + (e==FINAL_EVENT));
> +                        }
> +                    }
> +                    if(isDebugEnabled) {
> +                        log.debug("Thread:"+Thread.currentThread().getName()+
> +                                " exiting with FINAL EVENT:"+(e == FINAL_EVENT)
> +                                +", null:" + (e==null));
> +                    }
> +                    int size = l.size();
No need for a temporary variable.
> +                    if (size > 0) {
> +                        backendListenerClient.handleSampleResults(l, context);
> +                        l.clear();
> +                    }
> +                    if(!eof) {
> +                        LockSupport.parkNanos(100);
> +                    }
> +                }
> +            } catch (InterruptedException e) {
> +                // NOOP
> +            }
> +            // We may have been interrupted
> +            int size = l.size();
> +            if (size > 0) {
> +                backendListenerClient.handleSampleResults(l, context);
> +                l.clear();
> +            }
Same code as a few lines above, could be factored out into a method 
handleSamples(l, context)
> +            log.info("Worker ended");
> +        }
> +    }
> +
> +
> +    /**
> +     * Returns reference to <code>BackendListenerClient</code>.
Could use a {@link...}
> +     *
> +     *
> +     * @return BackendListenerClient reference.
> +     */
> +    static BackendListenerClient createBackendListenerClientImpl(Class<?> javaClass) {
> +        if (javaClass == null) { // failed to initialise the class
> +            return new ErrorBackendListenerClient();
> +        }
> +        BackendListenerClient client;
> +        try {
> +            client = (BackendListenerClient) javaClass.newInstance();
> +        } catch (Exception e) {
> +            log.error("Exception creating: " + javaClass, e);
> +            client = new ErrorBackendListenerClient();
> +        }
> +        return client;
I would return newInstance() in try Block and return new Error.. in 
catch Block. javaClass -> clientClass
> +    }
> +
> +    /**
> +     * Method called at the end of the test. This is called only on one instance
> +     * of BackendListener. This method will loop through all of the other
> +     * BackendListenerClients which have been registered (automatically in the
> +     * constructor) and notify them that the test has ended, allowing the
> +     * BackendListenerClients to cleanup.
> +     */
> +    @Override
> +    public void testEnded() {
> +        try {
> +            queue.put(FINAL_EVENT);
> +        } catch (Exception ex) {
> +            log.warn("testEnded() with exception:"+ex.getMessage(), ex);
> +        }
> +        if (queueWaits > 0) {
> +            log.warn("QueueWaits: "+queueWaits+"; QueueWaitTime: "+queueWaitTime+" (nanoseconds), you may need to increase queue capacity, see property 'backend_queue_capacity'");
> +        }
> +        synchronized (TEAR_DOWN_SET) {
> +            for (BackendListener backendListener : TEAR_DOWN_SET) {
> +                BackendListenerClient client = backendListener.backendListenerClient;
> +                if (client != null) {
> +                    try {
> +                        client.teardownTest(backendListener.context);
> +                    } catch (Exception e) {
> +                        throw new java.lang.IllegalStateException("Failed calling teardownTest", e);
If we throw an exception here, we will not try every client.
> +                    }
> +                }
> +            }
> +            TEAR_DOWN_SET.clear();
> +        }
> +    }
> +
> +    /* Implements TestStateListener.testEnded(String) */
> +    @Override
> +    public void testEnded(String host) {
> +        testEnded();
> +    }
> +
> +    /**
> +     * A {@link BackendListenerClient} implementation used for error handling. If an
> +     * error occurs while creating the real BackendListenerClient object, it is
> +     * replaced with an instance of this class. Each time a sample occurs with
> +     * this class, the result is marked as a failure so the user can see that
> +     * the test failed.
> +     */
> +    static class ErrorBackendListenerClient extends AbstractBackendListenerClient {
> +        /**
> +         * Return SampleResult with data on error.
> +         *
> +         * @see BackendListenerClient#runTest(JavaSamplerContext)
> +         */
> +        @Override
> +        public void handleSampleResults(List<SampleResult> sampleResults, BackendListenerContext context) {
> +            log.warn("ErrorBackendListenerClient#handleSampleResult called, noop");
> +            Thread.yield();
> +        }
> +    }
> +
> +    /* (non-Javadoc)
> +     * @see org.apache.jmeter.samplers.SampleListener#sampleStarted(org.apache.jmeter.samplers.SampleEvent)
> +     */
> +    @Override
> +    public void sampleStarted(SampleEvent e) {
> +        // NOOP
> +
> +    }
> +
> +    /* (non-Javadoc)
> +     * @see org.apache.jmeter.samplers.SampleListener#sampleStopped(org.apache.jmeter.samplers.SampleEvent)
> +     */
> +    @Override
> +    public void sampleStopped(SampleEvent e) {
> +        // NOOP
> +
> +    }
> +
> +    /**
> +     * Set the arguments (parameters) for the BackendListenerClient to be executed
> +     * with.
> +     *
> +     * @param args
> +     *            the new arguments. These replace any existing arguments.
> +     */
> +    public void setArguments(Arguments args) {
> +        setProperty(new TestElementProperty(ARGUMENTS, args));
> +    }
> +
> +    /**
> +     * Get the arguments (parameters) for the BackendListenerClient to be executed
> +     * with.
> +     *
> +     * @return the arguments
> +     */
> +    public Arguments getArguments() {
> +        return (Arguments) getProperty(ARGUMENTS).getObjectValue();
> +    }
> +
> +    /**
> +     * Sets the Classname of the BackendListenerClient object
> +     *
> +     * @param classname
> +     *            the new Classname value
> +     */
> +    public void setClassname(String classname) {
> +        setProperty(CLASSNAME, classname);
> +    }
> +
> +    /**
> +     * Gets the Classname of the BackendListenerClient object
> +     *
> +     * @return the Classname value
> +     */
> +    public String getClassname() {
> +        return getPropertyAsString(CLASSNAME);
> +    }
> +
> +    /**
> +     * Sets the queue size
> +     *
> +     * @param queueSize
> +     *
> +     */
> +    public void setQueueSize(int queueSize) {
> +        setProperty(QUEUE_SIZE, queueSize, DEFAULT_QUEUE_SIZE);
> +    }
> +
> +    /**
> +     * Gets the queue size
> +     *
> +     * @return int queueSize
> +     */
> +    public int getQueueSize() {
> +        return getPropertyAsInt(QUEUE_SIZE, DEFAULT_QUEUE_SIZE);
> +    }
> +}
>
> Propchange: jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/BackendListener.java
> ------------------------------------------------------------------------------
>      svn:mime-type = text/plain
>
> Added: jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/BackendListenerClient.java
> URL: http://svn.apache.org/viewvc/jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/BackendListenerClient.java?rev=1641081&view=auto
> ==============================================================================
> --- jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/BackendListenerClient.java (added)
> +++ jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/BackendListenerClient.java Sat Nov 22 15:36:37 2014
> @@ -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.jmeter.visualizers.backend;
> +
> +import java.util.List;
> +
> +import org.apache.jmeter.config.Arguments;
> +import org.apache.jmeter.samplers.SampleResult;
> +
> +/**
> + * This interface defines the interactions between the BackendListener and external
> + * Java programs which can be executed by JMeter. Any Java class which wants to
> + * be executed as a JMeter test must implement this interface (either directly
> + * or indirectly through AbstractBackendListenerClient).
> + * <p>
> + * JMeter will create one instance of a BackendListenerClient implementation for
> + * each user/thread in the test. Additional instances may be created for
> + * internal use by JMeter (for example, to find out what parameters are
> + * supported by the client).
> + * <p>
> + * When the test is started, setupTest() will be called on each thread's
> + * BackendListenerClient instance to initialize the client. Then handleSampleResult() will be
> + * called for each SampleResult notification. Finally, teardownTest() will be called
> + * to allow the client to do any necessary clean-up.
> + * <p>
> + * The JMeter BackendListener GUI allows a list of parameters to be defined for the
> + * test. These are passed to the various test methods through the
> + * {@link BackendListenerContext}. A list of default parameters can be defined
> + * through the getDefaultParameters() method. These parameters and any default
> + * values associated with them will be shown in the GUI. Users can add other
> + * parameters as well.
> + * <p>
> + * When possible, Listeners should extend {@link AbstractBackendListenerClient
> + * AbstractBackendListenerClient} rather than implementing BackendListenerClient
> + * directly. This should protect your tests from future changes to the
> + * interface. While it may be necessary to make changes to the BackendListenerClient
> + * interface from time to time (therefore requiring changes to any
> + * implementations of this interface), we intend to make this abstract class
> + * provide reasonable default implementations of any new methods so that
> + * subclasses do not necessarily need to be updated for new versions.
> + * Implementing BackendListenerClient directly will continue to be supported for
> + * cases where extending this class is not possible (for example, when the
> + * client class is already a subclass of some other class).
> + *
> + * @since 2.13
> + */
> +public interface BackendListenerClient {
> +    /**
> +     * Do any initialization required by this client. It is generally
> +     * recommended to do any initialization such as getting parameter values in
> +     * the setupTest method rather than the runTest method in order to add as
> +     * little overhead as possible to the test.
> +     *
> +     * @param context
> +     *            the context to run with. This provides access to
> +     *            initialization parameters.
> +     */
> +    void setupTest(BackendListenerContext context) throws Exception;
> +
> +    /**
> +     * Perform a single sample for each iteration. This method returns a
> +     * <code>SampleResult</code> object. <code>SampleResult</code> has many
> +     * fields which can be used. At a minimum, the test should use
> +     * <code>SampleResult.sampleStart</code> and
> +     * <code>SampleResult.sampleEnd</code>to set the time that the test
use {@link..} instead of <code>..?
> +     * required to execute. It is also a good idea to set the sampleLabel and
> +     * the successful flag.
> +     *
> +     * @see org.apache.jmeter.samplers.SampleResult#sampleStart()
> +     * @see org.apache.jmeter.samplers.SampleResult#sampleEnd()
> +     * @see org.apache.jmeter.samplers.SampleResult#setSuccessful(boolean)
> +     * @see org.apache.jmeter.samplers.SampleResult#setSampleLabel(String)
> +     *
> +     * @param context
> +     *            the context to run with. This provides access to
> +     *            initialization parameters.
> +     *
> +     */
> +    void handleSampleResults(List<SampleResult> sampleResults, BackendListenerContext context);
> +
> +    /**
> +     * Do any clean-up required by this test at the end of a test run.
> +     *
> +     * @param context
> +     *            the context to run with. This provides access to
> +     *            initialization parameters.
> +     */
> +    void teardownTest(BackendListenerContext context) throws Exception;
> +
> +    /**
> +     * Provide a list of parameters which this test supports. Any parameter
> +     * names and associated values returned by this method will appear in the
> +     * GUI by default so the user doesn't have to remember the exact names. The
> +     * user can add other parameters which are not listed here. If this method
> +     * returns null then no parameters will be listed. If the value for some
> +     * parameter is null then that parameter will be listed in the GUI with an
> +     * empty value.
> +     *
> +     * @return a specification of the parameters used by this test which should
> +     *         be listed in the GUI, or null if no parameters should be listed.
> +     */
> +    Arguments getDefaultParameters();
> +
> +    /**
> +     *
> +     * @param context
> +     * @param result
> +     * @return
> +     */
> +    SampleResult createSampleResult(
> +            BackendListenerContext context, SampleResult result);
> +}
>
> Propchange: jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/BackendListenerClient.java
> ------------------------------------------------------------------------------
>      svn:mime-type = text/plain
>
> Added: jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/BackendListenerContext.java
> URL: http://svn.apache.org/viewvc/jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/BackendListenerContext.java?rev=1641081&view=auto
> ==============================================================================
> --- jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/BackendListenerContext.java (added)
> +++ jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/BackendListenerContext.java Sat Nov 22 15:36:37 2014
> @@ -0,0 +1,237 @@
> +/*
> +
> + * 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.jmeter.visualizers.backend;
> +
> +import java.util.Iterator;
> +import java.util.Map;
> +
> +import org.apache.jmeter.config.Arguments;
> +import org.apache.jorphan.logging.LoggingManager;
> +import org.apache.log.Logger;
> +
> +/**
> + * BackendListenerContext is used to provide context information to a
> + * BackendListenerClient implementation. This currently consists of the
> + * initialization parameters which were specified in the GUI.
> + * @since 2.13
> + */
> +public class BackendListenerContext {
> +    /*
> +     * Implementation notes:
> +     *
> +     * All of the methods in this class are currently read-only. If update
> +     * methods are included in the future, they should be defined so that a
> +     * single instance of BackendListenerContext can be associated with each thread.
> +     * Therefore, no synchronization should be needed. The same instance should
> +     * be used for the call to setupTest, all calls to runTest, and the call to
> +     * teardownTest.
> +     */
> +
> +    /** Logging */
> +    private static final Logger log = LoggingManager.getLoggerForClass();
See naming comments for logger above
> +
> +    /**
> +     * Map containing the initialization parameters for the BackendListenerClient.
> +     */
> +    private final Map<String, String> params;
> +
> +    /**
> +     *
> +     * @param args
> +     *            the initialization parameters.
> +     */
> +    public BackendListenerContext(Arguments args) {
> +        this.params = args.getArgumentsAsMap();
> +    }
> +
> +    /**
> +     * Determine whether or not a value has been specified for the parameter
> +     * with this name.
> +     *
> +     * @param name
> +     *            the name of the parameter to test
> +     * @return true if the parameter value has been specified, false otherwise.
> +     */
> +    public boolean containsParameter(String name) {
hasParameter instead of containsParameter?
> +        return params.containsKey(name);
> +    }
> +
> +    /**
> +     * Get an iterator of the parameter names. Each entry in the Iterator is a
> +     * String.
> +     *
> +     * @return an Iterator of Strings listing the names of the parameters which
> +     *         have been specified for this test.
> +     */
> +    public Iterator<String> getParameterNamesIterator() {
> +        return params.keySet().iterator();
> +    }
> +
> +    /**
> +     * Get the value of a specific parameter as a String, or null if the value
> +     * was not specified.
> +     *
> +     * @param name
> +     *            the name of the parameter whose value should be retrieved
> +     * @return the value of the parameter, or null if the value was not
> +     *         specified
> +     */
> +    public String getParameter(String name) {
> +        return getParameter(name, null);
> +    }
> +
> +    /**
> +     * Get the value of a specified parameter as a String, or return the
> +     * specified default value if the value was not specified.
> +     *
> +     * @param name
> +     *            the name of the parameter whose value should be retrieved
> +     * @param defaultValue
> +     *            the default value to return if the value of this parameter was
> +     *            not specified
> +     * @return the value of the parameter, or the default value if the parameter
> +     *         was not specified
> +     */
> +    public String getParameter(String name, String defaultValue) {
> +        if (params == null || !params.containsKey(name)) {
> +            return defaultValue;
> +        }
> +        return params.get(name);
> +    }
> +
> +    /**
> +     * Get the value of a specified parameter as an integer. An exception will
> +     * be thrown if the parameter is not specified or if it is not an integer.
> +     * The value may be specified in decimal, hexadecimal, or octal, as defined
> +     * by Integer.decode().
> +     *
> +     * @param name
> +     *            the name of the parameter whose value should be retrieved
> +     * @return the value of the parameter
> +     *
> +     * @throws NumberFormatException
> +     *             if the parameter is not specified or is not an integer
> +     *
> +     * @see java.lang.Integer#decode(java.lang.String)
> +     */
> +    public int getIntParameter(String name) throws NumberFormatException {
> +        if (params == null || !params.containsKey(name)) {
> +            throw new NumberFormatException("No value for parameter named '" + name + "'.");
I would expect an IllegalArgumentException, if no parameter of that name 
is found
> +        }
> +
> +        return Integer.decode(params.get(name)).intValue();
> +    }
> +
> +    /**
> +     * Get the value of a specified parameter as an integer, or return the
> +     * specified default value if the value was not specified or is not an
> +     * integer. A warning will be logged if the value is not an integer. The
> +     * value may be specified in decimal, hexadecimal, or octal, as defined by
> +     * Integer.decode().
> +     *
> +     * @param name
> +     *            the name of the parameter whose value should be retrieved
> +     * @param defaultValue
> +     *            the default value to return if the value of this parameter was
> +     *            not specified
> +     * @return the value of the parameter, or the default value if the parameter
> +     *         was not specified
> +     *
> +     * @see java.lang.Integer#decode(java.lang.String)
> +     */
> +    public int getIntParameter(String name, int defaultValue) {
> +        if (params == null || !params.containsKey(name)) {
> +            return defaultValue;
> +        }
> +
> +        try {
> +            return Integer.decode(params.get(name)).intValue();
> +        } catch (NumberFormatException e) {
> +            log.warn("Value for parameter '" + name + "' not an integer: '" + params.get(name) + "'.  Using default: '"
> +                    + defaultValue + "'.", e);
> +            return defaultValue;
> +        }
> +    }
> +
> +    /**
> +     * Get the value of a specified parameter as a long. An exception will be
> +     * thrown if the parameter is not specified or if it is not a long. The
> +     * value may be specified in decimal, hexadecimal, or octal, as defined by
> +     * Long.decode().
> +     *
> +     * @param name
> +     *            the name of the parameter whose value should be retrieved
> +     * @return the value of the parameter
> +     *
> +     * @throws NumberFormatException
> +     *             if the parameter is not specified or is not a long
> +     *
> +     * @see Long#decode(String)
> +     */
> +    public long getLongParameter(String name) throws NumberFormatException {
> +        if (params == null || !params.containsKey(name)) {
> +            throw new NumberFormatException("No value for parameter named '" + name + "'.");
> +        }
> +
> +        return Long.decode(params.get(name)).longValue();
> +    }
> +
> +    /**
> +     * Get the value of a specified parameter as along, or return the specified
> +     * default value if the value was not specified or is not a long. A warning
> +     * will be logged if the value is not a long. The value may be specified in
> +     * decimal, hexadecimal, or octal, as defined by Long.decode().
> +     *
> +     * @param name
> +     *            the name of the parameter whose value should be retrieved
> +     * @param defaultValue
> +     *            the default value to return if the value of this parameter was
> +     *            not specified
> +     * @return the value of the parameter, or the default value if the parameter
> +     *         was not specified
> +     *
> +     * @see Long#decode(String)
> +     */
> +    public long getLongParameter(String name, long defaultValue) {
> +        if (params == null || !params.containsKey(name)) {
> +            return defaultValue;
> +        }
> +        try {
> +            return Long.decode(params.get(name)).longValue();
> +        } catch (NumberFormatException e) {
> +            log.warn("Value for parameter '" + name + "' not a long: '" + params.get(name) + "'.  Using default: '"
> +                    + defaultValue + "'.", e);
> +            return defaultValue;
> +        }
> +    }
> +
> +    /**
> +     *
> +     * @param name
> +     * @param defaultValue
> +     * @return
No javadoc? Again three warnings more :)
> +     */
> +    public boolean getBooleanParameter(String name, boolean defaultValue) {
> +        if (params == null || !params.containsKey(name)) {
> +            return defaultValue;
> +        }
> +        return Boolean.valueOf(params.get(name));
> +    }
> +}
>
> Propchange: jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/BackendListenerContext.java
> ------------------------------------------------------------------------------
>      svn:mime-type = text/plain
>
> Added: jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/BackendListenerGui.java
> URL: http://svn.apache.org/viewvc/jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/BackendListenerGui.java?rev=1641081&view=auto
> ==============================================================================
> --- jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/BackendListenerGui.java (added)
> +++ jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/BackendListenerGui.java Sat Nov 22 15:36:37 2014
> @@ -0,0 +1,282 @@
> +/*
> + * 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.jmeter.visualizers.backend;
> +
> +import java.awt.BorderLayout;
> +import java.awt.event.ActionEvent;
> +import java.awt.event.ActionListener;
> +import java.util.ArrayList;
> +import java.util.HashSet;
> +import java.util.List;
> +import java.util.Map;
> +import java.util.Set;
> +
> +import javax.swing.ComboBoxModel;
> +import javax.swing.JComboBox;
> +import javax.swing.JLabel;
> +import javax.swing.JPanel;
> +import javax.swing.JTextField;
> +
> +import org.apache.jmeter.config.Argument;
> +import org.apache.jmeter.config.Arguments;
> +import org.apache.jmeter.config.gui.ArgumentsPanel;
> +import org.apache.jmeter.gui.util.HorizontalPanel;
> +import org.apache.jmeter.testelement.TestElement;
> +import org.apache.jmeter.testelement.property.PropertyIterator;
> +import org.apache.jmeter.util.JMeterUtils;
> +import org.apache.jmeter.visualizers.gui.AbstractListenerGui;
> +import org.apache.jorphan.logging.LoggingManager;
> +import org.apache.jorphan.reflect.ClassFinder;
> +import org.apache.log.Logger;
> +
> +/**
> + * The <code>BackendListenerGui</code> class provides the user interface for the
> + * {@link BackendListener} object.
> + * @since 2.13
> + */
> +public class BackendListenerGui extends AbstractListenerGui implements ActionListener {
> +
> +    /**
> +     *
> +     */
> +    private static final long serialVersionUID = 4331668988576438604L;
> +
> +    /** Logging */
> +    private static final Logger log = LoggingManager.getLoggerForClass();
> +
> +    /** A combo box allowing the user to choose a backend class. */
> +    private JComboBox classnameCombo;
> +
> +    /**
> +     * A field allowing the user to specify the size of Queue
> +     */
> +    private JTextField queueSize;
> +
> +    /** A panel allowing the user to set arguments for this test. */
> +    private ArgumentsPanel argsPanel;
> +
> +    /**
> +     * Create a new BackendListenerGui as a standalone component.
> +     */
> +    public BackendListenerGui() {
> +        super();
> +        init();
> +    }
> +
> +
> +    /** {@inheritDoc} */
> +    @Override
> +    public String getLabelResource() {
> +        return "backend_listener"; // $NON-NLS-1$
> +    }
> +
> +    /**
> +     * Initialize the GUI components and layout.
> +     */
> +    private void init() {// called from ctor, so must not be overridable
> +        setLayout(new BorderLayout(0, 5));
> +
> +        setBorder(makeBorder());
> +        add(makeTitlePanel(), BorderLayout.NORTH);
> +
> +        JPanel classnameRequestPanel = new JPanel(new BorderLayout(0, 5));
> +        classnameRequestPanel.add(createClassnamePanel(), BorderLayout.NORTH);
> +        classnameRequestPanel.add(createParameterPanel(), BorderLayout.CENTER);
> +
> +        add(classnameRequestPanel, BorderLayout.CENTER);
> +    }
> +
> +    /**
> +     * Create a panel with GUI components allowing the user to select a test
> +     * class.
> +     *
> +     * @return a panel containing the relevant components
> +     */
> +    private JPanel createClassnamePanel() {
> +        List<String> possibleClasses = new ArrayList<String>();
> +
> +        try {
> +            // Find all the classes which implement the BackendListenerClient
> +            // interface.
> +            possibleClasses = ClassFinder.findClassesThatExtend(JMeterUtils.getSearchPaths(),
> +                    new Class[] { BackendListenerClient.class });
> +
> +            // Remove the BackendListener class from the list since it only
ErrorBackendListener
> +            // implements the interface for error conditions.
> +
> +            possibleClasses.remove(BackendListener.class.getName() + "$ErrorBackendListenerClient");
> +        } catch (Exception e) {
> +            log.debug("Exception getting interfaces.", e);
> +        }
> +
> +        JLabel label = new JLabel(JMeterUtils.getResString("backend_listener_classname")); // $NON-NLS-1$
> +
> +        classnameCombo = new JComboBox(possibleClasses.toArray());
> +        classnameCombo.addActionListener(this);
> +        classnameCombo.setEditable(false);
> +        label.setLabelFor(classnameCombo);
> +
> +        HorizontalPanel classNamePanel = new HorizontalPanel();
> +        classNamePanel.add(label);
> +        classNamePanel.add(classnameCombo);
> +
> +        queueSize = new JTextField("", 5);
> +        queueSize.setName("Queue Size"); //$NON-NLS-1$
> +        JLabel queueSizeLabel = new JLabel(JMeterUtils.getResString("backend_listener_queue_size")); // $NON-NLS-1$
> +        queueSizeLabel.setLabelFor(queueSize);
> +        HorizontalPanel queueSizePanel = new HorizontalPanel();
> +        queueSizePanel.add(queueSizeLabel, BorderLayout.WEST);
> +        queueSizePanel.add(queueSize);
> +
> +        JPanel panel = new JPanel(new BorderLayout(0, 5));
> +        panel.add(classNamePanel, BorderLayout.NORTH);
> +        panel.add(queueSizePanel, BorderLayout.CENTER);
> +        return panel;
> +    }
> +
> +    /**
> +     * Handle action events for this component. This method currently handles
> +     * events for the classname combo box.
> +     *
> +     * @param evt
I would spend the few extra characters to make it event instead of evt
> +     *            the ActionEvent to be handled
> +     */
> +    @Override
> +    public void actionPerformed(ActionEvent evt) {
> +        if (evt.getSource() == classnameCombo) {
> +            String className = ((String) classnameCombo.getSelectedItem()).trim();
> +            try {
> +                BackendListenerClient client = (BackendListenerClient) Class.forName(className, true,
> +                        Thread.currentThread().getContextClassLoader()).newInstance();
> +
> +                Arguments currArgs = new Arguments();
> +                argsPanel.modifyTestElement(currArgs);
> +                Map<String, String> currArgsMap = currArgs.getArgumentsAsMap();
> +
> +                Arguments newArgs = new Arguments();
> +                Arguments testParams = null;
> +                try {
> +                    testParams = client.getDefaultParameters();
> +                } catch (AbstractMethodError e) {
> +                    log.warn("BackendListenerClient doesn't implement "
> +                            + "getDefaultParameters.  Default parameters won't "
> +                            + "be shown.  Please update your client class: " + className);
> +                }
> +
> +                if (testParams != null) {
> +                    PropertyIterator i = testParams.getArguments().iterator();
I would try a for loop instead of explicitly using an iterator
> +                    while (i.hasNext()) {
> +                        Argument arg = (Argument) i.next().getObjectValue();
> +                        String name = arg.getName();
> +                        String value = arg.getValue();
> +
> +                        // If a user has set parameters in one test, and then
> +                        // selects a different test which supports the same
> +                        // parameters, those parameters should have the same
> +                        // values that they did in the original test.
> +                        if (currArgsMap.containsKey(name)) {
> +                            String newVal = currArgsMap.get(name);
> +                            if (newVal != null && newVal.length() > 0) {
> +                                value = newVal;
> +                            }
> +                        }
> +                        newArgs.addArgument(name, value);
> +                    }
> +                }
> +
> +                argsPanel.configure(newArgs);
> +            } catch (Exception e) {
> +                log.error("Error getting argument list for " + className, e);
> +            }
> +        }
> +    }
> +
> +    /**
> +     * Create a panel containing components allowing the user to provide
> +     * arguments to be passed to the test class instance.
> +     *
> +     * @return a panel containing the relevant components
> +     */
> +    private JPanel createParameterPanel() {
> +        argsPanel = new ArgumentsPanel(JMeterUtils.getResString("backend_listener_paramtable")); // $NON-NLS-1$
> +        return argsPanel;
> +    }
> +
> +    /** {@inheritDoc} */
> +    @Override
> +    public void configure(TestElement config) {
> +        super.configure(config);
> +
> +        argsPanel.configure((Arguments) config.getProperty(BackendListener.ARGUMENTS).getObjectValue());
> +
> +        String className = config.getPropertyAsString(BackendListener.CLASSNAME);
> +        if(checkContainsClassName(classnameCombo.getModel(), className)) {
> +            classnameCombo.setSelectedItem(className);
> +        } else {
> +            log.error("Error setting class:'"+className+"' in BackendListener: "+getName()+
> +                    ", check for a missing jar in your jmeter 'search_paths' and 'plugin_dependency_paths' properties");
> +        }
> +        queueSize.setText(Integer.toString(((BackendListener)config).getQueueSize()));
> +    }
> +
> +    /**
> +     * Check combo contains className
> +     * @param model ComboBoxModel
> +     * @param className String class name
> +     * @return boolean
explain "boolean" or the other params a bit more?
> +     */
> +    private static final boolean checkContainsClassName(ComboBoxModel model, String className) {
> +        int size = model.getSize();
> +        Set<String> set = new HashSet<String>(size);
> +        for (int i = 0; i < size; i++) {
> +            set.add((String)model.getElementAt(i));
> +        }
> +        return set.contains(className);
> +    }
> +
> +    /** {@inheritDoc} */
> +    @Override
> +    public TestElement createTestElement() {
> +        BackendListener config = new BackendListener();
> +        modifyTestElement(config);
> +        return config;
> +    }
> +
> +    /** {@inheritDoc} */
> +    @Override
> +    public void modifyTestElement(TestElement config) {
> +        configureTestElement(config);
> +        BackendListener backendListener = (BackendListener) config;
> +        backendListener.setArguments((Arguments) argsPanel.createTestElement());
> +        backendListener.setClassname(String.valueOf(classnameCombo.getSelectedItem()));
> +        backendListener.setQueueSize(Integer.parseInt(queueSize.getText()));
> +
> +    }
> +
> +    /* (non-Javadoc)
> +     * @see org.apache.jmeter.gui.AbstractJMeterGuiComponent#clearGui()
> +     */
> +    @Override
> +    public void clearGui() {
> +        super.clearGui();
> +        argsPanel.clearGui();
> +        classnameCombo.setSelectedIndex(0);
> +        queueSize.setText("");
> +    }
> +}
>
> Propchange: jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/BackendListenerGui.java
> ------------------------------------------------------------------------------
>      svn:mime-type = text/plain
>
> Added: jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/SamplerMetric.java
> URL: http://svn.apache.org/viewvc/jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/SamplerMetric.java?rev=1641081&view=auto
> ==============================================================================
> --- jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/SamplerMetric.java (added)
> +++ jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/SamplerMetric.java Sat Nov 22 15:36:37 2014
> @@ -0,0 +1,138 @@
> +/*
> + * 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.jmeter.visualizers.backend;
> +
> +import org.apache.commons.math3.stat.descriptive.DescriptiveStatistics;
> +import org.apache.jmeter.samplers.SampleResult;
> +
> +/**
> + * Sampler metric
> + * @since 2.13
> + */
> +public class SamplerMetric {
> +    // Limit to sliding window of 100 values
> +    private DescriptiveStatistics stats = new DescriptiveStatistics(100);
> +    private int success;
> +    private int failure;
successCount, failureCount? Why not initialize them as maxTime and the 
other values?
> +    private long maxTime=0L;
> +    private long minTime=Long.MAX_VALUE;
> +    private int maxActiveThreads = 0;
> +    private int minActiveThreads = Integer.MAX_VALUE;
> +    /**
> +     *
> +     */
> +    public SamplerMetric() {
> +    }
> +
> +    /**
> +     *
> +     * @param result SampleResult
> +     */
> +    public synchronized void add(SampleResult result) {
> +        if(result.isSuccessful()) {
> +            success++;
> +        } else {
> +            failure++;
> +        }
> +        long time = result.getTime();
> +        int activeThreads = result.getAllThreads();
> +        maxTime = Math.max(time, maxTime);
> +        minTime = Math.min(time, minTime);
> +        maxActiveThreads = Math.max(maxActiveThreads, activeThreads);
> +        minActiveThreads = Math.min(minActiveThreads, activeThreads);
> +        if(result.isSuccessful()) {
> +            // Should we also compute KO , all response time ?
KO? what does that mean? No space before comma
> +            // only take successful requests for time computing
> +            stats.addValue(time);
> +        }
> +    }
> +
> +    /**
> +     * Reset metric except for percentile related datas
> +     */
> +    public synchronized void resetForTimeInterval() {
> +        // We don't clear stats as it will slide as per my understanding of
> +        // http://commons.apache.org/proper/commons-math/userguide/stat.html
> +        success = 0;
> +        failure = 0;
> +        maxTime=0L;
> +        minTime=Long.MAX_VALUE;
> +        maxActiveThreads = 0;
> +        minActiveThreads = Integer.MAX_VALUE;
> +    }
> +
> +    /**
> +     * @return mean
mean of what?
> +     */
> +    public double getMean() {
> +        return stats.getMean();
> +    }
> +
> +    /**
> +     * @param percentile
values ranging from 0 to 1 or from 0 to 100?
> +     * @return
description?
> +     */
> +    public double getPercentile(double percentile) {
> +        return stats.getPercentile(percentile);
> +    }
> +
> +    /**
> +     *
> +     * @return total request
> +     */
> +    public int getTotal() {
> +        return success+failure;
> +    }
> +
> +    /**
> +     * @return the success
number of successful requests
> +     */
> +    public int getSuccess() {
> +        return success;
> +    }
> +
> +    /**
> +     * @return the failure
number of ... Or better getSuccessCount, getFailureCount?
> +     */
> +    public int getFailure() {
> +        return failure;
> +    }
> +
> +    /**
> +     * @return the maxTime
> +     */
> +    public long getMaxTime() {
> +        return maxTime;
> +    }
> +
> +    /**
> +     * @return the minTime
> +     */
> +    public long getMinTime() {
> +        return minTime;
> +    }
> +
> +    public int getMaxActiveThreads() {
> +        return maxActiveThreads;
> +    }
> +
> +    public int getMinActiveThreads() {
> +        return minActiveThreads;
> +    }
> +}
>
> Propchange: jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/SamplerMetric.java
> ------------------------------------------------------------------------------
>      svn:mime-type = text/plain
>
> 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=1641081&r1=1641080&r2=1641081&view=diff
> ==============================================================================
> --- jmeter/trunk/src/core/org/apache/jmeter/resources/messages.properties (original)
> +++ jmeter/trunk/src/core/org/apache/jmeter/resources/messages.properties Sat Nov 22 15:36:37 2014
> @@ -129,6 +129,10 @@ auth_manager_title=HTTP Authorization Ma
>   auths_stored=Authorizations Stored in the Authorization Manager
>   average=Average
>   average_bytes=Avg. Bytes
> +backend_listener=Backend Listener
> +backend_listener_classname=Backend Listener implementation
> +backend_listener_paramtable=Parameters
> +backend_listener_queue_size=Async Queue size
>   bind=Thread Bind
>   bouncy_castle_unavailable_message=The jars for bouncy castle are unavailable, please add them to your classpath.
>   browse=Browse...
>
> 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=1641081&r1=1641080&r2=1641081&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 Nov 22 15:36:37 2014
> @@ -123,6 +123,10 @@ auth_manager_title=Gestionnaire d'autori
>   auths_stored=Autorisations stock\u00E9es
>   average=Moyenne
>   average_bytes=Moy. octets
> +backend_listener=R\u00E9cepteur asynchrone
> +backend_listener_classname=Implémentation du r\u00E9cepteur asynchrone
> +backend_listener_paramtable=Param\u00E8tres
> +backend_listener_queue_size=Taille de la queue
>   bind=Connexion de l'unit\u00E9
>   bouncy_castle_unavailable_message=Les jars de bouncycastle sont indisponibles, ajoutez les au classpath.
>   browse=Parcourir...
>
> Modified: jmeter/trunk/src/core/org/apache/jmeter/samplers/SampleResult.java
> URL: http://svn.apache.org/viewvc/jmeter/trunk/src/core/org/apache/jmeter/samplers/SampleResult.java?rev=1641081&r1=1641080&r2=1641081&view=diff
> ==============================================================================
> --- jmeter/trunk/src/core/org/apache/jmeter/samplers/SampleResult.java (original)
> +++ jmeter/trunk/src/core/org/apache/jmeter/samplers/SampleResult.java Sat Nov 22 15:36:37 2014
> @@ -42,7 +42,7 @@ import org.apache.log.Logger;
>    * sample of an entry.
>    *
>    */
> -public class SampleResult implements Serializable {
> +public class SampleResult implements Serializable, Cloneable {
>   
>       private static final long serialVersionUID = 241L;
>   
> @@ -1349,4 +1349,13 @@ public class SampleResult implements Ser
>       public void cleanAfterSample() {
>           this.responseDataAsString = null;
>       }
> +
> +    @Override
> +    public Object clone() {
> +        try {
> +            return super.clone();
> +        } catch (CloneNotSupportedException e) {
> +            throw new IllegalStateException("This should not happen");
Would not be a CloneNotSupportedException be the right thing to be thrown?
> +        }
> +    }
>   }
>
> Modified: jmeter/trunk/src/core/org/apache/jmeter/save/SaveService.java
> URL: http://svn.apache.org/viewvc/jmeter/trunk/src/core/org/apache/jmeter/save/SaveService.java?rev=1641081&r1=1641080&r2=1641081&view=diff
> ==============================================================================
> --- jmeter/trunk/src/core/org/apache/jmeter/save/SaveService.java (original)
> +++ jmeter/trunk/src/core/org/apache/jmeter/save/SaveService.java Sat Nov 22 15:36:37 2014
> @@ -176,7 +176,7 @@ public class SaveService {
>       
>       // Must match _version property value in saveservice.properties
>       // used to ensure saveservice.properties and SaveService are updated simultaneously
> -    private static final String PROPVERSION = "2.7";// Expected version $NON-NLS-1$
> +    private static final String PROPVERSION = "2.8";// Expected version $NON-NLS-1$
>   
>       // Internal information only
>       private static String fileVersion = ""; // read from saveservice.properties file// $NON-NLS-1$
>
> Modified: jmeter/trunk/xdocs/changes.xml
> URL: http://svn.apache.org/viewvc/jmeter/trunk/xdocs/changes.xml?rev=1641081&r1=1641080&r2=1641081&view=diff
> ==============================================================================
> --- jmeter/trunk/xdocs/changes.xml (original)
> +++ jmeter/trunk/xdocs/changes.xml Sat Nov 22 15:36:37 2014
> @@ -188,6 +188,7 @@ See  <bugzilla>56357</bugzilla> for deta
>   
>   <h3>Listeners</h3>
>   <ul>
> +<li><bugzilla>55932</bugzilla> - Create a Async BackendListener to allow easy plug of new listener (Graphite, JDBC, Console,...)</li>
>   </ul>
>   
>   <h3>Timers, Assertions, Config, Pre- &amp; Post-Processors</h3>
>
> Modified: jmeter/trunk/xdocs/usermanual/component_reference.xml
> URL: http://svn.apache.org/viewvc/jmeter/trunk/xdocs/usermanual/component_reference.xml?rev=1641081&r1=1641080&r2=1641081&view=diff
> ==============================================================================
> --- jmeter/trunk/xdocs/usermanual/component_reference.xml (original)
> +++ jmeter/trunk/xdocs/usermanual/component_reference.xml Sat Nov 22 15:36:37 2014
> @@ -3380,6 +3380,19 @@ The Comparison Assertion Visualizer show
>    </properties>
>   </component>
>   
> +<component name="Backend Listener" index="&sect-num;.3.21"  width="777" height="266" screenshot="backend_listener.png">
> +<description>
> +The backend listener is an Asynchronous listener that enables you to plug custom implementations of <a href="../api/org/apache/jmeter/visualizers/backend/BackendListenerClient.html">BackendListenerClient</a>.
> +By default, a Graphite implementation is provided.
> +</description>
> + <properties>
> + <property name="Name" required="Yes">Descriptive name for this element that is shown in the tree.</property>
> + <property name="Backend Listener implementation" required="Yes">Class of the BackendListenerClient implementation.</property>
> + <property name="Async Queue size" required="Yes">Size of the queue that holds the SampleResults while they are processed asynchronously.</property>
> + <property name="Parameters" required="Yes">Parameters of the BackendListenerClient implementation.</property>
> + </properties>
> +</component>
> +
>   <a href="#">^</a>
>   
>   </section>
>
>

Regards
  Felix