diff --git a/backend/pom.xml b/backend/pom.xml index 1bed72227a..b4d37b6d32 100644 --- a/backend/pom.xml +++ b/backend/pom.xml @@ -150,10 +150,6 @@ org.apache.logging.log4j log4j-slf4j-impl - - org.apache-extras.beanshell - bsh - @@ -520,15 +516,6 @@ src/main/resources/jmeter/lib/ext jython-standalone.jar - - org.apache-extras.beanshell - bsh - 2.0b6 - jar - true - src/main/resources/jmeter/lib/ext - bsh-2.0b6.jar - ${project.build.directory}/wars false diff --git a/backend/src/main/java/io/metersphere/api/jmeter/JMeterService.java b/backend/src/main/java/io/metersphere/api/jmeter/JMeterService.java index fa8d36d982..220d4c7e25 100644 --- a/backend/src/main/java/io/metersphere/api/jmeter/JMeterService.java +++ b/backend/src/main/java/io/metersphere/api/jmeter/JMeterService.java @@ -6,13 +6,11 @@ import io.metersphere.commons.utils.LogUtil; import io.metersphere.config.JmeterProperties; import io.metersphere.i18n.Translator; import org.apache.commons.lang3.StringUtils; -import org.apache.jmeter.NewDriver; import org.apache.jmeter.config.Arguments; import org.apache.jmeter.save.SaveService; import org.apache.jmeter.util.JMeterUtils; import org.apache.jmeter.visualizers.backend.BackendListener; import org.apache.jorphan.collections.HashTree; - import org.springframework.context.i18n.LocaleContextHolder; import org.springframework.stereotype.Service; @@ -30,10 +28,6 @@ public class JMeterService { public void run(String testId, String debugReportId, InputStream is) { String JMETER_HOME = getJmeterHome(); - // 将当前类加载器设置为 loader ,解决由系统类加载器加载的 JMeter 无法动态加载 jar 包问题 - // 同时隔离在 beanshell 中访问由系统类加载器加载的其他类 - NewDriver.setContextClassLoader(); - String JMETER_PROPERTIES = JMETER_HOME + "/bin/jmeter.properties"; JMeterUtils.loadJMeterProperties(JMETER_PROPERTIES); JMeterUtils.setJMeterHome(JMETER_HOME); diff --git a/backend/src/main/java/org/apache/jmeter/NewDriver.java b/backend/src/main/java/org/apache/jmeter/NewDriver.java index 3ec3df97f8..b834a9b9d6 100644 --- a/backend/src/main/java/org/apache/jmeter/NewDriver.java +++ b/backend/src/main/java/org/apache/jmeter/NewDriver.java @@ -19,7 +19,6 @@ package org.apache.jmeter; import java.io.File; -import java.io.IOException; import java.io.PrintWriter; import java.io.StringWriter; import java.lang.reflect.Method; @@ -28,12 +27,7 @@ import java.net.URL; import java.security.AccessController; import java.security.PrivilegedAction; import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Date; -import java.util.LinkedList; -import java.util.List; -import java.util.StringTokenizer; +import java.util.*; /** * Main class for JMeter - sets up initial classpath and the loader. @@ -65,6 +59,14 @@ public final class NewDriver { Thread.currentThread().setContextClassLoader(loader); } + public static void loaderClass(String name) { + try { + loader.loadClass(name); + } catch (ClassNotFoundException e) { + e.printStackTrace(); + } + } + static { final List jars = new LinkedList<>(); final String initiaClasspath = System.getProperty(JAVA_CLASS_PATH); @@ -72,28 +74,13 @@ public final class NewDriver { // Find JMeter home dir from the initial classpath String tmpDir; -// StringTokenizer tok = new StringTokenizer(initiaClasspath, File.pathSeparator); -// if (tok.countTokens() == 1 -// || (tok.countTokens() == 2 // Java on Mac OS can add a second entry to the initial classpath -// && OS_NAME_LC.startsWith("mac os x")// $NON-NLS-1$ -// ) -// ) { -// File jar = new File(tok.nextToken()); -// try { -// tmpDir = jar.getCanonicalFile().getParentFile().getParent(); -// System.out.println(tmpDir + "111"); -// } catch (IOException e) { -// tmpDir = null; -// } -// } else {// e.g. started from IDE with full classpath + //只从 jmeter.home 加载 + tmpDir = System.getProperty("jmeter.home","");// Allow override $NON-NLS-1$ $NON-NLS-2$ + if (tmpDir.length() == 0) { + File userDir = new File(System.getProperty("user.dir"));// $NON-NLS-1$ + tmpDir = userDir.getAbsoluteFile().getParent(); + } - //只从 jmeter.home 加载 - tmpDir = System.getProperty("jmeter.home","");// Allow override $NON-NLS-1$ $NON-NLS-2$ - if (tmpDir.length() == 0) { - File userDir = new File(System.getProperty("user.dir"));// $NON-NLS-1$ - tmpDir = userDir.getAbsoluteFile().getParent(); - } -// } JMETER_INSTALLATION_DIRECTORY=tmpDir; /* diff --git a/backend/src/main/java/org/apache/jmeter/util/JSR223TestElement.java b/backend/src/main/java/org/apache/jmeter/util/JSR223TestElement.java new file mode 100644 index 0000000000..9f70de2d49 --- /dev/null +++ b/backend/src/main/java/org/apache/jmeter/util/JSR223TestElement.java @@ -0,0 +1,354 @@ +/* + * 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.util; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import java.io.Serializable; +import java.util.Collections; +import java.util.Map; +import java.util.Properties; + +import javax.script.Bindings; +import javax.script.Compilable; +import javax.script.CompiledScript; +import javax.script.ScriptEngine; +import javax.script.ScriptEngineManager; +import javax.script.ScriptException; + +import org.apache.commons.codec.digest.DigestUtils; +import org.apache.commons.collections.map.LRUMap; +import org.apache.commons.lang3.StringUtils; +import org.apache.jmeter.NewDriver; +import org.apache.jmeter.samplers.SampleResult; +import org.apache.jmeter.samplers.Sampler; +import org.apache.jmeter.testelement.TestStateListener; +import org.apache.jmeter.threads.JMeterContext; +import org.apache.jmeter.threads.JMeterContextService; +import org.apache.jmeter.threads.JMeterVariables; +import org.apache.jorphan.util.JOrphanUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Base class for JSR223 Test elements + * + * 将当前类加载器设置为 loader ,解决由系统类加载器加载的 JMeter 无法动态加载 jar 包问题 + * 同时隔离在 beanshell 中访问由系统类加载器加载的其他类 + */ +public abstract class JSR223TestElement extends ScriptingTestElement + implements Serializable, TestStateListener +{ + private static final long serialVersionUID = 232L; + + private static final Logger logger = LoggerFactory.getLogger(JSR223TestElement.class); + /** + * Cache of compiled scripts + */ + @SuppressWarnings("unchecked") // LRUMap does not support generics (yet) + private static final Map compiledScriptsCache = + Collections.synchronizedMap( + new LRUMap(JMeterUtils.getPropDefault("jsr223.compiled_scripts_cache_size", 100))); + + /** If not empty then script in ScriptText will be compiled and cached */ + private String cacheKey = ""; + + /** md5 of the script, used as an unique key for the cache */ + private String scriptMd5 = null; + + /** + * Initialization On Demand Holder pattern + */ + private static class LazyHolder { + private LazyHolder() { + super(); + } + public static final ScriptEngineManager INSTANCE = new ScriptEngineManager(); + } + + /** + * @return ScriptEngineManager singleton + */ + public static ScriptEngineManager getInstance() { + return LazyHolder.INSTANCE; + } + + public JSR223TestElement() { + super(); + } + + /** + * @return {@link ScriptEngine} for language defaulting to groovy if language is not set + * @throws ScriptException when no {@link ScriptEngine} could be found + */ + protected ScriptEngine getScriptEngine() throws ScriptException { + String lang = getScriptLanguageWithDefault(); + ScriptEngine scriptEngine = getInstance().getEngineByName(lang); + if (scriptEngine == null) { + throw new ScriptException("Cannot find engine named: '"+lang+"', ensure you set language field in JSR223 Test Element: "+getName()); + } + + return scriptEngine; + } + + /** + * @return script language or DEFAULT_SCRIPT_LANGUAGE if none is set + */ + private String getScriptLanguageWithDefault() { + String lang = getScriptLanguage(); + if (StringUtils.isNotEmpty(lang)) { + return lang; + } + return DEFAULT_SCRIPT_LANGUAGE; + } + + /** + * Populate variables to be passed to scripts + * @param bindings Bindings + */ + protected void populateBindings(Bindings bindings) { + final String label = getName(); + final String fileName = getFilename(); + final String scriptParameters = getParameters(); + // Use actual class name for log + final Logger elementLogger = LoggerFactory.getLogger(getClass().getName()+"."+getName()); + bindings.put("log", elementLogger); // $NON-NLS-1$ (this name is fixed) + bindings.put("Label", label); // $NON-NLS-1$ (this name is fixed) + bindings.put("FileName", fileName); // $NON-NLS-1$ (this name is fixed) + bindings.put("Parameters", scriptParameters); // $NON-NLS-1$ (this name is fixed) + String[] args=JOrphanUtils.split(scriptParameters, " ");//$NON-NLS-1$ + bindings.put("args", args); // $NON-NLS-1$ (this name is fixed) + // Add variables for access to context and variables + JMeterContext jmctx = JMeterContextService.getContext(); + bindings.put("ctx", jmctx); // $NON-NLS-1$ (this name is fixed) + JMeterVariables vars = jmctx.getVariables(); + bindings.put("vars", vars); // $NON-NLS-1$ (this name is fixed) + Properties props = JMeterUtils.getJMeterProperties(); + bindings.put("props", props); // $NON-NLS-1$ (this name is fixed) + // For use in debugging: + bindings.put("OUT", System.out); // NOSONAR $NON-NLS-1$ (this name is fixed) + + // Most subclasses will need these: + Sampler sampler = jmctx.getCurrentSampler(); + bindings.put("sampler", sampler); // $NON-NLS-1$ (this name is fixed) + SampleResult prev = jmctx.getPreviousResult(); + bindings.put("prev", prev); // $NON-NLS-1$ (this name is fixed) + } + + + /** + * This method will run inline script or file script with special behaviour for file script: + * - If ScriptEngine implements Compilable script will be compiled and cached + * - If not if will be run + * @param scriptEngine ScriptEngine + * @param pBindings {@link Bindings} might be null + * @return Object returned by script + * @throws IOException when reading the script fails + * @throws ScriptException when compiling or evaluation of the script fails + */ + protected Object processFileOrScript(ScriptEngine scriptEngine, final Bindings pBindings) + throws IOException, ScriptException { + Bindings bindings = pBindings; + if (bindings == null) { + bindings = scriptEngine.createBindings(); + } + populateBindings(bindings); + File scriptFile = new File(getFilename()); + // Hack: bsh-2.0b5.jar BshScriptEngine implements Compilable but throws + // "java.lang.Error: unimplemented" + boolean supportsCompilable = scriptEngine instanceof Compilable + && !("bsh.engine.BshScriptEngine".equals(scriptEngine.getClass().getName())); // NOSONAR // $NON-NLS-1$ + + ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader(); + // 将当前类加载器设置为 loader ,解决由系统类加载器加载的 JMeter 无法动态加载 jar 包问题 + // 同时隔离在 beanshell 中访问由系统类加载器加载的其他类 + NewDriver.setContextClassLoader(); + + try { + if (!StringUtils.isEmpty(getFilename())) { + if (scriptFile.exists() && scriptFile.canRead()) { + if (supportsCompilable) { + String newCacheKey = getScriptLanguage() + "#" + // $NON-NLS-1$ + scriptFile.getAbsolutePath() + "#" + // $NON-NLS-1$ + scriptFile.lastModified(); + CompiledScript compiledScript = compiledScriptsCache.get(newCacheKey); + if (compiledScript == null) { + synchronized (compiledScriptsCache) { + compiledScript = compiledScriptsCache.get(newCacheKey); + if (compiledScript == null) { + // TODO Charset ? + try (BufferedReader fileReader = new BufferedReader(new FileReader(scriptFile), + (int) scriptFile.length())) { + compiledScript = ((Compilable) scriptEngine).compile(fileReader); + compiledScriptsCache.put(newCacheKey, compiledScript); + } + } + } + } + return compiledScript.eval(bindings); + } else { + // TODO Charset ? + try (BufferedReader fileReader = new BufferedReader(new FileReader(scriptFile), + (int) scriptFile.length())) { + return scriptEngine.eval(fileReader, bindings); + } + } + } else { + throw new ScriptException("Script file '" + scriptFile.getAbsolutePath() + + "' does not exist or is unreadable for element:" + getName()); + } + } else if (!StringUtils.isEmpty(getScript())) { + if (supportsCompilable && + !ScriptingBeanInfoSupport.FALSE_AS_STRING.equals(cacheKey)) { + computeScriptMD5(); + CompiledScript compiledScript = compiledScriptsCache.get(this.scriptMd5); + if (compiledScript == null) { + synchronized (compiledScriptsCache) { + compiledScript = compiledScriptsCache.get(this.scriptMd5); + if (compiledScript == null) { + compiledScript = ((Compilable) scriptEngine).compile(getScript()); + compiledScriptsCache.put(this.scriptMd5, compiledScript); + } + } + } + + return compiledScript.eval(bindings); + } else { + return scriptEngine.eval(getScript(), bindings); + } + } else { + throw new ScriptException("Both script file and script text are empty for element:" + getName()); + } + } catch (ScriptException ex) { + Throwable rootCause = ex.getCause(); + if(isStopCondition(rootCause)) { + throw (RuntimeException) ex.getCause(); + } else { + throw ex; + } + } finally { + // 将当前类加载器设置回来,避免加载无法加载到系统类加载加载类 + Thread.currentThread().setContextClassLoader(contextClassLoader); + } + } + + /** + * @return boolean true if element is not compilable or if compilation succeeds + * @throws IOException if script is missing + * @throws ScriptException if compilation fails + */ + public boolean compile() + throws ScriptException, IOException { + String lang = getScriptLanguageWithDefault(); + ScriptEngine scriptEngine = getInstance().getEngineByName(lang); + boolean supportsCompilable = scriptEngine instanceof Compilable + && !("bsh.engine.BshScriptEngine".equals(scriptEngine.getClass().getName())); // NOSONAR // $NON-NLS-1$ + if(!supportsCompilable) { + return true; + } + if (!StringUtils.isEmpty(getScript())) { + try { + ((Compilable) scriptEngine).compile(getScript()); + return true; + } catch (ScriptException e) { // NOSONAR + logger.error("Error compiling script for test element {}, error:{}", getName(), e.getMessage()); + return false; + } + } else { + File scriptFile = new File(getFilename()); + try (BufferedReader fileReader = new BufferedReader(new FileReader(scriptFile), + (int) scriptFile.length())) { + try { + ((Compilable) scriptEngine).compile(fileReader); + return true; + } catch (ScriptException e) { // NOSONAR + logger.error("Error compiling script for test element {}, error:{}", getName(), e.getMessage()); + return false; + } + } + } + } + + /** + * compute MD5 if it is null + */ + private void computeScriptMD5() { + // compute the md5 of the script if needed + if(scriptMd5 == null) { + scriptMd5 = DigestUtils.md5Hex(getScript()); + } + } + + /** + * @return the cacheKey + */ + public String getCacheKey() { + return cacheKey; + } + + /** + * @param cacheKey the cacheKey to set + */ + public void setCacheKey(String cacheKey) { + this.cacheKey = cacheKey; + } + + /** + * @see org.apache.jmeter.testelement.TestStateListener#testStarted() + */ + @Override + public void testStarted() { + // NOOP + } + + /** + * @see org.apache.jmeter.testelement.TestStateListener#testStarted(java.lang.String) + */ + @Override + public void testStarted(String host) { + // NOOP + } + + /** + * @see org.apache.jmeter.testelement.TestStateListener#testEnded() + */ + @Override + public void testEnded() { + testEnded(""); + } + + /** + * @see org.apache.jmeter.testelement.TestStateListener#testEnded(java.lang.String) + */ + @Override + public void testEnded(String host) { + compiledScriptsCache.clear(); + this.scriptMd5 = null; + } + + public String getScriptLanguage() { + return scriptLanguage; + } + + public void setScriptLanguage(String s) { + scriptLanguage = s; + } +} \ No newline at end of file diff --git a/backend/src/main/java/org/apache/jmeter/visualizers.backend/BackendListener.java b/backend/src/main/java/org/apache/jmeter/visualizers.backend/BackendListener.java deleted file mode 100644 index ad32e82415..0000000000 --- a/backend/src/main/java/org/apache/jmeter/visualizers.backend/BackendListener.java +++ /dev/null @@ -1,334 +0,0 @@ -// -// Source code recreated from a .class file by IntelliJ IDEA -// (powered by Fernflower decompiler) -// - -package org.apache.jmeter.visualizers.backend; - -import java.io.Serializable; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.concurrent.ArrayBlockingQueue; -import java.util.concurrent.BlockingQueue; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.atomic.LongAdder; -import java.util.concurrent.locks.LockSupport; -import org.apache.jmeter.config.Arguments; -import org.apache.jmeter.engine.util.NoThreadClone; -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.TestStateListener; -import org.apache.jmeter.testelement.property.TestElementProperty; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -// 当前上下文类加载为 NewDriver 的类加载器,这里使用系统类加载器加载 APIBackendListenerClient - -public class BackendListener extends AbstractTestElement implements Backend, Serializable, SampleListener, TestStateListener, NoThreadClone, Remoteable { - private static final long serialVersionUID = 1L; - private static final Logger log = LoggerFactory.getLogger(BackendListener.class); - public static final String CLASSNAME = "classname"; - public static final String QUEUE_SIZE = "QUEUE_SIZE"; - private static final Object LOCK = new Object(); - public static final String ARGUMENTS = "arguments"; - private Class clientClass; - public static final String DEFAULT_QUEUE_SIZE = "5000"; - private static final transient SampleResult FINAL_SAMPLE_RESULT = new SampleResult(); - private static final Map queuesByTestElementName = new ConcurrentHashMap(); - private transient String myName; - private transient BackendListener.ListenerClientData listenerClientData; - - public BackendListener() { - this.setArguments(new Arguments()); - } - - public Object clone() { - BackendListener clone = (BackendListener)super.clone(); - clone.clientClass = this.clientClass; - return clone; - } - - private Class initClass() { - String name = this.getClassname().trim(); - - try { - // 当前上下文类加载为 NewDriver 的类加载器,这里使用系统类加载器加载 APIBackendListenerClient - return Class.forName(name, false, this.getClass().getClassLoader()); - } catch (Exception var3) { - log.error("{}\tException initialising: {}", new Object[]{this.whoAmI(), name, var3}); - return null; - } - } - - private String whoAmI() { - return Thread.currentThread().getName() + "@" + Integer.toHexString(this.hashCode()) + "-" + this.getName(); - } - - public void sampleOccurred(SampleEvent event) { - Arguments args = this.getArguments(); - BackendListenerContext context = new BackendListenerContext(args); - SampleResult sr = this.listenerClientData.client.createSampleResult(context, event.getResult()); - if (sr == null) { - if (log.isDebugEnabled()) { - log.debug("{} => Dropping SampleResult: {}", this.getName(), event.getResult()); - } - - } else { - try { - if (!this.listenerClientData.queue.offer(sr)) { - this.listenerClientData.queueWaits.add(1L); - long t1 = System.nanoTime(); - this.listenerClientData.queue.put(sr); - long t2 = System.nanoTime(); - this.listenerClientData.queueWaitTime.add(t2 - t1); - } - } catch (Exception var9) { - log.error("sampleOccurred, failed to queue the sample", var9); - } - - } - } - - private static void sendToListener(BackendListenerClient backendListenerClient, BackendListenerContext context, List sampleResults) { - if (!sampleResults.isEmpty()) { - backendListenerClient.handleSampleResults(sampleResults, context); - sampleResults.clear(); - } - - } - - private static BackendListenerClient createBackendListenerClientImpl(Class clientClass) { - if (clientClass == null) { - return new BackendListener.ErrorBackendListenerClient(); - } else { - try { - return (BackendListenerClient)clientClass.getDeclaredConstructor().newInstance(); - } catch (Exception var2) { - log.error("Exception creating: {}", clientClass, var2); - return new BackendListener.ErrorBackendListenerClient(); - } - } - } - - public void testStarted() { - this.testStarted("local"); - } - - public void testStarted(String host) { - if (log.isDebugEnabled()) { - log.debug("{}\ttestStarted({})", this.whoAmI(), host); - } - - String size = this.getQueueSize(); - - int queueSize; - try { - queueSize = Integer.parseInt(size); - } catch (NumberFormatException var12) { - log.warn("Invalid queue size '{}' defaulting to {}", size, "5000"); - queueSize = Integer.parseInt("5000"); - } - - Object var4 = LOCK; - synchronized(LOCK) { - this.myName = this.getName(); - this.listenerClientData = (BackendListener.ListenerClientData)queuesByTestElementName.get(this.myName); - if (this.listenerClientData == null) { - this.clientClass = this.initClass(); - BackendListenerClient backendListenerClient = createBackendListenerClientImpl(this.clientClass); - BackendListenerContext context = new BackendListenerContext((Arguments)this.getArguments().clone()); - this.listenerClientData = new BackendListener.ListenerClientData(); - this.listenerClientData.queue = new ArrayBlockingQueue(queueSize); - this.listenerClientData.queueWaits = new LongAdder(); - this.listenerClientData.queueWaitTime = new LongAdder(); - this.listenerClientData.latch = new CountDownLatch(1); - this.listenerClientData.client = backendListenerClient; - if (log.isInfoEnabled()) { - log.info("{}: Starting worker with class: {} and queue capacity: {}", new Object[]{this.getName(), this.clientClass, this.getQueueSize()}); - } - - BackendListener.Worker worker = new BackendListener.Worker(backendListenerClient, (Arguments)this.getArguments().clone(), this.listenerClientData); - worker.setDaemon(true); - worker.start(); - if (log.isInfoEnabled()) { - log.info("{}: Started worker with class: {}", this.getName(), this.clientClass); - } - - try { - backendListenerClient.setupTest(context); - } catch (Exception var10) { - throw new IllegalStateException("Failed calling setupTest", var10); - } - - queuesByTestElementName.put(this.myName, this.listenerClientData); - } - - this.listenerClientData.instanceCount++; - } - } - - public void testEnded(String host) { - Object var2 = LOCK; - synchronized(LOCK) { - BackendListener.ListenerClientData listenerClientDataForName = (BackendListener.ListenerClientData)queuesByTestElementName.get(this.myName); - if (log.isDebugEnabled()) { - log.debug("testEnded called on instance {}#{}", this.myName, listenerClientDataForName.instanceCount); - } - - if (listenerClientDataForName != null) { - listenerClientDataForName.instanceCount--; - if (listenerClientDataForName.instanceCount > 0) { - return; - } - - queuesByTestElementName.remove(this.myName); - } else { - log.error("No listener client data found for BackendListener {}", this.myName); - } - } - - try { - this.listenerClientData.queue.put(FINAL_SAMPLE_RESULT); - } catch (Exception var6) { - log.warn("testEnded() with exception: {}", var6.getMessage(), var6); - } - - if (this.listenerClientData.queueWaits.longValue() > 0L) { - log.warn("QueueWaits: {}; QueueWaitTime: {} (nanoseconds), you may need to increase queue capacity, see property 'backend_queue_capacity'", this.listenerClientData.queueWaits, this.listenerClientData.queueWaitTime); - } - - try { - this.listenerClientData.latch.await(); - BackendListenerContext context = new BackendListenerContext(this.getArguments()); - this.listenerClientData.client.teardownTest(context); - } catch (Exception var5) { - throw new IllegalStateException("Failed calling teardownTest", var5); - } - } - - public void testEnded() { - this.testEnded("local"); - } - - public void sampleStarted(SampleEvent e) { - } - - public void sampleStopped(SampleEvent e) { - } - - public void setArguments(Arguments args) { - args.removeArgument("useRegexpForSamplersList", "false"); - this.setProperty(new TestElementProperty("arguments", args)); - } - - public Arguments getArguments() { - return (Arguments)this.getProperty("arguments").getObjectValue(); - } - - public void setClassname(String classname) { - this.setProperty("classname", classname); - } - - public String getClassname() { - return this.getPropertyAsString("classname"); - } - - public void setQueueSize(String queueSize) { - this.setProperty("QUEUE_SIZE", queueSize, "5000"); - } - - public String getQueueSize() { - return this.getPropertyAsString("QUEUE_SIZE", "5000"); - } - - static class ErrorBackendListenerClient extends AbstractBackendListenerClient { - ErrorBackendListenerClient() { - } - - public void handleSampleResults(List sampleResults, BackendListenerContext context) { - BackendListener.log.warn("ErrorBackendListenerClient#handleSampleResult called, noop"); - Thread.yield(); - } - } - - private static final class Worker extends Thread { - private final BackendListener.ListenerClientData listenerClientData; - private final BackendListenerContext context; - private final BackendListenerClient backendListenerClient; - - private Worker(BackendListenerClient backendListenerClient, Arguments arguments, BackendListener.ListenerClientData listenerClientData) { - this.listenerClientData = listenerClientData; - arguments.addArgument("TestElement.name", this.getName()); - this.context = new BackendListenerContext(arguments); - this.backendListenerClient = backendListenerClient; - } - - public void run() { - boolean isDebugEnabled = BackendListener.log.isDebugEnabled(); - ArrayList sampleResults = new ArrayList(this.listenerClientData.queue.size()); - - try { - try { - boolean endOfLoop = false; - - while(!endOfLoop) { - if (isDebugEnabled) { - BackendListener.log.debug("Thread: {} taking SampleResult from queue: {}", Thread.currentThread().getName(), this.listenerClientData.queue.size()); - } - - SampleResult sampleResult = (SampleResult)this.listenerClientData.queue.take(); - if (isDebugEnabled) { - BackendListener.log.debug("Thread: {} took SampleResult: {}, isFinal: {}", new Object[]{Thread.currentThread().getName(), sampleResult, sampleResult == BackendListener.FINAL_SAMPLE_RESULT}); - } - - while(!(endOfLoop = sampleResult == BackendListener.FINAL_SAMPLE_RESULT) && sampleResult != null) { - sampleResults.add(sampleResult); - if (isDebugEnabled) { - BackendListener.log.debug("Thread: {} polling from queue: {}", Thread.currentThread().getName(), this.listenerClientData.queue.size()); - } - - sampleResult = (SampleResult)this.listenerClientData.queue.poll(); - if (isDebugEnabled) { - BackendListener.log.debug("Thread: {} took from queue: {}, isFinal: {}", new Object[]{Thread.currentThread().getName(), sampleResult, sampleResult == BackendListener.FINAL_SAMPLE_RESULT}); - } - } - - if (isDebugEnabled) { - BackendListener.log.debug("Thread: {} exiting with FINAL EVENT: {}, null: {}", new Object[]{Thread.currentThread().getName(), sampleResult == BackendListener.FINAL_SAMPLE_RESULT, sampleResult == null}); - } - - BackendListener.sendToListener(this.backendListenerClient, this.context, sampleResults); - if (!endOfLoop) { - LockSupport.parkNanos(100L); - } - } - } catch (InterruptedException var8) { - Thread.currentThread().interrupt(); - } - - BackendListener.sendToListener(this.backendListenerClient, this.context, sampleResults); - BackendListener.log.info("Worker ended"); - } finally { - this.listenerClientData.latch.countDown(); - } - - } - } - - private static final class ListenerClientData { - private BackendListenerClient client; - private BlockingQueue queue; - private LongAdder queueWaits; - private LongAdder queueWaitTime; - private int instanceCount; - private CountDownLatch latch; - - private ListenerClientData() { - } - } -}