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.converters;
020:
021: import java.io.ByteArrayOutputStream;
022: import java.io.File;
023: import java.io.FileInputStream;
024: import java.io.FileNotFoundException;
025: import java.io.IOException;
026: import java.io.UnsupportedEncodingException;
027: import java.net.URL;
028:
029: import org.apache.jmeter.assertions.AssertionResult;
030: import org.apache.jmeter.samplers.SampleEvent;
031: import org.apache.jmeter.samplers.SampleResult;
032: import org.apache.jmeter.samplers.SampleSaveConfiguration;
033: import org.apache.jmeter.save.SaveService;
034: import org.apache.jorphan.util.Converter;
035: import com.thoughtworks.xstream.mapper.Mapper;
036: import com.thoughtworks.xstream.converters.MarshallingContext;
037: import com.thoughtworks.xstream.converters.UnmarshallingContext;
038: import com.thoughtworks.xstream.converters.collections.AbstractCollectionConverter;
039: import com.thoughtworks.xstream.io.HierarchicalStreamReader;
040: import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
041:
042: /**
043: * XStream Converter for the SampleResult class
044: */
045: public class SampleResultConverter extends AbstractCollectionConverter {
046: //private static final Logger log = LoggingManager.getLoggerForClass();
047:
048: private static final String JAVA_LANG_STRING = "java.lang.String"; //$NON-NLS-1$
049: private static final String ATT_CLASS = "class"; //$NON-NLS-1$
050:
051: // Element tags. Must be unique. Keep sorted.
052: protected static final String TAG_COOKIES = "cookies"; //$NON-NLS-1$
053: protected static final String TAG_METHOD = "method"; //$NON-NLS-1$
054: protected static final String TAG_QUERY_STRING = "queryString"; //$NON-NLS-1$
055: protected static final String TAG_REDIRECT_LOCATION = "redirectLocation"; //$NON-NLS-1$
056: protected static final String TAG_REQUEST_HEADER = "requestHeader"; //$NON-NLS-1$
057:
058: //NOT USED protected static final String TAG_URL = "requestUrl"; //$NON-NLS-1$
059:
060: protected static final String TAG_RESPONSE_DATA = "responseData"; //$NON-NLS-1$
061: protected static final String TAG_RESPONSE_HEADER = "responseHeader"; //$NON-NLS-1$
062: protected static final String TAG_SAMPLER_DATA = "samplerData"; //$NON-NLS-1$
063: protected static final String TAG_RESPONSE_FILE = "responseFile"; //$NON-NLS-1$
064:
065: // samplerData attributes. Must be unique. Keep sorted by string value.
066: // Ensure the Listener documentation is updated when new attributes are added
067: private static final String ATT_BYTES = "by"; //$NON-NLS-1$
068: private static final String ATT_DATA_ENCODING = "de"; //$NON-NLS-1$
069: private static final String ATT_DATA_TYPE = "dt"; //$NON-NLS-1$
070: private static final String ATT_ERROR_COUNT = "ec"; //$NON-NLS-1$
071: private static final String ATT_HOSTNAME = "hn"; //$NON-NLS-1$
072: private static final String ATT_LABEL = "lb"; //$NON-NLS-1$
073: private static final String ATT_LATENCY = "lt"; //$NON-NLS-1$
074:
075: private static final String ATT_ALL_THRDS = "na"; //$NON-NLS-1$
076: private static final String ATT_GRP_THRDS = "ng"; //$NON-NLS-1$
077:
078: // N.B. Originally the response code was saved with the code "rs"
079: // but retrieved with the code "rc". Changed to always use "rc", but
080: // allow for "rs" when restoring values.
081: private static final String ATT_RESPONSE_CODE = "rc"; //$NON-NLS-1$
082: private static final String ATT_RESPONSE_MESSAGE = "rm"; //$NON-NLS-1$
083: private static final String ATT_RESPONSE_CODE_OLD = "rs"; //$NON-NLS-1$
084:
085: private static final String ATT_SUCCESS = "s"; //$NON-NLS-1$
086: private static final String ATT_SAMPLE_COUNT = "sc"; //$NON-NLS-1$
087: private static final String ATT_TIME = "t"; //$NON-NLS-1$
088: private static final String ATT_THREADNAME = "tn"; //$NON-NLS-1$
089: private static final String ATT_TIME_STAMP = "ts"; //$NON-NLS-1$
090:
091: /**
092: * Returns the converter version; used to check for possible
093: * incompatibilities
094: */
095: public static String getVersion() {
096: return "$Revision: 595166 $"; //$NON-NLS-1$
097: }
098:
099: /*
100: * (non-Javadoc)
101: *
102: * @see com.thoughtworks.xstream.converters.Converter#canConvert(java.lang.Class)
103: */
104: public boolean canConvert(Class arg0) {
105: return SampleResult.class.equals(arg0);
106: }
107:
108: /*
109: * (non-Javadoc)
110: *
111: * @see com.thoughtworks.xstream.converters.Converter#marshal(java.lang.Object,
112: * com.thoughtworks.xstream.io.HierarchicalStreamWriter,
113: * com.thoughtworks.xstream.converters.MarshallingContext)
114: */
115: public void marshal(Object obj, HierarchicalStreamWriter writer,
116: MarshallingContext context) {
117: SampleResult res = (SampleResult) obj;
118: SampleSaveConfiguration save = res.getSaveConfig();
119: setAttributes(writer, context, res, save);
120: saveAssertions(writer, context, res, save);
121: saveSubResults(writer, context, res, save);
122: saveResponseHeaders(writer, context, res, save);
123: saveRequestHeaders(writer, context, res, save);
124: saveResponseData(writer, context, res, save);
125: saveSamplerData(writer, context, res, save);
126: }
127:
128: /**
129: * @param writer
130: * @param res
131: * @param save
132: */
133: protected void saveSamplerData(HierarchicalStreamWriter writer,
134: MarshallingContext context, SampleResult res,
135: SampleSaveConfiguration save) {
136: if (save.saveSamplerData(res)) {
137: writeString(writer, TAG_SAMPLER_DATA, res.getSamplerData());
138: }
139: if (save.saveUrl()) {
140: final URL url = res.getURL();
141: if (url != null) {
142: writeItem(url, context, writer);
143: }
144: }
145: }
146:
147: /**
148: * @param writer
149: * @param res
150: * @param save
151: */
152: protected void saveResponseData(HierarchicalStreamWriter writer,
153: MarshallingContext context, SampleResult res,
154: SampleSaveConfiguration save) {
155: if (save.saveResponseData(res)) {
156: writer.startNode(TAG_RESPONSE_DATA);
157: writer.addAttribute(ATT_CLASS, JAVA_LANG_STRING);
158: try {
159: if (SampleResult.TEXT.equals(res.getDataType())) {
160: writer.setValue(new String(res.getResponseData(),
161: res.getDataEncodingWithDefault()));
162: }
163: // Otherwise don't save anything - no point
164: } catch (UnsupportedEncodingException e) {
165: writer
166: .setValue("Unsupported encoding in response data, can't record.");
167: }
168: writer.endNode();
169: }
170: if (save.saveFileName()) {
171: writer.startNode(TAG_RESPONSE_FILE);
172: writer.addAttribute(ATT_CLASS, JAVA_LANG_STRING);
173: writer.setValue(res.getResultFileName());
174: writer.endNode();
175: }
176: }
177:
178: /**
179: * @param writer
180: * @param res
181: * @param save
182: */
183: protected void saveRequestHeaders(HierarchicalStreamWriter writer,
184: MarshallingContext context, SampleResult res,
185: SampleSaveConfiguration save) {
186: if (save.saveRequestHeaders()) {
187: writeString(writer, TAG_REQUEST_HEADER, res
188: .getRequestHeaders());
189: }
190: }
191:
192: /**
193: * @param writer
194: * @param res
195: * @param save
196: */
197: protected void saveResponseHeaders(HierarchicalStreamWriter writer,
198: MarshallingContext context, SampleResult res,
199: SampleSaveConfiguration save) {
200: if (save.saveResponseHeaders()) {
201: writeString(writer, TAG_RESPONSE_HEADER, res
202: .getResponseHeaders());
203: }
204: }
205:
206: /**
207: * @param writer
208: * @param context
209: * @param res
210: * @param save
211: */
212: protected void saveSubResults(HierarchicalStreamWriter writer,
213: MarshallingContext context, SampleResult res,
214: SampleSaveConfiguration save) {
215: if (save.saveSubresults()) {
216: SampleResult[] subResults = res.getSubResults();
217: for (int i = 0; i < subResults.length; i++) {
218: subResults[i].setSaveConfig(save);
219: writeItem(subResults[i], context, writer);
220: }
221: }
222: }
223:
224: /**
225: * @param writer
226: * @param context
227: * @param res
228: * @param save
229: */
230: protected void saveAssertions(HierarchicalStreamWriter writer,
231: MarshallingContext context, SampleResult res,
232: SampleSaveConfiguration save) {
233: if (save.saveAssertions()) {
234: AssertionResult[] assertionResults = res
235: .getAssertionResults();
236: for (int i = 0; i < assertionResults.length; i++) {
237: writeItem(assertionResults[i], context, writer);
238: }
239: }
240: }
241:
242: /**
243: * @param writer
244: * @param res
245: * @param save
246: */
247: protected void setAttributes(HierarchicalStreamWriter writer,
248: MarshallingContext context, SampleResult res,
249: SampleSaveConfiguration save) {
250: if (save.saveTime())
251: writer.addAttribute(ATT_TIME, Long.toString(res.getTime()));
252: if (save.saveLatency())
253: writer.addAttribute(ATT_LATENCY, Long.toString(res
254: .getLatency()));
255: if (save.saveTimestamp())
256: writer.addAttribute(ATT_TIME_STAMP, Long.toString(res
257: .getTimeStamp()));
258: if (save.saveSuccess())
259: writer.addAttribute(ATT_SUCCESS, Boolean.toString(res
260: .isSuccessful()));
261: if (save.saveLabel())
262: writer.addAttribute(ATT_LABEL, ConversionHelp.encode(res
263: .getSampleLabel()));
264: if (save.saveCode())
265: writer.addAttribute(ATT_RESPONSE_CODE, ConversionHelp
266: .encode(res.getResponseCode()));
267: if (save.saveMessage())
268: writer.addAttribute(ATT_RESPONSE_MESSAGE, ConversionHelp
269: .encode(res.getResponseMessage()));
270: if (save.saveThreadName())
271: writer.addAttribute(ATT_THREADNAME, ConversionHelp
272: .encode(res.getThreadName()));
273: if (save.saveDataType())
274: writer.addAttribute(ATT_DATA_TYPE, ConversionHelp
275: .encode(res.getDataType()));
276: if (save.saveEncoding())
277: writer.addAttribute(ATT_DATA_ENCODING, ConversionHelp
278: .encode(res.getDataEncodingNoDefault()));
279: if (save.saveBytes())
280: writer.addAttribute(ATT_BYTES, String.valueOf(res
281: .getBytes()));
282: if (save.saveSampleCount()) {
283: writer.addAttribute(ATT_SAMPLE_COUNT, String.valueOf(res
284: .getSampleCount()));
285: writer.addAttribute(ATT_ERROR_COUNT, String.valueOf(res
286: .getErrorCount()));
287: }
288: if (save.saveThreadCounts()) {
289: writer.addAttribute(ATT_GRP_THRDS, String.valueOf(res
290: .getGroupThreads()));
291: writer.addAttribute(ATT_ALL_THRDS, String.valueOf(res
292: .getAllThreads()));
293: }
294: if (save.saveHostname()) {
295: SampleEvent event = (SampleEvent) context
296: .get(SaveService.SAMPLE_EVENT_OBJECT);
297: if (event != null) {
298: writer.addAttribute(ATT_HOSTNAME, event.getHostname());
299: }
300: }
301: }
302:
303: /**
304: * @param writer
305: * @param tag
306: * @param value
307: */
308: protected void writeString(HierarchicalStreamWriter writer,
309: String tag, String value) {
310: if (value != null) {
311: writer.startNode(tag);
312: writer.addAttribute(ATT_CLASS, JAVA_LANG_STRING);
313: writer.setValue(value);
314: writer.endNode();
315: }
316: }
317:
318: /*
319: * (non-Javadoc)
320: *
321: * @see com.thoughtworks.xstream.converters.Converter#unmarshal(com.thoughtworks.xstream.io.HierarchicalStreamReader,
322: * com.thoughtworks.xstream.converters.UnmarshallingContext)
323: */
324: public Object unmarshal(HierarchicalStreamReader reader,
325: UnmarshallingContext context) {
326: SampleResult res = (SampleResult) createCollection(context
327: .getRequiredType());
328: retrieveAttributes(reader, context, res);
329: while (reader.hasMoreChildren()) {
330: reader.moveDown();
331: Object subItem = readItem(reader, context, res);
332: retrieveItem(reader, context, res, subItem);
333: reader.moveUp();
334: }
335:
336: // If we have a file, but no data, then read the file
337: String resultFileName = res.getResultFileName();
338: if (resultFileName.length() > 0
339: && res.getResponseData().length == 0) {
340: readFile(resultFileName, res);
341: }
342: return res;
343: }
344:
345: /**
346: *
347: * @param reader
348: * @param context
349: * @param res
350: * @return true if the item was processed (for HTTPResultConverter)
351: */
352: protected boolean retrieveItem(HierarchicalStreamReader reader,
353: UnmarshallingContext context, SampleResult res,
354: Object subItem) {
355: String nodeName = reader.getNodeName();
356: if (subItem instanceof AssertionResult) {
357: res.addAssertionResult((AssertionResult) subItem);
358: } else if (subItem instanceof SampleResult) {
359: res.storeSubResult((SampleResult) subItem);
360: } else if (nodeName.equals(TAG_RESPONSE_HEADER)) {
361: res.setResponseHeaders((String) subItem);
362: } else if (nodeName.equals(TAG_REQUEST_HEADER)) {
363: res.setRequestHeaders((String) subItem);
364: } else if (nodeName.equals(TAG_RESPONSE_DATA)) {
365: final String responseData = (String) subItem;
366: if (responseData.length() > 0) {
367: final String dataEncoding = res
368: .getDataEncodingWithDefault();
369: try {
370: res.setResponseData(responseData
371: .getBytes(dataEncoding));
372: } catch (UnsupportedEncodingException e) {
373: res
374: .setResponseData(("Can't support the char set: " + dataEncoding)
375: .getBytes());
376: res.setDataType(SampleResult.TEXT);
377: }
378: }
379: } else if (nodeName.equals(TAG_SAMPLER_DATA)) {
380: res.setSamplerData((String) subItem);
381: } else if (nodeName.equals(TAG_RESPONSE_FILE)) {
382: res.setResultFileName((String) subItem);
383: // Don't try restoring the URL TODO: wy not?
384: } else {
385: return false;
386: }
387: return true;
388: }
389:
390: /**
391: * @param reader
392: * @param res
393: */
394: protected void retrieveAttributes(HierarchicalStreamReader reader,
395: UnmarshallingContext context, SampleResult res) {
396: res.setSampleLabel(ConversionHelp.decode(reader
397: .getAttribute(ATT_LABEL)));
398: res.setDataEncoding(ConversionHelp.decode(reader
399: .getAttribute(ATT_DATA_ENCODING)));
400: res.setDataType(ConversionHelp.decode(reader
401: .getAttribute(ATT_DATA_TYPE)));
402: String oldrc = reader.getAttribute(ATT_RESPONSE_CODE_OLD);
403: if (oldrc != null) {
404: res.setResponseCode(ConversionHelp.decode(oldrc));
405: } else {
406: res.setResponseCode(ConversionHelp.decode(reader
407: .getAttribute(ATT_RESPONSE_CODE)));
408: }
409: res.setResponseMessage(ConversionHelp.decode(reader
410: .getAttribute(ATT_RESPONSE_MESSAGE)));
411: res.setSuccessful(Converter.getBoolean(reader
412: .getAttribute(ATT_SUCCESS), true));
413: res.setThreadName(ConversionHelp.decode(reader
414: .getAttribute(ATT_THREADNAME)));
415: res.setStampAndTime(Converter.getLong(reader
416: .getAttribute(ATT_TIME_STAMP)), Converter
417: .getLong(reader.getAttribute(ATT_TIME)));
418: res.setLatency(Converter.getLong(reader
419: .getAttribute(ATT_LATENCY)));
420: res.setBytes(Converter.getInt(reader.getAttribute(ATT_BYTES)));
421: res.setSampleCount(Converter.getInt(reader
422: .getAttribute(ATT_SAMPLE_COUNT), 1)); // default is 1
423: res.setErrorCount(Converter.getInt(reader
424: .getAttribute(ATT_ERROR_COUNT), 0)); // default is 0
425: res.setGroupThreads(Converter.getInt(reader
426: .getAttribute(ATT_GRP_THRDS)));
427: res.setAllThreads(Converter.getInt(reader
428: .getAttribute(ATT_ALL_THRDS)));
429: }
430:
431: protected void readFile(String resultFileName, SampleResult res) {
432: File in = null;
433: FileInputStream fis = null;
434: try {
435: in = new File(resultFileName);
436: fis = new FileInputStream(in);
437: ByteArrayOutputStream outstream = new ByteArrayOutputStream(
438: res.getBytes());
439: byte[] buffer = new byte[4096];
440: int len;
441: while ((len = fis.read(buffer)) > 0) {
442: outstream.write(buffer, 0, len);
443: }
444: outstream.close();
445: res.setResponseData(outstream.toByteArray());
446: } catch (FileNotFoundException e) {
447: //log.warn(e.getLocalizedMessage());
448: } catch (IOException e) {
449: //log.warn(e.getLocalizedMessage());
450: } finally {
451: try {
452: if (fis != null)
453: fis.close();
454: } catch (IOException e) {
455: }
456: }
457: }
458:
459: /**
460: * @param arg0
461: */
462: public SampleResultConverter(Mapper arg0) {
463: super(arg0);
464: }
465: }
|