public static void main(String args[]) { int port = 8080; if (args.length > 0) { port = Integer.parseInt(args[0]); } LoggingManager.setPriority("INFO"); // default level LoggingManager.setLoggingLevels(System.getProperties()); // allow override by system properties HttpMirrorServer serv = new HttpMirrorServer(port); serv.start(); }
public class BSFAssertion extends BSFTestElement implements Cloneable, Assertion, TestBean { private static final Logger log = LoggingManager.getLoggerForClass(); private static final long serialVersionUID = 234L; public AssertionResult getResult(SampleResult response) { AssertionResult result = new AssertionResult(getName()); try { BSFManager mgr = getManager(); if (mgr == null) { result.setFailure(true); result.setError(true); result.setFailureMessage("BSF Manager not found"); return result; } mgr.declareBean("SampleResult", response, SampleResult.class); mgr.declareBean("AssertionResult", result, AssertionResult.class); processFileOrScript(mgr); mgr.terminate(); result.setError(false); } catch (BSFException e) { log.warn("Problem in BSF script " + e); result.setError(true); result.setFailureMessage(e.toString()); } return result; } }
protected void initManager(ScriptEngineManager sem) { final String label = getName(); final String fileName = getFilename(); final String scriptParameters = getParameters(); // Use actual class name for log final Logger logger = LoggingManager.getLoggerForShortName(getClass().getName()); sem.put("log", logger); sem.put("Label", label); sem.put("FileName", fileName); sem.put("Parameters", scriptParameters); String[] args = JOrphanUtils.split(scriptParameters, " "); // $NON-NLS-1$ sem.put("args", args); // Add variables for access to context and variables JMeterContext jmctx = JMeterContextService.getContext(); sem.put("ctx", jmctx); JMeterVariables vars = jmctx.getVariables(); sem.put("vars", vars); Properties props = JMeterUtils.getJMeterProperties(); sem.put("props", props); // For use in debugging: sem.put("OUT", System.out); // Most subclasses will need these: Sampler sampler = jmctx.getCurrentSampler(); sem.put("sampler", sampler); SampleResult prev = jmctx.getPreviousResult(); sem.put("prev", prev); }
protected void initManager(BSFManager mgr) throws BSFException { final String label = getName(); final String fileName = getFilename(); final String scriptParameters = getParameters(); // Use actual class name for log final Logger logger = LoggingManager.getLoggerForShortName(getClass().getName()); mgr.declareBean("log", logger, Logger.class); // $NON-NLS-1$ mgr.declareBean("Label", label, String.class); // $NON-NLS-1$ mgr.declareBean("FileName", fileName, String.class); // $NON-NLS-1$ mgr.declareBean("Parameters", scriptParameters, String.class); // $NON-NLS-1$ String[] args = JOrphanUtils.split(scriptParameters, " "); // $NON-NLS-1$ mgr.declareBean("args", args, args.getClass()); // $NON-NLS-1$ // Add variables for access to context and variables JMeterContext jmctx = JMeterContextService.getContext(); JMeterVariables vars = jmctx.getVariables(); Properties props = JMeterUtils.getJMeterProperties(); mgr.declareBean("ctx", jmctx, jmctx.getClass()); // $NON-NLS-1$ mgr.declareBean("vars", vars, vars.getClass()); // $NON-NLS-1$ mgr.declareBean("props", props, props.getClass()); // $NON-NLS-1$ // For use in debugging: mgr.declareBean("OUT", System.out, PrintStream.class); // $NON-NLS-1$ // Most subclasses will need these: Sampler sampler = jmctx.getCurrentSampler(); mgr.declareBean("sampler", sampler, Sampler.class); SampleResult prev = jmctx.getPreviousResult(); mgr.declareBean("prev", prev, SampleResult.class); }
/** * This module controls the Sequence in which user details are returned. This module uses round * robin allocation of users. * * @version $Revision: 701738 $ */ public class UserSequence implements Serializable { private static final long serialVersionUID = 233L; private static final Logger log = LoggingManager.getLoggerForClass(); // ------------------------------------------- // Constants and Data Members // ------------------------------------------- private List allUsers; private transient Iterator indexOfUsers; // ------------------------------------------- // Constructors // ------------------------------------------- public UserSequence() {} /** * Load all user and parameter data into the sequence module. * * <p>ie a Set of Mapped "parameter names and parameter values" for each user to be loaded into * the sequencer. */ public UserSequence(List allUsers) { this.allUsers = allUsers; // initalise pointer to first user indexOfUsers = allUsers.iterator(); } // ------------------------------------------- // Methods // ------------------------------------------- /** * Returns the parameter data for the next user in the sequence * * @return a Map object of parameter names and matching parameter values for the next user */ public synchronized Map getNextUserMods() { // Use round robin allocation of user details if (!indexOfUsers.hasNext()) { indexOfUsers = allUsers.iterator(); } Map user; if (indexOfUsers.hasNext()) { user = (Map) indexOfUsers.next(); log.debug( "UserSequence.getNextuserMods(): current parameters will be " + "changed to: " + user); } else { // no entries in all users, therefore create an empty Map object user = new HashMap(); } return user; } }
/** * @author Sergey Marakhov * @author Linh Pham */ public class AndroidDriverConfig extends WebDriverConfig<AndroidDriver> implements ThreadListener { private static final long serialVersionUID = 100L; private static final Logger LOGGER = LoggingManager.getLoggerForClass(); private static final String ANDROID_DRIVER_HOST_PORT = "AndroidDriverConfig.driver_host_port"; @Override public void threadStarted() { LOGGER.info("AndroidDriverConfig.threadStarted()"); if (hasThreadBrowser()) { LOGGER.warn( "Thread: " + currentThreadName() + " already has a WebDriver(" + getThreadBrowser() + ") associated with it. ThreadGroup can only contain a single WebDriverConfig."); return; } setThreadBrowser(createBrowser()); } DesiredCapabilities createCapabilities() { DesiredCapabilities capabilities = new DesiredCapabilities(); capabilities.setCapability(CapabilityType.PROXY, createProxy()); return capabilities; } @Override public void threadFinished() { final AndroidDriver androidDriver = removeThreadBrowser(); if (androidDriver != null) { androidDriver.quit(); } } @Override protected AndroidDriver createBrowser() { try { return new AndroidDriver(new URL(getAndroidDriverUrl()), createCapabilities()); } catch (MalformedURLException e) { LOGGER.error("MalformedURLException thrown for invalid URL: " + getAndroidDriverUrl()); return null; } } private String getAndroidDriverUrl() { return "http://localhost:" + getAndroidDriverHostPort() + "/wd/hub"; } public void setAndroidDriverHostPort(String port) { setProperty(ANDROID_DRIVER_HOST_PORT, port); } public String getAndroidDriverHostPort() { return getPropertyAsString(ANDROID_DRIVER_HOST_PORT); } }
public class TimeInMillis extends AbstractFunction { private static final List<String> desc = new LinkedList<String>(); private static final String KEY = "__TimeInMillis"; private static final int MAX_PARAM_COUNT = 1; private static final int MIN_PARAM_COUNT = 0; private static final Logger log = LoggingManager.getLoggerForClass(); private Object[] values; static { desc.add("(Optional)Pass the milliseconds that should be added/subtracted from current time."); } /** No-arg constructor. */ public TimeInMillis() { super(); } /** {@inheritDoc} */ @Override public synchronized String execute(SampleResult previousResult, Sampler currentSampler) throws InvalidVariableException { // JMeterVariables vars = getVariables(); Calendar cal = Calendar.getInstance(); if (values.length == 1) { // If user has provided offset value then adjust the time. log.info("Got one paramenter"); try { Integer offsetTime = new Integer(((CompoundVariable) values[0]).execute().trim()); cal.add(Calendar.MILLISECOND, offsetTime); } catch (Exception e) { // In case user pass invalid parameter. throw new InvalidVariableException(e); } } return String.valueOf(cal.getTimeInMillis()); } /** {@inheritDoc} */ @Override public synchronized void setParameters(Collection<CompoundVariable> parameters) throws InvalidVariableException { checkParameterCount(parameters, MIN_PARAM_COUNT, MAX_PARAM_COUNT); values = parameters.toArray(); } /** {@inheritDoc} */ @Override public String getReferenceKey() { return KEY; } /** {@inheritDoc} */ @Override public List<String> getArgumentDesc() { return desc; } }
/** * This class implements a listener for SMTP events and a monitor for all threads sending mail. The * main purpose is to synchronize the send action with the end of communication with remote smtp * server, so that sending time can be measured. */ public class SynchronousTransportListener extends TransportAdapter { private static final Logger logger = LoggingManager.getLoggerForClass(); private boolean finished = false; private final Object LOCK = new Object(); /** Creates a new instance of SynchronousTransportListener */ public SynchronousTransportListener() {} /** {@inheritDoc} */ @Override public void messageDelivered(TransportEvent e) { logger.debug("Message delivered"); finish(); } /** {@inheritDoc} */ @Override public void messageNotDelivered(TransportEvent e) { logger.debug("Message not delivered"); finish(); } /** {@inheritDoc} */ @Override public void messagePartiallyDelivered(TransportEvent e) { logger.debug("Message partially delivered"); finish(); } /** * Synchronized-method * * @throws InterruptedException */ public void attend() throws InterruptedException { synchronized (LOCK) { while (!finished) { LOCK.wait(); } } } /** Synchronized-method */ public void finish() { finished = true; synchronized (LOCK) { LOCK.notify(); } } }
/** Implements the Add Parent menu command */ public class ChangeParent implements Command { private static final Logger log = LoggingManager.getLoggerForClass(); private static final Set<String> commands = new HashSet<String>(); static { commands.add(ActionNames.CHANGE_PARENT); } public ChangeParent() {} public void doAction(ActionEvent e) { String name = ((Component) e.getSource()).getName(); GuiPackage guiPackage = GuiPackage.getInstance(); JMeterTreeNode currentNode = guiPackage.getTreeListener().getCurrentNode(); if (!(currentNode.getUserObject() instanceof Controller)) { Toolkit.getDefaultToolkit().beep(); return; } try { guiPackage.updateCurrentNode(); TestElement controller = guiPackage.createTestElement(name); changeParent(controller, guiPackage, currentNode); } catch (Exception err) { Toolkit.getDefaultToolkit().beep(); log.error("Failed to change parent", err); } } public Set<String> getActionNames() { return commands; } private void changeParent( TestElement newParent, GuiPackage guiPackage, JMeterTreeNode currentNode) { JMeterTreeModel treeModel = guiPackage.getTreeModel(); JMeterTreeNode newNode = new JMeterTreeNode(newParent, treeModel); JMeterTreeNode parentNode = (JMeterTreeNode) currentNode.getParent(); int index = parentNode.getIndex(currentNode); treeModel.insertNodeInto(newNode, parentNode, index); treeModel.removeNodeFromParent(currentNode); int childCount = currentNode.getChildCount(); for (int i = 0; i < childCount; i++) { // Using index 0 is voluntary as child is removed in next step and added to new parent JMeterTreeNode node = (JMeterTreeNode) currentNode.getChildAt(0); treeModel.removeNodeFromParent(node); treeModel.insertNodeInto(node, newNode, newNode.getChildCount()); } } }
/** @author undera */ public class JMXMetric extends AbstractPerfMonMetric { private static final Logger log = LoggingManager.getLoggerForClass(); private final AbstractJMXDataProvider dataProvider; private int dividingFactor = 1; public JMXMetric(MetricParams params, JMXConnectorHelper jmxHelper) { super(null); String url = "localhost:4711"; String user = ""; String pwd = ""; for (int i = 0; i < params.params.length; i++) { if (params.params[i].startsWith("url=")) { url = MetricParams.getParamValue(params.params[i]); } else if (params.params[i].startsWith("user="******"password="******"'url' parameter required for metric type 'jmx'"); } MBeanServerConnection mBeanServerConn = jmxHelper.getServerConnection(url, user, pwd); try { dataProvider = AbstractJMXDataProvider.getProvider(mBeanServerConn, params.type); } catch (Exception ex) { log.debug("Failed to get MX Bean data provider", ex); throw new RuntimeException("Failed to get MX Bean data provider", ex); } dividingFactor = getUnitDividingFactor(params.getUnit()); } public void getValue(StringBuffer res) throws Exception { if (dataProvider.isBytesValue()) { dataProvider.getValue(res, dividingFactor); } else { dataProvider.getValue(res); } } }
public class SocketEmulatorInputStream extends InputStream { private static final Logger log = LoggingManager.getLoggerForClass(); private byte[] bytes; private int pos = 0; public SocketEmulatorInputStream(byte[] hexStringToByteArray) { this(); setBytesToRead(hexStringToByteArray); } public SocketEmulatorInputStream() { bytes = null; pos = 0; log.info("Created input stream emulator"); } public final void setBytesToRead(byte[] hexStringToByteArray) { log.debug("Set bytes to read: " + Integer.toString(hexStringToByteArray.length)); bytes = hexStringToByteArray; } public final void setBytesToRead(String str) { setBytesToRead(str.getBytes()); } @Override public int read() throws IOException { if (bytes == null) { log.debug("Expected emulator data was not set"); return -1; } if (pos >= bytes.length) { log.debug("End of data reached, resetting buffer"); bytes = null; pos = 0; return -1; } else { final byte byteToret = bytes[pos]; pos++; // log.debug("Byte: #"+Integer.toString(pos)+" "+Byte.toString(byteToret)); return byteToret; } } }
/* * Note: This helper class appeared in JavaWorld in June 2001 * (http://www.javaworld.com) and was written by Michael Daconta. * */ public class FocusRequester implements Runnable { private static final Logger log = LoggingManager.getLoggerForClass(); private final Component comp; public FocusRequester(Component comp) { this.comp = comp; try { SwingUtilities.invokeLater(this); } catch (Exception e) { log.error("", e); // $NON-NLS-1$ } } @Override public void run() { comp.requestFocus(); } }
public class JSR223PostProcessor extends JSR223TestElement implements Cloneable, PostProcessor, TestBean { private static final Logger log = LoggingManager.getLoggerForClass(); private static final long serialVersionUID = 232L; public void process() { try { ScriptEngineManager sem = getManager(); if (sem == null) { return; } processFileOrScript(sem); } catch (ScriptException e) { log.warn("Problem in JSR223 script " + e); } catch (IOException e) { log.warn("Problem in JSR223 script " + e); } } }
/** Implements an HTML Pane with local hyperlinking enabled. */ public class HtmlPane extends JTextPane { private static final Logger log = LoggingManager.getLoggerForClass(); public HtmlPane() { this.addHyperlinkListener( new HyperlinkListener() { public void hyperlinkUpdate(HyperlinkEvent e) { if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) { String ref = e.getURL().getRef(); if (ref != null && ref.length() > 0) { log.debug("reference to scroll to = " + ref); scrollToReference(ref); } } } }); } public void scrollToReference(String reference) { super.scrollToReference(reference); } }
/** * Thread that copies a stream in the background; closes both input and output streams. * * @since 2.8 */ class StreamCopier extends Thread { private static final Logger log = LoggingManager.getLoggerForClass(); private final InputStream is; private final OutputStream os; /** * @param is {@link InputStream} * @param is {@link OutputStream} * @throws IOException */ StreamCopier(InputStream is, OutputStream os) throws IOException { this.is = is; this.os = os; } /** @see java.lang.Thread#run() */ @Override public void run() { final boolean isSystemOutput = os.equals(System.out) || os.equals(System.err); try { IOUtils.copyLarge(is, os); if (!isSystemOutput) { os.close(); } is.close(); } catch (IOException e) { log.warn("Error writing stream", e); } finally { IOUtils.closeQuietly(is); if (!isSystemOutput) { IOUtils.closeQuietly(os); } } } }
public class PluginManagerMenuCreator implements MenuCreator { private static final Logger log = LoggingManager.getLoggerForClass(); @Override public JMenuItem[] getMenuItemsAtLocation(MENU_LOCATION location) { if (location == MENU_LOCATION.OPTIONS) { try { PluginManagerCMDInstaller.main(new String[0]); } catch (Throwable e) { log.warn("Was unable to install pmgr cmdline tool", e); } try { return new JMenuItem[] {new PluginManagerMenuItem()}; } catch (Throwable e) { log.error("Failed to load Plugins Manager", e); return new JMenuItem[0]; } } else { return new JMenuItem[0]; } } @Override public javax.swing.JMenu[] getTopLevelMenus() { return new javax.swing.JMenu[0]; } @Override public boolean localeChanged(javax.swing.MenuElement menu) { return false; } @Override public void localeChanged() {} }
/** Implements batch reporting for remote testing. */ public class StatisticalSampleSender implements SampleSender, Serializable { private static final Logger log = LoggingManager.getLoggerForClass(); private static final int DEFAULT_NUM_SAMPLE_THRESHOLD = 100; private static final long DEFAULT_TIME_THRESHOLD = 60000L; private RemoteSampleListener listener; private List sampleStore = new ArrayList(); private Map sampleTable = new HashMap(); private int numSamplesThreshold; private int sampleCount; private long timeThreshold; private long batchSendTime = -1; public StatisticalSampleSender() { log.warn("Constructor only intended for use in testing"); } /** * Constructor * * @param listener that the List of sample events will be sent to. */ StatisticalSampleSender(RemoteSampleListener listener) { this.listener = listener; init(); log.info( "Using batching for this run." + " Thresholds: num=" + numSamplesThreshold + ", time=" + timeThreshold); } /** * Checks for the Jmeter properties num_sample_threshold and time_threshold, and assigns defaults * if not found. */ private void init() { this.numSamplesThreshold = JMeterUtils.getPropDefault("num_sample_threshold", DEFAULT_NUM_SAMPLE_THRESHOLD); this.timeThreshold = JMeterUtils.getPropDefault("time_threshold", DEFAULT_TIME_THRESHOLD); } /** * Checks if any sample events are still present in the sampleStore and sends them to the * listener. Informs the listener of the testended. */ public void testEnded() { try { if (sampleStore.size() != 0) { sendBatch(); } listener.testEnded(); } catch (RemoteException err) { log.warn("testEnded()", err); } } /** * Checks if any sample events are still present in the sampleStore and sends them to the * listener. Informs the listener of the testended. * * @param host the hostname that the test has ended on. */ public void testEnded(String host) { try { if (sampleStore.size() != 0) { sendBatch(); } listener.testEnded(host); } catch (RemoteException err) { log.warn("testEnded(hostname)", err); } } /** * Stores sample events untill either a time or sample threshold is breached. Both thresholds are * reset if one fires. If only one threshold is set it becomes the only value checked against. * When a threhold is breached the list of sample events is sent to a listener where the event are * fired locally. * * @param e a Sample Event */ public void sampleOccurred(SampleEvent e) { synchronized (sampleStore) { // Locate the statistical sample colector String key = StatisticalSampleResult.getKey(e); StatisticalSampleResult statResult = (StatisticalSampleResult) sampleTable.get(key); if (statResult == null) { statResult = new StatisticalSampleResult(e.getResult()); // store the new statistical result collector sampleTable.put(key, statResult); // add a new wrapper samplevent sampleStore.add(new SampleEvent(statResult, e.getThreadGroup())); } statResult.add(e.getResult()); sampleCount++; if (numSamplesThreshold != -1) { if (sampleCount >= numSamplesThreshold) { try { if (log.isDebugEnabled()) { log.debug("Firing sample"); } sendBatch(); } catch (RemoteException err) { log.warn("sampleOccurred", err); } } } if (timeThreshold != -1) { long now = System.currentTimeMillis(); // Checking for and creating initial timestamp to cheak against if (batchSendTime == -1) { this.batchSendTime = now + timeThreshold; } if (batchSendTime < now) { try { if (log.isDebugEnabled()) { log.debug("Firing time"); } sendBatch(); this.batchSendTime = now + timeThreshold; } catch (RemoteException err) { log.warn("sampleOccurred", err); } } } } } private void sendBatch() throws RemoteException { if (sampleStore.size() > 0) { listener.processBatch(sampleStore); sampleStore.clear(); sampleTable.clear(); sampleCount = 0; } } }
/** * HtmlParser implementation using regular expressions. * * <p>This class will find RLs specified in the following ways (where <b>url</b> represents the RL * being found: * * <ul> * <li><img src=<b>url</b> ... > * <li><script src=<b>url</b> ... > * <li><applet code=<b>url</b> ... > * <li><input type=image src=<b>url</b> ... > * <li><body background=<b>url</b> ... > * <li><table background=<b>url</b> ... > * <li><td background=<b>url</b> ... > * <li><tr background=<b>url</b> ... > * <li><applet ... codebase=<b>url</b> ... > * <li><embed src=<b>url</b> ... > * <li><embed codebase=<b>url</b> ... > * <li><object codebase=<b>url</b> ... > * <li><link rel=stylesheet href=<b>url</b>... gt; * <li><bgsound src=<b>url</b> ... > * <li><frame src=<b>url</b> ... > * </ul> * * <p>This class will take into account the following construct: * * <ul> * <li><base href=<b>url</b>> * </ul> * * <p>But not the following: * * <ul> * <li>< ... codebase=<b>url</b> ... > * </ul> */ class RegexpHTMLParser extends HTMLParser { private static final Logger log = LoggingManager.getLoggerForClass(); /** * Regexp fragment matching a tag attribute's value (including the equals sign and any spaces * before it). Note it matches unquoted values, which to my understanding, are not conformant to * any of the HTML specifications, but are still quite common in the web and all browsers seem to * understand them. */ private static final String VALUE = "\\s*=\\s*(?:\"([^\"]*)\"|'([^']*)'|([^\"'\\s>\\\\][^\\s>]*)(?=[\\s>]))"; // Note there's 3 capturing groups per value /** Regexp fragment matching the separation between two tag attributes. */ private static final String SEP = "\\s(?:[^>]*\\s)?"; /** Regular expression used against the HTML code to find the URIs of images, etc.: */ private static final String REGEXP = "<(?:" + "!--.*?-->" + "|BASE" + SEP + "HREF" + VALUE + "|(?:IMG|SCRIPT|FRAME|IFRAME|BGSOUND)" + SEP + "SRC" + VALUE + "|APPLET" + SEP + "CODE(?:BASE)?" + VALUE + "|(?:EMBED|OBJECT)" + SEP + "(?:SRC|CODEBASE|DATA)" + VALUE + "|(?:BODY|TABLE|TR|TD)" + SEP + "BACKGROUND" + VALUE + "|[^<]+?STYLE\\s*=['\"].*?URL\\(\\s*['\"](.+?)['\"]\\s*\\)" + "|INPUT(?:" + SEP + "(?:SRC" + VALUE + "|TYPE\\s*=\\s*(?:\"image\"|'image'|image(?=[\\s>])))){2,}" + "|LINK(?:" + SEP + "(?:HREF" + VALUE + "|REL\\s*=\\s*(?:\"stylesheet\"|'stylesheet'|stylesheet(?=[\\s>])))){2,}" + ")"; // Number of capturing groups possibly containing Base HREFs: private static final int NUM_BASE_GROUPS = 3; /** Thread-local input: */ private static final ThreadLocal<PatternMatcherInput> localInput = new ThreadLocal<PatternMatcherInput>() { @Override protected PatternMatcherInput initialValue() { return new PatternMatcherInput(new char[0]); } }; /** {@inheritDoc} */ @Override protected boolean isReusable() { return true; } /** Make sure to compile the regular expression upon instantiation: */ protected RegexpHTMLParser() { super(); } /** {@inheritDoc} */ @Override public Iterator<URL> getEmbeddedResourceURLs( String userAgent, byte[] html, URL baseUrl, URLCollection urls, String encoding) throws HTMLParseException { Pattern pattern = null; Perl5Matcher matcher = null; try { matcher = JMeterUtils.getMatcher(); PatternMatcherInput input = localInput.get(); // TODO: find a way to avoid the cost of creating a String here -- // probably a new PatternMatcherInput working on a byte[] would do // better. input.setInput(new String(html, encoding)); pattern = JMeterUtils.getPatternCache() .getPattern( REGEXP, Perl5Compiler.CASE_INSENSITIVE_MASK | Perl5Compiler.SINGLELINE_MASK | Perl5Compiler.READ_ONLY_MASK); while (matcher.contains(input, pattern)) { MatchResult match = matcher.getMatch(); String s; if (log.isDebugEnabled()) { log.debug("match groups " + match.groups() + " " + match.toString()); } // Check for a BASE HREF: for (int g = 1; g <= NUM_BASE_GROUPS && g <= match.groups(); g++) { s = match.group(g); if (s != null) { if (log.isDebugEnabled()) { log.debug("new baseUrl: " + s + " - " + baseUrl.toString()); } try { baseUrl = ConversionUtils.makeRelativeURL(baseUrl, s); } catch (MalformedURLException e) { // Doesn't even look like a URL? // Maybe it isn't: Ignore the exception. if (log.isDebugEnabled()) { log.debug("Can't build base URL from RL " + s + " in page " + baseUrl, e); } } } } for (int g = NUM_BASE_GROUPS + 1; g <= match.groups(); g++) { s = match.group(g); if (s != null) { if (log.isDebugEnabled()) { log.debug("group " + g + " - " + match.group(g)); } urls.addURL(s, baseUrl); } } } return urls.iterator(); } catch (UnsupportedEncodingException e) { throw new HTMLParseException(e.getMessage(), e); } catch (MalformedCachePatternException e) { throw new HTMLParseException(e.getMessage(), e); } finally { JMeterUtils.clearMatcherMemory(matcher, pattern); } } }
/** This is the JMeter server main code. */ public final class RemoteJMeterEngineImpl extends java.rmi.server.UnicastRemoteObject implements RemoteJMeterEngine { private static final long serialVersionUID = 240L; private static final Logger log = LoggingManager.getLoggerForClass(); static final String JMETER_ENGINE_RMI_NAME = "JMeterEngine"; // $NON-NLS-1$ private transient JMeterEngine backingEngine; private transient Thread ownerThread; private static final int DEFAULT_RMI_PORT = JMeterUtils.getPropDefault("server.rmi.port", 1099); // $NON-NLS-1$ private static final int DEFAULT_LOCAL_PORT = JMeterUtils.getPropDefault("server.rmi.localport", 0); // $NON-NLS-1$ static { if (DEFAULT_LOCAL_PORT != 0) { System.out.println("Using local port: " + DEFAULT_LOCAL_PORT); } } // Should we create our own copy of the RMI registry? private static final boolean createServer = JMeterUtils.getPropDefault("server.rmi.create", true); // $NON-NLS-1$ private final Object LOCK = new Object(); private final int rmiPort; private Properties remotelySetProperties; private RemoteJMeterEngineImpl(int localPort, int rmiPort) throws RemoteException { super(localPort); // Create this object using the specified port (0 means anonymous) this.rmiPort = rmiPort; System.out.println("Created remote object: " + this.getRef().remoteToString()); } public static void startServer(int rmiPort) throws RemoteException { RemoteJMeterEngineImpl engine = new RemoteJMeterEngineImpl(DEFAULT_LOCAL_PORT, rmiPort == 0 ? DEFAULT_RMI_PORT : rmiPort); engine.init(); } private void init() throws RemoteException { log.info("Starting backing engine on " + this.rmiPort); InetAddress localHost = null; // Bug 47980 - allow override of local hostname String host = System.getProperties().getProperty("java.rmi.server.hostname"); // $NON-NLS-1$ try { if (host == null) { localHost = InetAddress.getLocalHost(); } else { localHost = InetAddress.getByName(host); } } catch (UnknownHostException e1) { throw new RemoteException("Cannot start. Unable to get local host IP address.", e1); } log.info("IP address=" + localHost.getHostAddress()); String hostName = localHost.getHostName(); // BUG 52469 : Allow loopback address for SSH Tunneling of RMI traffic if (localHost.isLoopbackAddress() && host == null) { throw new RemoteException("Cannot start. " + hostName + " is a loopback address."); } if (localHost.isSiteLocalAddress()) { // should perhaps be log.warn, but this causes the client-server test to fail log.info( "IP address is a site-local address; this may cause problems with remote access.\n" + "\tCan be overridden by defining the system property 'java.rmi.server.hostname' - see jmeter-server script file"); } log.debug("This = " + this); if (createServer) { log.info("Creating RMI registry (server.rmi.create=true)"); try { LocateRegistry.createRegistry(this.rmiPort); } catch (RemoteException e) { String msg = "Problem creating registry: " + e; log.warn(msg); System.err.println(msg); System.err.println("Continuing..."); } } try { Registry reg = LocateRegistry.getRegistry(this.rmiPort); reg.rebind(JMETER_ENGINE_RMI_NAME, this); log.info("Bound to registry on port " + this.rmiPort); } catch (Exception ex) { log.error( "rmiregistry needs to be running to start JMeter in server " + "mode\n\t" + ex.toString()); // Throw an Exception to ensure caller knows ... throw new RemoteException("Cannot start. See server log file.", ex); } } /** * Adds a feature to the ThreadGroup attribute of the RemoteJMeterEngineImpl object. * * @param testTree the feature to be added to the ThreadGroup attribute */ @Override public void rconfigure(HashTree testTree, String host, File jmxBase, String scriptName) throws RemoteException { log.info("Creating JMeter engine on host " + host + " base '" + jmxBase + "'"); synchronized (LOCK) { // close window where another remote client might jump in if (backingEngine != null && backingEngine.isActive()) { log.warn("Engine is busy - cannot create JMeter engine"); throw new IllegalStateException("Engine is busy - please try later"); } ownerThread = Thread.currentThread(); backingEngine = new StandardJMeterEngine(host); backingEngine.configure(testTree); // sets active = true } FileServer.getFileServer().setScriptName(scriptName); FileServer.getFileServer().setBase(jmxBase); } @Override public void rrunTest() throws RemoteException, JMeterEngineException, IllegalStateException { log.info("Running test"); checkOwner("runTest"); backingEngine.runTest(); } @Override public void rreset() throws RemoteException, IllegalStateException { // Mail on userlist reported NPE here - looks like only happens if there are network errors, but // check anyway if (backingEngine != null) { log.info("Reset"); checkOwner("reset"); backingEngine.reset(); } else { log.warn("Backing engine is null, ignoring reset"); } } @Override public void rstopTest(boolean now) throws RemoteException { if (now) { log.info("Stopping test ..."); } else { log.info("Shutting test ..."); } backingEngine.stopTest(now); log.info("... stopped"); } /* * Called by: * - ClientJMeterEngine.exe() which is called on remoteStop */ @Override public void rexit() throws RemoteException { log.info("Exitting"); backingEngine.exit(); // Tidy up any objects we created Registry reg = LocateRegistry.getRegistry(this.rmiPort); try { reg.unbind(JMETER_ENGINE_RMI_NAME); } catch (NotBoundException e) { log.warn(JMETER_ENGINE_RMI_NAME + " is not bound", e); } log.info("Unbound from registry"); // Help with garbage control JMeterUtils.helpGC(); } @Override public void rsetProperties(Properties p) throws RemoteException, IllegalStateException { checkOwner("setProperties"); if (remotelySetProperties != null) { Properties jmeterProperties = JMeterUtils.getJMeterProperties(); log.info("Cleaning previously set properties " + remotelySetProperties); for (Iterator<?> iterator = remotelySetProperties.keySet().iterator(); iterator.hasNext(); ) { String key = (String) iterator.next(); jmeterProperties.remove(key); } } backingEngine.setProperties(p); this.remotelySetProperties = p; } /** * Check if the caller owns the engine. * * @param methodName the name of the method for the log message * @throws IllegalStateException if the caller is not the owner. */ private void checkOwner(String methodName) throws IllegalStateException { if (ownerThread != null && ownerThread != Thread.currentThread()) { String msg = "The engine is not owned by this thread - cannot call " + methodName; log.warn(msg); throw new IllegalStateException(msg); } } }
/** * Utility class to handle text files as a single lump of text. * * <p>Note this is just as memory-inefficient as handling a text file can be. Use with restraint. * * @version $Revision$ */ public class TextFile extends File { private static final long serialVersionUID = 240L; private static final Logger log = LoggingManager.getLoggerForClass(); /** File encoding. null means use the platform's default. */ private String encoding = null; /** * Create a TextFile object to handle the named file with the given encoding. * * @param filename File to be read & written through this object. * @param encoding Encoding to be used when reading & writing this file. */ public TextFile(File filename, String encoding) { super(filename.toString()); setEncoding(encoding); } /** * Create a TextFile object to handle the named file with the platform default encoding. * * @param filename File to be read & written through this object. */ public TextFile(File filename) { super(filename.toString()); } /** * Create a TextFile object to handle the named file with the platform default encoding. * * @param filename Name of the file to be read & written through this object. */ public TextFile(String filename) { super(filename); } /** * Create a TextFile object to handle the named file with the given encoding. * * @param filename Name of the file to be read & written through this object. * @param encoding Encoding to be used when reading & writing this file. */ public TextFile(String filename, String encoding) { super(filename); setEncoding(encoding); } /** * Create the file with the given string as content -- or replace it's content with the given * string if the file already existed. * * @param body New content for the file. */ public void setText(String body) { Writer writer = null; try { if (encoding == null) { writer = new FileWriter(this); } else { writer = new OutputStreamWriter(new FileOutputStream(this), encoding); } writer.write(body); writer.flush(); } catch (IOException ioe) { log.error("", ioe); } finally { JOrphanUtils.closeQuietly(writer); } } /** * Read the whole file content and return it as a string. * * @return the content of the file */ public String getText() { String lineEnd = System.getProperty("line.separator"); // $NON-NLS-1$ StringBuilder sb = new StringBuilder(); Reader reader = null; BufferedReader br = null; try { if (encoding == null) { reader = new FileReader(this); } else { reader = new InputStreamReader(new FileInputStream(this), encoding); } br = new BufferedReader(reader); String line = "NOTNULL"; // $NON-NLS-1$ while (line != null) { line = br.readLine(); if (line != null) { sb.append(line + lineEnd); } } } catch (IOException ioe) { log.error("", ioe); // $NON-NLS-1$ } finally { JOrphanUtils.closeQuietly(br); // closes reader as well } return sb.toString(); } /** @return Encoding being used to read & write this file. */ public String getEncoding() { return encoding; } /** @param string Encoding to be used to read & write this file. */ public void setEncoding(String string) { encoding = string; } /** {@inheritDoc} */ @Override public int hashCode() { final int prime = 31; int result = super.hashCode(); result = prime * result + ((encoding == null) ? 0 : encoding.hashCode()); return result; } /** {@inheritDoc} */ @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (!super.equals(obj)) { return false; } if (!(obj instanceof TextFile)) { return false; } TextFile other = (TextFile) obj; if (encoding == null) { return other.encoding == null; } return encoding.equals(other.encoding); } }
/** Implements binary length-prefixed binary data. This is used in ISO8583 for example. */ public class LengthPrefixedBinaryTCPClientImpl extends TCPClientDecorator { private static final Logger log = LoggingManager.getLoggerForClass(); private final int lengthPrefixLen = JMeterUtils.getPropDefault("tcp.binarylength.prefix.length", 2); // $NON-NLS-1$ public LengthPrefixedBinaryTCPClientImpl() { super(new BinaryTCPClientImpl()); tcpClient.setEolByte(Byte.MAX_VALUE + 1); } /** {@inheritDoc} */ @Override public void write(OutputStream os, String s) throws IOException { os.write(intToByteArray(s.length() / 2, lengthPrefixLen)); if (log.isDebugEnabled()) { log.debug("Wrote: " + s.length() / 2 + " bytes"); } this.tcpClient.write(os, s); } /** {@inheritDoc} */ @Override public void write(OutputStream os, InputStream is) throws IOException { this.tcpClient.write(os, is); } /** {@inheritDoc} */ @Override public String read(InputStream is) throws ReadException { byte[] msg = new byte[0]; int msgLen = 0; byte[] lengthBuffer = new byte[lengthPrefixLen]; try { if (is.read(lengthBuffer, 0, lengthPrefixLen) == lengthPrefixLen) { msgLen = byteArrayToInt(lengthBuffer); msg = new byte[msgLen]; int bytes = JOrphanUtils.read(is, msg, 0, msgLen); if (bytes < msgLen) { log.warn("Incomplete message read, expected: " + msgLen + " got: " + bytes); } } String buffer = JOrphanUtils.baToHexString(msg); if (log.isDebugEnabled()) { log.debug("Read: " + msgLen + "\n" + buffer); } return buffer; } catch (IOException e) { throw new ReadException("", e, JOrphanUtils.baToHexString(msg)); } } /** * Not useful, as the byte is never used. * * <p>{@inheritDoc} */ @Override public byte getEolByte() { return tcpClient.getEolByte(); } /** {@inheritDoc} */ @Override public void setEolByte(int eolInt) { throw new UnsupportedOperationException("Cannot set eomByte for prefixed messages"); } }
public class UserParameters extends AbstractTestElement implements Serializable, PreProcessor, LoopIterationListener { private static final Logger log = LoggingManager.getLoggerForClass(); private static final long serialVersionUID = 233L; public static final String NAMES = "UserParameters.names"; // $NON-NLS-1$ public static final String THREAD_VALUES = "UserParameters.thread_values"; // $NON-NLS-1$ public static final String PER_ITERATION = "UserParameters.per_iteration"; // $NON-NLS-1$ /* * Although the lock appears to be an instance lock, in fact the lock is * shared between all threads in a thread group, but different thread groups * have different locks - see the clone() method below * * The lock ensures that all the variables are processed together, which is * important for functions such as __CSVRead and _StringFromFile. */ private transient Object lock = new Object(); private Object readResolve() { // Lock object must exist lock = new Object(); return this; } public CollectionProperty getNames() { return (CollectionProperty) getProperty(NAMES); } public CollectionProperty getThreadLists() { return (CollectionProperty) getProperty(THREAD_VALUES); } /** * The list of names of the variables to hold values. This list must come in the same order as the * sub lists that are given to {@link #setThreadLists(Collection)}. */ public void setNames(Collection<?> list) { setProperty(new CollectionProperty(NAMES, list)); } /** * The list of names of the variables to hold values. This list must come in the same order as the * sub lists that are given to {@link #setThreadLists(CollectionProperty)}. */ public void setNames(CollectionProperty list) { setProperty(list); } /** * The thread list is a list of lists. Each list within the parent list is a collection of values * for a simulated user. As many different sets of values can be supplied in this fashion to cause * JMeter to set different values to variables for different test threads. */ public void setThreadLists(Collection<?> threadLists) { setProperty(new CollectionProperty(THREAD_VALUES, threadLists)); } /** * The thread list is a list of lists. Each list within the parent list is a collection of values * for a simulated user. As many different sets of values can be supplied in this fashion to cause * JMeter to set different values to variables for different test threads. */ public void setThreadLists(CollectionProperty threadLists) { setProperty(threadLists); } private CollectionProperty getValues() { CollectionProperty threadValues = (CollectionProperty) getProperty(THREAD_VALUES); if (threadValues.size() > 0) { return (CollectionProperty) threadValues.get(getThreadContext().getThreadNum() % threadValues.size()); } return new CollectionProperty("noname", new LinkedList<Object>()); } public boolean isPerIteration() { return getPropertyAsBoolean(PER_ITERATION); } public void setPerIteration(boolean perIter) { setProperty(new BooleanProperty(PER_ITERATION, perIter)); } @Override public void process() { if (log.isDebugEnabled()) { log.debug(Thread.currentThread().getName() + " process " + isPerIteration()); // $NON-NLS-1$ } if (!isPerIteration()) { setValues(); } } private void setValues() { synchronized (lock) { if (log.isDebugEnabled()) { log.debug( Thread.currentThread().getName() + " Running up named: " + getName()); // $NON-NLS-1$ } PropertyIterator namesIter = getNames().iterator(); PropertyIterator valueIter = getValues().iterator(); JMeterVariables jmvars = getThreadContext().getVariables(); while (namesIter.hasNext() && valueIter.hasNext()) { String name = namesIter.next().getStringValue(); String value = valueIter.next().getStringValue(); if (log.isDebugEnabled()) { log.debug( Thread.currentThread().getName() + " saving variable: " + name + "=" + value); //$NON-NLS-1$ } jmvars.put(name, value); } } } /** @see LoopIterationListener#iterationStart(LoopIterationEvent) */ @Override public void iterationStart(LoopIterationEvent event) { if (log.isDebugEnabled()) { log.debug( Thread.currentThread().getName() + " iteration start " + isPerIteration()); // $NON-NLS-1$ } if (isPerIteration()) { setValues(); } } /* * (non-Javadoc) A new instance is created for each thread group, and the * clone() method is then called to create copies for each thread in a * thread group. This means that the lock object is common to a thread * group; separate thread groups have separate locks. If this is not * intended, the lock object could be made static. * * @see java.lang.Object#clone() */ @Override public Object clone() { UserParameters up = (UserParameters) super.clone(); up.lock = lock; // ensure that clones share the same lock object return up; } /** {@inheritDoc} */ @Override protected void mergeIn(TestElement element) { // super.mergeIn(element); } }
public class DependencyResolver { private static final Logger log = LoggingManager.getLoggerForClass(); public static final String JAVA_CLASS_PATH = "java.class.path"; protected final Set<Plugin> deletions = new HashSet<>(); protected final Set<Plugin> additions = new HashSet<>(); protected final Map<String, String> libAdditions = new HashMap<>(); protected final Set<String> libDeletions = new HashSet<>(); protected final Map<Plugin, Boolean> allPlugins; public DependencyResolver(Map<Plugin, Boolean> allPlugins) { this.allPlugins = allPlugins; resolveFlags(); resolveUpgrades(); resolveDeleteByDependency(); resolveInstallByDependency(); resolveDeleteLibs(); resolveInstallLibs(); } // TODO: return iterators to make values read-only public Set<Plugin> getDeletions() { return deletions; } public Set<Plugin> getAdditions() { return additions; } public Map<String, String> getLibAdditions() { return libAdditions; } public Set<String> getLibDeletions() { return libDeletions; } private Plugin getPluginByID(String id) { for (Plugin plugin : allPlugins.keySet()) { if (plugin.getID().equals(id)) { return plugin; } } throw new RuntimeException("Plugin not found by ID: " + id); } private Set<Plugin> getDependants(Plugin plugin) { Set<Plugin> res = new HashSet<>(); for (Plugin pAll : allPlugins.keySet()) { for (String depID : pAll.getDepends()) { if (depID.equals(plugin.getID())) { res.add(pAll); } } } return res; } private void resolveFlags() { for (Map.Entry<Plugin, Boolean> entry : allPlugins.entrySet()) { if (entry.getKey().isInstalled()) { if (!entry.getValue()) { deletions.add(entry.getKey()); } } else if (entry.getValue()) { additions.add(entry.getKey()); } } } private void resolveUpgrades() { // detect upgrades for (Map.Entry<Plugin, Boolean> entry : allPlugins.entrySet()) { Plugin plugin = entry.getKey(); if (entry.getValue() && plugin.isInstalled() && !plugin.getInstalledVersion().equals(plugin.getCandidateVersion())) { log.debug("Upgrade: " + plugin); deletions.add(plugin); additions.add(plugin); } } } private void resolveDeleteByDependency() { // delete by depend boolean hasModifications = true; while (hasModifications) { log.debug("Check uninstall dependencies"); hasModifications = false; for (Plugin plugin : deletions) { if (!additions.contains(plugin)) { for (Plugin dep : getDependants(plugin)) { if (!deletions.contains(dep) && dep.isInstalled()) { log.debug("Add to deletions: " + dep); deletions.add(dep); hasModifications = true; } if (additions.contains(dep)) { log.debug("Remove from additions: " + dep); additions.remove(dep); hasModifications = true; } } } if (hasModifications) { break; // prevent ConcurrentModificationException } } } } private void resolveInstallByDependency() { // resolve dependencies boolean hasModifications = true; while (hasModifications) { log.debug("Check install dependencies: " + additions); hasModifications = false; for (Plugin plugin : additions) { for (String pluginID : plugin.getDepends()) { Plugin depend = getPluginByID(pluginID); if (!depend.isInstalled() || deletions.contains(depend)) { if (!additions.contains(depend)) { log.debug("Add to install: " + depend); additions.add(depend); hasModifications = true; } } } if (hasModifications) { break; // prevent ConcurrentModificationException } } } } private void resolveInstallLibs() { for (Plugin plugin : additions) { Map<String, String> libs = plugin.getLibs(plugin.getCandidateVersion()); for (String lib : libs.keySet()) { if (Plugin.getLibInstallPath(lib) == null) { libAdditions.put(lib, libs.get(lib)); } } } } private void resolveDeleteLibs() { for (Plugin plugin : deletions) { if (additions.contains(plugin)) { // skip upgrades continue; } Map<String, String> libs = plugin.getLibs(plugin.getInstalledVersion()); for (String lib : libs.keySet()) { if (Plugin.getLibInstallPath(lib) != null) { libDeletions.add(lib); } else { log.warn("Did not find library to uninstall it: " + lib); } } } for (Plugin plugin : allPlugins.keySet()) { if (additions.contains(plugin) || (plugin.isInstalled() && !deletions.contains(plugin))) { String ver = additions.contains(plugin) ? plugin.getCandidateVersion() : plugin.getInstalledVersion(); // log.debug("Affects " + plugin + " v" + ver); Map<String, String> libs = plugin.getLibs(ver); for (String lib : libs.keySet()) { if (libDeletions.contains(lib)) { log.debug("Won't delete lib " + lib + " since it is used by " + plugin); libDeletions.remove(lib); } } } } } }
/** * ForeachController that iterates over a list of variables named XXXX_NN stored in {@link * JMeterVariables} where NN is a number starting from 1 to number of occurences. This list of * variable is usually set by PostProcessor (Regexp PostProcessor or {@link HtmlExtractor}) * Iteration can take the full list or only a subset (configured through indexes) */ public class ForeachController extends GenericController implements Serializable { private static final Logger log = LoggingManager.getLoggerForClass(); private static final long serialVersionUID = 240L; private static final String INPUTVAL = "ForeachController.inputVal"; // $NON-NLS-1$ private static final String START_INDEX = "ForeachController.startIndex"; // $NON-NLS-1$ private static final String END_INDEX = "ForeachController.endIndex"; // $NON-NLS-1$ private static final String RETURNVAL = "ForeachController.returnVal"; // $NON-NLS-1$ private static final String USE_SEPARATOR = "ForeachController.useSeparator"; // $NON-NLS-1$ private static final String INDEX_DEFAULT_VALUE = ""; // start/end index default value for string getters and setters private int loopCount = 0; private static final String DEFAULT_SEPARATOR = "_"; // $NON-NLS-1$ public ForeachController() {} /** @param startIndex Start index of loop */ public void setStartIndex(String startIndex) { setProperty(START_INDEX, startIndex, INDEX_DEFAULT_VALUE); } /** @return start index of loop */ private int getStartIndex() { // Although the default is not the same as for the string value, it is only used internally return getPropertyAsInt(START_INDEX, 0); } /** @return start index of loop as String */ public String getStartIndexAsString() { return getPropertyAsString(START_INDEX, INDEX_DEFAULT_VALUE); } /** @param endIndex End index of loop */ public void setEndIndex(String endIndex) { setProperty(END_INDEX, endIndex, INDEX_DEFAULT_VALUE); } /** @return end index of loop */ private int getEndIndex() { // Although the default is not the same as for the string value, it is only used internally return getPropertyAsInt(END_INDEX, Integer.MAX_VALUE); } /** @return end index of loop */ public String getEndIndexAsString() { return getPropertyAsString(END_INDEX, INDEX_DEFAULT_VALUE); } public void setInputVal(String inputValue) { setProperty(new StringProperty(INPUTVAL, inputValue)); } private String getInputVal() { getProperty(INPUTVAL).recoverRunningVersion(null); return getInputValString(); } public String getInputValString() { return getPropertyAsString(INPUTVAL); } public void setReturnVal(String inputValue) { setProperty(new StringProperty(RETURNVAL, inputValue)); } private String getReturnVal() { getProperty(RETURNVAL).recoverRunningVersion(null); return getReturnValString(); } public String getReturnValString() { return getPropertyAsString(RETURNVAL); } private String getSeparator() { return getUseSeparator() ? DEFAULT_SEPARATOR : ""; // $NON-NLS-1$ } public void setUseSeparator(boolean b) { setProperty(new BooleanProperty(USE_SEPARATOR, b)); } public boolean getUseSeparator() { return getPropertyAsBoolean(USE_SEPARATOR, true); } /** {@inheritDoc} */ @Override public boolean isDone() { if (loopCount >= getEndIndex()) { return true; } JMeterContext context = getThreadContext(); StringBuilder builder = new StringBuilder(getInputVal().length() + getSeparator().length() + 3); String inputVariable = builder .append(getInputVal()) .append(getSeparator()) .append(Integer.toString(loopCount + 1)) .toString(); final JMeterVariables variables = context.getVariables(); final Object currentVariable = variables.getObject(inputVariable); if (currentVariable != null) { variables.putObject(getReturnVal(), currentVariable); if (log.isDebugEnabled()) { log.debug("ForEach resultstring isDone=" + variables.get(getReturnVal())); } return false; } return super.isDone(); } /** Tests that JMeterVariables contain inputVal_<count>, if not we can stop iterating */ private boolean endOfArguments() { JMeterContext context = getThreadContext(); String inputVariable = getInputVal() + getSeparator() + (loopCount + 1); if (context.getVariables().getObject(inputVariable) != null) { log.debug("ForEach resultstring eofArgs= false"); return false; } log.debug("ForEach resultstring eofArgs= true"); return true; } // Prevent entry if nothing to do @Override public Sampler next() { if (emptyList()) { reInitialize(); resetLoopCount(); return null; } return super.next(); } /** * Check if there are any matching entries * * @return whether any entries in the list */ private boolean emptyList() { JMeterContext context = getThreadContext(); StringBuilder builder = new StringBuilder(getInputVal().length() + getSeparator().length() + 3); String inputVariable = builder .append(getInputVal()) .append(getSeparator()) .append(Integer.toString(loopCount + 1)) .toString(); if (context.getVariables().getObject(inputVariable) != null) { return false; } if (log.isDebugEnabled()) { log.debug("No entries found - null first entry: " + inputVariable); } return true; } /** {@inheritDoc} */ @Override protected Sampler nextIsNull() throws NextIsNullException { reInitialize(); // Conditions to reset the loop count if (endOfArguments() // no more variables to iterate || loopCount >= getEndIndex() // we reached end index ) { // setDone(true); resetLoopCount(); return null; } return next(); } protected void incrementLoopCount() { loopCount++; } protected void resetLoopCount() { loopCount = getStartIndex(); } /** {@inheritDoc} */ @Override protected int getIterCount() { return loopCount + 1; } /** {@inheritDoc} */ @Override protected void reInitialize() { setFirst(true); resetCurrent(); incrementLoopCount(); recoverRunningVersion(); } /** {@inheritDoc} */ @Override public void triggerEndOfLoop() { super.triggerEndOfLoop(); resetLoopCount(); } /** * Reset loopCount to Start index * * @see org.apache.jmeter.control.GenericController#initialize() */ @Override public void initialize() { super.initialize(); loopCount = getStartIndex(); } }
/** Use this Keystore for JMeter specific KeyStores. */ public final class JmeterKeyStore { private static final Logger LOG = LoggingManager.getLoggerForClass(); private final KeyStore store; /** first index to consider for a key */ private final int startIndex; /** last index to consider for a key */ private final int endIndex; /** name of the default alias */ private String clientCertAliasVarName; private String[] names = new String[0]; // default empty array to prevent NPEs private Map<String, PrivateKey> privateKeyByAlias = new HashMap<String, PrivateKey>(); private Map<String, X509Certificate[]> certsByAlias = new HashMap<String, X509Certificate[]>(); // @GuardedBy("this") private int last_user; /** * @param type type of the {@link KeyStore} * @param startIndex which keys should be considered starting from <code>0</code> * @param endIndex which keys should be considered up to <code>count - 1</code> * @param clientCertAliasVarName name for the default key, if empty use the first key available * @throws KeyStoreException when the type of the keystore is not supported * @throws IllegalArgumentException when <code>startIndex</code> < 0, <code>endIndex</code> * < 0 or <code>endIndex</code> < </code>startIndex</code> */ private JmeterKeyStore(String type, int startIndex, int endIndex, String clientCertAliasVarName) throws KeyStoreException { if (startIndex < 0 || endIndex < 0 || endIndex < startIndex) { throw new IllegalArgumentException( "Invalid index(es). Start=" + startIndex + ", end=" + endIndex); } this.store = KeyStore.getInstance(type); this.startIndex = startIndex; this.endIndex = endIndex; this.clientCertAliasVarName = clientCertAliasVarName; } /** * Process the input stream and try to read the keys from the store * * @param is {@link InputStream} from which the store should be loaded * @param pword the password used to check the integrity of the store * @throws IOException if there is a problem decoding or reading the store. A bad password might * be the cause for this, or an empty store * @throws CertificateException if any of the certificated in the store can not be loaded * @throws NoSuchAlgorithmException if the algorithm to check the integrity of the store can not * be found * @throws KeyStoreException if the store has not been initialized (should not happen here) * @throws UnrecoverableKeyException if the key can not be recovered from the store (should not * happen here, either) */ public void load(InputStream is, String pword) throws NoSuchAlgorithmException, CertificateException, IOException, KeyStoreException, UnrecoverableKeyException { char pw[] = pword == null ? null : pword.toCharArray(); store.load(is, pw); ArrayList<String> v_names = new ArrayList<String>(); this.privateKeyByAlias = new HashMap<String, PrivateKey>(); this.certsByAlias = new HashMap<String, X509Certificate[]>(); if (null != is) { // No point checking an empty keystore PrivateKey _key = null; int index = 0; Enumeration<String> aliases = store.aliases(); while (aliases.hasMoreElements()) { String alias = aliases.nextElement(); if (store.isKeyEntry(alias)) { if (index >= startIndex && index <= endIndex) { _key = (PrivateKey) store.getKey(alias, pw); if (null == _key) { throw new IOException("No key found for alias: " + alias); // Should not happen } Certificate[] chain = store.getCertificateChain(alias); if (null == chain) { throw new IOException("No certificate chain found for alias: " + alias); } v_names.add(alias); X509Certificate[] x509certs = new X509Certificate[chain.length]; for (int i = 0; i < x509certs.length; i++) { x509certs[i] = (X509Certificate) chain[i]; } privateKeyByAlias.put(alias, _key); certsByAlias.put(alias, x509certs); } index++; } } if (null == _key) { throw new IOException("No key(s) found"); } if (index <= endIndex - startIndex) { LOG.warn( "Did not find all requested aliases. Start=" + startIndex + ", end=" + endIndex + ", found=" + certsByAlias.size()); } } /* * Note: if is == null, the arrays will be empty */ this.names = v_names.toArray(new String[v_names.size()]); } /** * Get the ordered certificate chain for a specific alias. * * @param alias the alias for which the certificate chain should be given * @return the certificate chain for the alias * @throws IllegalArgumentException if no chain could be found for the alias */ public X509Certificate[] getCertificateChain(String alias) { X509Certificate[] result = this.certsByAlias.get(alias); if (result != null) { return result; } // API expects null not empty array, see // http://docs.oracle.com/javase/6/docs/api/javax/net/ssl/X509KeyManager.html throw new IllegalArgumentException("No certificate found for alias:'" + alias + "'"); } /** * Get the next or only alias. * * @return the next or only alias. * @throws IllegalArgumentException if {@link JmeterKeyStore#clientCertAliasVarName * clientCertAliasVarName} is not empty and no key for this alias could be found */ public String getAlias() { if (!StringUtils.isEmpty(clientCertAliasVarName)) { // We return even if result is null String aliasName = JMeterContextService.getContext().getVariables().get(clientCertAliasVarName); if (StringUtils.isEmpty(aliasName)) { LOG.error("No var called '" + clientCertAliasVarName + "' found"); throw new IllegalArgumentException("No var called '" + clientCertAliasVarName + "' found"); } return aliasName; } int length = this.names.length; if (length == 0) { // i.e. is == null return null; } return this.names[getIndexAndIncrement(length)]; } public int getAliasCount() { return this.names.length; } public String getAlias(int index) { int length = this.names.length; if (length == 0 && index == 0) { // i.e. is == null return null; } if (index >= length || index < 0) { throw new ArrayIndexOutOfBoundsException(index); } return this.names[index]; } /** * Return the private Key for a specific alias * * @param alias the name of the alias for the private key * @return the private key for the given <code>alias</code> * @throws IllegalArgumentException when no private key could be found */ public PrivateKey getPrivateKey(String alias) { PrivateKey pk = this.privateKeyByAlias.get(alias); if (pk != null) { return pk; } throw new IllegalArgumentException("No PrivateKey found for alias:'" + alias + "'"); } /** * Create a keystore which returns a range of aliases (if available) * * @param type store type (e.g. JKS) * @param startIndex first index (from 0) * @param endIndex last index (to count -1) * @param clientCertAliasVarName name of the default key to, if empty the first key will be used * as default key * @return the keystore * @throws KeyStoreException when the type of the store is not supported * @throws IllegalArgumentException when <code>startIndex</code> < 0, <code>endIndex</code> * < 0, or <code>endIndex</code> < <code>startIndex</code> */ public static JmeterKeyStore getInstance( String type, int startIndex, int endIndex, String clientCertAliasVarName) throws KeyStoreException { return new JmeterKeyStore(type, startIndex, endIndex, clientCertAliasVarName); } /** * Create a keystore which returns the first alias only. * * @param type of the store e.g. JKS * @return the keystore * @throws KeyStoreException when the type of the store is not supported */ public static JmeterKeyStore getInstance(String type) throws KeyStoreException { return getInstance(type, 0, 0, null); } /** * Gets current index and increment by rolling if index is equal to length * * @param length Number of keys to roll */ private int getIndexAndIncrement(int length) { synchronized (this) { int result = last_user++; if (last_user >= length) { last_user = 0; } return result; } } /** * Compiles the list of all client aliases with a private key. TODO Currently, keyType and issuers * are both ignored. * * @param keyType the key algorithm type name (RSA, DSA, etc.) * @param issuers the CA certificates we are narrowing our selection on. * @return the array of aliases; may be empty */ public String[] getClientAliases(String keyType, Principal[] issuers) { int count = getAliasCount(); String[] aliases = new String[count]; for (int i = 0; i < aliases.length; i++) { // if (keys[i].getAlgorithm().equals(keyType)){ // // } aliases[i] = this.names[i]; } if (aliases.length > 0) { return aliases; } else { // API expects null not empty array, see // http://docs.oracle.com/javase/6/docs/api/javax/net/ssl/X509KeyManager.html return null; } } }
public class MD5HexAssertion extends AbstractTestElement implements Serializable, Assertion { private static final Logger log = LoggingManager.getLoggerForClass(); /** Key for storing assertion-informations in the jmx-file. */ private static final String MD5HEX_KEY = "MD5HexAssertion.size"; /* * @param response @return */ public AssertionResult getResult(SampleResult response) { AssertionResult result = new AssertionResult(getName()); result.setFailure(false); byte[] resultData = response.getResponseData(); if (resultData.length == 0) { result.setError(false); result.setFailure(true); result.setFailureMessage("Response was null"); return result; } // no point in checking if we don't have anything to compare against if (getAllowedMD5Hex().equals("")) { result.setError(false); result.setFailure(true); result.setFailureMessage("MD5Hex to test against is empty"); return result; } String md5Result = baMD5Hex(resultData); // String md5Result = DigestUtils.md5Hex(resultData); if (!md5Result.equalsIgnoreCase(getAllowedMD5Hex())) { result.setFailure(true); Object[] arguments = {md5Result, getAllowedMD5Hex()}; String message = MessageFormat.format( JMeterUtils.getResString("md5hex_assertion_failure"), arguments); // $NON-NLS-1$ result.setFailureMessage(message); } return result; } public void setAllowedMD5Hex(String hex) { setProperty(new StringProperty(MD5HexAssertion.MD5HEX_KEY, hex)); } public String getAllowedMD5Hex() { return getPropertyAsString(MD5HexAssertion.MD5HEX_KEY); } // package protected so can be accessed by test class static String baMD5Hex(byte ba[]) { byte[] md5Result = {}; try { MessageDigest md; md = MessageDigest.getInstance("MD5"); md5Result = md.digest(ba); } catch (NoSuchAlgorithmException e) { log.error("", e); } return JOrphanUtils.baToHexString(md5Result); } }
/** @author Maciej Zaleski */ public class WebSocketSampler extends AbstractSampler implements TestStateListener { private static final Logger log = LoggingManager.getLoggerForClass(); private static final String ARG_VAL_SEP = "="; // $NON-NLS-1$ private static final String QRY_SEP = "&"; // $NON-NLS-1$ private static final String WS_PREFIX = "ws://"; // $NON-NLS-1$ private static final String WSS_PREFIX = "wss://"; // $NON-NLS-1$ private static final String DEFAULT_PROTOCOL = "ws"; private static Map<String, ServiceSocket> connectionList; public WebSocketSampler() { super(); setName("WebSocket sampler"); } private ServiceSocket getConnectionSocket() throws URISyntaxException, Exception { URI uri = getUri(); String connectionId = getThreadName() + getConnectionId(); ServiceSocket socket; WebSocketClient webSocketClient; if (isStreamingConnection()) { if (connectionList.containsKey(connectionId)) { socket = connectionList.get(connectionId); socket.initialize(); return socket; } else { socket = new ServiceSocket(this); connectionList.put(connectionId, socket); } } else { socket = new ServiceSocket(this); } SslContextFactory sslContexFactory = new SslContextFactory(); sslContexFactory.setTrustAll(isIgnoreSslErrors()); webSocketClient = new WebSocketClient(sslContexFactory); webSocketClient.start(); ClientUpgradeRequest request = new ClientUpgradeRequest(); webSocketClient.connect(socket, uri, request); int connectionTimeout = Integer.parseInt(getConnectionTimeout()); socket.awaitOpen(connectionTimeout, TimeUnit.MILLISECONDS); return socket; } @Override public SampleResult sample(Entry entry) { ServiceSocket socket = null; SampleResult sampleResult = new SampleResult(); sampleResult.setSampleLabel(getName()); sampleResult.setDataEncoding(getContentEncoding()); StringBuilder errorList = new StringBuilder(); errorList.append("\n\n[Problems]\n"); boolean isOK = false; String payloadMessage = getRequestPayload(); sampleResult.setSamplerData(payloadMessage); sampleResult.sampleStart(); try { socket = getConnectionSocket(); if (socket == null) { sampleResult.setResponseCode("500"); sampleResult.setSuccessful(false); sampleResult.sampleEnd(); sampleResult.setResponseMessage(errorList.toString()); errorList.append(" - Connection couldn't be opened").append("\n"); return sampleResult; } if (!payloadMessage.isEmpty()) { socket.sendMessage(payloadMessage); } int responseTimeout = Integer.parseInt(getResponseTimeout()); socket.awaitClose(responseTimeout, TimeUnit.MILLISECONDS); if (socket.getResponseMessage() == null || socket.getResponseMessage().isEmpty()) { sampleResult.setResponseCode("204"); } if (socket.getError() != 0) { isOK = false; sampleResult.setResponseCode(socket.getError().toString()); } else { sampleResult.setResponseCodeOK(); isOK = true; } sampleResult.setResponseData(socket.getResponseMessage(), getContentEncoding()); } catch (URISyntaxException e) { errorList .append(" - Invalid URI syntax: ") .append(e.getMessage()) .append("\n") .append(StringUtils.join(e.getStackTrace(), "\n")) .append("\n"); } catch (IOException e) { errorList .append(" - IO Exception: ") .append(e.getMessage()) .append("\n") .append(StringUtils.join(e.getStackTrace(), "\n")) .append("\n"); } catch (NumberFormatException e) { errorList .append(" - Cannot parse number: ") .append(e.getMessage()) .append("\n") .append(StringUtils.join(e.getStackTrace(), "\n")) .append("\n"); } catch (InterruptedException e) { errorList .append(" - Execution interrupted: ") .append(e.getMessage()) .append("\n") .append(StringUtils.join(e.getStackTrace(), "\n")) .append("\n"); } catch (Exception e) { errorList .append(" - Unexpected error: ") .append(e.getMessage()) .append("\n") .append(StringUtils.join(e.getStackTrace(), "\n")) .append("\n"); } sampleResult.sampleEnd(); sampleResult.setSuccessful(isOK); String logMessage = (socket != null) ? socket.getLogMessage() : ""; sampleResult.setResponseMessage(logMessage + errorList); return sampleResult; } @Override public void setName(String name) { if (name != null) { setProperty(TestElement.NAME, name); } } @Override public String getName() { return getPropertyAsString(TestElement.NAME); } @Override public void setComment(String comment) { setProperty(new StringProperty(TestElement.COMMENTS, comment)); } @Override public String getComment() { return getProperty(TestElement.COMMENTS).getStringValue(); } public URI getUri() throws URISyntaxException { String path = this.getContextPath(); // Hack to allow entire URL to be provided in host field if (path.startsWith(WS_PREFIX) || path.startsWith(WSS_PREFIX)) { return new URI(path); } String domain = getServerAddress(); String protocol = getProtocol(); // HTTP URLs must be absolute, allow file to be relative if (!path.startsWith("/")) { // $NON-NLS-1$ path = "/" + path; // $NON-NLS-1$ } String queryString = getQueryString(getContentEncoding()); if (isProtocolDefaultPort()) { return new URI(protocol, null, domain, -1, path, queryString, null); } return new URI( protocol, null, domain, Integer.parseInt(getServerPort()), path, queryString, null); } /** * Tell whether the default port for the specified protocol is used * * @return true if the default port number for the protocol is used, false otherwise */ public boolean isProtocolDefaultPort() { final int port = Integer.parseInt(getServerPort()); final String protocol = getProtocol(); return ("ws".equalsIgnoreCase(protocol) && port == HTTPConstants.DEFAULT_HTTP_PORT) || ("wss".equalsIgnoreCase(protocol) && port == HTTPConstants.DEFAULT_HTTPS_PORT); } public String getServerPort() { final String port_s = getPropertyAsString("serverPort", "0"); Integer port; String protocol = getProtocol(); try { port = Integer.parseInt(port_s); } catch (Exception ex) { port = 0; } if (port == 0) { if ("wss".equalsIgnoreCase(protocol)) { return String.valueOf(HTTPConstants.DEFAULT_HTTPS_PORT); } else if ("ws".equalsIgnoreCase(protocol)) { return String.valueOf(HTTPConstants.DEFAULT_HTTP_PORT); } } return port.toString(); } public void setServerPort(String port) { setProperty("serverPort", port); } public String getResponseTimeout() { return getPropertyAsString("responseTimeout", "20000"); } public void setResponseTimeout(String responseTimeout) { setProperty("responseTimeout", responseTimeout); } public String getConnectionTimeout() { return getPropertyAsString("connectionTimeout", "5000"); } public void setConnectionTimeout(String connectionTimeout) { setProperty("connectionTimeout", connectionTimeout); } public void setProtocol(String protocol) { setProperty("protocol", protocol); } public String getProtocol() { String protocol = getPropertyAsString("protocol"); if (protocol == null || protocol.isEmpty()) { return DEFAULT_PROTOCOL; } return protocol; } public void setServerAddress(String serverAddress) { setProperty("serverAddress", serverAddress); } public String getServerAddress() { return getPropertyAsString("serverAddress"); } public void setImplementation(String implementation) { setProperty("implementation", implementation); } public String getImplementation() { return getPropertyAsString("implementation"); } public void setContextPath(String contextPath) { setProperty("contextPath", contextPath); } public String getContextPath() { return getPropertyAsString("contextPath"); } public void setContentEncoding(String contentEncoding) { setProperty("contentEncoding", contentEncoding); } public String getContentEncoding() { return getPropertyAsString("contentEncoding", "UTF-8"); } public void setRequestPayload(String requestPayload) { setProperty("requestPayload", requestPayload); } public String getRequestPayload() { return getPropertyAsString("requestPayload"); } public void setIgnoreSslErrors(Boolean ignoreSslErrors) { setProperty("ignoreSslErrors", ignoreSslErrors); } public Boolean isIgnoreSslErrors() { return getPropertyAsBoolean("ignoreSslErrors"); } public void setStreamingConnection(Boolean streamingConnection) { setProperty("streamingConnection", streamingConnection); } public Boolean isStreamingConnection() { return getPropertyAsBoolean("streamingConnection"); } public void setConnectionId(String connectionId) { setProperty("connectionId", connectionId); } public String getConnectionId() { return getPropertyAsString("connectionId"); } public void setResponsePattern(String responsePattern) { setProperty("responsePattern", responsePattern); } public String getResponsePattern() { return getPropertyAsString("responsePattern"); } public void setCloseConncectionPattern(String closeConncectionPattern) { setProperty("closeConncectionPattern", closeConncectionPattern); } public String getCloseConncectionPattern() { return getPropertyAsString("closeConncectionPattern"); } public void setProxyAddress(String proxyAddress) { setProperty("proxyAddress", proxyAddress); } public String getProxyAddress() { return getPropertyAsString("proxyAddress"); } public void setProxyPassword(String proxyPassword) { setProperty("proxyPassword", proxyPassword); } public String getProxyPassword() { return getPropertyAsString("proxyPassword"); } public void setProxyPort(String proxyPort) { setProperty("proxyPort", proxyPort); } public String getProxyPort() { return getPropertyAsString("proxyPort"); } public void setProxyUsername(String proxyUsername) { setProperty("proxyUsername", proxyUsername); } public String getProxyUsername() { return getPropertyAsString("proxyUsername"); } public void setMessageBacklog(String messageBacklog) { setProperty("messageBacklog", messageBacklog); } public String getMessageBacklog() { return getPropertyAsString("messageBacklog", "3"); } public String getQueryString(String contentEncoding) { // Check if the sampler has a specified content encoding if (JOrphanUtils.isBlank(contentEncoding)) { // We use the encoding which should be used according to the HTTP spec, which is UTF-8 contentEncoding = EncoderCache.URL_ARGUMENT_ENCODING; } StringBuilder buf = new StringBuilder(); PropertyIterator iter = getQueryStringParameters().iterator(); boolean first = true; while (iter.hasNext()) { HTTPArgument item = null; Object objectValue = iter.next().getObjectValue(); try { item = (HTTPArgument) objectValue; } catch (ClassCastException e) { item = new HTTPArgument((Argument) objectValue); } final String encodedName = item.getEncodedName(); if (encodedName.length() == 0) { continue; // Skip parameters with a blank name (allows use of optional variables in // parameter lists) } if (!first) { buf.append(QRY_SEP); } else { first = false; } buf.append(encodedName); if (item.getMetaData() == null) { buf.append(ARG_VAL_SEP); } else { buf.append(item.getMetaData()); } // Encode the parameter value in the specified content encoding try { buf.append(item.getEncodedValue(contentEncoding)); } catch (UnsupportedEncodingException e) { log.warn( "Unable to encode parameter in encoding " + contentEncoding + ", parameter value not included in query string"); } } return buf.toString(); } public void setQueryStringParameters(Arguments queryStringParameters) { setProperty(new TestElementProperty("queryStringParameters", queryStringParameters)); } public Arguments getQueryStringParameters() { Arguments args = (Arguments) getProperty("queryStringParameters").getObjectValue(); return args; } @Override public void testStarted() { testStarted("unknown"); } @Override public void testStarted(String host) { connectionList = new ConcurrentHashMap<String, ServiceSocket>(); } @Override public void testEnded() { testEnded("unknown"); } @Override public void testEnded(String host) { for (ServiceSocket socket : connectionList.values()) { socket.close(); } } }
public class BaseTestListenerImpl implements BaseTestListener { // static variables /** Logger */ private static final Logger LOGGER = LoggingManager.getLoggerForClass(); private final Translator<SampleEvent, BaseSampleEntity[]> mTranslator; /** Aggregates data for the trend line */ private final Aggregator<Long, AggregationKey, Integer> mTrendLineAggregator; /** * Efficiently writes objects to the DB. Defaulted to {@link NOPSampleWriter}, but initialized to * real object during {@link #testStarted()} */ private final AsynchSampleWriter<AgentDataPoint> mSWriter; /** * Handles retries, in case the agent is locked. Defaulted to {@link NOPSampleWriter}, but set to * real updater during {@link #testStarted()} */ private final SampleWriter<TestJobAgentWorker> mAgentUpdater; private final Provider<TestJobAgentWorker> mAgentProvider; private final Long mTimeBound; private final Long mAgentThreadCount; private final String mTargetWebServer; private final Timer mTrendLineTimer; private final TimerTask mTrendLineTask; private final long mTrendLinePeriod; /** used to represent all threads, all actions/transactiosn */ private final AggregationKey mNullKey; /** * Bypasses both {@link #mLimitErrorSamples} and {@link #mErrorSampleLimitCountDown}, will keep * all raw data for all trends (action, transaction, errors) */ private final boolean mCollectRawData; // 609828[Error store limit] Limit the maximum error number to be stored. /** * When this counter reaches 0, no more error samples will be collected. However, error counts and * percentages will still be processed. */ private final AtomicInteger mErrorSampleLimitCountDown; /** * Unchangeable value that indicates if individual error samples should be limit if < 0, then * bypasses the limit set by {@link #mErrorSampleLimitCountDown} */ private final boolean mLimitErrorSamples; private Timestamp mStartTimeStamp; private Thread mAgentUpdateThread; /** * @param writer * @param agentUpdater * @param translator * @param trendLineAggregator * @param agentProvider * @param timeBound * @param agentThreadCount * @param targetWebServer * @param trendLineTimer * @param trendLineTask * @param trendLinePeriod * @param nullAggregatorKey * @param collectRawData * @param errorSampleLimit */ @Inject public BaseTestListenerImpl( AsynchSampleWriter<AgentDataPoint> writer, SampleWriter<TestJobAgentWorker> agentUpdater, Translator<SampleEvent, BaseSampleEntity[]> translator, Aggregator<Long, AggregationKey, Integer> trendLineAggregator, @Retrieve Provider<TestJobAgentWorker> agentProvider, @Named("timebound") Long timeBound, @Named("threadCount") Long agentThreadCount, @Named("webServer") String targetWebServer, @Named("trend.line") Timer trendLineTimer, @Named("trend.line") TimerTask trendLineTask, @Named("trend.line.period") long trendLinePeriod, @Named("null") AggregationKey nullAggregatorKey, @Named("collect.raw.data") boolean collectRawData, @Named("error.sample.limit") int errorSampleLimit) { // TODO [write error to file] pass in a new writer for error (wrap the MS Writer for database) mTranslator = translator; mTrendLineAggregator = trendLineAggregator; mSWriter = writer; mAgentUpdater = agentUpdater; mAgentProvider = agentProvider; mTimeBound = timeBound; mAgentThreadCount = agentThreadCount; mTargetWebServer = targetWebServer; // 609828[Error store limit] Limit the maximum error number to be stored. mErrorSampleLimitCountDown = new AtomicInteger(errorSampleLimit); mLimitErrorSamples = errorSampleLimit >= 0; // 615093: [Error limit -1] Error limit -1 doesn't work well. LOGGER.info( String.format( "Will limit error sample collection [%b] to [%d]", mLimitErrorSamples, mErrorSampleLimitCountDown.get())); mTrendLineTimer = trendLineTimer; mTrendLineTask = trendLineTask; mTrendLinePeriod = trendLinePeriod; mNullKey = nullAggregatorKey; mCollectRawData = collectRawData; mTrendLineTimer.schedule(mTrendLineTask, mTrendLinePeriod, mTrendLinePeriod); mStartTimeStamp = new Timestamp(System.currentTimeMillis()); updateAgent(); mAgentUpdateThread = new Thread( new Runnable() { @Override public void run() { LOGGER.info("Running agent update Thread"); try { while (!Thread.interrupted()) { LOGGER.info("Waiting for agent update"); Thread.sleep((long) (2 * Math.random() * 1000)); LOGGER.info("Updating agent"); updateAgent(); } } catch (InterruptedException e) { LOGGER.info("agent update thread interrupted"); } LOGGER.info("agent update stop"); } }); mAgentUpdateThread.setDaemon(true); mAgentUpdateThread.setName("agent update thread"); mAgentUpdateThread.start(); } private void updateAgent() { // We need to write the agent to the db, // We'll potentially need to retry due to possible database locking // so we use the JPAAgentUpdater that already knows // how to do this try { // initial agent parameters final TestJobAgentWorker lAgent = mAgentProvider.get(); LOGGER.info("Successfully retrieved agent " + lAgent); if (lAgent.getProcessID() != null) { LOGGER.info( "Process succsesfully retrieved " + lAgent.getProcessID() + ". Stopping agent update thread"); mAgentUpdateThread.interrupt(); return; } LOGGER.info("PID not yet set, retrieving and updating"); configureAgentInitialParameters(lAgent); LOGGER.info("Updating agent"); mAgentUpdater.write(lAgent); } catch (Exception e) { LOGGER.error("Couldn't write the agent", e); } } private void configureAgentInitialParameters(final TestJobAgentWorker lAgent) throws UnknownHostException { lAgent.setTimeBound(mTimeBound); lAgent.setThreadNumber(mAgentThreadCount); lAgent.setTargetWebServer(mTargetWebServer); HibernateUtils.setMachineData(lAgent); lAgent.setStartTimestamp(mStartTimeStamp); lAgent.setComputationalInterval(mTrendLinePeriod); } /* (non-Javadoc) * @see com.microstrategy.mfloadtest.jdbcwriter.BaseTestListener#sampleOccurred(org.apache.jmeter.samplers.SampleEvent) */ @Override public void sampleOccurred(SampleEvent event) { // multi threads will be accessing this // with different callstacks // do not check for the mSession==null, // all the objects here are safe without a db connection // will obtain the entities in order: // action, transaction, errors final BaseSampleEntity[] lEntities = mTranslator.translate(event); if (LOGGER.isDebugEnabled()) { LOGGER.debug("Sending entries to aggregator"); } final ArrayList<BaseSampleEntity> lErrors = new ArrayList<BaseSampleEntity>(); // make sure to populate all the aggregators // in the same interval // within the same interval synchronized (mTrendLineAggregator) { for (BaseSampleEntity lEntity : lEntities) { if (lEntity instanceof ActionSampleEntity) { sendActionToAggregator((ActionSampleEntity) lEntity); } else if (lEntity instanceof SampleEntity) { sendTransactionToAggregator((SampleEntity) lEntity); } else if (lEntity instanceof ErrorSampleEntity) { if (!mLimitErrorSamples || mErrorSampleLimitCountDown.decrementAndGet() >= 0) { lErrors.add(lEntity); } else if (LOGGER.isDebugEnabled()) { LOGGER.debug("Error not logged, because limit was reached"); } sendErrorToAggregator((ErrorSampleEntity) lEntity); } } } if (LOGGER.isDebugEnabled()) { // be careful about performance LOGGER.debug(String.format("entries commited %s", mTrendLineAggregator)); LOGGER.debug("sending entities to writer"); } if (mCollectRawData) { // this has to happen at the end, because the transactions are lost mSWriter.write(lEntities); } else { mSWriter.write(lErrors.toArray(new BaseSampleEntity[0])); } } private void sendErrorToAggregator(ErrorSampleEntity lEntity) { LOGGER.debug("sending error to aggregator"); final AggregationKey lKey = new AggregationKey( AggregationKey.Type.ERROR, lEntity.getThreadGroup(), lEntity.getTransaction()); // just add 1, what we need is the count mTrendLineAggregator.getMetric(MetricID.COUNT, lKey).addSample(1L); } private void sendTransactionToAggregator(SampleEntity lEntity) { LOGGER.debug("sending transaction to aggregator"); final AggregationKey lKey = new AggregationKey( AggregationKey.Type.TRANSACTION, lEntity.getThreadGroup(), lEntity.getTransaction()); mTrendLineAggregator .getMetric(MetricID.RESPONSE_TIME, lKey) .addSample(lEntity.getResponseTime()); } private void sendActionToAggregator(ActionSampleEntity lAction) { if (LOGGER.isDebugEnabled()) { LOGGER.debug("sending action to aggregator"); } final AggregationKey lKey = new AggregationKey( AggregationKey.Type.ACTION, lAction.getThreadGroup(), lAction.getTransaction()); mTrendLineAggregator .getMetric(MetricID.RESPONSE_TIME, lKey) .addSample(lAction.getResponseTime()); mTrendLineAggregator .getMetric(MetricID.THREAD_COUNT, mNullKey) .addSample(lAction.getActiveThreads()); mTrendLineAggregator.getMetric(MetricID.BYTE_COUNT, lKey).addSample(lAction.getByteCount()); if (LOGGER.isDebugEnabled()) { LOGGER.debug(String.format("Response Time [%s]%d", lKey, lAction.getResponseTime())); LOGGER.debug(String.format("Active Threads [%s]%d", lKey, lAction.getActiveThreads())); LOGGER.debug(String.format("Byte Count [%s]%d", lKey, lAction.getByteCount())); } } /* (non-Javadoc) * @see com.microstrategy.mfloadtest.jdbcwriter.BaseTestListener#testEnded() */ @Override public void testEnded() { // this can only come from 1 thread final Timestamp lTimeStamp = new Timestamp(new Date().getTime()); // do unconditionally mTrendLineTimer.cancel(); try { final TestJobAgentWorker lAgent = mAgentProvider.get(); lAgent.setEndTimestamp(lTimeStamp); lAgent.setLastNumberOfActiveThreads(0l); mAgentUpdater.write(lAgent); mSWriter.flush(); mSWriter.close(); mAgentUpdateThread.interrupt(); } catch (Exception e) { LOGGER.error("testEnded", e); throw new RuntimeException("testEnded", e); } } }
/** * A function which understands BeanShell * * @since 1.X */ public class BeanShell extends AbstractFunction { private static final Logger log = LoggingManager.getLoggerForClass(); private static final List<String> desc = new LinkedList<String>(); private static final String KEY = "__BeanShell"; // $NON-NLS-1$ public static final String INIT_FILE = "beanshell.function.init"; // $NON-NLS-1$ static { desc.add(JMeterUtils.getResString("bsh_function_expression")); // $NON-NLS1$ desc.add(JMeterUtils.getResString("function_name_paropt")); // $NON-NLS1$ } private Object[] values; private BeanShellInterpreter bshInterpreter = null; public BeanShell() {} /** {@inheritDoc} */ @Override public synchronized String execute(SampleResult previousResult, Sampler currentSampler) throws InvalidVariableException { if (bshInterpreter == null) // did we find BeanShell? { throw new InvalidVariableException("BeanShell not found"); } JMeterContext jmctx = JMeterContextService.getContext(); JMeterVariables vars = jmctx.getVariables(); String script = ((CompoundVariable) values[0]).execute(); String varName = ""; // $NON-NLS-1$ if (values.length > 1) { varName = ((CompoundVariable) values[1]).execute().trim(); } String resultStr = ""; // $NON-NLS-1$ log.debug("Script=" + script); try { // Pass in some variables if (currentSampler != null) { bshInterpreter.set("Sampler", currentSampler); // $NON-NLS-1$ } if (previousResult != null) { bshInterpreter.set("SampleResult", previousResult); // $NON-NLS-1$ } // Allow access to context and variables directly bshInterpreter.set("ctx", jmctx); // $NON-NLS-1$ bshInterpreter.set("vars", vars); // $NON-NLS-1$ bshInterpreter.set("props", JMeterUtils.getJMeterProperties()); // $NON-NLS-1$ bshInterpreter.set("threadName", Thread.currentThread().getName()); // $NON-NLS-1$ // Execute the script Object bshOut = bshInterpreter.eval(script); if (bshOut != null) { resultStr = bshOut.toString(); } if (vars != null && varName.length() > 0) { // vars will be null on TestPlan vars.put(varName, resultStr); } } catch (Exception ex) // Mainly for bsh.EvalError { log.warn("Error running BSH script", ex); } log.debug("Output=" + resultStr); return resultStr; } /* * Helper method for use by scripts * */ public void log_info(String s) { log.info(s); } /** {@inheritDoc} */ @Override public synchronized void setParameters(Collection<CompoundVariable> parameters) throws InvalidVariableException { checkParameterCount(parameters, 1, 2); values = parameters.toArray(); try { bshInterpreter = new BeanShellInterpreter(JMeterUtils.getProperty(INIT_FILE), log); } catch (ClassNotFoundException e) { throw new InvalidVariableException("BeanShell not found", e); } } /** {@inheritDoc} */ @Override public String getReferenceKey() { return KEY; } /** {@inheritDoc} */ @Override public List<String> getArgumentDesc() { return desc; } }
/** @author undera */ public class RawRequestSourcePreProcessor extends AbstractTestElement implements PreProcessor, NoThreadClone { public static final String regexp = "\\s"; private static final Logger log = LoggingManager.getLoggerForClass(); public static final String VARIABLE_NAME = "variable_name"; public static final String FILENAME = "filename"; public static final String REWIND = "rewind"; public static final String ENCODE_HEX = "isHex"; private FileChannel file; private final ByteBuffer metaBuf = ByteBuffer.allocateDirect(1024); private final ByteBuffer oneByte = ByteBuffer.allocateDirect(1); public static final Charset binaryCharset = Charset.forName("UTF8"); public RawRequestSourcePreProcessor() { super(); } @Override public synchronized void process() { if (file == null) { log.info("Creating file object: " + getFileName()); try { file = new FileInputStream(getFileName()).getChannel(); } catch (FileNotFoundException ex) { log.error(getFileName(), ex); return; } } String rawData; try { rawData = readNextChunk(getNextChunkSize()); } catch (EndOfFileException ex) { if (getRewindOnEOF()) { if (log.isDebugEnabled()) { log.debug("Rewind file"); } try { file.position(0); } catch (IOException ex1) { log.error("Cannot rewind", ex1); } process(); return; } else { log.info("End of file reached: " + getFileName()); if (JMeterContextService.getContext().getThread() != null) { JMeterContextService.getContext().getThread().stop(); } throw new RuntimeEOFException("End of file reached", ex); } } catch (IOException ex) { log.error("Error reading next chunk", ex); throw new RuntimeException("Error reading next chunk", ex); } final JMeterVariables vars = JMeterContextService.getContext().getVariables(); if (vars != null) { vars.put(getVarName(), rawData); } } private synchronized String readNextChunk(int capacity) throws IOException { if (capacity == 0) { throw new EndOfFileException("Zero chunk size, possibly end of file reached."); } ByteBuffer buf = ByteBuffer.allocateDirect(capacity); byte[] dst = new byte[capacity]; int cnt = file.read(buf); // log.debug("Read " + cnt); if (cnt != capacity) { throw new IOException( "Expected chunk size (" + capacity + ") differs from read bytes count (" + cnt + ")"); } buf.flip(); buf.get(dst); if (log.isDebugEnabled()) { log.debug("Chunk : " + new String(dst)); } if (isHexEncode()) { return JOrphanUtils.baToHexString(dst); } else { return new String(dst, binaryCharset); } } private int getNextChunkSize() throws IOException { metaBuf.clear(); while (true) { byte b = getOneByte(); if (b == 10 || b == 13) { // if we have \r\n then skip \n byte b2 = getOneByte(); if (b2 != 10) { file.position(file.position() - 1); } // ignore newlines before length marker if (metaBuf.position() > 0) { break; } } else { // if (log.isDebugEnabled()) log.debug("Read byte: "+b); metaBuf.put(b); } } // if (log.isDebugEnabled()) log.debug("Meta line: // "+JMeterPluginsUtils.byteBufferToString(metaBuf)); byte[] bLine = new byte[metaBuf.position()]; metaBuf.rewind(); metaBuf.get(bLine); String sLine = new String(bLine).trim(); String[] ar = sLine.split(regexp); if (log.isDebugEnabled()) { log.debug("Chunk size: " + ar[0]); } int res = 0; try { res = Integer.parseInt(ar[0]); } catch (NumberFormatException ex) { log.error("Error reading chunk size near: " + sLine, ex); throw new IOExceptionWithCause(ex); } return res; } private byte getOneByte() throws IOException { oneByte.rewind(); if (file.read(oneByte) < 1) { throw new EndOfFileException(getFileName()); } return oneByte.get(0); } public String getVarName() { return getPropertyAsString(VARIABLE_NAME); } public void setVarName(String name) { setProperty(VARIABLE_NAME, name); } public String getFileName() { return getPropertyAsString(FILENAME); } public void setFileName(String filename) { setProperty(FILENAME, filename); file = null; } public void setRewindOnEOF(boolean isRew) { setProperty(new BooleanProperty(REWIND, isRew)); } public boolean getRewindOnEOF() { return getPropertyAsBoolean(REWIND); } public boolean isHexEncode() { return getPropertyAsBoolean(ENCODE_HEX); } public void setEncodeHex(boolean b) { setProperty(ENCODE_HEX, b); } }