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