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 BDCFC17767 for ; Sun, 23 Nov 2014 10:38:02 +0000 (UTC) Received: (qmail 33304 invoked by uid 500); 23 Nov 2014 10:38:02 -0000 Delivered-To: apmail-jmeter-dev-archive@jmeter.apache.org Received: (qmail 33282 invoked by uid 500); 23 Nov 2014 10:38:02 -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 33269 invoked by uid 99); 23 Nov 2014 10:38:01 -0000 Received: from nike.apache.org (HELO nike.apache.org) (192.87.106.230) by apache.org (qpsmtpd/0.29) with ESMTP; Sun, 23 Nov 2014 10:38:01 +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; Sun, 23 Nov 2014 10:37:31 +0000 Received: from [192.168.178.43] (dslb-188-109-035-015.188.109.pools.vodafone-ip.de [188.109.35.15]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by h1611079.stratoserver.net (Postfix) with ESMTPSA id 057AF4948036 for ; Sun, 23 Nov 2014 11:37:28 +0100 (CET) Message-ID: <5471B8E8.3060706@internetallee.de> Date: Sun, 23 Nov 2014 11:37:28 +0100 From: Felix Schumacher User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:31.0) Gecko/20100101 Thunderbird/31.2.0 MIME-Version: 1.0 To: dev@jmeter.apache.org 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/ References: <20141122153639.360D6238899C@eris.apache.org> <5470D42C.7090605@internetallee.de> In-Reply-To: Content-Type: text/plain; charset=windows-1252; format=flowed Content-Transfer-Encoding: 7bit X-Virus-Checked: Checked by ClamAV on apache.org 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 >>> 1.0 >>> @@ -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 createBackendListenerClientImpl(Class >>> javaClass) { >>> + if (javaClass == null) { // failed to initialise the class >>> + return new ErrorBackendListenerClient(); >>> + } >>> + BackendListenerClient client; >>> + try { >>> + client = (BackendListenerClient) javaClass.newInstance(); >>> + } catch (Exception e) { >>> + log.error("Exception creating: " + javaClass, e); >>> + client = new ErrorBackendListenerClient(); >>> + } >>> + return client; >>> >> I would return newInstance() in try Block and return new Error.. in catch >> Block. javaClass -> clientClass >> >>> + } >>> + >>> + /** >>> + * Method called at the end of the test. This is called only on one >>> instance >>> + * of BackendListener. This method will loop through all of the other >>> + * BackendListenerClients which have been registered (automatically >>> in the >>> + * constructor) and notify them that the test has ended, allowing the >>> + * BackendListenerClients to cleanup. >>> + */ >>> + @Override >>> + public void testEnded() { >>> + try { >>> + queue.put(FINAL_EVENT); >>> + } catch (Exception ex) { >>> + log.warn("testEnded() with exception:"+ex.getMessage(), ex); >>> + } >>> + if (queueWaits > 0) { >>> + log.warn("QueueWaits: "+queueWaits+"; QueueWaitTime: >>> "+queueWaitTime+" (nanoseconds), you may need to increase queue capacity, >>> see property 'backend_queue_capacity'"); >>> + } >>> + synchronized (TEAR_DOWN_SET) { >>> + for (BackendListener backendListener : TEAR_DOWN_SET) { >>> + BackendListenerClient client = backendListener. >>> backendListenerClient; >>> + if (client != null) { >>> + try { >>> + client.teardownTest(backendListener.context); >>> + } catch (Exception e) { >>> + throw new java.lang.IllegalStateException("Failed >>> calling teardownTest", e); >>> >> If we throw an exception here, we will not try every client. >> >>> + } >>> + } >>> + } >>> + TEAR_DOWN_SET.clear(); >>> + } >>> + } >>> + >>> + /* Implements TestStateListener.testEnded(String) */ >>> + @Override >>> + public void testEnded(String host) { >>> + testEnded(); >>> + } >>> + >>> + /** >>> + * A {@link BackendListenerClient} implementation used for error >>> handling. If an >>> + * error occurs while creating the real BackendListenerClient >>> object, it is >>> + * replaced with an instance of this class. Each time a sample >>> occurs with >>> + * this class, the result is marked as a failure so the user can see >>> that >>> + * the test failed. >>> + */ >>> + static class ErrorBackendListenerClient extends >>> AbstractBackendListenerClient { >>> + /** >>> + * Return SampleResult with data on error. >>> + * >>> + * @see BackendListenerClient#runTest(JavaSamplerContext) >>> + */ >>> + @Override >>> + public void handleSampleResults(List >>> 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())); >>> + >>> + } >>> + >>> + /* (non-Javadoc) >>> + * @see org.apache.jmeter.gui.AbstractJMeterGuiComponent#clearGui() >>> + */ >>> + @Override >>> + public void clearGui() { >>> + super.clearGui(); >>> + argsPanel.clearGui(); >>> + classnameCombo.setSelectedIndex(0); >>> + queueSize.setText(""); >>> + } >>> +} >>> >>> Propchange: jmeter/trunk/src/components/org/apache/jmeter/visualizers/ >>> backend/BackendListenerGui.java >>> ------------------------------------------------------------ >>> ------------------ >>> svn:mime-type = text/plain >>> >>> Added: jmeter/trunk/src/components/org/apache/jmeter/visualizers/ >>> backend/SamplerMetric.java >>> URL: http://svn.apache.org/viewvc/jmeter/trunk/src/components/ >>> org/apache/jmeter/visualizers/backend/SamplerMetric.java? >>> rev=1641081&view=auto >>> ============================================================ >>> ================== >>> --- jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/SamplerMetric.java >>> (added) >>> +++ jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/SamplerMetric.java >>> Sat Nov 22 15:36:37 2014 >>> @@ -0,0 +1,138 @@ >>> +/* >>> + * Licensed to the Apache Software Foundation (ASF) under one or more >>> + * contributor license agreements. See the NOTICE file distributed with >>> + * this work for additional information regarding copyright ownership. >>> + * The ASF licenses this file to You under the Apache License, Version >>> 2.0 >>> + * (the "License"); you may not use this file except in compliance with >>> + * the License. You may obtain a copy of the License at >>> + * >>> + * http://www.apache.org/licenses/LICENSE-2.0 >>> + * >>> + * Unless required by applicable law or agreed to in writing, software >>> + * distributed under the License is distributed on an "AS IS" BASIS, >>> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or >>> implied. >>> + * See the License for the specific language governing permissions and >>> + * limitations under the License. >>> + * >>> + */ >>> + >>> +package org.apache.jmeter.visualizers.backend; >>> + >>> +import org.apache.commons.math3.stat.descriptive.DescriptiveStatistics; >>> +import org.apache.jmeter.samplers.SampleResult; >>> + >>> +/** >>> + * Sampler metric >>> + * @since 2.13 >>> + */ >>> +public class SamplerMetric { >>> + // Limit to sliding window of 100 values >>> + private DescriptiveStatistics stats = new DescriptiveStatistics(100); >>> + private int success; >> >