// $Header: /home/cvs/jakarta-jmeter/src/core/org/apache/jmeter/save/OldSaveService.java,v 1.9.2.3 2005/09/20 15:28:23 woolfel Exp $
/*
* Copyright 2001-2005 The Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.jmeter.save;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.text.ParseException;
import java.util.Collection;
import java.util.Date;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
import java.util.Vector;
import org.apache.avalon.framework.configuration.Configuration;
import org.apache.avalon.framework.configuration.ConfigurationException;
import org.apache.avalon.framework.configuration.DefaultConfiguration;
import org.apache.avalon.framework.configuration.DefaultConfigurationBuilder;
import org.apache.avalon.framework.configuration.DefaultConfigurationSerializer;
import org.apache.jmeter.assertions.AssertionResult;
import org.apache.jmeter.samplers.SampleResult;
import org.apache.jmeter.samplers.SampleSaveConfiguration;
import org.apache.jmeter.testelement.TestElement;
import org.apache.jmeter.testelement.property.CollectionProperty;
import org.apache.jmeter.testelement.property.JMeterProperty;
import org.apache.jmeter.testelement.property.MapProperty;
import org.apache.jmeter.testelement.property.StringProperty;
import org.apache.jmeter.testelement.property.TestElementProperty;
import org.apache.jmeter.util.NameUpdater;
import org.apache.jorphan.collections.HashTree;
import org.apache.jorphan.collections.ListedHashTree;
import org.apache.jorphan.logging.LoggingManager;
import org.apache.jorphan.util.JOrphanUtils;
import org.apache.log.Logger;
import org.xml.sax.SAXException;
/**
* This class provides a means for saving test results. Test results are
* typically saved in an XML file, but other storage mechanisms may also be
* used, for instance, CSV files or databases.
*
* @version $Revision: 1.9.2.3 $ $Date: 2005/09/20 15:28:23 $
*/
public final class OldSaveService implements SaveServiceConstants {
transient private static final Logger log = LoggingManager.getLoggerForClass();
// Initial config from properties
static private final SampleSaveConfiguration _saveConfig = SampleSaveConfiguration.staticConfig();
private static DefaultConfigurationBuilder builder = new DefaultConfigurationBuilder();
/**
* Private constructor to prevent instantiation.
*/
private OldSaveService() {
}
/**
* Make a SampleResult given a delimited string.
*
* @param delim
* @return SampleResult
*/
public static SampleResult makeResultFromDelimitedString(String delim) {
SampleResult result = null;
long timeStamp = 0;
long elapsed = 0;
StringTokenizer splitter = new StringTokenizer(delim, _saveConfig.getDelimiter());
String text = null;
try {
if (_saveConfig.printMilliseconds()) {
text = splitter.nextToken();
timeStamp = Long.parseLong(text);
} else if (_saveConfig.formatter() != null) {
text = splitter.nextToken();
Date stamp = _saveConfig.formatter().parse(text);
timeStamp = stamp.getTime();
}
if (_saveConfig.saveTime()) {
text = splitter.nextToken();
elapsed = Long.parseLong(text);
}
result = new SampleResult(timeStamp, elapsed);
if (_saveConfig.saveLabel()) {
text = splitter.nextToken();
result.setSampleLabel(text);
}
if (_saveConfig.saveCode()) {
text = splitter.nextToken();
result.setResponseCode(text);
}
if (_saveConfig.saveMessage()) {
text = splitter.nextToken();
result.setResponseMessage(text);
}
if (_saveConfig.saveThreadName()) {
text = splitter.nextToken();
result.setThreadName(text);
}
if (_saveConfig.saveDataType()) {
text = splitter.nextToken();
result.setDataType(text);
}
if (_saveConfig.saveSuccess()) {
text = splitter.nextToken();
result.setSuccessful(Boolean.valueOf(text).booleanValue());
}
if (_saveConfig.saveAssertionResultsFailureMessage()) {
text = splitter.nextToken();
}
} catch (NumberFormatException e) {
log.warn("Error parsing number " + e);
throw e;
} catch (ParseException e) {
log.warn("Error parsing line " + e);
throw new RuntimeException(e.toString());
}
return result;
}
/**
* Generates the field names for the output file
*
* @return the field names as a string
*/
public static String printableFieldNamesToString() {
return printableFieldNamesToString(_saveConfig);
}
/**
* Generates the field names for the output file
*
* @return the field names as a string
*/
public static String printableFieldNamesToString(SampleSaveConfiguration saveConfig) {
StringBuffer text = new StringBuffer();
String delim = saveConfig.getDelimiter();
if (saveConfig.saveTimestamp() || (saveConfig.formatter() != null)) {
text.append(SaveServiceConstants.TIME_STAMP);
text.append(delim);
}
if (saveConfig.saveTime()) {
text.append(SaveServiceConstants.TIME);
text.append(delim);
}
if (saveConfig.saveLabel()) {
text.append(SaveServiceConstants.LABEL);
text.append(delim);
}
if (saveConfig.saveCode()) {
text.append(SaveServiceConstants.RESPONSE_CODE);
text.append(delim);
}
if (saveConfig.saveMessage()) {
text.append(SaveServiceConstants.RESPONSE_MESSAGE);
text.append(delim);
}
if (saveConfig.saveThreadName()) {
text.append(SaveServiceConstants.THREAD_NAME);
text.append(delim);
}
if (saveConfig.saveDataType()) {
text.append(SaveServiceConstants.DATA_TYPE);
text.append(delim);
}
if (saveConfig.saveSuccess()) {
text.append(SaveServiceConstants.SUCCESSFUL);
text.append(delim);
}
if (saveConfig.saveAssertionResultsFailureMessage()) {
text.append(SaveServiceConstants.FAILURE_MESSAGE);
text.append(delim);
}
String resultString = null;
int size = text.length();
int delSize = delim.length();
// Strip off the trailing delimiter
if (size >= delSize) {
resultString = text.substring(0, size - delSize);
} else {
resultString = text.toString();
}
return resultString;
}
public static void saveSubTree(HashTree subTree, OutputStream writer) throws IOException {
Configuration config = (Configuration) getConfigsFromTree(subTree).get(0);
DefaultConfigurationSerializer saver = new DefaultConfigurationSerializer();
saver.setIndent(true);
try {
saver.serialize(writer, config);
} catch (SAXException e) {
throw new IOException("SAX implementation problem");
} catch (ConfigurationException e) {
throw new IOException("Problem using Avalon Configuration tools");
}
}
/**
* Method will save aggregate statistics as CSV. For now I put it here.
* Not sure if it should go in the newer SaveService instead of here.
* if we ever decide to get rid of this class, we'll need to move this
* method to the new save service.
* @param data
* @param writer
* @throws IOException
*/
public static void saveCSVStats(Vector data, FileWriter writer) throws IOException {
for (int idx=0; idx < data.size(); idx++) {
Vector row = (Vector)data.elementAt(idx);
for (int idy=0; idy < row.size(); idy++) {
if (idy > 0) {
writer.write(",");
}
Object item = row.elementAt(idy);
writer.write( String.valueOf(item) );
}
writer.write(System.getProperty("line.separator"));
}
}
public static SampleResult getSampleResult(Configuration config) {
SampleResult result = new SampleResult(config.getAttributeAsLong(TIME_STAMP, 0L), config.getAttributeAsLong(
TIME, 0L));
result.setThreadName(config.getAttribute(THREAD_NAME, ""));
result.setDataType(config.getAttribute(DATA_TYPE, ""));
result.setResponseCode(config.getAttribute(RESPONSE_CODE, ""));
result.setResponseMessage(config.getAttribute(RESPONSE_MESSAGE, ""));
result.setSuccessful(config.getAttributeAsBoolean(SUCCESSFUL, false));
result.setSampleLabel(config.getAttribute(LABEL, ""));
result.setResponseData(getBinaryData(config.getChild(BINARY)));
Configuration[] subResults = config.getChildren(SAMPLE_RESULT_TAG_NAME);
for (int i = 0; i < subResults.length; i++) {
result.addSubResult(getSampleResult(subResults[i]));
}
Configuration[] assResults = config.getChildren(ASSERTION_RESULT_TAG_NAME);
for (int i = 0; i < assResults.length; i++) {
result.addAssertionResult(getAssertionResult(assResults[i]));
}
Configuration[] samplerData = config.getChildren("property");
for (int i = 0; i < samplerData.length; i++) {
result.setSamplerData(samplerData[i].getValue(""));
}
return result;
}
private static List getConfigsFromTree(HashTree subTree) {
Iterator iter = subTree.list().iterator();
List configs = new LinkedList();
while (iter.hasNext()) {
TestElement item = (TestElement) iter.next();
DefaultConfiguration config = new DefaultConfiguration("node", "node");
config.addChild(getConfigForTestElement(null, item));
List configList = getConfigsFromTree(subTree.getTree(item));
Iterator iter2 = configList.iterator();
while (iter2.hasNext()) {
config.addChild((Configuration) iter2.next());
}
configs.add(config);
}
return configs;
}
public static Configuration getConfiguration(byte[] bin) {
DefaultConfiguration config = new DefaultConfiguration(BINARY, "JMeter Save Service");
try {
config.setValue(new String(bin, "UTF-8"));
} catch (UnsupportedEncodingException e) {
log.error("", e);
}
return config;
}
public static byte[] getBinaryData(Configuration config) {
if (config == null) {
return new byte[0];
}
try {
return config.getValue("").getBytes("UTF-8");
} catch (UnsupportedEncodingException e) {
return new byte[0];
}
}
public static AssertionResult getAssertionResult(Configuration config) {
AssertionResult result = new AssertionResult();
result.setError(config.getAttributeAsBoolean(ERROR, false));
result.setFailure(config.getAttributeAsBoolean(FAILURE, false));
result.setFailureMessage(config.getAttribute(FAILURE_MESSAGE, ""));
return result;
}
public static Configuration getConfiguration(AssertionResult assResult) {
DefaultConfiguration config = new DefaultConfiguration(ASSERTION_RESULT_TAG_NAME, "JMeter Save Service");
config.setAttribute(FAILURE_MESSAGE, assResult.getFailureMessage());
config.setAttribute(ERROR, "" + assResult.isError());
config.setAttribute(FAILURE, "" + assResult.isFailure());
return config;
}
/**
* This method determines the content of the result data that will be
* stored.
*
* @param result
* the object containing all of the data that has been collected.
* @param funcTest
* an indicator of whether the user wants all data recorded.
*/
public static Configuration getConfiguration(SampleResult result, SampleSaveConfiguration saveConfig) {
DefaultConfiguration config = new DefaultConfiguration(SAMPLE_RESULT_TAG_NAME, "JMeter Save Service");
if (saveConfig.saveTime()) {
config.setAttribute(TIME, "" + result.getTime());
}
if (saveConfig.saveLabel()) {
config.setAttribute(LABEL, result.getSampleLabel());
}
if (saveConfig.saveCode()) {
config.setAttribute(RESPONSE_CODE, result.getResponseCode());
}
if (saveConfig.saveMessage()) {
config.setAttribute(RESPONSE_MESSAGE, result.getResponseMessage());
}
if (saveConfig.saveThreadName()) {
config.setAttribute(THREAD_NAME, result.getThreadName());
}
if (saveConfig.saveDataType()) {
config.setAttribute(DATA_TYPE, result.getDataType());
}
if (saveConfig.printMilliseconds()) {
config.setAttribute(TIME_STAMP, "" + result.getTimeStamp());
} else if (saveConfig.formatter() != null) {
String stamp = saveConfig.formatter().format(new Date(result.getTimeStamp()));
config.setAttribute(TIME_STAMP, stamp);
}
if (saveConfig.saveSuccess()) {
config.setAttribute(SUCCESSFUL, JOrphanUtils.booleanToString(result.isSuccessful()));
}
SampleResult[] subResults = result.getSubResults();
if (subResults != null) {
for (int i = 0; i < subResults.length; i++) {
config.addChild(getConfiguration(subResults[i], saveConfig));
}
}
AssertionResult[] assResults = result.getAssertionResults();
if (saveConfig.saveSamplerData(result)) {
config.addChild(createConfigForString("samplerData", result.getSamplerData()));
}
if (saveConfig.saveAssertions() && assResults != null) {
for (int i = 0; i < assResults.length; i++) {
config.addChild(getConfiguration(assResults[i]));
}
}
if (saveConfig.saveResponseData(result)) {
config.addChild(getConfiguration(result.getResponseData()));
}
return config;
}
/**
* Convert a result into a string, where the fields of the result are
* separated by the default delimiter.
*
* @param sample
* the test result to be converted
* @return the separated value representation of the result
*/
public static String resultToDelimitedString(SampleResult sample) {
return resultToDelimitedString(sample, sample.getSaveConfig().getDelimiter());
}
/**
* Convert a result into a string, where the fields of the result are
* separated by a specified String.
*
* @param sample
* the test result to be converted
* @param delimiter
* the separation string
* @return the separated value representation of the result
*/
public static String resultToDelimitedString(SampleResult sample, String delimiter) {
StringBuffer text = new StringBuffer();
SampleSaveConfiguration saveConfig = sample.getSaveConfig();
if (saveConfig.saveTimestamp()) {
text.append(sample.getTimeStamp());
text.append(delimiter);
} else if (saveConfig.formatter() != null) {
String stamp = saveConfig.formatter().format(new Date(sample.getTimeStamp()));
text.append(stamp);
text.append(delimiter);
}
if (saveConfig.saveTime()) {
text.append(sample.getTime());
text.append(delimiter);
}
if (saveConfig.saveLabel()) {
text.append(sample.getSampleLabel());
text.append(delimiter);
}
if (saveConfig.saveCode()) {
text.append(sample.getResponseCode());
text.append(delimiter);
}
if (saveConfig.saveMessage()) {
text.append(sample.getResponseMessage());
text.append(delimiter);
}
if (saveConfig.saveThreadName()) {
text.append(sample.getThreadName());
text.append(delimiter);
}
if (saveConfig.saveDataType()) {
text.append(sample.getDataType());
text.append(delimiter);
}
if (saveConfig.saveSuccess()) {
text.append(sample.isSuccessful());
text.append(delimiter);
}
if (saveConfig.saveAssertionResultsFailureMessage()) {
String message = null;
AssertionResult[] results = sample.getAssertionResults();
if ((results != null) && (results.length > 0)) {
message = results[0].getFailureMessage();
}
if (message != null) {
text.append(message);
}
text.append(delimiter);
}
// text.append(sample.getSamplerData().toString());
// text.append(getAssertionResult(sample));
String resultString = null;
int size = text.length();
int delSize = delimiter.length();
// Strip off the trailing delimiter
if (size >= delSize) {
resultString = text.substring(0, size - delSize);
} else {
resultString = text.toString();
}
return resultString;
}
public static Configuration getConfigForTestElement(String named, TestElement item) {
TestElementSaver saver = new TestElementSaver(named);
item.traverse(saver);
Configuration config = saver.getConfiguration();
/*
* DefaultConfiguration config = new DefaultConfiguration("testelement",
* "testelement");
*
* if (named != null) { config.setAttribute("name", named); } if
* (item.getProperty(TestElement.TEST_CLASS) != null) {
* config.setAttribute("class", (String)
* item.getProperty(TestElement.TEST_CLASS)); } else {
* config.setAttribute("class", item.getClass().getName()); } Iterator
* iter = item.getPropertyNames().iterator();
*
* while (iter.hasNext()) { String name = (String) iter.next(); Object
* value = item.getProperty(name);
*
* if (value instanceof TestElement) {
* config.addChild(getConfigForTestElement(name, (TestElement) value)); }
* else if (value instanceof Collection) {
* config.addChild(createConfigForCollection(name, (Collection) value)); }
* else if (value != null) { config.addChild(createConfigForString(name,
* value.toString())); } }
*/
return config;
}
/*
*
* NOTUSED private static Configuration createConfigForCollection( String
* propertyName, Collection list) { DefaultConfiguration config = new
* DefaultConfiguration("collection", "collection");
*
* if (propertyName != null) { config.setAttribute("name", propertyName); }
* config.setAttribute("class", list.getClass().getName()); Iterator iter =
* list.iterator();
*
* while (iter.hasNext()) { Object item = iter.next();
*
* if (item instanceof TestElement) { config.addChild(
* getConfigForTestElement(null, (TestElement) item)); } else if (item
* instanceof Collection) { config.addChild( createConfigForCollection(null,
* (Collection) item)); } else {
* config.addChild(createConfigForString(item.toString())); } } return
* config; }
*/
/*
* NOTUSED
*
* private static Configuration createConfigForString(String value) {
* DefaultConfiguration config = new DefaultConfiguration("string",
* "string");
*
* config.setValue(value); config.setAttribute(XML_SPACE, PRESERVE); return
* config; }
*/
private static Configuration createConfigForString(String name, String value) {
if (value == null) {
value = "";
}
DefaultConfiguration config = new DefaultConfiguration("property", "property");
config.setAttribute("name", name);
config.setValue(value);
config.setAttribute(XML_SPACE, PRESERVE);
return config;
}
public synchronized static HashTree loadSubTree(InputStream in) throws IOException {
try {
Configuration config = builder.build(in);
HashTree loadedTree = generateNode(config);
return loadedTree;
} catch (ConfigurationException e) {
String message = "Problem loading using Avalon Configuration tools";
log.error(message, e);
throw new IOException(message);
} catch (SAXException e) {
String message = "Problem with SAX implementation";
log.error(message, e);
throw new IOException(message);
}
}
public static TestElement createTestElement(Configuration config) throws ConfigurationException,
ClassNotFoundException, IllegalAccessException, InstantiationException {
TestElement element = null;
String testClass = config.getAttribute("class");
String gui_class="";
Configuration[] children = config.getChildren();
for (int i = 0; i < children.length; i++) {
if (children[i].getName().equals("property")) {
if (children[i].getAttribute("name").equals(TestElement.GUI_CLASS)){
gui_class=children[i].getValue();
}
}
}
String newClass = NameUpdater.getCurrentTestName(testClass,gui_class);
element = (TestElement) Class.forName(newClass).newInstance();
for (int i = 0; i < children.length; i++) {
if (children[i].getName().equals("property")) {
try {
JMeterProperty prop = createProperty(children[i], newClass);
if (prop!=null) element.setProperty(prop);
} catch (Exception ex) {
log.error("Problem loading property", ex);
element.setProperty(children[i].getAttribute("name"), "");
}
} else if (children[i].getName().equals("testelement")) {
element.setProperty(new TestElementProperty(children[i].getAttribute("name", ""),
createTestElement(children[i])));
} else if (children[i].getName().equals("collection")) {
element.setProperty(new CollectionProperty(children[i].getAttribute("name", ""),
createCollection(children[i], newClass)));
} else if (children[i].getName().equals("map")) {
element.setProperty(new MapProperty(children[i].getAttribute("name", ""),
createMap(children[i],newClass)));
}
}
return element;
}
private static Collection createCollection(Configuration config, String testClass) throws ConfigurationException,
ClassNotFoundException, IllegalAccessException, InstantiationException {
Collection coll = (Collection) Class.forName(config.getAttribute("class")).newInstance();
Configuration[] items = config.getChildren();
for (int i = 0; i < items.length; i++) {
if (items[i].getName().equals("property")) {
JMeterProperty prop = createProperty(items[i], testClass);
if (prop!=null) coll.add(prop);
} else if (items[i].getName().equals("testelement")) {
coll.add(new TestElementProperty(items[i].getAttribute("name", ""), createTestElement(items[i])));
} else if (items[i].getName().equals("collection")) {
coll.add(new CollectionProperty(items[i].getAttribute("name", ""),
createCollection(items[i], testClass)));
} else if (items[i].getName().equals("string")) {
JMeterProperty prop = createProperty(items[i], testClass);
if (prop!=null) coll.add(prop);
} else if (items[i].getName().equals("map")) {
coll.add(new MapProperty(items[i].getAttribute("name", ""), createMap(items[i], testClass)));
}
}
return coll;
}
private static JMeterProperty createProperty(Configuration config, String testClass) throws IllegalAccessException,
ClassNotFoundException, InstantiationException {
String value = config.getValue("");
String name = config.getAttribute("name", value);
String oname = name;
String type = config.getAttribute("propType", StringProperty.class.getName());
// Do upgrade translation:
name = NameUpdater.getCurrentName(name, testClass);
if (TestElement.GUI_CLASS.equals(name)) {
value = NameUpdater.getCurrentName(value);
} else if (TestElement.TEST_CLASS.equals(name)) {
value=testClass; // must always agree
} else {
value = NameUpdater.getCurrentName(value, name, testClass);
}
// Delete any properties whose name converts to the empty string
if (oname.length() != 0 && name.length()==0) {
return null;
}
// Create the property:
JMeterProperty prop = (JMeterProperty) Class.forName(type).newInstance();
prop.setName(name);
prop.setObjectValue(value);
return prop;
}
private static Map createMap(Configuration config, String testClass) throws ConfigurationException,
ClassNotFoundException, IllegalAccessException, InstantiationException {
Map map = (Map) Class.forName(config.getAttribute("class")).newInstance();
Configuration[] items = config.getChildren();
for (int i = 0; i < items.length; i++) {
if (items[i].getName().equals("property")) {
JMeterProperty prop = createProperty(items[i], testClass);
if (prop!=null) map.put(prop.getName(), prop);
} else if (items[i].getName().equals("testelement")) {
map.put(items[i].getAttribute("name", ""), new TestElementProperty(items[i].getAttribute("name", ""),
createTestElement(items[i])));
} else if (items[i].getName().equals("collection")) {
map.put(items[i].getAttribute("name"), new CollectionProperty(items[i].getAttribute("name", ""),
createCollection(items[i], testClass)));
} else if (items[i].getName().equals("map")) {
map.put(items[i].getAttribute("name", ""), new MapProperty(items[i].getAttribute("name", ""),
createMap(items[i], testClass)));
}
}
return map;
}
private static HashTree generateNode(Configuration config) {
TestElement element = null;
try {
element = createTestElement(config.getChild("testelement"));
} catch (Exception e) {
log.error("Problem loading part of file", e);
return null;
}
HashTree subTree = new ListedHashTree(element);
Configuration[] subNodes = config.getChildren("node");
for (int i = 0; i < subNodes.length; i++) {
HashTree t = generateNode(subNodes[i]);
if (t != null) {
subTree.add(element, t);
}
}
return subTree;
}
}