/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
*/
/*
* Created on Sep 7, 2004
*/
package org.apache.jmeter.samplers;
import java.io.Serializable;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.Properties;
import org.apache.commons.lang3.CharUtils;
import org.apache.commons.lang3.time.FastDateFormat;
import org.apache.jmeter.save.CSVSaveService;
import org.apache.jmeter.testelement.TestPlan;
import org.apache.jmeter.util.JMeterUtils;
import org.apache.jorphan.util.JMeterError;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/*
* N.B. to add a new field, remember the following
* - static _xyz
* - instance xyz=_xyz
* - clone s.xyz = xyz (perhaps)
* - setXyz(boolean)
* - saveXyz()
* - add Xyz to SAVE_CONFIG_NAMES list
* - update SampleSaveConfigurationConverter to add new fields to marshall() and shouldSerialiseMember()
* - update ctor SampleSaveConfiguration(boolean value) to set the value if it is a boolean property
* - update SampleResultConverter and/or HTTPSampleConverter
* - update CSVSaveService: CSV_XXXX, makeResultFromDelimitedString, printableFieldNamesToString, static{}
* - update messages.properties to add save_xyz entry
* - update jmeter.properties to add new property
* - update listeners.xml to add new property, CSV and XML names etc.
* - take screenshot sample_result_config.png
* - update listeners.xml and component_reference.xml with new dimensions (might not change)
*/
/**
* Holds details of which sample attributes to save.
*
* The pop-up dialogue for this is created by the class SavePropertyDialog, which assumes:
* <p>
* For each field <em>XXX</em>
* <ul>
* <li>methods have the signature "boolean save<em>XXX</em>()"</li>
* <li>a corresponding "void set<em>XXX</em>(boolean)" method</li>
* <li>messages.properties contains the key save_<em>XXX</em></li>
* </ul>
*/
public class SampleSaveConfiguration implements Cloneable, Serializable {
private static final long serialVersionUID = 8L;
private static final Logger log = LoggerFactory.getLogger(SampleSaveConfiguration.class);
// ---------------------------------------------------------------------
// PROPERTY FILE CONSTANTS
// ---------------------------------------------------------------------
/** Indicates that the results file should be in XML format. * */
private static final String XML = "xml"; // $NON_NLS-1$
/** Indicates that the results file should be in CSV format. * */
private static final String CSV = "csv"; // $NON_NLS-1$
/** Indicates that the results should be stored in a database. * */
//NOTUSED private static final String DATABASE = "db"; // $NON_NLS-1$
/** A properties file indicator for true. * */
private static final String TRUE = "true"; // $NON_NLS-1$
/** A properties file indicator for false. * */
private static final String FALSE = "false"; // $NON_NLS-1$
/** A properties file indicator for milliseconds. * */
public static final String MILLISECONDS = "ms"; // $NON_NLS-1$
/** A properties file indicator for none. * */
public static final String NONE = "none"; // $NON_NLS-1$
/** A properties file indicator for the first of a series. * */
private static final String FIRST = "first"; // $NON_NLS-1$
/** A properties file indicator for all of a series. * */
private static final String ALL = "all"; // $NON_NLS-1$
/***************************************************************************
* The name of the property indicating which assertion results should be
* saved.
**************************************************************************/
public static final String ASSERTION_RESULTS_FAILURE_MESSAGE_PROP =
"jmeter.save.saveservice.assertion_results_failure_message"; // $NON_NLS-1$
/***************************************************************************
* The name of the property indicating which assertion results should be
* saved.
**************************************************************************/
private static final String ASSERTION_RESULTS_PROP = "jmeter.save.saveservice.assertion_results"; // $NON_NLS-1$
/***************************************************************************
* The name of the property indicating which delimiter should be used when
* saving in a delimited values format.
**************************************************************************/
public static final String DEFAULT_DELIMITER_PROP = "jmeter.save.saveservice.default_delimiter"; // $NON_NLS-1$
/***************************************************************************
* The name of the property indicating which format should be used when
* saving the results, e.g., xml or csv.
**************************************************************************/
private static final String OUTPUT_FORMAT_PROP = "jmeter.save.saveservice.output_format"; // $NON_NLS-1$
/***************************************************************************
* The name of the property indicating whether field names should be printed
* to a delimited file.
**************************************************************************/
private static final String PRINT_FIELD_NAMES_PROP = "jmeter.save.saveservice.print_field_names"; // $NON_NLS-1$
/***************************************************************************
* The name of the property indicating whether the data type should be
* saved.
**************************************************************************/
private static final String SAVE_DATA_TYPE_PROP = "jmeter.save.saveservice.data_type"; // $NON_NLS-1$
/***************************************************************************
* The name of the property indicating whether the label should be saved.
**************************************************************************/
private static final String SAVE_LABEL_PROP = "jmeter.save.saveservice.label"; // $NON_NLS-1$
/***************************************************************************
* The name of the property indicating whether the response code should be
* saved.
**************************************************************************/
private static final String SAVE_RESPONSE_CODE_PROP = "jmeter.save.saveservice.response_code"; // $NON_NLS-1$
/***************************************************************************
* The name of the property indicating whether the response data should be
* saved.
**************************************************************************/
private static final String SAVE_RESPONSE_DATA_PROP = "jmeter.save.saveservice.response_data"; // $NON_NLS-1$
private static final String SAVE_RESPONSE_DATA_ON_ERROR_PROP = "jmeter.save.saveservice.response_data.on_error"; // $NON_NLS-1$
/***************************************************************************
* The name of the property indicating whether the response message should
* be saved.
**************************************************************************/
private static final String SAVE_RESPONSE_MESSAGE_PROP = "jmeter.save.saveservice.response_message"; // $NON_NLS-1$
/***************************************************************************
* The name of the property indicating whether the success indicator should
* be saved.
**************************************************************************/
private static final String SAVE_SUCCESSFUL_PROP = "jmeter.save.saveservice.successful"; // $NON_NLS-1$
/***************************************************************************
* The name of the property indicating whether the thread name should be
* saved.
**************************************************************************/
private static final String SAVE_THREAD_NAME_PROP = "jmeter.save.saveservice.thread_name"; // $NON_NLS-1$
// Save bytes read
private static final String SAVE_BYTES_PROP = "jmeter.save.saveservice.bytes"; // $NON_NLS-1$
// Save bytes written
private static final String SAVE_SENT_BYTES_PROP = "jmeter.save.saveservice.sent_bytes"; // $NON_NLS-1$
// Save URL
private static final String SAVE_URL_PROP = "jmeter.save.saveservice.url"; // $NON_NLS-1$
// Save fileName for ResultSaver
private static final String SAVE_FILENAME_PROP = "jmeter.save.saveservice.filename"; // $NON_NLS-1$
// Save hostname for ResultSaver
private static final String SAVE_HOSTNAME_PROP = "jmeter.save.saveservice.hostname"; // $NON_NLS-1$
/***************************************************************************
* The name of the property indicating whether the time should be saved.
**************************************************************************/
private static final String SAVE_TIME_PROP = "jmeter.save.saveservice.time"; // $NON_NLS-1$
/***************************************************************************
* The name of the property giving the format of the time stamp
**************************************************************************/
private static final String TIME_STAMP_FORMAT_PROP = "jmeter.save.saveservice.timestamp_format"; // $NON_NLS-1$
private static final String SUBRESULTS_PROP = "jmeter.save.saveservice.subresults"; // $NON_NLS-1$
private static final String ASSERTIONS_PROP = "jmeter.save.saveservice.assertions"; // $NON_NLS-1$
private static final String LATENCY_PROP = "jmeter.save.saveservice.latency"; // $NON_NLS-1$
private static final String CONNECT_TIME_PROP = "jmeter.save.saveservice.connect_time"; // $NON_NLS-1$
private static final String SAMPLERDATA_PROP = "jmeter.save.saveservice.samplerData"; // $NON_NLS-1$
private static final String RESPONSEHEADERS_PROP = "jmeter.save.saveservice.responseHeaders"; // $NON_NLS-1$
private static final String REQUESTHEADERS_PROP = "jmeter.save.saveservice.requestHeaders"; // $NON_NLS-1$
private static final String ENCODING_PROP = "jmeter.save.saveservice.encoding"; // $NON_NLS-1$
// optional processing instruction for line 2; e.g.
// <?xml-stylesheet type="text/xsl" href="../extras/jmeter-results-detail-report_21.xsl"?>
private static final String XML_PI = "jmeter.save.saveservice.xml_pi"; // $NON_NLS-1$
private static final String SAVE_THREAD_COUNTS = "jmeter.save.saveservice.thread_counts"; // $NON_NLS-1$
private static final String SAVE_SAMPLE_COUNT = "jmeter.save.saveservice.sample_count"; // $NON_NLS-1$
private static final String SAVE_IDLE_TIME = "jmeter.save.saveservice.idle_time"; // $NON_NLS-1$
// Defaults from properties:
private static final boolean TIME;
private static final boolean TIMESTAMP;
private static final boolean SUCCESS;
private static final boolean LABEL;
private static final boolean CODE;
private static final boolean MESSAGE;
private static final boolean THREAD_NAME;
private static final boolean IS_XML;
private static final boolean RESPONSE_DATA;
private static final boolean DATATYPE;
private static final boolean ENCODING;
private static final boolean ASSERTIONS;
private static final boolean LATENCY;
private static final boolean CONNECT_TIME;
private static final boolean SUB_RESULTS;
private static final boolean SAMPLER_DATA;
private static final boolean FIELD_NAMES;
private static final boolean RESPONSE_HEADERS;
private static final boolean REQUEST_HEADERS;
private static final boolean RESPONSE_DATA_ON_ERROR;
private static final boolean SAVE_ASSERTION_RESULTS_FAILURE_MESSAGE;
private static final int ASSERTIONS_RESULT_TO_SAVE;
// TODO turn into method?
public static final int SAVE_NO_ASSERTIONS = 0;
public static final int SAVE_FIRST_ASSERTION = SAVE_NO_ASSERTIONS + 1;
public static final int SAVE_ALL_ASSERTIONS = SAVE_FIRST_ASSERTION + 1;
private static final boolean PRINT_MILLISECONDS;
private static final boolean BYTES;
private static final boolean SENT_BYTES;
private static final boolean URL;
private static final boolean FILE_NAME;
private static final boolean HOST_NAME;
private static final boolean THREAD_COUNTS;
private static final boolean SAMPLE_COUNT;
private static final String DATE_FORMAT;
/**
* The string used to separate fields when stored to disk, for example, the
* comma for CSV files.
*/
private static final String DELIMITER;
private static final boolean IDLE_TIME;
public static final String DEFAULT_DELIMITER = ","; // $NON_NLS-1$
/**
* Read in the properties having to do with saving from a properties file.
*/
static {
Properties props = JMeterUtils.getJMeterProperties();
SUB_RESULTS = TRUE.equalsIgnoreCase(props.getProperty(SUBRESULTS_PROP, TRUE));
ASSERTIONS = TRUE.equalsIgnoreCase(props.getProperty(ASSERTIONS_PROP, TRUE));
LATENCY = TRUE.equalsIgnoreCase(props.getProperty(LATENCY_PROP, TRUE));
CONNECT_TIME = TRUE.equalsIgnoreCase(props.getProperty(CONNECT_TIME_PROP, TRUE));
SAMPLER_DATA = TRUE.equalsIgnoreCase(props.getProperty(SAMPLERDATA_PROP, FALSE));
RESPONSE_HEADERS = TRUE.equalsIgnoreCase(props.getProperty(RESPONSEHEADERS_PROP, FALSE));
REQUEST_HEADERS = TRUE.equalsIgnoreCase(props.getProperty(REQUESTHEADERS_PROP, FALSE));
ENCODING = TRUE.equalsIgnoreCase(props.getProperty(ENCODING_PROP, FALSE));
String dlm = JMeterUtils.getDelimiter(props.getProperty(DEFAULT_DELIMITER_PROP, DEFAULT_DELIMITER));
char ch = dlm.charAt(0);
if (CharUtils.isAsciiAlphanumeric(ch) || ch == CSVSaveService.QUOTING_CHAR){
throw new JMeterError("Delimiter '"+ch+"' must not be alphanumeric or "+CSVSaveService.QUOTING_CHAR+".");
}
if (ch != '\t' && !CharUtils.isAsciiPrintable(ch)){
throw new JMeterError("Delimiter (code "+(int)ch+") must be printable.");
}
DELIMITER = dlm;
FIELD_NAMES = TRUE.equalsIgnoreCase(props.getProperty(PRINT_FIELD_NAMES_PROP, TRUE));
DATATYPE = TRUE.equalsIgnoreCase(props.getProperty(SAVE_DATA_TYPE_PROP, TRUE));
LABEL = TRUE.equalsIgnoreCase(props.getProperty(SAVE_LABEL_PROP, TRUE));
CODE = TRUE.equalsIgnoreCase(props.getProperty(SAVE_RESPONSE_CODE_PROP, TRUE));
RESPONSE_DATA = TRUE.equalsIgnoreCase(props.getProperty(SAVE_RESPONSE_DATA_PROP, FALSE));
RESPONSE_DATA_ON_ERROR = TRUE.equalsIgnoreCase(props.getProperty(SAVE_RESPONSE_DATA_ON_ERROR_PROP, FALSE));
MESSAGE = TRUE.equalsIgnoreCase(props.getProperty(SAVE_RESPONSE_MESSAGE_PROP, TRUE));
SUCCESS = TRUE.equalsIgnoreCase(props.getProperty(SAVE_SUCCESSFUL_PROP, TRUE));
THREAD_NAME = TRUE.equalsIgnoreCase(props.getProperty(SAVE_THREAD_NAME_PROP, TRUE));
BYTES = TRUE.equalsIgnoreCase(props.getProperty(SAVE_BYTES_PROP, TRUE));
SENT_BYTES = TRUE.equalsIgnoreCase(props.getProperty(SAVE_SENT_BYTES_PROP, TRUE));
URL = TRUE.equalsIgnoreCase(props.getProperty(SAVE_URL_PROP, FALSE));
FILE_NAME = TRUE.equalsIgnoreCase(props.getProperty(SAVE_FILENAME_PROP, FALSE));
HOST_NAME = TRUE.equalsIgnoreCase(props.getProperty(SAVE_HOSTNAME_PROP, FALSE));
TIME = TRUE.equalsIgnoreCase(props.getProperty(SAVE_TIME_PROP, TRUE));
String temporaryTimestampFormat = props.getProperty(TIME_STAMP_FORMAT_PROP, MILLISECONDS);
PRINT_MILLISECONDS = MILLISECONDS.equalsIgnoreCase(temporaryTimestampFormat);
if (!PRINT_MILLISECONDS && !NONE.equalsIgnoreCase(temporaryTimestampFormat)) {
DATE_FORMAT = validateFormat(temporaryTimestampFormat);
} else {
DATE_FORMAT = null;
}
TIMESTAMP = !NONE.equalsIgnoreCase(temporaryTimestampFormat);// reversed compare allows for null
SAVE_ASSERTION_RESULTS_FAILURE_MESSAGE = TRUE.equalsIgnoreCase(props.getProperty(
ASSERTION_RESULTS_FAILURE_MESSAGE_PROP, TRUE));
String whichAssertionResults = props.getProperty(ASSERTION_RESULTS_PROP, NONE);
if (NONE.equals(whichAssertionResults)) {
ASSERTIONS_RESULT_TO_SAVE = SAVE_NO_ASSERTIONS;
} else if (FIRST.equals(whichAssertionResults)) {
ASSERTIONS_RESULT_TO_SAVE = SAVE_FIRST_ASSERTION;
} else if (ALL.equals(whichAssertionResults)) {
ASSERTIONS_RESULT_TO_SAVE = SAVE_ALL_ASSERTIONS;
} else {
ASSERTIONS_RESULT_TO_SAVE = 0;
}
String howToSave = props.getProperty(OUTPUT_FORMAT_PROP, CSV);
if (XML.equals(howToSave)) {
IS_XML = true;
} else {
if (!CSV.equals(howToSave)) {
log.warn("{} has unexepected value: '{}' - assuming 'csv' format", OUTPUT_FORMAT_PROP, howToSave);
}
IS_XML = false;
}
THREAD_COUNTS=TRUE.equalsIgnoreCase(props.getProperty(SAVE_THREAD_COUNTS, TRUE));
SAMPLE_COUNT=TRUE.equalsIgnoreCase(props.getProperty(SAVE_SAMPLE_COUNT, FALSE));
IDLE_TIME=TRUE.equalsIgnoreCase(props.getProperty(SAVE_IDLE_TIME, TRUE));
}
private static final SampleSaveConfiguration STATIC_SAVE_CONFIGURATION = new SampleSaveConfiguration();
// for test code only
static final String CONFIG_GETTER_PREFIX = "save"; // $NON-NLS-1$
// for test code only
static final String CONFIG_SETTER_PREFIX = "set"; // $NON-NLS-1$
/**
* List of saveXXX/setXXX(boolean) methods which is used to build the Sample Result Save Configuration dialog.
* New method names should be added at the end so that existing layouts are not affected.
*/
// The current order is derived from http://jmeter.apache.org/usermanual/listeners.html#csvlogformat
// TODO this may not be the ideal order; fix further and update the screenshot(s)
public static final List<String> SAVE_CONFIG_NAMES = Collections.unmodifiableList(Arrays.asList(new String[]{
"AsXml",
"FieldNames", // CSV
"Timestamp",
"Time", // elapsed
"Label",
"Code", // Response Code
"Message", // Response Message
"ThreadName",
"DataType",
"Success",
"AssertionResultsFailureMessage",
"Bytes",
"SentBytes",
"ThreadCounts", // grpThreads and allThreads
"Url",
"FileName",
"Latency",
"ConnectTime",
"Encoding",
"SampleCount", // Sample and Error Count
"Hostname",
"IdleTime",
"RequestHeaders", // XML
"SamplerData", // XML
"ResponseHeaders", // XML
"ResponseData", // XML
"Subresults", // XML
"Assertions", // XML
}));
// N.B. Remember to update the equals and hashCode methods when adding new variables.
// Initialise values from properties
private boolean time = TIME;
private boolean latency = LATENCY;
private boolean connectTime=CONNECT_TIME;
private boolean timestamp = TIMESTAMP;
private boolean success = SUCCESS;
private boolean label = LABEL;
private boolean code = CODE;
private boolean message = MESSAGE;
private boolean threadName = THREAD_NAME;
private boolean dataType = DATATYPE;
private boolean encoding = ENCODING;
private boolean assertions = ASSERTIONS;
private boolean subresults = SUB_RESULTS;
private boolean responseData = RESPONSE_DATA;
private boolean samplerData = SAMPLER_DATA;
private boolean xml = IS_XML;
private boolean fieldNames = FIELD_NAMES;
private boolean responseHeaders = RESPONSE_HEADERS;
private boolean requestHeaders = REQUEST_HEADERS;
private boolean responseDataOnError = RESPONSE_DATA_ON_ERROR;
private boolean saveAssertionResultsFailureMessage = SAVE_ASSERTION_RESULTS_FAILURE_MESSAGE;
private boolean url = URL;
private boolean bytes = BYTES;
private boolean sentBytes = SENT_BYTES;
private boolean fileName = FILE_NAME;
private boolean hostname = HOST_NAME;
private boolean threadCounts = THREAD_COUNTS;
private boolean sampleCount = SAMPLE_COUNT;
private boolean idleTime = IDLE_TIME;
// Does not appear to be used (yet)
private int assertionsResultsToSave = ASSERTIONS_RESULT_TO_SAVE;
// Don't save this, as it is derived from the time format
private boolean printMilliseconds = PRINT_MILLISECONDS;
private transient String dateFormat = DATE_FORMAT;
/** A formatter for the time stamp.
* Make transient as we don't want to save the FastDateFormat class
* Also, there's currently no way to change the value via the GUI, so changing it
* later means editting the JMX, or recreating the Listener.
*/
private transient FastDateFormat timestampFormatter =
dateFormat != null ? FastDateFormat.getInstance(dateFormat) : null;
// Don't save this, as not settable via GUI
private String delimiter = DELIMITER;
// Don't save this - only needed for processing CSV headers currently
private transient int varCount = 0;
public SampleSaveConfiguration() {
}
/**
* Alternate constructor for use by CsvSaveService
*
* @param value initial setting for boolean fields used in Config dialogue
*/
public SampleSaveConfiguration(boolean value) {
assertions = value;
bytes = value;
code = value;
connectTime = value;
dataType = value;
encoding = value;
fieldNames = value;
fileName = value;
hostname = value;
idleTime = value;
label = value;
latency = value;
message = value;
printMilliseconds = PRINT_MILLISECONDS;//is derived from properties only
requestHeaders = value;
responseData = value;
responseDataOnError = value;
responseHeaders = value;
sampleCount = value;
samplerData = value;
saveAssertionResultsFailureMessage = value;
sentBytes = value;
subresults = value;
success = value;
threadCounts = value;
threadName = value;
time = value;
timestamp = value;
url = value;
xml = value;
}
public int getVarCount() { // Only for use by CSVSaveService
return varCount;
}
public void setVarCount(int varCount) { // Only for use by CSVSaveService
this.varCount = varCount;
}
// Give access to initial configuration
public static SampleSaveConfiguration staticConfig() {
return STATIC_SAVE_CONFIGURATION;
}
/**
* Convert a config name to the method name of the getter.
* The getter method returns a boolean.
* @param configName the config name
* @return the getter method name
*/
public static final String getterName(String configName) {
return CONFIG_GETTER_PREFIX + configName;
}
/**
* Convert a config name to the method name of the setter
* The setter method requires a boolean parameter.
* @param configName the config name
* @return the setter method name
*/
public static final String setterName(String configName) {
return CONFIG_SETTER_PREFIX + configName;
}
/**
* Validate pattern
* @param temporaryTimestampFormat DateFormat pattern
* @return format if ok or null
*/
private static String validateFormat(String temporaryTimestampFormat) {
try {
new SimpleDateFormat(temporaryTimestampFormat);
if(log.isDebugEnabled()) {
log.debug("Successfully validated pattern value {} for property {}",
temporaryTimestampFormat, TIME_STAMP_FORMAT_PROP);
}
return temporaryTimestampFormat;
} catch(IllegalArgumentException ex) {
log.error("Invalid pattern value {} for property {}", temporaryTimestampFormat, TIME_STAMP_FORMAT_PROP,
ex);
return null;
}
}
private Object readResolve(){
setupDateFormat(DATE_FORMAT);
return this;
}
/**
* Initialize threadSafeLenientFormatter
* @param pDateFormat String date format
*/
private void setupDateFormat(String pDateFormat) {
this.dateFormat = pDateFormat;
if(dateFormat != null) {
this.timestampFormatter = FastDateFormat.getInstance(dateFormat);
} else {
this.timestampFormatter = null;
}
}
@Override
public Object clone() {
try {
SampleSaveConfiguration clone = (SampleSaveConfiguration)super.clone();
if(this.dateFormat != null) {
clone.timestampFormatter = (FastDateFormat)this.threadSafeLenientFormatter().clone();
}
return clone;
}
catch(CloneNotSupportedException e) {
throw new RuntimeException("Should not happen",e);
}
}
@Override
public boolean equals(Object obj) {
if(this == obj) {
return true;
}
if((obj == null) || (obj.getClass() != this.getClass())) {
return false;
}
// We know we are comparing to another SampleSaveConfiguration
SampleSaveConfiguration s = (SampleSaveConfiguration)obj;
boolean primitiveValues = s.time == time &&
s.latency == latency &&
s.connectTime == connectTime &&
s.timestamp == timestamp &&
s.success == success &&
s.label == label &&
s.code == code &&
s.message == message &&
s.threadName == threadName &&
s.dataType == dataType &&
s.encoding == encoding &&
s.assertions == assertions &&
s.subresults == subresults &&
s.responseData == responseData &&
s.samplerData == samplerData &&
s.xml == xml &&
s.fieldNames == fieldNames &&
s.responseHeaders == responseHeaders &&
s.requestHeaders == requestHeaders &&
s.assertionsResultsToSave == assertionsResultsToSave &&
s.saveAssertionResultsFailureMessage == saveAssertionResultsFailureMessage &&
s.printMilliseconds == printMilliseconds &&
s.responseDataOnError == responseDataOnError &&
s.url == url &&
s.bytes == bytes &&
s.sentBytes == sentBytes &&
s.fileName == fileName &&
s.hostname == hostname &&
s.sampleCount == sampleCount &&
s.idleTime == idleTime &&
s.threadCounts == threadCounts;
boolean stringValues = false;
if(primitiveValues) {
stringValues = Objects.equals(delimiter, s.delimiter);
}
boolean complexValues = false;
if(primitiveValues && stringValues) {
complexValues = Objects.equals(dateFormat, s.dateFormat);
}
return primitiveValues && stringValues && complexValues;
}
@Override
public int hashCode() {
int hash = 7;
hash = 31 * hash + (time ? 1 : 0);
hash = 31 * hash + (latency ? 1 : 0);
hash = 31 * hash + (connectTime ? 1 : 0);
hash = 31 * hash + (timestamp ? 1 : 0);
hash = 31 * hash + (success ? 1 : 0);
hash = 31 * hash + (label ? 1 : 0);
hash = 31 * hash + (code ? 1 : 0);
hash = 31 * hash + (message ? 1 : 0);
hash = 31 * hash + (threadName ? 1 : 0);
hash = 31 * hash + (dataType ? 1 : 0);
hash = 31 * hash + (encoding ? 1 : 0);
hash = 31 * hash + (assertions ? 1 : 0);
hash = 31 * hash + (subresults ? 1 : 0);
hash = 31 * hash + (responseData ? 1 : 0);
hash = 31 * hash + (samplerData ? 1 : 0);
hash = 31 * hash + (xml ? 1 : 0);
hash = 31 * hash + (fieldNames ? 1 : 0);
hash = 31 * hash + (responseHeaders ? 1 : 0);
hash = 31 * hash + (requestHeaders ? 1 : 0);
hash = 31 * hash + assertionsResultsToSave;
hash = 31 * hash + (saveAssertionResultsFailureMessage ? 1 : 0);
hash = 31 * hash + (printMilliseconds ? 1 : 0);
hash = 31 * hash + (responseDataOnError ? 1 : 0);
hash = 31 * hash + (url ? 1 : 0);
hash = 31 * hash + (bytes ? 1 : 0);
hash = 31 * hash + (sentBytes ? 1 : 0);
hash = 31 * hash + (fileName ? 1 : 0);
hash = 31 * hash + (hostname ? 1 : 0);
hash = 31 * hash + (threadCounts ? 1 : 0);
hash = 31 * hash + (delimiter != null ? delimiter.hashCode() : 0);
hash = 31 * hash + (dateFormat != null ? dateFormat.hashCode() : 0);
hash = 31 * hash + (sampleCount ? 1 : 0);
hash = 31 * hash + (idleTime ? 1 : 0);
return hash;
}
///////////////////// Start of standard save/set access methods /////////////////////
public boolean saveResponseHeaders() {
return responseHeaders;
}
public void setResponseHeaders(boolean r) {
responseHeaders = r;
}
public boolean saveRequestHeaders() {
return requestHeaders;
}
public void setRequestHeaders(boolean r) {
requestHeaders = r;
}
public boolean saveAssertions() {
return assertions;
}
public void setAssertions(boolean assertions) {
this.assertions = assertions;
}
public boolean saveCode() {
return code;
}
public void setCode(boolean code) {
this.code = code;
}
public boolean saveDataType() {
return dataType;
}
public void setDataType(boolean dataType) {
this.dataType = dataType;
}
public boolean saveEncoding() {
return encoding;
}
public void setEncoding(boolean encoding) {
this.encoding = encoding;
}
public boolean saveLabel() {
return label;
}
public void setLabel(boolean label) {
this.label = label;
}
public boolean saveLatency() {
return latency;
}
public void setLatency(boolean latency) {
this.latency = latency;
}
public boolean saveConnectTime() {
return connectTime;
}
public void setConnectTime(boolean connectTime) {
this.connectTime = connectTime;
}
public boolean saveMessage() {
return message;
}
public void setMessage(boolean message) {
this.message = message;
}
public boolean saveResponseData(SampleResult res) {
return responseData || TestPlan.getFunctionalMode() || (responseDataOnError && !res.isSuccessful());
}
public boolean saveResponseData()
{
return responseData;
}
public void setResponseData(boolean responseData) {
this.responseData = responseData;
}
public boolean saveSamplerData(SampleResult res) {
return samplerData || TestPlan.getFunctionalMode() // as per 2.0 branch
|| (responseDataOnError && !res.isSuccessful());
}
public boolean saveSamplerData()
{
return samplerData;
}
public void setSamplerData(boolean samplerData) {
this.samplerData = samplerData;
}
public boolean saveSubresults() {
return subresults;
}
public void setSubresults(boolean subresults) {
this.subresults = subresults;
}
public boolean saveSuccess() {
return success;
}
public void setSuccess(boolean success) {
this.success = success;
}
public boolean saveThreadName() {
return threadName;
}
public void setThreadName(boolean threadName) {
this.threadName = threadName;
}
public boolean saveTime() {
return time;
}
public void setTime(boolean time) {
this.time = time;
}
public boolean saveTimestamp() {
return timestamp;
}
public void setTimestamp(boolean timestamp) {
this.timestamp = timestamp;
}
public boolean saveAsXml() {
return xml;
}
public void setAsXml(boolean xml) {
this.xml = xml;
}
public boolean saveFieldNames() {
return fieldNames;
}
public void setFieldNames(boolean printFieldNames) {
this.fieldNames = printFieldNames;
}
public boolean saveUrl() {
return url;
}
public void setUrl(boolean save) {
this.url = save;
}
public boolean saveBytes() {
return bytes;
}
public void setBytes(boolean save) {
this.bytes = save;
}
public boolean saveSentBytes() {
return sentBytes;
}
public void setSentBytes(boolean save) {
this.sentBytes = save;
}
public boolean saveFileName() {
return fileName;
}
public void setFileName(boolean save) {
this.fileName = save;
}
public boolean saveAssertionResultsFailureMessage() {
return saveAssertionResultsFailureMessage;
}
public void setAssertionResultsFailureMessage(boolean b) {
saveAssertionResultsFailureMessage = b;
}
public boolean saveThreadCounts() {
return threadCounts;
}
public void setThreadCounts(boolean save) {
this.threadCounts = save;
}
public boolean saveSampleCount() {
return sampleCount;
}
public void setSampleCount(boolean save) {
this.sampleCount = save;
}
///////////////// End of standard field accessors /////////////////////
/**
* Intended for use by CsvSaveService (and test cases)
* @param fmt
* format of the date to be saved. If <code>null</code>
* milliseconds since epoch will be printed
*/
public void setDateFormat(String fmt){
printMilliseconds = fmt == null; // maintain relationship
setupDateFormat(fmt);
}
public boolean printMilliseconds() {
return printMilliseconds;
}
/**
* @return {@link DateFormat} non lenient
*/
public DateFormat strictDateFormatter() {
if(dateFormat != null) {
return new SimpleDateFormat(dateFormat);
} else {
return null;
}
}
/**
* @return {@link FastDateFormat} Thread safe lenient formatter
*/
public FastDateFormat threadSafeLenientFormatter() {
// When restored by XStream threadSafeLenientFormatter may not have
// been initialized
if(timestampFormatter == null) {
timestampFormatter =
dateFormat != null ? FastDateFormat.getInstance(dateFormat) : null;
}
return timestampFormatter;
}
public int assertionsResultsToSave() {
return assertionsResultsToSave;
}
public String getDelimiter() {
return delimiter;
}
public String getXmlPi() {
return JMeterUtils.getJMeterProperties().getProperty(XML_PI, ""); // Defaults to empty;
}
// Used by old Save service
public void setDelimiter(String delim) {
delimiter=delim;
}
// Used by SampleSaveConfigurationConverter.unmarshall()
public void setDefaultDelimiter() {
delimiter=DELIMITER;
}
// Used by SampleSaveConfigurationConverter.unmarshall()
public void setDefaultTimeStampFormat() {
printMilliseconds=PRINT_MILLISECONDS;
setupDateFormat(DATE_FORMAT);
}
public boolean saveHostname(){
return hostname;
}
public void setHostname(boolean save){
hostname = save;
}
public boolean saveIdleTime() {
return idleTime;
}
public void setIdleTime(boolean save) {
idleTime = save;
}
}