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