Return-Path: X-Original-To: apmail-jmeter-dev-archive@minotaur.apache.org Delivered-To: apmail-jmeter-dev-archive@minotaur.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id 1897410B5B for ; Sat, 29 Nov 2014 10:52:55 +0000 (UTC) Received: (qmail 63407 invoked by uid 500); 29 Nov 2014 10:52:54 -0000 Delivered-To: apmail-jmeter-dev-archive@jmeter.apache.org Received: (qmail 63371 invoked by uid 500); 29 Nov 2014 10:52:54 -0000 Mailing-List: contact dev-help@jmeter.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@jmeter.apache.org Delivered-To: mailing list dev@jmeter.apache.org Received: (qmail 63359 invoked by uid 99); 29 Nov 2014 10:52:53 -0000 Received: from nike.apache.org (HELO nike.apache.org) (192.87.106.230) by apache.org (qpsmtpd/0.29) with ESMTP; Sat, 29 Nov 2014 10:52:53 +0000 X-ASF-Spam-Status: No, hits=-0.0 required=5.0 tests=SPF_PASS X-Spam-Check-By: apache.org Received-SPF: pass (nike.apache.org: local policy) Received: from [81.169.162.220] (HELO h1611079.stratoserver.net) (81.169.162.220) by apache.org (qpsmtpd/0.29) with ESMTP; Sat, 29 Nov 2014 10:52:22 +0000 Received: by h1611079.stratoserver.net (Postfix, from userid 5001) id 74BE34AC822B; Sat, 29 Nov 2014 11:51:49 +0100 (CET) X-Spam-Checker-Version: SpamAssassin 3.3.2 (2011-06-06) on h1611079.stratoserver.net X-Spam-Level: Received: from [192.168.178.41] (dslb-088-076-016-227.088.076.pools.vodafone-ip.de [88.76.16.227]) (using TLSv1.2 with cipher DHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by h1611079.stratoserver.net (Postfix) with ESMTPSA id 86FC0494803D for ; Sat, 29 Nov 2014 11:51:35 +0100 (CET) Message-ID: <1417258294.7281.15.camel@cat> 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/ From: Felix Schumacher To: dev@jmeter.apache.org Date: Sat, 29 Nov 2014 11:51:34 +0100 In-Reply-To: References: <20141122153639.360D6238899C@eris.apache.org> <5470D42C.7090605@internetallee.de> <5471B8E8.3060706@internetallee.de> Content-Type: text/plain; charset="ISO-8859-15" X-Mailer: Evolution 3.10.4-0ubuntu2 Mime-Version: 1.0 Content-Transfer-Encoding: 7bit X-Virus-Checked: Checked by ClamAV on apache.org X-Old-Spam-Status: No, score=-2.9 required=5.0 tests=ALL_TRUSTED,BAYES_00 autolearn=ham version=3.3.2 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 @@ > >>>> > >>>> > >>>> > >>>> + > >>>> > >>>> + > >>>> > >>>> > >>>> > >>>> @@ -438,8 +440,10 @@ > >>>> > >>>> > >>>> > >>>> + > >>>> > >>>> - > >>>> + > >>>> + > >>>> > >>>> > >>>> > >>>> @@ -2909,7 +2913,9 @@ run JMeter unless all the JMeter jars ar > >>>> > >>>> > >>>> > >>>> + > >>>> > >>>> + > >>>> > >>>> > >>>> > >>>> > >>>> 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 @@ > >>>> > >>>> > >>>> > >>>> + > >>>> > >>>> + > >>>> > >>>> > >>>> > >>>> > >>>> 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. > >>>> 2.1.1 > >>>> 3.3.2 > >>>> 1.2 > >>>> + 3.3 > >>>> 3.3 > >>>> + 2.2 > >>>> 2.1.6 > >>>> 2.1 >>>> version> > >>>> 1.0 >>>> version> > >>>> @@ -181,11 +183,21 @@ under the License. > >>>> ${commons-logging.version} > >>>> > >>>> > >>>> + commons-math3 > >>>> + commons-math3 > >>>> + ${commons-math3.version} > >>>> + > >>>> + > >>>> commons-net > >>>> commons-net > >>>> ${commons-net.version} > >>>> > >>>> > >>>> + commons-pool2 > >>>> + commons-pool2 > >>>> + ${commons-pool2.version} > >>>> + > >>>> + > >>>> dnsjava > >>>> dnsjava > >>>> ${dnsjava.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). > >>>> + *

> >>>> + * 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 metricsPerSampler > >>>> = > >>>> new ConcurrentHashMap(); > >>>> + > >>>> + /* 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 > >>>> > >>>> 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 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 TEAR_DOWN_SET = new > >>>> HashSet(); > >>>> + > >>>> + /** > >>>> + * 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 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(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 queue; > >>>> + private final BackendListenerContext context; > >>>> + private final BackendListenerClient backendListenerClient; > >>>> + private Worker(Class javaClass, BackendListenerClient > >>>> backendListenerClient, Arguments arguments, BlockingQueue > >>>> 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 l = new ArrayList(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 BackendListenerClient. > >>>> > >>>> 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 > >>>> 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). > >>>> + *

> >>>> + * 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). > >>>> + *

> >>>> + * 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. > >>>> + *

> >>>> + * 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. > >>>> + *

> >>>> + * 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 > >>>> + * SampleResult object. SampleResult has > >>>> many > >>>> + * fields which can be used. At a minimum, the test should use > >>>> + * SampleResult.sampleStart and > >>>> + * SampleResult.sampleEndto set the time that the > >>>> test > >>>> > >>>> use {@link..} instead of ..? > >>> > >>> + * 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 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 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 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 BackendListenerGui 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 possibleClasses = new ArrayList(); > >>>> + > >>>> + 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 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 set = new HashSet(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())); > >>>> + > >>>> + } > >>>> + > >>>> > >>> >