0001: /*
0002: * Licensed to the Apache Software Foundation (ASF) under one or more
0003: * contributor license agreements. See the NOTICE file distributed with
0004: * this work for additional information regarding copyright ownership.
0005: * The ASF licenses this file to You under the Apache License, Version 2.0
0006: * (the "License"); you may not use this file except in compliance with
0007: * the License. You may obtain a copy of the License at
0008: *
0009: * http://www.apache.org/licenses/LICENSE-2.0
0010: *
0011: * Unless required by applicable law or agreed to in writing, software
0012: * distributed under the License is distributed on an "AS IS" BASIS,
0013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0014: * See the License for the specific language governing permissions and
0015: * limitations under the License.
0016: *
0017: */
0018:
0019: package org.apache.jmeter.samplers;
0020:
0021: import java.io.Serializable;
0022: import java.io.UnsupportedEncodingException;
0023: import java.net.HttpURLConnection;
0024: import java.net.URL;
0025: import java.util.ArrayList;
0026: import java.util.HashSet;
0027: import java.util.List;
0028: import java.util.Set;
0029:
0030: import org.apache.avalon.framework.configuration.Configuration;
0031: import org.apache.jmeter.assertions.AssertionResult;
0032: import org.apache.jmeter.util.JMeterUtils;
0033: import org.apache.jorphan.logging.LoggingManager;
0034: import org.apache.jorphan.util.JOrphanUtils;
0035: import org.apache.log.Logger;
0036:
0037: // For unit tests, @see TestSampleResult
0038:
0039: /**
0040: * This is a nice packaging for the various information returned from taking a
0041: * sample of an entry.
0042: *
0043: */
0044: public class SampleResult implements Serializable {
0045:
0046: public static final String DEFAULT_HTTP_ENCODING = "ISO-8859-1"; // $NON-NLS-1$
0047:
0048: // Needs to be accessible from Test code
0049: static final Logger log = LoggingManager.getLoggerForClass();
0050:
0051: // Bug 33196 - encoding ISO-8859-1 is only suitable for Western countries
0052: // However the suggested System.getProperty("file.encoding") is Cp1252 on
0053: // Windows
0054: // So use a new property with the original value as default
0055: // needs to be accessible from test code
0056: static final String DEFAULT_ENCODING = JMeterUtils.getPropDefault(
0057: "sampleresult.default.encoding", // $NON-NLS-1$
0058: DEFAULT_HTTP_ENCODING);
0059:
0060: /**
0061: * Data type value indicating that the response data is text.
0062: *
0063: * @see #getDataType
0064: * @see #setDataType(java.lang.String)
0065: */
0066: public final static String TEXT = "text"; // $NON-NLS-1$
0067:
0068: /**
0069: * Data type value indicating that the response data is binary.
0070: *
0071: * @see #getDataType
0072: * @see #setDataType(java.lang.String)
0073: */
0074: public final static String BINARY = "bin"; // $NON-NLS-1$
0075:
0076: /* empty arrays which can be returned instead of null */
0077: private static final byte[] EMPTY_BA = new byte[0];
0078:
0079: private static final SampleResult[] EMPTY_SR = new SampleResult[0];
0080:
0081: private static final AssertionResult[] EMPTY_AR = new AssertionResult[0];
0082:
0083: private SampleSaveConfiguration saveConfig;
0084:
0085: private SampleResult parent = null;
0086:
0087: /**
0088: * @param propertiesToSave
0089: * The propertiesToSave to set.
0090: */
0091: public void setSaveConfig(SampleSaveConfiguration propertiesToSave) {
0092: this .saveConfig = propertiesToSave;
0093: }
0094:
0095: public SampleSaveConfiguration getSaveConfig() {
0096: return saveConfig;
0097: }
0098:
0099: private byte[] responseData = EMPTY_BA;
0100:
0101: private String responseCode = "";// Never return null
0102:
0103: private String label = "";// Never return null
0104:
0105: private String resultFileName = ""; // Filename used by ResultSaver
0106:
0107: private String samplerData;
0108:
0109: private String threadName = ""; // Never return null
0110:
0111: private String responseMessage = "";
0112:
0113: private String responseHeaders = ""; // Never return null
0114:
0115: private String contentType = ""; // e.g. text/html; charset=utf-8
0116:
0117: private String requestHeaders = "";
0118:
0119: // TODO timeStamp == 0 means either not yet initialised or no stamp available (e.g. when loading a results file)
0120: private long timeStamp = 0;// the time stamp - can be start or end
0121:
0122: private long startTime = 0;
0123:
0124: private long endTime = 0;
0125:
0126: private long idleTime = 0;// Allow for non-sample time
0127:
0128: private long pauseTime = 0;// Start of pause (if any)
0129:
0130: private List assertionResults;
0131:
0132: private List subResults;
0133:
0134: private String dataType = ""; // Don't return null if not set
0135:
0136: private boolean success;
0137:
0138: private Set files; // files that this sample has been saved in
0139:
0140: private String dataEncoding;// (is this really the character set?) e.g.
0141: // ISO-8895-1, UTF-8
0142:
0143: private long time = 0; // elapsed time
0144:
0145: private long latency = 0; // time to first response
0146:
0147: private boolean stopThread = false; // Should thread terminate?
0148:
0149: private boolean stopTest = false; // Should test terminate?
0150:
0151: private boolean isMonitor = false;
0152:
0153: private int sampleCount = 1;
0154:
0155: private int bytes = 0;
0156:
0157: private volatile int groupThreads = 0; // Active threads in this thread group
0158:
0159: private volatile int allThreads = 0; // Active threads in all thread groups
0160:
0161: // TODO do contentType and/or dataEncoding belong in HTTPSampleResult instead?
0162:
0163: private final static String TOTAL_TIME = "totalTime"; // $NON-NLS-1$
0164:
0165: private static final boolean startTimeStamp = JMeterUtils
0166: .getPropDefault("sampleresult.timestamp.start", false); // $NON-NLS-1$
0167:
0168: static {
0169: if (startTimeStamp) {
0170: log.info("Note: Sample TimeStamps are START times");
0171: } else {
0172: log.info("Note: Sample TimeStamps are END times");
0173: }
0174: log.info("sampleresult.default.encoding is set to "
0175: + DEFAULT_ENCODING);
0176: }
0177:
0178: public SampleResult() {
0179: time = 0;
0180: }
0181:
0182: /**
0183: * Construct a 'parent' result for an already-existing result, essentially
0184: * cloning it
0185: *
0186: * @param res
0187: * existing sample result
0188: */
0189: public SampleResult(SampleResult res) {
0190: //TODO - why not just copy all the fields? Do we need the calculations that some of the set() methods perform?
0191: //TODO - why are the following not copied:
0192: // assertionResults, bytes, idleTime, latency, parent,pauseTime,resultFileName,sampleCount,samplerData,saveConfig
0193: // stopTest, stopThread, subResults,threadName
0194: setStartTime(res.getStartTime());
0195: setEndTime(res.getStartTime());
0196: // was setElapsed(0) which is the same as setStartTime=setEndTime=now
0197:
0198: setSampleLabel(res.getSampleLabel());
0199: setRequestHeaders(res.getRequestHeaders());
0200: setResponseData(res.getResponseData());
0201: setResponseCode(res.getResponseCode());
0202: setSuccessful(res.isSuccessful());
0203: setResponseMessage(res.getResponseMessage());
0204: setDataType(res.getDataType());
0205: setResponseHeaders(res.getResponseHeaders());
0206: setContentType(res.getContentType());
0207: setDataEncoding(res.getDataEncodingNoDefault());
0208: setURL(res.getURL());
0209:
0210: setGroupThreads(res.getGroupThreads());
0211: setAllThreads(res.getAllThreads());
0212:
0213: addSubResult(res); // this will add res.getTime() to getTime().
0214: }
0215:
0216: public boolean isStampedAtStart() {
0217: return startTimeStamp;
0218: }
0219:
0220: /**
0221: * Create a sample with a specific elapsed time but don't allow the times to
0222: * be changed later
0223: *
0224: * (only used by HTTPSampleResult)
0225: *
0226: * @param elapsed
0227: * time
0228: * @param atend
0229: * create the sample finishing now, else starting now
0230: */
0231: protected SampleResult(long elapsed, boolean atend) {
0232: long now = System.currentTimeMillis();
0233: if (atend) {
0234: setTimes(now - elapsed, now);
0235: } else {
0236: setTimes(now, now + elapsed);
0237: }
0238: }
0239:
0240: /**
0241: * Create a sample with specific start and end times for test purposes, but
0242: * don't allow the times to be changed later
0243: *
0244: * (used by StatVisualizerModel.Test)
0245: *
0246: * @param start
0247: * start time
0248: * @param end
0249: * end time
0250: */
0251: public static SampleResult createTestSample(long start, long end) {
0252: SampleResult res = new SampleResult();
0253: res.setStartTime(start);
0254: res.setEndTime(end);
0255: return res;
0256: }
0257:
0258: /**
0259: * Create a sample with a specific elapsed time for test purposes, but don't
0260: * allow the times to be changed later
0261: *
0262: * @param elapsed -
0263: * desired elapsed time
0264: */
0265: public static SampleResult createTestSample(long elapsed) {
0266: long now = System.currentTimeMillis();
0267: return createTestSample(now, now + elapsed);
0268: }
0269:
0270: /**
0271: * Allow users to create a sample with specific timestamp and elapsed times
0272: * for cloning purposes, but don't allow the times to be changed later
0273: *
0274: * Currently used by OldSaveService, CSVSaveService and StatisticalSampleResult
0275: *
0276: * @param stamp -
0277: * this may be a start time or an end time
0278: * @param elapsed
0279: */
0280: public SampleResult(long stamp, long elapsed) {
0281: stampAndTime(stamp, elapsed);
0282: }
0283:
0284: // Helper method to maintain timestamp relationships
0285: private void stampAndTime(long stamp, long elapsed) {
0286: if (startTimeStamp) {
0287: startTime = stamp;
0288: endTime = stamp + elapsed;
0289: } else {
0290: startTime = stamp - elapsed;
0291: endTime = stamp;
0292: }
0293: timeStamp = stamp;
0294: time = elapsed;
0295: }
0296:
0297: /*
0298: * For use by SaveService only.
0299: *
0300: * @param stamp -
0301: * this may be a start time or an end time
0302: * @param elapsed
0303: */
0304: public void setStampAndTime(long stamp, long elapsed) {
0305: if (startTime != 0 || endTime != 0) {
0306: throw new RuntimeException(
0307: "Calling setStampAndTime() after start/end times have been set");
0308: }
0309: stampAndTime(stamp, elapsed);
0310: }
0311:
0312: /**
0313: * Method to set the elapsed time for a sample. Retained for backward
0314: * compatibility with 3rd party add-ons.
0315: * It is assumed that the method is only called at the end of a sample
0316: * and that timeStamps are end-times
0317: *
0318: * Also used by SampleResultConverter when creating results from files.
0319: *
0320: * Must not be used in conjunction with sampleStart()/End()
0321: *
0322: * @deprecated use sampleStart() and sampleEnd() instead
0323: * @param elapsed
0324: * time in milliseconds
0325: */
0326: public void setTime(long elapsed) {
0327: if (startTime != 0 || endTime != 0) {
0328: throw new RuntimeException(
0329: "Calling setTime() after start/end times have been set");
0330: }
0331: long now = System.currentTimeMillis();
0332: setTimes(now - elapsed, now);
0333: }
0334:
0335: public void setMarked(String filename) {
0336: if (files == null) {
0337: files = new HashSet();
0338: }
0339: files.add(filename);
0340: }
0341:
0342: public boolean isMarked(String filename) {
0343: return files != null && files.contains(filename);
0344: }
0345:
0346: public String getResponseCode() {
0347: return responseCode;
0348: }
0349:
0350: private static final String OK = Integer
0351: .toString(HttpURLConnection.HTTP_OK);
0352:
0353: /**
0354: * Set response code to OK, i.e. "200"
0355: *
0356: */
0357: public void setResponseCodeOK() {
0358: responseCode = OK;
0359: }
0360:
0361: public void setResponseCode(String code) {
0362: responseCode = code;
0363: }
0364:
0365: public boolean isResponseCodeOK() {
0366: return responseCode.equals(OK);
0367: }
0368:
0369: public String getResponseMessage() {
0370: return responseMessage;
0371: }
0372:
0373: public void setResponseMessage(String msg) {
0374: responseMessage = msg;
0375: }
0376:
0377: public void setResponseMessageOK() {
0378: responseMessage = "OK"; // $NON-NLS-1$
0379: }
0380:
0381: public String getThreadName() {
0382: return threadName;
0383: }
0384:
0385: public void setThreadName(String threadName) {
0386: this .threadName = threadName;
0387: }
0388:
0389: /**
0390: * Get the sample timestamp, which may be either the start time or the end time.
0391: *
0392: * @see #getStartTime()
0393: * @see #getEndTime()
0394: *
0395: * @return timeStamp in milliseconds
0396: */
0397: public long getTimeStamp() {
0398: return timeStamp;
0399: }
0400:
0401: public String getSampleLabel() {
0402: return label;
0403: }
0404:
0405: public void setSampleLabel(String label) {
0406: this .label = label;
0407: }
0408:
0409: public void addAssertionResult(AssertionResult assertResult) {
0410: if (assertionResults == null) {
0411: assertionResults = new ArrayList();
0412: }
0413: assertionResults.add(assertResult);
0414: }
0415:
0416: /**
0417: * Gets the assertion results associated with this sample.
0418: *
0419: * @return an array containing the assertion results for this sample.
0420: * Returns empty array if there are no assertion results.
0421: */
0422: public AssertionResult[] getAssertionResults() {
0423: if (assertionResults == null) {
0424: return EMPTY_AR;
0425: }
0426: return (AssertionResult[]) assertionResults
0427: .toArray(new AssertionResult[0]);
0428: }
0429:
0430: public void addSubResult(SampleResult subResult) {
0431: String tn = getThreadName();
0432: if (tn.length() == 0) {
0433: tn = Thread.currentThread().getName();//TODO do this more efficiently
0434: this .setThreadName(tn);
0435: }
0436: subResult.setThreadName(tn);
0437: if (subResults == null) {
0438: subResults = new ArrayList();
0439: }
0440: subResults.add(subResult);
0441: // Extend the time to the end of the added sample
0442: setEndTime(subResult.getEndTime());
0443: // Include the byte count for the added sample
0444: setBytes(getBytes() + subResult.getBytes());
0445: subResult.setParent(this );
0446: }
0447:
0448: /**
0449: * Add a subresult read from a results file.
0450: *
0451: * As for addSubResult(), except that the fields don't need to be accumulated
0452: *
0453: * @param subResult
0454: */
0455: public void storeSubResult(SampleResult subResult) {
0456: if (subResults == null) {
0457: subResults = new ArrayList();
0458: }
0459: subResults.add(subResult);
0460: subResult.setParent(this );
0461: }
0462:
0463: /**
0464: * Gets the subresults associated with this sample.
0465: *
0466: * @return an array containing the subresults for this sample. Returns an
0467: * empty array if there are no subresults.
0468: */
0469: public SampleResult[] getSubResults() {
0470: if (subResults == null) {
0471: return EMPTY_SR;
0472: }
0473: return (SampleResult[]) subResults.toArray(new SampleResult[0]);
0474: }
0475:
0476: public void configure(Configuration info) {
0477: time = info.getAttributeAsLong(TOTAL_TIME, 0L);
0478: }
0479:
0480: /**
0481: * Sets the responseData attribute of the SampleResult object.
0482: *
0483: * If the parameter is null, then the responseData is set to an empty byte array.
0484: * This ensures that getResponseData() can never be null.
0485: *
0486: * @param response
0487: * the new responseData value
0488: */
0489: public void setResponseData(byte[] response) {
0490: responseData = response == null ? EMPTY_BA : response;
0491: }
0492:
0493: /**
0494: * Sets the responseData attribute of the SampleResult object.
0495: *
0496: * @param response
0497: * the new responseData value (String)
0498: *
0499: * @deprecated - only intended for use from BeanShell code
0500: */
0501: public void setResponseData(String response) {
0502: responseData = response.getBytes();
0503: }
0504:
0505: /**
0506: * Gets the responseData attribute of the SampleResult object.
0507: *
0508: * @return the responseData value (cannot be null)
0509: */
0510: public byte[] getResponseData() {
0511: return responseData;
0512: }
0513:
0514: /**
0515: * Gets the responseData of the SampleResult object as a String
0516: *
0517: * @return the responseData value as a String, converted according to the encoding
0518: */
0519: public String getResponseDataAsString() {
0520: try {
0521: return new String(responseData,
0522: getDataEncodingWithDefault());
0523: } catch (UnsupportedEncodingException e) {
0524: log.warn("Using platform default as "
0525: + getDataEncodingWithDefault() + " caused " + e);
0526: return new String(responseData);
0527: }
0528: }
0529:
0530: public void setSamplerData(String s) {
0531: samplerData = s;
0532: }
0533:
0534: public String getSamplerData() {
0535: return samplerData;
0536: }
0537:
0538: /**
0539: * Get the time it took this sample to occur.
0540: *
0541: * @return elapsed time in milliseonds
0542: *
0543: */
0544: public long getTime() {
0545: return time;
0546: }
0547:
0548: public boolean isSuccessful() {
0549: return success;
0550: }
0551:
0552: public void setDataType(String dataType) {
0553: this .dataType = dataType;
0554: }
0555:
0556: public String getDataType() {
0557: return dataType;
0558: }
0559:
0560: /**
0561: * Set Encoding and DataType from ContentType
0562: * @param ct - content type (may be null)
0563: */
0564: public void setEncodingAndType(String ct) {
0565: if (ct != null) {
0566: // Extract charset and store as DataEncoding
0567: // N.B. The meta tag:
0568: // <META http-equiv="content-type" content="text/html; charset=foobar">
0569: // is now processed by HTTPSampleResult#getDataEncodingWithDefault
0570: final String CS_PFX = "charset="; // $NON-NLS-1$
0571: int cset = ct.toLowerCase().indexOf(CS_PFX);
0572: if (cset >= 0) {
0573: // TODO - assumes charset is not followed by anything else
0574: String charSet = ct.substring(cset + CS_PFX.length());
0575: // Check for quoted string
0576: if (charSet.startsWith("\"")) { // $NON-NLS-1$
0577: setDataEncoding(charSet.substring(1, charSet
0578: .length() - 1)); // remove quotes
0579: } else {
0580: setDataEncoding(charSet);
0581: }
0582: }
0583: if (isTextType(ct)) {
0584: setDataType(TEXT);
0585: } else {
0586: setDataType(BINARY);
0587: }
0588: }
0589: }
0590:
0591: // List of types that can be processed as text
0592: private static final String[] TEXT_TYPES = { "text/", //$NON-NLS-1$
0593: "application/javascript", //$NON-NLS-1$
0594: "application/json", //$NON-NLS-1$
0595: "application/xhtml+xml", //$NON-NLS-1$
0596: };
0597:
0598: // Additional types as needed
0599: private static final String[] TEXT_TYPES_OPT = JOrphanUtils.split(
0600: JMeterUtils.getPropDefault("content-type_text", ""), ","); //$NON-NLS-1$ $NON-NLS-2$ $NON-NLS-3$
0601:
0602: /*
0603: * Determine if content-type can be displayed as text or not.
0604: *
0605: * @param ct content type
0606: * @return true if content-type is of type text.
0607: */
0608: private static boolean isTextType(String ct) {
0609: for (int i = 0; i < TEXT_TYPES.length; i++) {
0610: if (ct.startsWith(TEXT_TYPES[i])) {
0611: return true;
0612: }
0613: }
0614: for (int i = 0; i < TEXT_TYPES_OPT.length; i++) {
0615: if (ct.startsWith(TEXT_TYPES_OPT[i])) {
0616: return true;
0617: }
0618: }
0619: return false;
0620: }
0621:
0622: /**
0623: * Sets the successful attribute of the SampleResult object.
0624: *
0625: * @param success
0626: * the new successful value
0627: */
0628: public void setSuccessful(boolean success) {
0629: this .success = success;
0630: }
0631:
0632: /**
0633: * Returns the display name.
0634: *
0635: * @return display name of this sample result
0636: */
0637: public String toString() {
0638: return getSampleLabel();
0639: }
0640:
0641: /**
0642: * Returns the dataEncoding or the default if no dataEncoding was provided
0643: *
0644: * @deprecated use getDataEncodingWithDefault() or getDataEncodingNoDefault() as needed.
0645: */
0646: public String getDataEncoding() {
0647: if (dataEncoding != null) {
0648: return dataEncoding;
0649: }
0650: return DEFAULT_ENCODING;
0651: }
0652:
0653: /**
0654: * Returns the dataEncoding or the default if no dataEncoding was provided
0655: */
0656: public String getDataEncodingWithDefault() {
0657: if (dataEncoding != null && dataEncoding.length() > 0) {
0658: return dataEncoding;
0659: }
0660: return DEFAULT_ENCODING;
0661: }
0662:
0663: /**
0664: * Returns the dataEncoding or the default if no dataEncoding was provided
0665: */
0666: public String getDataEncodingNoDefault() {
0667: return dataEncoding;
0668: }
0669:
0670: /**
0671: * Sets the dataEncoding.
0672: *
0673: * @param dataEncoding
0674: * the dataEncoding to set, e.g. ISO-8895-1, UTF-8
0675: */
0676: public void setDataEncoding(String dataEncoding) {
0677: this .dataEncoding = dataEncoding;
0678: }
0679:
0680: /**
0681: * @return whether to stop the test
0682: */
0683: public boolean isStopTest() {
0684: return stopTest;
0685: }
0686:
0687: /**
0688: * @return whether to stop this thread
0689: */
0690: public boolean isStopThread() {
0691: return stopThread;
0692: }
0693:
0694: /**
0695: * @param b
0696: */
0697: public void setStopTest(boolean b) {
0698: stopTest = b;
0699: }
0700:
0701: /**
0702: * @param b
0703: */
0704: public void setStopThread(boolean b) {
0705: stopThread = b;
0706: }
0707:
0708: /**
0709: * @return the request headers
0710: */
0711: public String getRequestHeaders() {
0712: return requestHeaders;
0713: }
0714:
0715: /**
0716: * @return the response headers
0717: */
0718: public String getResponseHeaders() {
0719: return responseHeaders;
0720: }
0721:
0722: /**
0723: * @param string -
0724: * request headers
0725: */
0726: public void setRequestHeaders(String string) {
0727: requestHeaders = string;
0728: }
0729:
0730: /**
0731: * @param string -
0732: * response headers
0733: */
0734: public void setResponseHeaders(String string) {
0735: responseHeaders = string;
0736: }
0737:
0738: /**
0739: * @return the full content type - e.g. text/html [;charset=utf-8 ]
0740: */
0741: public String getContentType() {
0742: return contentType;
0743: }
0744:
0745: /**
0746: * Get the media type from the Content Type
0747: * @return the media type - e.g. text/html (without charset, if any)
0748: */
0749: public String getMediaType() {
0750: return JOrphanUtils.trim(contentType, " ;").toLowerCase();
0751: }
0752:
0753: /**
0754: * @param string
0755: */
0756: public void setContentType(String string) {
0757: contentType = string;
0758: }
0759:
0760: /**
0761: * @return idleTime
0762: */
0763: public long getIdleTime() {
0764: return idleTime;
0765: }
0766:
0767: /**
0768: * @return the end time
0769: */
0770: public long getEndTime() {
0771: return endTime;
0772: }
0773:
0774: /**
0775: * @return the start time
0776: */
0777: public long getStartTime() {
0778: return startTime;
0779: }
0780:
0781: /*
0782: * Helper methods N.B. setStartTime must be called before setEndTime
0783: *
0784: * setStartTime is used by HTTPSampleResult to clone the parent sampler and
0785: * allow the original start time to be kept
0786: */
0787: protected final void setStartTime(long start) {
0788: startTime = start;
0789: if (startTimeStamp) {
0790: timeStamp = startTime;
0791: }
0792: }
0793:
0794: protected void setEndTime(long end) {
0795: endTime = end;
0796: if (!startTimeStamp) {
0797: timeStamp = endTime;
0798: }
0799: if (startTime == 0) {
0800: log.error("setEndTime must be called after setStartTime",
0801: new Throwable("Invalid call sequence"));
0802: // TODO should this throw an error?
0803: } else {
0804: time = endTime - startTime - idleTime;
0805: }
0806: }
0807:
0808: private void setTimes(long start, long end) {
0809: setStartTime(start);
0810: setEndTime(end);
0811: }
0812:
0813: /**
0814: * Record the start time of a sample
0815: *
0816: */
0817: public void sampleStart() {
0818: if (startTime == 0) {
0819: setStartTime(System.currentTimeMillis());
0820: } else {
0821: log.error("sampleStart called twice", new Throwable(
0822: "Invalid call sequence"));
0823: }
0824: }
0825:
0826: /**
0827: * Record the end time of a sample and calculate the elapsed time
0828: *
0829: */
0830: public void sampleEnd() {
0831: if (endTime == 0) {
0832: setEndTime(System.currentTimeMillis());
0833: } else {
0834: log.error("sampleEnd called twice", new Throwable(
0835: "Invalid call sequence"));
0836: }
0837: }
0838:
0839: /**
0840: * Pause a sample
0841: *
0842: */
0843: public void samplePause() {
0844: if (pauseTime != 0) {
0845: log.error("samplePause called twice", new Throwable(
0846: "Invalid call sequence"));
0847: }
0848: pauseTime = System.currentTimeMillis();
0849: }
0850:
0851: /**
0852: * Resume a sample
0853: *
0854: */
0855: public void sampleResume() {
0856: if (pauseTime == 0) {
0857: log.error("sampleResume without samplePause",
0858: new Throwable("Invalid call sequence"));
0859: }
0860: idleTime += System.currentTimeMillis() - pauseTime;
0861: pauseTime = 0;
0862: }
0863:
0864: /**
0865: * When a Sampler is working as a monitor
0866: *
0867: * @param monitor
0868: */
0869: public void setMonitor(boolean monitor) {
0870: isMonitor = monitor;
0871: }
0872:
0873: /**
0874: * If the sampler is a monitor, method will return true.
0875: *
0876: * @return true if the sampler is a monitor
0877: */
0878: public boolean isMonitor() {
0879: return isMonitor;
0880: }
0881:
0882: /**
0883: * For the JMS sampler, it can perform multiple samples for greater degree
0884: * of accuracy.
0885: *
0886: * @param count
0887: */
0888: public void setSampleCount(int count) {
0889: sampleCount = count;
0890: }
0891:
0892: /**
0893: * return the sample count. by default, the value is 1.
0894: *
0895: * @return the sample count
0896: */
0897: public int getSampleCount() {
0898: return sampleCount;
0899: }
0900:
0901: /**
0902: * Returns the count of errors.
0903: *
0904: * @return 0 - or 1 if the sample failed
0905: */
0906: public int getErrorCount() {
0907: return success ? 0 : 1;
0908: }
0909:
0910: public void setErrorCount(int i) {// for reading from CSV files
0911: // ignored currently
0912: }
0913:
0914: /*
0915: * TODO: error counting needs to be sorted out after 2.3 final.
0916: * At present the Statistical Sampler tracks errors separately
0917: * It would make sense to move the error count here, but this would
0918: * mean lots of changes.
0919: * It's also tricky maintaining the count - it can't just be incremented/decremented
0920: * when the success flag is set as this may be done multiple times.
0921: * The work-round for now is to do the work in the StatisticalSampleResult,
0922: * which overrides this method.
0923: * Note that some JMS samplers also create samples with > 1 sample count
0924: * Also the Transaction Controller probably needs to be changed to do
0925: * proper sample and error accounting.
0926: * The purpose of this work-round is to allow at least minimal support for
0927: * errors in remote statistical batch mode.
0928: *
0929: */
0930: /**
0931: * In the event the sampler does want to pass back the actual contents, we
0932: * still want to calculate the throughput. The bytes is the bytes of the
0933: * response data.
0934: *
0935: * @param length
0936: */
0937: public void setBytes(int length) {
0938: bytes = length;
0939: }
0940:
0941: /**
0942: * return the bytes returned by the response.
0943: *
0944: * @return byte count
0945: */
0946: public int getBytes() {
0947: return bytes == 0 ? responseData.length : bytes;
0948: }
0949:
0950: /**
0951: * @return Returns the latency.
0952: */
0953: public long getLatency() {
0954: return latency;
0955: }
0956:
0957: /**
0958: * Set the time to the first response
0959: *
0960: */
0961: public void latencyEnd() {
0962: latency = System.currentTimeMillis() - startTime - idleTime;
0963: }
0964:
0965: /**
0966: * This is only intended for use by SampleResultConverter!
0967: *
0968: * @param latency
0969: * The latency to set.
0970: */
0971: public void setLatency(long latency) {
0972: this .latency = latency;
0973: }
0974:
0975: /**
0976: * This is only intended for use by SampleResultConverter!
0977: *
0978: * @param timeStamp
0979: * The timeStamp to set.
0980: */
0981: public void setTimeStamp(long timeStamp) {
0982: this .timeStamp = timeStamp;
0983: }
0984:
0985: private URL location;
0986:
0987: public void setURL(URL location) {
0988: this .location = location;
0989: }
0990:
0991: public URL getURL() {
0992: return location;
0993: }
0994:
0995: /**
0996: * Get a String representation of the URL (if defined).
0997: *
0998: * @return ExternalForm of URL, or empty string if url is null
0999: */
1000: public String getUrlAsString() {
1001: return location == null ? "" : location.toExternalForm();
1002: }
1003:
1004: /**
1005: * @return Returns the parent.
1006: */
1007: public SampleResult getParent() {
1008: return parent;
1009: }
1010:
1011: /**
1012: * @param parent
1013: * The parent to set.
1014: */
1015: public void setParent(SampleResult parent) {
1016: this .parent = parent;
1017: }
1018:
1019: public String getResultFileName() {
1020: return resultFileName;
1021: }
1022:
1023: public void setResultFileName(String resultFileName) {
1024: this .resultFileName = resultFileName;
1025: }
1026:
1027: public int getGroupThreads() {
1028: return groupThreads;
1029: }
1030:
1031: public void setGroupThreads(int n) {
1032: this .groupThreads = n;
1033: }
1034:
1035: public int getAllThreads() {
1036: return allThreads;
1037: }
1038:
1039: public void setAllThreads(int n) {
1040: this.allThreads = n;
1041: }
1042: }
|