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: package org.apache.jmeter.testelement;
019:
020: import java.io.File;
021: import java.io.Serializable;
022: import java.util.ArrayList;
023: import java.util.Calendar;
024: import java.util.Date;
025: import java.util.HashMap;
026: import java.util.Iterator;
027: import java.util.List;
028: import java.util.Set;
029:
030: import org.apache.jmeter.report.DataSet;
031: import org.apache.jmeter.reporters.ResultCollector;
032: import org.apache.jmeter.samplers.SampleResult;
033: import org.apache.jmeter.visualizers.SamplingStatCalculator;
034:
035: /**
036: * @author Peter Lin
037: *
038: * The purpose of TableData is to contain the results of a single .jtl file.
039: * It is equivalent to what the AggregateListener table. A HashMap is used
040: * to store the data. The URL is the key and the value is SamplingStatCalculator
041: */
042: public class JTLData implements Serializable, DataSet {
043:
044: protected HashMap data = new HashMap();
045: protected String jtl_file = null;
046: protected long startTimestamp = 0;
047: protected long endTimestamp = 0;
048: protected File inputFile = null;
049:
050: /**
051: *
052: */
053: public JTLData() {
054: super ();
055: }
056:
057: /**
058: * Return a Set of the URL's
059: * @return
060: */
061: public Set getURLs() {
062: return this .data.keySet();
063: }
064:
065: /**
066: * Return a Set of the values
067: * @return
068: */
069: public Set getStats() {
070: return this .data.entrySet();
071: }
072:
073: /**
074: * The purpose of the method is to make it convienant to pass a list
075: * of the URL's and return a list of the SamplingStatCalculators. If
076: * no URL's match, the list is empty.
077: * The SamplingStatCalculators will be returned in the same sequence
078: * as the url list.
079: * @param urls
080: * @return
081: */
082: public List getStats(List urls) {
083: ArrayList items = new ArrayList();
084: Iterator itr = urls.iterator();
085: if (itr.hasNext()) {
086: SamplingStatCalculator row = (SamplingStatCalculator) itr
087: .next();
088: if (row != null) {
089: items.add(row);
090: }
091: }
092: return items;
093: }
094:
095: public void setDataSource(String absolutePath) {
096: this .jtl_file = absolutePath;
097: }
098:
099: public String getDataSource() {
100: return this .jtl_file;
101: }
102:
103: public String getDataSourceName() {
104: if (inputFile == null) {
105: inputFile = new File(getDataSource());
106: }
107: return inputFile.getName().substring(0,
108: inputFile.getName().length() - 4);
109: }
110:
111: public void setStartTimestamp(long stamp) {
112: this .startTimestamp = stamp;
113: }
114:
115: public long getStartTimestamp() {
116: return this .startTimestamp;
117: }
118:
119: public void setEndTimestamp(long stamp) {
120: this .endTimestamp = stamp;
121: }
122:
123: public long getEndTimestamp() {
124: return this .endTimestamp;
125: }
126:
127: /**
128: * The date we use for the result is the start timestamp. The
129: * reasoning is that a test may run for a long time, but it
130: * is most likely scheduled to run using CRON on unix or
131: * scheduled task in windows.
132: * @return
133: */
134: public Date getDate() {
135: return new Date(this .startTimestamp);
136: }
137:
138: public String getMonthDayDate() {
139: Calendar cal = Calendar.getInstance();
140: cal.setTimeInMillis(this .startTimestamp);
141: return String.valueOf(cal.get(Calendar.MONTH)) + " - "
142: + String.valueOf(cal.get(Calendar.DAY_OF_MONTH));
143: }
144:
145: public String getMonthDayYearDate() {
146: Calendar cal = Calendar.getInstance();
147: cal.setTimeInMillis(this .startTimestamp);
148: return String.valueOf(cal.get(Calendar.MONTH)) + " - "
149: + String.valueOf(cal.get(Calendar.DAY_OF_MONTH))
150: + " - " + String.valueOf(cal.get(Calendar.YEAR));
151: }
152:
153: /**
154: * The method will SamplingStatCalculator for the given URL. If the URL
155: * doesn't exist, the method returns null.
156: * @param url
157: * @return
158: */
159: public SamplingStatCalculator getStatistics(String url) {
160: if (this .data.containsKey(url)) {
161: return (SamplingStatCalculator) this .data.get(url);
162: } else {
163: return null;
164: }
165: }
166:
167: /**
168: * The implementation loads a single .jtl file and cleans up the
169: * ResultCollector.
170: */
171: public void loadData() {
172: if (this .getDataSource() != null) {
173: ResultCollector rc = new ResultCollector();
174: rc.setFilename(this .getDataSource());
175: rc.setListener(this );
176: rc.loadExistingFile();
177: // we clean up the ResultCollector to make sure there's
178: // no slow leaks
179: rc.clear();
180: rc.setListener(null);
181: rc = null;
182: }
183: }
184:
185: /**
186: * the implementation will set the start timestamp if the HashMap
187: * is empty. otherwise it will set the end timestamp using the
188: * end time
189: */
190: public void add(SampleResult sample) {
191: if (data.size() == 0) {
192: this .startTimestamp = sample.getStartTime();
193: } else {
194: this .endTimestamp = sample.getEndTime();
195: }
196: // now add the samples to the HashMap
197: String url = sample.getSampleLabel();
198: if (url == null) {
199: url = sample.getURL().toString();
200: }
201: SamplingStatCalculator row = (SamplingStatCalculator) data
202: .get(url);
203: if (row == null) {
204: row = new SamplingStatCalculator();
205: // just like the aggregate listener, we use the sample label to represent
206: // a row. in this case, we use it as a key.
207: this .data.put(url, row);
208: }
209: row.addSample(sample);
210: }
211:
212: /**
213: * By default, the method always returns true. Subclasses can over
214: * ride the implementation.
215: */
216: public boolean isStats() {
217: return true;
218: }
219: }
|