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.reporters;
020:
021: import java.io.File;
022: import java.io.FileNotFoundException;
023: import java.io.FileOutputStream;
024: import java.io.IOException;
025: import java.io.Serializable;
026:
027: import org.apache.jmeter.samplers.Clearable;
028: import org.apache.jmeter.samplers.SampleEvent;
029: import org.apache.jmeter.samplers.SampleListener;
030: import org.apache.jmeter.samplers.SampleResult;
031: import org.apache.jmeter.testelement.AbstractTestElement;
032: import org.apache.jorphan.logging.LoggingManager;
033: import org.apache.jorphan.util.JOrphanUtils;
034: import org.apache.log.Logger;
035:
036: /**
037: * Save Result responseData to a set of files TODO - perhaps save other items
038: * such as headers?
039: *
040: * This is mainly intended for validation tests
041: *
042: */
043: public class ResultSaver extends AbstractTestElement implements
044: Serializable, SampleListener, Clearable {
045: private static final Logger log = LoggingManager
046: .getLoggerForClass();
047:
048: // File name sequence number
049: private static long sequenceNumber = 0;
050:
051: public static final String FILENAME = "FileSaver.filename"; // $NON-NLS-1$
052:
053: public static final String ERRORS_ONLY = "FileSaver.errorsonly"; // $NON-NLS-1$
054:
055: private static synchronized long nextNumber() {
056: return ++sequenceNumber;
057: }
058:
059: /*
060: * Constructor is initially called once for each occurrence in the test plan
061: * For GUI, several more instances are created Then clear is called at start
062: * of test Called several times during test startup The name will not
063: * necessarily have been set at this point.
064: */
065: public ResultSaver() {
066: super ();
067: // log.debug(Thread.currentThread().getName());
068: // System.out.println(">> "+me+" "+this.getName()+"
069: // "+Thread.currentThread().getName());
070: }
071:
072: /*
073: * Constructor for use during startup (intended for non-GUI use) @param name
074: * of summariser
075: */
076: public ResultSaver(String name) {
077: this ();
078: setName(name);
079: }
080:
081: /*
082: * This is called once for each occurrence in the test plan, before the
083: * start of the test. The super.clear() method clears the name (and all
084: * other properties), so it is called last.
085: */
086: // TODO: is this clearData, clearGui or TestElement.clear() ?
087: public void clear() {
088: // System.out.println("-- "+me+this.getName()+"
089: // "+Thread.currentThread().getName());
090: super .clear();
091: sequenceNumber = 0; // TODO is this the right thing to do?
092: }
093:
094: // TODO - is this the same as the above?
095: public void clearData() {
096: }
097:
098: /**
099: * Saves the sample result (and any sub results) in files
100: *
101: * @see org.apache.jmeter.samplers.SampleListener#sampleOccurred(org.apache.jmeter.samplers.SampleEvent)
102: */
103: public void sampleOccurred(SampleEvent e) {
104: processSample(e.getResult());
105: }
106:
107: /**
108: * Recurse the whole (sub)result hierarchy.
109: *
110: * @param s Sample result
111: */
112: private void processSample(SampleResult s) {
113: saveSample(s);
114: SampleResult[] sr = s.getSubResults();
115: for (int i = 0; i < sr.length; i++) {
116: processSample(sr[i]);
117: }
118: }
119:
120: /**
121: * @param s
122: * SampleResult to save
123: */
124: private void saveSample(SampleResult s) {
125: // Should we save successful samples?
126: if (s.isSuccessful() && getErrorsOnly())
127: return;
128:
129: nextNumber();
130: String fileName = makeFileName(s.getContentType());
131: log.debug("Saving " + s.getSampleLabel() + " in " + fileName);
132: s.setResultFileName(fileName);// Associate sample with file name
133: File out = new File(fileName);
134: FileOutputStream pw = null;
135: try {
136: pw = new FileOutputStream(out);
137: pw.write(s.getResponseData());
138: } catch (FileNotFoundException e1) {
139: log.error("Error creating sample file for "
140: + s.getSampleLabel(), e1);
141: } catch (IOException e1) {
142: log.error("Error saving sample " + s.getSampleLabel(), e1);
143: } finally {
144: JOrphanUtils.closeQuietly(pw);
145: }
146: }
147:
148: /**
149: * @return fileName composed of fixed prefix, a number, and a suffix derived
150: * from the contentType e.g. Content-Type:
151: * text/html;charset=ISO-8859-1
152: */
153: private String makeFileName(String contentType) {
154: String suffix = "unknown";
155: if (contentType != null) {
156: int i = contentType.indexOf("/");
157: if (i != -1) {
158: int j = contentType.indexOf(";");
159: if (j != -1) {
160: suffix = contentType.substring(i + 1, j);
161: } else {
162: suffix = contentType.substring(i + 1);
163: }
164: }
165: }
166: return getFilename() + sequenceNumber + "." + suffix;
167: }
168:
169: /*
170: * (non-Javadoc)
171: *
172: * @see org.apache.jmeter.samplers.SampleListener#sampleStarted(org.apache.jmeter.samplers.SampleEvent)
173: */
174: public void sampleStarted(SampleEvent e) {
175: // not used
176: }
177:
178: /*
179: * (non-Javadoc)
180: *
181: * @see org.apache.jmeter.samplers.SampleListener#sampleStopped(org.apache.jmeter.samplers.SampleEvent)
182: */
183: public void sampleStopped(SampleEvent e) {
184: // not used
185: }
186:
187: private String getFilename() {
188: return getPropertyAsString(FILENAME);
189: }
190:
191: private boolean getErrorsOnly() {
192: return getPropertyAsBoolean(ERRORS_ONLY);
193: }
194:
195: }
|