001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: *
017: */
018:
019: package org.apache.jmeter.save;
020:
021: import java.io.ByteArrayOutputStream;
022: import java.io.IOException;
023: import java.io.InputStream;
024: import java.io.OutputStream;
025: import java.io.UnsupportedEncodingException;
026: import java.util.Collection;
027: import java.util.Date;
028: import java.util.Iterator;
029: import java.util.LinkedList;
030: import java.util.List;
031: import java.util.Map;
032:
033: import org.apache.avalon.framework.configuration.Configuration;
034: import org.apache.avalon.framework.configuration.ConfigurationException;
035: import org.apache.avalon.framework.configuration.DefaultConfiguration;
036: import org.apache.avalon.framework.configuration.DefaultConfigurationBuilder;
037: import org.apache.avalon.framework.configuration.DefaultConfigurationSerializer;
038: import org.apache.jmeter.assertions.AssertionResult;
039: import org.apache.jmeter.reporters.ResultCollector;
040: import org.apache.jmeter.samplers.SampleResult;
041: import org.apache.jmeter.samplers.SampleSaveConfiguration;
042: import org.apache.jmeter.testelement.TestElement;
043: import org.apache.jmeter.testelement.property.CollectionProperty;
044: import org.apache.jmeter.testelement.property.JMeterProperty;
045: import org.apache.jmeter.testelement.property.MapProperty;
046: import org.apache.jmeter.testelement.property.StringProperty;
047: import org.apache.jmeter.testelement.property.TestElementProperty;
048: import org.apache.jmeter.util.NameUpdater;
049: import org.apache.jmeter.visualizers.Visualizer;
050: import org.apache.jorphan.collections.HashTree;
051: import org.apache.jorphan.collections.ListedHashTree;
052: import org.apache.jorphan.logging.LoggingManager;
053: import org.apache.log.Logger;
054: import org.xml.sax.SAXException;
055:
056: /**
057: * This class saves/restores the original Avalon XML format (not used by default).
058: *
059: * This may be removed in a future release.
060: */
061: public final class OldSaveService {
062: private static final Logger log = LoggingManager
063: .getLoggerForClass();
064:
065: // ---------------------------------------------------------------------
066: // XML RESULT FILE CONSTANTS AND FIELD NAME CONSTANTS
067: // ---------------------------------------------------------------------
068:
069: // Shared with TestElementSaver
070: final static String PRESERVE = "preserve"; // $NON-NLS-1$
071: final static String XML_SPACE = "xml:space"; // $NON-NLS-1$
072:
073: private static final String ASSERTION_RESULT_TAG_NAME = "assertionResult"; // $NON-NLS-1$
074: private static final String BINARY = "binary"; // $NON-NLS-1$
075: private static final String DATA_TYPE = "dataType"; // $NON-NLS-1$
076: private static final String ERROR = "error"; // $NON-NLS-1$
077: private static final String FAILURE = "failure"; // $NON-NLS-1$
078: private static final String FAILURE_MESSAGE = "failureMessage"; // $NON-NLS-1$
079: private static final String LABEL = "label"; // $NON-NLS-1$
080: private static final String RESPONSE_CODE = "responseCode"; // $NON-NLS-1$
081: private static final String RESPONSE_MESSAGE = "responseMessage"; // $NON-NLS-1$
082: private static final String SAMPLE_RESULT_TAG_NAME = "sampleResult"; // $NON-NLS-1$
083: private static final String SUCCESSFUL = "success"; // $NON-NLS-1$
084: private static final String THREAD_NAME = "threadName"; // $NON-NLS-1$
085: private static final String TIME = "time"; // $NON-NLS-1$
086: private static final String TIME_STAMP = "timeStamp"; // $NON-NLS-1$
087:
088: private static DefaultConfigurationBuilder builder = new DefaultConfigurationBuilder();
089:
090: /**
091: * Private constructor to prevent instantiation.
092: */
093: private OldSaveService() {
094: }
095:
096: public static void saveSubTree(HashTree subTree, OutputStream writer)
097: throws IOException {
098: Configuration config = (Configuration) getConfigsFromTree(
099: subTree).get(0);
100: DefaultConfigurationSerializer saver = new DefaultConfigurationSerializer();
101:
102: saver.setIndent(true);
103: try {
104: saver.serialize(writer, config);
105: } catch (SAXException e) {
106: throw new IOException("SAX implementation problem");
107: } catch (ConfigurationException e) {
108: throw new IOException(
109: "Problem using Avalon Configuration tools");
110: }
111: }
112:
113: /**
114: * Read sampleResult from Avalon XML file.
115: *
116: * @param config Avalon configuration
117: * @return sample result
118: */
119: // Probably no point in converting this to return a SampleEvent
120: public static SampleResult getSampleResult(Configuration config) {
121: SampleResult result = new SampleResult(config
122: .getAttributeAsLong(TIME_STAMP, 0L), config
123: .getAttributeAsLong(TIME, 0L));
124:
125: result.setThreadName(config.getAttribute(THREAD_NAME, "")); // $NON-NLS-1$
126: result.setDataType(config.getAttribute(DATA_TYPE, ""));
127: result.setResponseCode(config.getAttribute(RESPONSE_CODE, "")); // $NON-NLS-1$
128: result.setResponseMessage(config.getAttribute(RESPONSE_MESSAGE,
129: "")); // $NON-NLS-1$
130: result.setSuccessful(config.getAttributeAsBoolean(SUCCESSFUL,
131: false));
132: result.setSampleLabel(config.getAttribute(LABEL, "")); // $NON-NLS-1$
133: result.setResponseData(getBinaryData(config.getChild(BINARY)));
134: Configuration[] subResults = config
135: .getChildren(SAMPLE_RESULT_TAG_NAME);
136:
137: for (int i = 0; i < subResults.length; i++) {
138: result.storeSubResult(getSampleResult(subResults[i]));
139: }
140: Configuration[] assResults = config
141: .getChildren(ASSERTION_RESULT_TAG_NAME);
142:
143: for (int i = 0; i < assResults.length; i++) {
144: result
145: .addAssertionResult(getAssertionResult(assResults[i]));
146: }
147:
148: Configuration[] samplerData = config.getChildren("property"); // $NON-NLS-1$
149: for (int i = 0; i < samplerData.length; i++) {
150: result.setSamplerData(samplerData[i].getValue("")); // $NON-NLS-1$
151: }
152: return result;
153: }
154:
155: private static List getConfigsFromTree(HashTree subTree) {
156: Iterator iter = subTree.list().iterator();
157: List configs = new LinkedList();
158:
159: while (iter.hasNext()) {
160: TestElement item = (TestElement) iter.next();
161: DefaultConfiguration config = new DefaultConfiguration(
162: "node", "node"); // $NON-NLS-1$ // $NON-NLS-2$
163:
164: config.addChild(getConfigForTestElement(null, item));
165: List configList = getConfigsFromTree(subTree.getTree(item));
166: Iterator iter2 = configList.iterator();
167:
168: while (iter2.hasNext()) {
169: config.addChild((Configuration) iter2.next());
170: }
171: configs.add(config);
172: }
173: return configs;
174: }
175:
176: private static Configuration getConfiguration(byte[] bin) {
177: DefaultConfiguration config = new DefaultConfiguration(BINARY,
178: "JMeter Save Service"); // $NON-NLS-1$
179:
180: try {
181: config.setValue(new String(bin, "UTF-8")); // $NON-NLS-1$
182: } catch (UnsupportedEncodingException e) {
183: log.error("", e); // $NON-NLS-1$
184: }
185: return config;
186: }
187:
188: private static byte[] getBinaryData(Configuration config) {
189: if (config == null) {
190: return new byte[0];
191: }
192: try {
193: return config.getValue("").getBytes("UTF-8"); // $NON-NLS-1$
194: } catch (UnsupportedEncodingException e) {
195: return new byte[0];
196: }
197: }
198:
199: private static AssertionResult getAssertionResult(
200: Configuration config) {
201: AssertionResult result = new AssertionResult(""); //TODO provide proper name?
202: result.setError(config.getAttributeAsBoolean(ERROR, false));
203: result.setFailure(config.getAttributeAsBoolean(FAILURE, false));
204: result.setFailureMessage(config.getAttribute(FAILURE_MESSAGE,
205: ""));
206: return result;
207: }
208:
209: private static Configuration getConfiguration(
210: AssertionResult assResult) {
211: DefaultConfiguration config = new DefaultConfiguration(
212: ASSERTION_RESULT_TAG_NAME, "JMeter Save Service");
213:
214: config.setAttribute(FAILURE_MESSAGE, assResult
215: .getFailureMessage());
216: config.setAttribute(ERROR, "" + assResult.isError());
217: config.setAttribute(FAILURE, "" + assResult.isFailure());
218: return config;
219: }
220:
221: /**
222: * This method determines the content of the result data that will be
223: * stored for the Avalon XML format.
224: *
225: * @param result
226: * the object containing all of the data that has been collected.
227: * @param saveConfig
228: * the configuration giving the data items to be saved.
229: * N.B. It is rather out of date, as many fields are not saved.
230: * However it is probably not worth updating, as no-one should be using the format.
231: */
232: public static Configuration getConfiguration(SampleResult result,
233: SampleSaveConfiguration saveConfig) {
234: DefaultConfiguration config = new DefaultConfiguration(
235: SAMPLE_RESULT_TAG_NAME, "JMeter Save Service"); // $NON-NLS-1$
236:
237: if (saveConfig.saveTime()) {
238: config.setAttribute(TIME, String.valueOf(result.getTime()));
239: }
240: if (saveConfig.saveLabel()) {
241: config.setAttribute(LABEL, result.getSampleLabel());
242: }
243: if (saveConfig.saveCode()) {
244: config
245: .setAttribute(RESPONSE_CODE, result
246: .getResponseCode());
247: }
248: if (saveConfig.saveMessage()) {
249: config.setAttribute(RESPONSE_MESSAGE, result
250: .getResponseMessage());
251: }
252: if (saveConfig.saveThreadName()) {
253: config.setAttribute(THREAD_NAME, result.getThreadName());
254: }
255: if (saveConfig.saveDataType()) {
256: config.setAttribute(DATA_TYPE, result.getDataType());
257: }
258:
259: if (saveConfig.printMilliseconds()) {
260: config.setAttribute(TIME_STAMP, String.valueOf(result
261: .getTimeStamp()));
262: } else if (saveConfig.formatter() != null) {
263: String stamp = saveConfig.formatter().format(
264: new Date(result.getTimeStamp()));
265:
266: config.setAttribute(TIME_STAMP, stamp);
267: }
268:
269: if (saveConfig.saveSuccess()) {
270: config.setAttribute(SUCCESSFUL, Boolean.toString(result
271: .isSuccessful()));
272: }
273:
274: SampleResult[] subResults = result.getSubResults();
275:
276: if (subResults != null) {
277: for (int i = 0; i < subResults.length; i++) {
278: config.addChild(getConfiguration(subResults[i],
279: saveConfig));
280: }
281: }
282:
283: AssertionResult[] assResults = result.getAssertionResults();
284:
285: if (saveConfig.saveSamplerData(result)) {
286: config.addChild(createConfigForString("samplerData", result
287: .getSamplerData())); // $NON-NLS-1$
288: }
289: if (saveConfig.saveAssertions() && assResults != null) {
290: for (int i = 0; i < assResults.length; i++) {
291: config.addChild(getConfiguration(assResults[i]));
292: }
293: }
294: if (saveConfig.saveResponseData(result)) {
295: config.addChild(getConfiguration(result.getResponseData()));
296: }
297: return config;
298: }
299:
300: private static Configuration getConfigForTestElement(String named,
301: TestElement item) {
302: TestElementSaver saver = new TestElementSaver(named);
303: item.traverse(saver);
304: Configuration config = saver.getConfiguration();
305: /*
306: * DefaultConfiguration config = new DefaultConfiguration("testelement",
307: * "testelement");
308: *
309: * if (named != null) { config.setAttribute("name", named); } if
310: * (item.getProperty(TestElement.TEST_CLASS) != null) {
311: * config.setAttribute("class", (String)
312: * item.getProperty(TestElement.TEST_CLASS)); } else {
313: * config.setAttribute("class", item.getClass().getName()); } Iterator
314: * iter = item.getPropertyNames().iterator();
315: *
316: * while (iter.hasNext()) { String name = (String) iter.next(); Object
317: * value = item.getProperty(name);
318: *
319: * if (value instanceof TestElement) {
320: * config.addChild(getConfigForTestElement(name, (TestElement) value)); }
321: * else if (value instanceof Collection) {
322: * config.addChild(createConfigForCollection(name, (Collection) value)); }
323: * else if (value != null) { config.addChild(createConfigForString(name,
324: * value.toString())); } }
325: */
326: return config;
327: }
328:
329: private static Configuration createConfigForString(String name,
330: String value) {
331: if (value == null) {
332: value = "";
333: }
334: DefaultConfiguration config = new DefaultConfiguration(
335: "property", "property");
336:
337: config.setAttribute("name", name);
338: config.setValue(value);
339: config.setAttribute(XML_SPACE, PRESERVE);
340: return config;
341: }
342:
343: public synchronized static HashTree loadSubTree(InputStream in)
344: throws IOException {
345: try {
346: Configuration config = builder.build(in);
347: HashTree loadedTree = generateNode(config);
348:
349: return loadedTree;
350: } catch (ConfigurationException e) {
351: String message = "Problem loading using Avalon Configuration tools";
352: log.error(message, e);
353: throw new IOException(message);
354: } catch (SAXException e) {
355: String message = "Problem with SAX implementation";
356: log.error(message, e);
357: throw new IOException(message);
358: }
359: }
360:
361: private static TestElement createTestElement(Configuration config)
362: throws ConfigurationException, ClassNotFoundException,
363: IllegalAccessException, InstantiationException {
364: TestElement element = null;
365:
366: String testClass = config.getAttribute("class"); // $NON-NLS-1$
367:
368: String gui_class = ""; // $NON-NLS-1$
369: Configuration[] children = config.getChildren();
370: for (int i = 0; i < children.length; i++) {
371: if (children[i].getName().equals("property")) { // $NON-NLS-1$
372: if (children[i].getAttribute("name").equals(
373: TestElement.GUI_CLASS)) { // $NON-NLS-1$
374: gui_class = children[i].getValue();
375: }
376: }
377: }
378:
379: String newClass = NameUpdater.getCurrentTestName(testClass,
380: gui_class);
381:
382: element = (TestElement) Class.forName(newClass).newInstance();
383:
384: for (int i = 0; i < children.length; i++) {
385: if (children[i].getName().equals("property")) { // $NON-NLS-1$
386: try {
387: JMeterProperty prop = createProperty(children[i],
388: newClass);
389: if (prop != null)
390: element.setProperty(prop);
391: } catch (Exception ex) {
392: log.error("Problem loading property", ex);
393: element.setProperty(children[i]
394: .getAttribute("name"), ""); // $NON-NLS-1$ // $NON-NLS-2$
395: }
396: } else if (children[i].getName().equals("testelement")) { // $NON-NLS-1$
397: element.setProperty(new TestElementProperty(children[i]
398: .getAttribute("name", ""), // $NON-NLS-1$ // $NON-NLS-2$
399: createTestElement(children[i])));
400: } else if (children[i].getName().equals("collection")) { // $NON-NLS-1$
401: element.setProperty(new CollectionProperty(children[i]
402: .getAttribute("name", ""), // $NON-NLS-1$ // $NON-NLS-2$
403: createCollection(children[i], newClass)));
404: } else if (children[i].getName().equals("map")) { // $NON-NLS-1$
405: element.setProperty(new MapProperty(children[i]
406: .getAttribute("name", ""), // $NON-NLS-1$ // $NON-NLS-2$
407: createMap(children[i], newClass)));
408: }
409: }
410: return element;
411: }
412:
413: private static Collection createCollection(Configuration config,
414: String testClass) throws ConfigurationException,
415: ClassNotFoundException, IllegalAccessException,
416: InstantiationException {
417: Collection coll = (Collection) Class.forName(
418: config.getAttribute("class")).newInstance(); // $NON-NLS-1$
419: Configuration[] items = config.getChildren();
420:
421: for (int i = 0; i < items.length; i++) {
422: if (items[i].getName().equals("property")) { // $NON-NLS-1$
423: JMeterProperty prop = createProperty(items[i],
424: testClass);
425: if (prop != null)
426: coll.add(prop);
427: } else if (items[i].getName().equals("testelement")) { // $NON-NLS-1$
428: coll.add(new TestElementProperty(items[i].getAttribute(
429: "name", ""), createTestElement(items[i]))); // $NON-NLS-1$ // $NON-NLS-2$
430: } else if (items[i].getName().equals("collection")) { // $NON-NLS-1$
431: coll.add(new CollectionProperty(items[i].getAttribute(
432: "name", ""), // $NON-NLS-1$ // $NON-NLS-2$
433: createCollection(items[i], testClass)));
434: } else if (items[i].getName().equals("string")) { // $NON-NLS-1$
435: JMeterProperty prop = createProperty(items[i],
436: testClass);
437: if (prop != null)
438: coll.add(prop);
439: } else if (items[i].getName().equals("map")) { // $NON-NLS-1$
440: coll.add(new MapProperty(items[i].getAttribute("name",
441: ""), createMap(items[i], testClass))); // $NON-NLS-1$ // $NON-NLS-2$
442: }
443: }
444: return coll;
445: }
446:
447: private static JMeterProperty createProperty(Configuration config,
448: String testClass) throws IllegalAccessException,
449: ClassNotFoundException, InstantiationException {
450: String value = config.getValue(""); // $NON-NLS-1$
451: String name = config.getAttribute("name", value); // $NON-NLS-1$
452: String oname = name;
453: String type = config.getAttribute("propType",
454: StringProperty.class.getName()); // $NON-NLS-1$
455:
456: // Do upgrade translation:
457: name = NameUpdater.getCurrentName(name, testClass);
458: if (TestElement.GUI_CLASS.equals(name)) {
459: value = NameUpdater.getCurrentName(value);
460: } else if (TestElement.TEST_CLASS.equals(name)) {
461: value = testClass; // must always agree
462: } else {
463: value = NameUpdater.getCurrentName(value, name, testClass);
464: }
465:
466: // Delete any properties whose name converts to the empty string
467: if (oname.length() != 0 && name.length() == 0) {
468: return null;
469: }
470:
471: // Create the property:
472: JMeterProperty prop = (JMeterProperty) Class.forName(type)
473: .newInstance();
474: prop.setName(name);
475: prop.setObjectValue(value);
476:
477: return prop;
478: }
479:
480: private static Map createMap(Configuration config, String testClass)
481: throws ConfigurationException, ClassNotFoundException,
482: IllegalAccessException, InstantiationException {
483: Map map = (Map) Class.forName(config.getAttribute("class"))
484: .newInstance();
485: Configuration[] items = config.getChildren();
486:
487: for (int i = 0; i < items.length; i++) {
488: if (items[i].getName().equals("property")) { // $NON-NLS-1$
489: JMeterProperty prop = createProperty(items[i],
490: testClass);
491: if (prop != null)
492: map.put(prop.getName(), prop);
493: } else if (items[i].getName().equals("testelement")) { // $NON-NLS-1$
494: map.put(items[i].getAttribute("name", ""),
495: new TestElementProperty(items[i].getAttribute(
496: "name", ""), // $NON-NLS-1$ // $NON-NLS-2$
497: createTestElement(items[i])));
498: } else if (items[i].getName().equals("collection")) { // $NON-NLS-1$
499: map.put(items[i].getAttribute("name"), // $NON-NLS-1$
500: new CollectionProperty(items[i].getAttribute(
501: "name", ""), // $NON-NLS-1$ // $NON-NLS-2$
502: createCollection(items[i], testClass)));
503: } else if (items[i].getName().equals("map")) { // $NON-NLS-1$
504: map.put(items[i].getAttribute("name", ""), // $NON-NLS-1$ // $NON-NLS-2$
505: new MapProperty(items[i].getAttribute("name",
506: ""), // $NON-NLS-1$ // $NON-NLS-2$
507: createMap(items[i], testClass)));
508: }
509: }
510: return map;
511: }
512:
513: private static HashTree generateNode(Configuration config) {
514: TestElement element = null;
515:
516: try {
517: element = createTestElement(config.getChild("testelement")); // $NON-NLS-1$
518: } catch (Exception e) {
519: log.error("Problem loading part of file", e);
520: return null;
521: }
522: HashTree subTree = new ListedHashTree(element);
523: Configuration[] subNodes = config.getChildren("node"); // $NON-NLS-1$
524:
525: for (int i = 0; i < subNodes.length; i++) {
526: HashTree t = generateNode(subNodes[i]);
527:
528: if (t != null) {
529: subTree.add(element, t);
530: }
531: }
532: return subTree;
533: }
534:
535: // Called by ResultCollector#loadExistingFile()
536: public static void processSamples(String filename,
537: Visualizer visualizer, ResultCollector rc)
538: throws SAXException, IOException, ConfigurationException {
539: DefaultConfigurationBuilder cfgbuilder = new DefaultConfigurationBuilder();
540: Configuration savedSamples = cfgbuilder.buildFromFile(filename);
541: Configuration[] samples = savedSamples.getChildren();
542: for (int i = 0; i < samples.length; i++) {
543: SampleResult result = OldSaveService
544: .getSampleResult(samples[i]);
545: if (rc.isSampleWanted(result.isSuccessful())) {
546: visualizer.add(result);
547: }
548: }
549: }
550:
551: // Called by ResultCollector#recordResult()
552: public static String getSerializedSampleResult(SampleResult result,
553: DefaultConfigurationSerializer slzr,
554: SampleSaveConfiguration cfg) throws SAXException,
555: IOException, ConfigurationException {
556: ByteArrayOutputStream tempOut = new ByteArrayOutputStream();
557:
558: slzr.serialize(tempOut, OldSaveService.getConfiguration(result,
559: cfg));
560: String serVer = tempOut.toString();
561: String lineSep = System.getProperty("line.separator"); // $NON-NLS-1$
562: /*
563: * Remove the <?xml ... ?> prefix.
564: * When using the x-jars (xakan etc) or Java 1.4, the serialised output has a
565: * newline after the prefix. However, when using Java 1.5 without the x-jars, the output
566: * has no newline at all.
567: */
568: int index = serVer.indexOf(lineSep); // Is there a new-line?
569: if (index > -1) {// Yes, assume it follows the prefix
570: return serVer.substring(index);
571: }
572: if (serVer.startsWith("<?xml")) { // $NON-NLS-1$
573: index = serVer.indexOf("?>");// must exist // $NON-NLS-1$
574: return lineSep + serVer.substring(index + 2);// +2 for ?>
575: }
576: return serVer;
577: }
578: }
|