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() {
- }
- }
-}