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 01893101A9 for ; Sun, 30 Nov 2014 20:33:56 +0000 (UTC) Received: (qmail 82319 invoked by uid 500); 30 Nov 2014 20:33:55 -0000 Delivered-To: apmail-jmeter-dev-archive@jmeter.apache.org Received: (qmail 82291 invoked by uid 500); 30 Nov 2014 20:33:55 -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 82279 invoked by uid 99); 30 Nov 2014 20:33:55 -0000 Received: from nike.apache.org (HELO nike.apache.org) (192.87.106.230) by apache.org (qpsmtpd/0.29) with ESMTP; Sun, 30 Nov 2014 20:33:55 +0000 X-ASF-Spam-Status: No, hits=1.5 required=5.0 tests=HTML_MESSAGE,RCVD_IN_DNSWL_LOW,SPF_PASS X-Spam-Check-By: apache.org Received-SPF: pass (nike.apache.org: domain of philippe.mouawad@gmail.com designates 209.85.213.181 as permitted sender) Received: from [209.85.213.181] (HELO mail-ig0-f181.google.com) (209.85.213.181) by apache.org (qpsmtpd/0.29) with ESMTP; Sun, 30 Nov 2014 20:33:12 +0000 Received: by mail-ig0-f181.google.com with SMTP id l13so8408006iga.2 for ; Sun, 30 Nov 2014 12:32:01 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=mime-version:in-reply-to:references:date:message-id:subject:from:to :content-type; bh=F4ZkmS3BMWhPG6XjJDwoZCDHp1mqxJdlxy7s6PaVvJI=; b=bwQjVDzIRSS6Pofs76v53yhnRSn8HhtCZKyvbezL0ImVoZOw6kYtYgfXhvyg7Fn7HJ IsTUgqY1V/HuP8E6N2QpSLk1J1D8gBSI+PtNsma2ox28/2+WA9tRjeOr15E/MMLRaSt0 eaQfJAnig4Lu2wuHvROcG0GS0EHK1mMcLBVQyiox9AFtCvhJ/pqOpOSTYlZeYtXg0Q9W HDPMfLzRG8jx0gypo+o6MFOM7bvV5/F6lweUWf1NSvNmb6ylf6SKj2N/aEaYWu724tQ9 dK73VM07WBsfBJIjLbZSt0nYBhqTXfValM4z0aLVMOZVDkpldsnxYFUn74IhX4goWduw 0UhQ== MIME-Version: 1.0 X-Received: by 10.50.4.102 with SMTP id j6mr42590470igj.37.1417379520756; Sun, 30 Nov 2014 12:32:00 -0800 (PST) Received: by 10.42.22.198 with HTTP; Sun, 30 Nov 2014 12:32:00 -0800 (PST) In-Reply-To: References: <20141122153639.360D6238899C@eris.apache.org> <5470D42C.7090605@internetallee.de> <5471B8E8.3060706@internetallee.de> <1417258294.7281.15.camel@cat> Date: Sun, 30 Nov 2014 21:32:00 +0100 Message-ID: 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: Philippe Mouawad To: "dev@jmeter.apache.org" Content-Type: multipart/alternative; boundary=001a11c31f6ed8c3e70509196273 X-Virus-Checked: Checked by ClamAV on apache.org --001a11c31f6ed8c3e70509196273 Content-Type: text/plain; charset=ISO-8859-1 On Sun, Nov 30, 2014 at 10:19 AM, Felix Schumacher < felix.schumacher@internetallee.de> wrote: > > > Am 29. November 2014 21:12:00 MEZ, schrieb Philippe Mouawad < > philippe.mouawad@gmail.com>: > >Hi Felix > > > >My answer inline. > >Regards > > > >On Sat, Nov 29, 2014 at 11:51 AM, Felix Schumacher < > >felix.schumacher@internetallee.de> wrote: > > > >> Hello Philippe, > >> > >> Am Sonntag, den 23.11.2014, 12:22 +0100 schrieb Philippe Mouawad: > >> > Thanks a lot for your review which pointed to a synchronisation > >issue > >> that > >> > I fixed, good catch! > >> > > >> > I think I took all your notes into account, let me know if I forgot > >> > something. > >> in SamplerMetric you have used a sliding window for the statistics. > >> * Should we make the length of the window configurable? > >> > > > >Yes but it's a new property and we have a lot :-) > But the size of the window depends on the number of samples per time slot. > Perhaps it could be dynamically sized? > You mean it needs to be increased if there is a big number of requests in time slot for 1 sample ? Please clarfify so that I am sure to understand. For now I made it configurable through a property. > > > > > > >> * Should min/max and minThreads/maxThreads be limited to the sliding > >> window, also? At least min and max would be simple to do. > >> > > > >Dev team opinion is welcome, maybe it would be better > >- min would be percentile(0) > >- max would be percentile(100) > > The stats field has methods to get the minimum and the maximum values. I > would take those. > OK , done > > >for minThreads, maxThreads, how would you do it ? > > Create another statistical field for the number of threads. Then we could > provide correct answers for max/min thread numbers plus > mean/average/percentile. > > For this one, I don't see in fact the use case, as number of threads will not vary a lot so in what way do you think it is incorrect ? Maybe my question is stupid as I don't see currently the problem but I may be wrong. Can you clarify ? Thx > Regards > Felix > > > > > > >> Regards > >> Felix > >> > > >> > Regards > >> > Philippe > >> > > >> > On Sunday, November 23, 2014, Felix Schumacher < > >> > felix.schumacher@internetallee.de> wrote: > >> > > >> > > Hi Phillipe, > >> > > Am 22.11.2014 um 19:29 schrieb Philippe Mouawad: > >> > > > >> > >> Hi Felix, > >> > >> As I said in thread, I commited code and will improve, feel free > >to > >> fix > >> > >> javadocs issues on your side. > >> > >> I will review your comment. > >> > >> > >> > >> I have spent many hours if not days on this code and I am aware > >it is > >> not > >> > >> yet fully completed (although tests are promising) but my aim > >when > >> > >> commiting it was to have feedback and help to finish it. > >> > >> > >> > > I did not mean to offend you. I can clearly see, that you put a > >lot of > >> > > effort > >> > > in this listener and I will surely try to integrate jmeter into > >our > >> > > collectd server. > >> > > > >> > > Regards > >> > > Felix > >> > > > >> > >> > >> > >> Regards > >> > >> Philippe > >> > >> > >> > >> On Sat, Nov 22, 2014 at 7:21 PM, Felix Schumacher < > >> > >> felix.schumacher@internetallee.de> wrote: > >> > >> > >> > >> Hello Philippe, > >> > >>> > >> > >>> I have hidden a few comments inside the cited code. > >> > >>> They are mostly around javadoc and naming things. > >> > >>> > >> > >>> Am 22.11.2014 um 16:36 schrieb pmouawad@apache.org: > >> > >>> > >> > >>> Author: pmouawad > >> > >>>> Date: Sat Nov 22 15:36:37 2014 > >> > >>>> New Revision: 1641081 > >> > >>>> > >> > >>>> URL: http://svn.apache.org/r1641081 > >> > >>>> Log: > >> > >>>> Bug 55932 - Create a Async BackendListener to allow easy plug > >of new > >> > >>>> listener (Graphite, JDBC, Console,...) > >> > >>>> Bugzilla Id: 55932 > >> > >>>> > >> > >>>> Added: > >> > >>>> > >jmeter/trunk/src/components/org/apache/jmeter/visualizers/ > >> > >>>> backend/ > >> > >>>> > >jmeter/trunk/src/components/org/apache/jmeter/visualizers/ > >> > >>>> backend/ > >> > >>>> AbstractBackendListenerClient.java (with props) > >> > >>>> > >jmeter/trunk/src/components/org/apache/jmeter/visualizers/ > >> > >>>> backend/BackendListener.java > >> > >>>> (with props) > >> > >>>> > >jmeter/trunk/src/components/org/apache/jmeter/visualizers/ > >> > >>>> backend/BackendListenerClient.java (with props) > >> > >>>> > >jmeter/trunk/src/components/org/apache/jmeter/visualizers/ > >> > >>>> backend/BackendListenerContext.java > >> > >>>> (with props) > >> > >>>> > >jmeter/trunk/src/components/org/apache/jmeter/visualizers/ > >> > >>>> backend/BackendListenerGui.java (with props) > >> > >>>> > >jmeter/trunk/src/components/org/apache/jmeter/visualizers/ > >> > >>>> backend/SamplerMetric.java > >> > >>>> (with props) > >> > >>>> Modified: > >> > >>>> jmeter/trunk/bin/saveservice.properties > >> > >>>> jmeter/trunk/build.properties > >> > >>>> jmeter/trunk/build.xml > >> > >>>> jmeter/trunk/eclipse.classpath > >> > >>>> jmeter/trunk/res/maven/ApacheJMeter_parent.pom > >> > >>>> jmeter/trunk/src/core/org/apache/jmeter/resources/ > >> > >>>> messages.properties > >> > >>>> jmeter/trunk/src/core/org/apache/jmeter/resources/ > >> > >>>> messages_fr.properties > >> > >>>> jmeter/trunk/src/core/org/apache/jmeter/samplers/ > >> > >>>> SampleResult.java > >> > >>>> > >jmeter/trunk/src/core/org/apache/jmeter/save/SaveService.java > >> > >>>> jmeter/trunk/xdocs/changes.xml > >> > >>>> jmeter/trunk/xdocs/usermanual/component_reference.xml > >> > >>>> > >> > >>>> Modified: jmeter/trunk/bin/saveservice.properties > >> > >>>> URL: > >http://svn.apache.org/viewvc/jmeter/trunk/bin/saveservice. > >> > >>>> properties?rev=1641081&r1=1641080&r2=1641081&view=diff > >> > >>>> ============================================================ > >> > >>>> ================== > >> > >>>> --- jmeter/trunk/bin/saveservice.properties (original) > >> > >>>> +++ jmeter/trunk/bin/saveservice.properties Sat Nov 22 > >15:36:37 2014 > >> > >>>> @@ -53,7 +53,8 @@ _file_version=$Revision$ > >> > >>>> # 2.5 = 2.10 > >> > >>>> # 2.6 = 2.11 > >> > >>>> # 2.7 = 2.12 > >> > >>>> -_version=2.7 > >> > >>>> +# 2.8 = 2.13 > >> > >>>> +_version=2.8 > >> > >>>> # > >> > >>>> # > >> > >>>> # Character set encoding used to read and write JMeter XML > >files > >> and > >> > >>>> CSV results > >> > >>>> @@ -78,6 +79,8 @@ AssertionVisualizer=org.apache.jmeter.vi > >> > >>>> > >AuthManager=org.apache.jmeter.protocol.http.control.AuthManager > >> > >>>> > >> Authorization=org.apache.jmeter.protocol.http.control.Authorization > >> > >>>> AuthPanel=org.apache.jmeter.protocol.http.gui.AuthPanel > >> > >>>> > >> > >+BackendListener=org.apache.jmeter.visualizers.backend.BackendListener > >> > >>>> +BackendListenerGui=org.apache.jmeter.visualizers. > >> > >>>> backend.BackendListenerGui > >> > >>>> BarChart=org.apache.jmeter.testelement.BarChart > >> > >>>> BarChartGui=org.apache.jmeter.report.gui.BarChartGui > >> > >>>> > >> BeanShellAssertion=org.apache.jmeter.assertions.BeanShellAssertion > >> > >>>> > >> > >>>> Modified: jmeter/trunk/build.properties > >> > >>>> URL: > >http://svn.apache.org/viewvc/jmeter/trunk/build.properties? > >> > >>>> rev=1641081&r1=1641080&r2=1641081&view=diff > >> > >>>> ============================================================ > >> > >>>> ================== > >> > >>>> --- jmeter/trunk/build.properties (original) > >> > >>>> +++ jmeter/trunk/build.properties Sat Nov 22 15:36:37 2014 > >> > >>>> @@ -118,11 +118,21 @@ commons-logging.loc = ${maven2.r > >> > >>>> #commons-logging.md5 = > >E2C390FE739B2550A218262B28F290CE > >> > >>>> commons-logging.md5 = > >040b4b4d8eac886f6b4a2a3bd2f31b00 > >> > >>>> +commons-math3.version = 3.3 > >> > >>>> +commons-math3.jar = > >commons-math3-${commons-math3. > >> > >>>> version}.jar > >> > >>>> +commons-math3.loc = ${maven2.repo}/org/apache/ > >> > >>>> commons/commons-math3/${commons-math3.version} > >> > >>>> +commons-math3.md5 = > >87346cf2772dc2becf106c45e0f63863 > >> > >>>> + > >> > >>>> commons-net.version = 3.3 > >> > >>>> commons-net.jar = > >> commons-net-${commons-net.version}.jar > >> > >>>> commons-net.loc = ${maven2.repo}/commons-net/ > >> > >>>> commons-net/${commons-net.version} > >> > >>>> commons-net.md5 = > >c077ca61598e9c21f43f8b6488fbbee9 > >> > >>>> +commons-pool2.version = 2.2 > >> > >>>> +commons-pool2.jar = > >commons-pool2-${commons-pool2. > >> > >>>> version}.jar > >> > >>>> +commons-pool2.loc = ${maven2.repo}/org/apache/ > >> > >>>> commons/commons-pool2/${commons-pool2.version} > >> > >>>> +commons-pool2.md5 = > >51b56c92883812c56fbeb339866ce2df > >> > >>>> + > >> > >>>> # dnsjava for DNSCacheManager > >> > >>>> dnsjava.version = 2.1.6 > >> > >>>> dnsjava.jar = > >dnsjava-${dnsjava.version}.jar > >> > >>>> > >> > >>>> Modified: jmeter/trunk/build.xml > >> > >>>> URL: http://svn.apache.org/viewvc/jmeter/trunk/build.xml?rev= > >> > >>>> 1641081&r1=1641080&r2=1641081&view=diff > >> > >>>> ============================================================ > >> > >>>> ================== > >> > >>>> --- jmeter/trunk/build.xml (original) > >> > >>>> +++ jmeter/trunk/build.xml Sat Nov 22 15:36:37 2014 > >> > >>>> @@ -365,7 +365,9 @@ > >> > >>>> > >> > >>>> > >> > >>>> > >> > >>>> + > >> > >>>> > >> > >>>> + > >> > >>>> > >> > >>>> >name="${lib.dir}/${excalibur-datasource.jar}"/> > >> > >>>> >name="${lib.dir}/${excalibur-instrument.jar}"/> > >> > >>>> @@ -438,8 +440,10 @@ > >> > >>>> >location="${lib.dir}/${commons-jexl2.jar}"/> > >> > >>>> >location="${lib.dir}/${commons-lang3.jar}"/> > >> > >>>> >location="${lib.dir}/${commons-logging.jar}"/> > >> > >>>> + > >> > >>>> > >> > >>>> - > >> > >>>> + >location="${lib.dir}/${commons-pool2.jar}"/> > >> > >>>> + > >> > >>>> >> location="${lib.dir}/${excalibur-datasource.jar}"/> > >> > >>>> >> location="${lib.dir}/${excalibur-instrument.jar}"/> > >> > >>>> >location="${lib.dir}/${excalibur-logger.jar}"/> > >> > >>>> @@ -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 @@ > >> > >>>> >> path="lib/commons-jexl-2.1.1.jar"/> > >> > >>>> >path="lib/commons-lang3-3.3.2. > >> > >>>> jar"/> > >> > >>>> >path="lib/commons-logging-1.2. > >> > >>>> jar"/> > >> > >>>> + >path="lib/commons-math3-3.3.jar"/> > >> > >>>> >path="lib/commons-net-3.3.jar"/> > >> > >>>> + >path="lib/commons-pool2-2.2.jar"/> > >> > >>>> >path="lib/dnsjava-2.1.6.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. > >> > >>>> 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())); > >> > >>>> + > >> > >>>> + } > >> > >>>> + > >> > >>>> > >> > >>> > >> > > >> > >> > >> > > -- Cordialement. Philippe Mouawad. --001a11c31f6ed8c3e70509196273--