+ * (only used by HTTPSampleResult) + * + * @param elapsed time + * @param atend create the sample finishing now, else starting now + */ + protected SampleResult(long elapsed, boolean atend) { + this(); + long now = currentTimeInMillis(); + if (atend) { + setTimes(now - elapsed, now); + } else { + setTimes(now, now + elapsed); + } + } + + /** + * Allow users to create a sample with specific timestamp and elapsed times + * for cloning purposes, but don't allow the times to be changed later + *
+ * Currently used by CSVSaveService and + * StatisticalSampleResult + * + * @param stamp this may be a start time or an end time (both in + * milliseconds) + * @param elapsed time in milliseconds + */ + public SampleResult(long stamp, long elapsed) { + this(); + stampAndTime(stamp, elapsed); + } + + private long initOffset() { + if (useNanoTime) { + return nanoThreadSleep > 0 ? NanoOffset.getNanoOffset() : System.currentTimeMillis() - sampleNsClockInMs(); + } else { + return Long.MIN_VALUE; + } + } + + /** + * @param propertiesToSave The propertiesToSave to set. + */ + public void setSaveConfig(SampleSaveConfiguration propertiesToSave) { + this.saveConfig = propertiesToSave; + } + + public SampleSaveConfiguration getSaveConfig() { + return saveConfig; + } + + public boolean isStampedAtStart() { + return START_TIMESTAMP; + } + + /** + * Create a sample with specific start and end times for test purposes, but + * don't allow the times to be changed later + *
+ * (used by StatVisualizerModel.Test)
+ *
+ * @param start start time in milliseconds since unix epoch
+ * @param end end time in milliseconds since unix epoch
+ * @return sample with given start and end time
+ */
+ public static SampleResult createTestSample(long start, long end) {
+ SampleResult res = new SampleResult();
+ res.setStartTime(start);
+ res.setEndTime(end);
+ return res;
+ }
+
+ /**
+ * Create a sample with a specific elapsed time for test purposes, but don't
+ * allow the times to be changed later
+ *
+ * @param elapsed - desired elapsed time in milliseconds
+ * @return sample that starts 'now' and ends elapsed
milliseconds later
+ */
+ public static SampleResult createTestSample(long elapsed) {
+ long now = System.currentTimeMillis();
+ return createTestSample(now, now + elapsed);
+ }
+
+ private static long sampleNsClockInMs() {
+ return System.nanoTime() / 1000000;
+ }
+
+ /**
+ * Helper method to get 1 ms resolution timing.
+ *
+ * @return the current time in milliseconds
+ * @throws RuntimeException when useNanoTime
is true
but
+ * nanoTimeOffset
is not set
+ */
+ public long currentTimeInMillis() {
+ if (useNanoTime) {
+ if (nanoTimeOffset == Long.MIN_VALUE) {
+ throw new IllegalStateException("Invalid call; nanoTimeOffset has not been set");
+ }
+ return sampleNsClockInMs() + nanoTimeOffset;
+ }
+ return System.currentTimeMillis();
+ }
+
+ // Helper method to maintain timestamp relationships
+ private void stampAndTime(long stamp, long elapsed) {
+ if (START_TIMESTAMP) {
+ startTime = stamp;
+ endTime = stamp + elapsed;
+ } else {
+ startTime = stamp - elapsed;
+ endTime = stamp;
+ }
+ timeStamp = stamp;
+ elapsedTime = elapsed;
+ }
+
+ /**
+ * For use by SaveService only.
+ *
+ * @param stamp this may be a start time or an end time (both in milliseconds)
+ * @param elapsed time in milliseconds
+ * @throws RuntimeException when startTime
or endTime
has been
+ * set already
+ */
+ public void setStampAndTime(long stamp, long elapsed) {
+ if (startTime != 0 || endTime != 0) {
+ throw new IllegalStateException("Calling setStampAndTime() after start/end times have been set");
+ }
+ stampAndTime(stamp, elapsed);
+ }
+
+ /**
+ * Set the "marked" flag to show that the result has been written to the file.
+ *
+ * @param filename the name of the file
+ * @return true
if the result was previously marked
+ */
+ public boolean markFile(String filename) {
+ return !files.add(filename != null ? filename : NULL_FILENAME);
+ }
+
+ public String getResponseCode() {
+ return responseCode;
+ }
+
+ /**
+ * Set response code to OK, i.e. "200"
+ */
+ public void setResponseCodeOK() {
+ responseCode = OK_CODE;
+ }
+
+ public void setResponseCode(String code) {
+ responseCode = code;
+ }
+
+ public boolean isResponseCodeOK() {
+ return responseCode.equals(OK_CODE);
+ }
+
+ public String getResponseMessage() {
+ return responseMessage;
+ }
+
+ public void setResponseMessage(String msg) {
+ responseMessage = msg;
+ }
+
+ public void setResponseMessageOK() {
+ responseMessage = OK_MSG;
+ }
+
+ /**
+ * Set result statuses OK - shorthand method to set:
+ *
+ * As for {@link SampleResult#addSubResult(SampleResult) + * addSubResult(SampleResult)}, except that the fields don't need to be + * accumulated + * + * @param subResult the {@link SampleResult} to be added + */ + public void storeSubResult(SampleResult subResult) { + storeSubResult(subResult, isRenameSampleLabel()); + } + + /** + * Add a subresult read from a results file. + *
+ * As for {@link SampleResult#addSubResult(SampleResult) + * addSubResult(SampleResult)}, except that the fields don't need to be + * accumulated + * + * @param subResult the {@link SampleResult} to be added + * @param renameSubResults boolean do we rename subResults based on position + */ + private void storeSubResult(SampleResult subResult, boolean renameSubResults) { + if (subResults == null) { + subResults = new ArrayList<>(); + } + if (renameSubResults) { + subResult.setSampleLabel(getSampleLabel() + "-" + subResultIndex++); + } + subResults.add(subResult); + subResult.setParent(this); + } + + /** + * Gets the subresults associated with this sample. + * + * @return an array containing the subresults for this sample. Returns an + * empty array if there are no subresults. + */ + public SampleResult[] getSubResults() { + if (subResults == null) { + return EMPTY_SR; + } + return subResults.toArray(new SampleResult[subResults.size()]); + } + + /** + * Sets the responseData attribute of the SampleResult object. + *
+ * If the parameter is null, then the responseData is set to an empty byte array. + * This ensures that getResponseData() can never be null. + * + * @param response the new responseData value + */ + public void setResponseData(byte[] response) { + responseDataAsString = null; + responseData = response == null ? EMPTY_BA : response; + } + + /** + * Sets the responseData attribute of the SampleResult object. + * Should only be called after setting the dataEncoding (if necessary) + * + * @param response the new responseData value (String) + * @deprecated - only intended for use from BeanShell code + */ + @Deprecated + public void setResponseData(String response) { + responseDataAsString = null; + try { + responseData = response.getBytes(getDataEncodingWithDefault()); + } catch (UnsupportedEncodingException e) { + log.warn("Could not convert string, using default encoding. " + e.getLocalizedMessage()); + responseData = response.getBytes(Charset.defaultCharset()); // N.B. default charset is used deliberately here + } + } + + /** + * Sets the encoding and responseData attributes of the SampleResult object. + * + * @param response the new responseData value (String) + * @param encoding the encoding to set and then use (if null, use platform default) + */ + public void setResponseData(final String response, final String encoding) { + responseDataAsString = null; + String encodeUsing = encoding != null ? encoding : DEFAULT_CHARSET; + try { + responseData = response.getBytes(encodeUsing); + setDataEncoding(encodeUsing); + } catch (UnsupportedEncodingException e) { + log.warn("Could not convert string using '" + encodeUsing + + "', using default encoding: " + DEFAULT_CHARSET, e); + responseData = response.getBytes(Charset.defaultCharset()); // N.B. default charset is used deliberately here + setDataEncoding(DEFAULT_CHARSET); + } + } + + /** + * Gets the responseData attribute of the SampleResult object. + *
+ * Note that some samplers may not store all the data, in which case + * getResponseData().length will be incorrect. + *
+ * Instead, always use {@link #getBytes()} to obtain the sample result byte count. + *
+ * + * @return the responseData value (cannot be null) + */ + public byte[] getResponseData() { + return responseData; + } + + /** + * Gets the responseData of the SampleResult object as a String + * + * @return the responseData value as a String, converted according to the encoding + */ + public String getResponseDataAsString() { + try { + if (responseDataAsString == null) { + responseDataAsString = new String(responseData, getDataEncodingWithDefault()); + } + return responseDataAsString; + } catch (UnsupportedEncodingException e) { + log.warn("Using platform default as " + getDataEncodingWithDefault() + " caused " + e); + return new String(responseData, Charset.defaultCharset()); // N.B. default charset is used deliberately here + } + } + + public void setSamplerData(String s) { + samplerData = s; + } + + public String getSamplerData() { + return samplerData; + } + + /** + * Get the time it took this sample to occur. + * + * @return elapsed time in milliseconds + */ + public long getTime() { + return elapsedTime; + } + + public boolean isSuccessful() { + return success; + } + + /** + * Sets the data type of the sample. + * + * @param dataType String containing {@link #BINARY} or {@link #TEXT} + * @see #BINARY + * @see #TEXT + */ + public void setDataType(String dataType) { + this.dataType = dataType; + } + + /** + * Returns the data type of the sample. + * + * @return String containing {@link #BINARY} or {@link #TEXT} or the empty string + * @see #BINARY + * @see #TEXT + */ + public String getDataType() { + return dataType; + } + + /** + * Extract and save the DataEncoding and DataType from the parameter provided. + * Does not save the full content Type. + * + * @param ct - content type (may be null) + * @see #setContentType(String) which should be used to save the full content-type string + */ + public void setEncodingAndType(String ct) { + if (ct != null) { + // Extract charset and store as DataEncoding + // N.B. The meta tag: + // + // is now processed by HTTPSampleResult#getDataEncodingWithDefault + final String charsetPrefix = "charset="; // $NON-NLS-1$ + int cset = ct.toLowerCase(java.util.Locale.ENGLISH).indexOf(charsetPrefix); + if (cset >= 0) { + String charSet = ct.substring(cset + charsetPrefix.length()); + // handle: ContentType: text/plain; charset=ISO-8859-1; format=flowed + int semiColon = charSet.indexOf(';'); + if (semiColon >= 0) { + charSet = charSet.substring(0, semiColon); + } + // Check for quoted string + if (charSet.startsWith("\"") || charSet.startsWith("\'")) { // $NON-NLS-1$ + setDataEncoding(charSet.substring(1, charSet.length() - 1)); // remove quotes + } else { + setDataEncoding(charSet); + } + } + if (isBinaryType(ct)) { + setDataType(BINARY); + } else { + setDataType(TEXT); + } + } + } + + /* + * Determine if content-type is known to be binary, i.e. not displayable as text. + * + * @param ct content type + * @return true if content-type is of type binary. + */ + public static boolean isBinaryType(String ct) { + for (String entry : NON_BINARY_TYPES) { + if (ct.startsWith(entry)) { + return false; + } + } + for (String binaryType : BINARY_TYPES) { + if (ct.startsWith(binaryType)) { + return true; + } + } + return false; + } + + /** + * Sets the successful attribute of the SampleResult object. + * + * @param success the new successful value + */ + public void setSuccessful(boolean success) { + this.success = success; + } + + /** + * Returns the display name. + * + * @return display name of this sample result + */ + @Override + public String toString() { + return getSampleLabel(); + } + + /** + * Returns the dataEncoding or the default if no dataEncoding was provided. + * + * @return the value of the dataEncoding or DEFAULT_ENCODING + */ + public String getDataEncodingWithDefault() { + return getDataEncodingWithDefault(DEFAULT_ENCODING); + } + + /** + * Returns the dataEncoding or the default if no dataEncoding was provided. + * + * @param defaultEncoding the default to be applied + * @return the value of the dataEncoding or the provided default + */ + protected String getDataEncodingWithDefault(String defaultEncoding) { + if (dataEncoding != null && dataEncoding.length() > 0) { + return dataEncoding; + } + return defaultEncoding; + } + + /** + * Returns the dataEncoding. May be null or the empty String. + * + * @return the value of the dataEncoding + */ + public String getDataEncodingNoDefault() { + return dataEncoding; + } + + /** + * Sets the dataEncoding. + * + * @param dataEncoding the dataEncoding to set, e.g. ISO-8895-1, UTF-8 + */ + public void setDataEncoding(String dataEncoding) { + this.dataEncoding = dataEncoding; + } + + /** + * @return whether to stop the test waiting for current running Sampler to end + */ + public boolean isStopTest() { + return stopTest; + } + + /** + * @return whether to stop the test now interrupting current running samplers + */ + public boolean isStopTestNow() { + return stopTestNow; + } + + /** + * @return whether to stop this thread + */ + public boolean isStopThread() { + return stopThread; + } + + public void setStopTest(boolean b) { + stopTest = b; + } + + public void setStopTestNow(boolean b) { + stopTestNow = b; + } + + public void setStopThread(boolean b) { + stopThread = b; + } + + /** + * @return the request headers + */ + public String getRequestHeaders() { + return requestHeaders; + } + + /** + * @return the response headers + */ + public String getResponseHeaders() { + return responseHeaders; + } + + /** + * @param string - + * request headers + */ + public void setRequestHeaders(String string) { + requestHeaders = string; + } + + /** + * @param string - + * response headers + */ + public void setResponseHeaders(String string) { + responseHeaders = string; + } + + /** + * @return the full content type - e.g. text/html [;charset=utf-8 ] + */ + public String getContentType() { + return contentType; + } + + /** + * Get the media type from the Content Type + * + * @return the media type - e.g. text/html (without charset, if any) + */ + public String getMediaType() { + return JOrphanUtils.trim(contentType, " ;").toLowerCase(java.util.Locale.ENGLISH); + } + + /** + * Stores the content-type string, e.g.text/xml; charset=utf-8
+ *
+ * @param string the content-type to be set
+ * @see #setEncodingAndType(String) which can be used to extract the charset.
+ */
+ public void setContentType(String string) {
+ contentType = string;
+ }
+
+ /**
+ * @return idleTime
+ */
+ public long getIdleTime() {
+ return idleTime;
+ }
+
+ /**
+ * @return the end time
+ */
+ public long getEndTime() {
+ return endTime;
+ }
+
+ /**
+ * @return the start time
+ */
+ public long getStartTime() {
+ return startTime;
+ }
+
+ /*
+ * Helper methods N.B. setStartTime must be called before setEndTime
+ *
+ * setStartTime is used by HTTPSampleResult to clone the parent sampler and
+ * allow the original start time to be kept
+ */
+ protected final void setStartTime(long start) {
+ startTime = start;
+ if (START_TIMESTAMP) {
+ timeStamp = startTime;
+ }
+ }
+
+ public void setEndTime(long end) {
+ endTime = end;
+ if (!START_TIMESTAMP) {
+ timeStamp = endTime;
+ }
+ if (startTime == 0) {
+ log.error("setEndTime must be called after setStartTime", new Throwable(INVALID_CALL_SEQUENCE_MSG));
+ } else {
+ elapsedTime = endTime - startTime - idleTime;
+ }
+ }
+
+ /**
+ * Set idle time pause.
+ * For use by SampleResultConverter/CSVSaveService.
+ *
+ * @param idle long
+ */
+ public void setIdleTime(long idle) {
+ idleTime = idle;
+ }
+
+ private void setTimes(long start, long end) {
+ setStartTime(start);
+ setEndTime(end);
+ }
+
+ /**
+ * Record the start time of a sample
+ */
+ public void sampleStart() {
+ if (startTime == 0) {
+ setStartTime(currentTimeInMillis());
+ } else {
+ log.error("sampleStart called twice", new Throwable(INVALID_CALL_SEQUENCE_MSG));
+ }
+ }
+
+ /**
+ * Record the end time of a sample and calculate the elapsed time
+ */
+ public void sampleEnd() {
+ if (endTime == 0) {
+ setEndTime(currentTimeInMillis());
+ } else {
+ log.error("sampleEnd called twice", new Throwable(INVALID_CALL_SEQUENCE_MSG));
+ }
+ }
+
+ /**
+ * Pause a sample
+ */
+ public void samplePause() {
+ if (pauseTime != 0) {
+ log.error("samplePause called twice", new Throwable(INVALID_CALL_SEQUENCE_MSG));
+ }
+ pauseTime = currentTimeInMillis();
+ }
+
+ /**
+ * Resume a sample
+ */
+ public void sampleResume() {
+ if (pauseTime == 0) {
+ log.error("sampleResume without samplePause", new Throwable(INVALID_CALL_SEQUENCE_MSG));
+ }
+ idleTime += currentTimeInMillis() - pauseTime;
+ pauseTime = 0;
+ }
+
+ /**
+ * When a Sampler is working as a monitor
+ *
+ * @param monitor flag whether this sampler is working as a monitor
+ * @deprecated since 3.2 NOOP
+ */
+ @Deprecated
+ public void setMonitor(boolean monitor) {
+ // NOOP
+ }
+
+ /**
+ * If the sampler is a monitor, method will return true.
+ *
+ * @return true if the sampler is a monitor
+ * @deprecated since 3.2 always return false
+ */
+ @Deprecated
+ public boolean isMonitor() {
+ return false;
+ }
+
+ /**
+ * The statistical sample sender aggregates several samples to save on
+ * transmission costs.
+ *
+ * @param count number of samples represented by this instance
+ */
+ public void setSampleCount(int count) {
+ sampleCount = count;
+ }
+
+ /**
+ * return the sample count. by default, the value is 1.
+ *
+ * @return the sample count
+ */
+ public int getSampleCount() {
+ return sampleCount;
+ }
+
+ /**
+ * Returns the count of errors.
+ *
+ * @return 0 - or 1 if the sample failed
+ *
+ * TODO do we need allow for nested samples?
+ */
+ public int getErrorCount() {
+ return success ? 0 : 1;
+ }
+
+ public void setErrorCount(int i) {// for reading from CSV files
+ // ignored currently
+ }
+
+ /*
+ * TODO: error counting needs to be sorted out.
+ *
+ * At present the Statistical Sampler tracks errors separately
+ * It would make sense to move the error count here, but this would
+ * mean lots of changes.
+ * It's also tricky maintaining the count - it can't just be incremented/decremented
+ * when the success flag is set as this may be done multiple times.
+ * The work-round for now is to do the work in the StatisticalSampleResult,
+ * which overrides this method.
+ * Note that some JMS samplers also create samples with > 1 sample count
+ * Also the Transaction Controller probably needs to be changed to do
+ * proper sample and error accounting.
+ * The purpose of this work-round is to allow at least minimal support for
+ * errors in remote statistical batch mode.
+ *
+ */
+
+ /**
+ * In the event the sampler does want to pass back the actual contents, we
+ * still want to calculate the throughput. The bytes are the bytes of the
+ * response data.
+ *
+ * @param length the number of bytes of the response data for this sample
+ */
+ public void setBytes(long length) {
+ bytes = length;
+ }
+
+ /**
+ * In the event the sampler does want to pass back the actual contents, we
+ * still want to calculate the throughput. The bytes are the bytes of the
+ * response data.
+ *
+ * @param length the number of bytes of the response data for this sample
+ * @deprecated use setBytes(long)
+ */
+ @Deprecated
+ public void setBytes(int length) {
+ setBytes((long) length);
+ }
+
+ /**
+ * @param sentBytesCount long sent bytes
+ */
+ public void setSentBytes(long sentBytesCount) {
+ sentBytes = sentBytesCount;
+ }
+
+ /**
+ * @return the sentBytes
+ */
+ public long getSentBytes() {
+ return sentBytes;
+ }
+
+ /**
+ * return the bytes returned by the response.
+ *
+ * @return byte count
+ * @deprecated use getBytesAsLong
+ */
+ @Deprecated
+ public int getBytes() {
+ return (int) getBytesAsLong();
+ }
+
+ /**
+ * return the bytes returned by the response.
+ *
+ * @return byte count
+ */
+ public long getBytesAsLong() {
+ long tmpSum = this.getHeadersSize() + this.getBodySizeAsLong();
+ return tmpSum == 0 ? bytes : tmpSum;
+ }
+
+ /**
+ * @return Returns the latency.
+ */
+ public long getLatency() {
+ return latency;
+ }
+
+ /**
+ * Set the time to the first response
+ */
+ public void latencyEnd() {
+ latency = currentTimeInMillis() - startTime - idleTime;
+ }
+
+ /**
+ * This is only intended for use by SampleResultConverter!
+ *
+ * @param latency The latency to set.
+ */
+ public void setLatency(long latency) {
+ this.latency = latency;
+ }
+
+ /**
+ * @return Returns the connect time.
+ */
+ public long getConnectTime() {
+ return connectTime;
+ }
+
+ /**
+ * Set the time to the end of connecting
+ */
+ public void connectEnd() {
+ connectTime = currentTimeInMillis() - startTime - idleTime;
+ }
+
+ /**
+ * This is only intended for use by SampleResultConverter!
+ *
+ * @param time The connect time to set.
+ */
+ public void setConnectTime(long time) {
+ this.connectTime = time;
+ }
+
+ /**
+ * This is only intended for use by SampleResultConverter!
+ *
+ * @param timeStamp The timeStamp to set.
+ */
+ public void setTimeStamp(long timeStamp) {
+ this.timeStamp = timeStamp;
+ }
+
+
+ public void setURL(URL location) {
+ this.location = location;
+ }
+
+ public URL getURL() {
+ return location;
+ }
+
+ /**
+ * Get a String representation of the URL (if defined).
+ *
+ * @return ExternalForm of URL, or empty string if url is null
+ */
+ public String getUrlAsString() {
+ return location == null ? "" : location.toExternalForm();
+ }
+
+ /**
+ * @return Returns the parent.
+ */
+ public SampleResult getParent() {
+ return parent;
+ }
+
+ /**
+ * @param parent The parent to set.
+ */
+ public void setParent(SampleResult parent) {
+ this.parent = parent;
+ }
+
+ public String getResultFileName() {
+ return resultFileName;
+ }
+
+ public void setResultFileName(String resultFileName) {
+ this.resultFileName = resultFileName;
+ }
+
+ public int getGroupThreads() {
+ return groupThreads;
+ }
+
+ public void setGroupThreads(int n) {
+ this.groupThreads = n;
+ }
+
+ public int getAllThreads() {
+ return allThreads;
+ }
+
+ public void setAllThreads(int n) {
+ this.allThreads = n;
+ }
+
+ // Bug 47394
+
+ /**
+ * Allow custom SampleSenders to drop unwanted assertionResults
+ */
+ public void removeAssertionResults() {
+ this.assertionResults = null;
+ }
+
+ /**
+ * Allow custom SampleSenders to drop unwanted subResults
+ */
+ public void removeSubResults() {
+ this.subResults = null;
+ }
+
+ /**
+ * Set the headers size in bytes
+ *
+ * @param size the number of bytes of the header
+ */
+ public void setHeadersSize(int size) {
+ this.headersSize = size;
+ }
+
+ /**
+ * Get the headers size in bytes
+ *
+ * @return the headers size
+ */
+ public int getHeadersSize() {
+ return headersSize;
+ }
+
+ /**
+ * @return the body size in bytes
+ * @deprecated replaced by getBodySizeAsLong()
+ */
+ @Deprecated
+ public int getBodySize() {
+ return (int) getBodySizeAsLong();
+ }
+
+ /**
+ * @return the body size in bytes
+ */
+ public long getBodySizeAsLong() {
+ return bodySize == 0 ? responseData.length : bodySize;
+ }
+
+ /**
+ * @param bodySize the body size to set
+ */
+ public void setBodySize(long bodySize) {
+ this.bodySize = bodySize;
+ }
+
+ /**
+ * @param bodySize the body size to set
+ * @deprecated use setBodySize(long)
+ */
+ @Deprecated
+ public void setBodySize(int bodySize) {
+ this.bodySize = bodySize;
+ }
+
+ private static class NanoOffset extends Thread {
+
+ private static volatile long nanoOffset;
+
+ static long getNanoOffset() {
+ return nanoOffset;
+ }
+
+ @Override
+ public void run() {
+ // Wait longer than a clock pulse (generally 10-15ms)
+ getOffset(30L); // Catch an early clock pulse to reduce slop.
+ while (true) {
+ getOffset(NANOTHREAD_SLEEP); // Can now afford to wait a bit longer between checks
+ }
+ }
+
+ private static void getOffset(long wait) {
+ try {
+ TimeUnit.MILLISECONDS.sleep(wait);
+ long clock = System.currentTimeMillis();
+ long nano = SampleResult.sampleNsClockInMs();
+ nanoOffset = clock - nano;
+ } catch (InterruptedException ignore) {
+ // ignored
+ Thread.currentThread().interrupt();
+ }
+ }
+ }
+
+ /**
+ * @return the startNextThreadLoop
+ * @deprecated use {@link SampleResult#getTestLogicalAction()}
+ */
+ @Deprecated
+ public boolean isStartNextThreadLoop() {
+ return testLogicalAction == TestLogicalAction.START_NEXT_ITERATION_OF_THREAD;
+ }
+
+ /**
+ * @param startNextThreadLoop the startNextLoop to set
+ * @deprecated use SampleResult#setTestLogicalAction(TestLogicalAction)
+ */
+ @Deprecated
+ public void setStartNextThreadLoop(boolean startNextThreadLoop) {
+ if (startNextThreadLoop) {
+ testLogicalAction = TestLogicalAction.START_NEXT_ITERATION_OF_THREAD;
+ } else {
+ testLogicalAction = TestLogicalAction.CONTINUE;
+ }
+ }
+
+ /**
+ * Clean up cached data
+ */
+ public void cleanAfterSample() {
+ this.responseDataAsString = null;
+ }
+
+ @Override
+ public Object clone() {
+ try {
+ return super.clone();
+ } catch (CloneNotSupportedException e) {
+ throw new IllegalStateException("This should not happen");
+ }
+ }
+
+ @Override
+ public List