jmeter-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Felix Schumacher <felix.schumac...@internetallee.de>
Subject 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/
Date Sat, 29 Nov 2014 10:51:34 GMT
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()));
> >>>> +
> >>>> +    }
> >>>> +
> >>>>
> >>>
> 



Mime
View raw message