001: /*
002: * soapUI, copyright (C) 2004-2007 eviware.com
003: *
004: * soapUI is free software; you can redistribute it and/or modify it under the
005: * terms of version 2.1 of the GNU Lesser General Public License as published by
006: * the Free Software Foundation.
007: *
008: * soapUI is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
009: * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
010: * See the GNU Lesser General Public License for more details at gnu.org.
011: */
012:
013: package com.eviware.soapui.impl.wsdl.loadtest.data;
014:
015: import java.util.ArrayList;
016: import java.util.EnumMap;
017: import java.util.HashMap;
018: import java.util.List;
019: import java.util.Map;
020:
021: import javax.swing.event.TableModelEvent;
022: import javax.swing.event.TableModelListener;
023: import javax.swing.table.AbstractTableModel;
024:
025: import org.apache.log4j.Logger;
026:
027: import com.eviware.soapui.SoapUI;
028: import com.eviware.soapui.impl.wsdl.loadtest.WsdlLoadTest;
029: import com.eviware.soapui.impl.wsdl.loadtest.data.LoadTestStatistics.Statistic;
030: import com.eviware.soapui.model.support.LoadTestRunListenerAdapter;
031: import com.eviware.soapui.model.testsuite.LoadTestRunContext;
032: import com.eviware.soapui.model.testsuite.LoadTestRunner;
033:
034: /**
035: * Collector of statistics to be exposed as TableModels
036: *
037: * @author Ole.Matzura
038: */
039:
040: public class StatisticsHistory {
041: private final LoadTestStatistics statistics;
042: private List<long[][]> data = new ArrayList<long[][]>();
043: private List<Long> threadCounts = new ArrayList<Long>();
044: private Map<Integer, TestStepStatisticsHistory> testStepStatisticHistories = new HashMap<Integer, TestStepStatisticsHistory>();
045: private EnumMap<Statistic, StatisticsValueHistory> statisticsValueHistories = new EnumMap<Statistic, StatisticsValueHistory>(
046: Statistic.class);
047:
048: @SuppressWarnings("unused")
049: private final static Logger logger = Logger
050: .getLogger(StatisticsHistory.class);
051: private long resolution = 0;
052: private InternalTableModelListener internalTableModelListener = new InternalTableModelListener();
053: private Updater updater = new Updater();
054:
055: public StatisticsHistory(LoadTestStatistics statistics) {
056: this .statistics = statistics;
057:
058: statistics.addTableModelListener(internalTableModelListener);
059: statistics.getLoadTest().addLoadTestRunListener(
060: new LoadTestRunListenerAdapter() {
061:
062: public void beforeLoadTest(
063: LoadTestRunner loadTestRunner,
064: LoadTestRunContext context) {
065: if (resolution > 0)
066: new Thread(
067: updater,
068: StatisticsHistory.this .statistics
069: .getLoadTest().getName()
070: + " StatisticsHistory Updater")
071: .start();
072: }
073: });
074: }
075:
076: public long getResolution() {
077: return resolution;
078: }
079:
080: public void setResolution(long resolution) {
081: long old = this .resolution;
082: this .resolution = resolution;
083:
084: if (resolution > 0 && old == 0
085: && statistics.getLoadTest().getHistoryLimit() != 0) {
086: new Thread(updater, statistics.getLoadTest().getName()
087: + " StatisticsHistory Updater").start();
088: }
089: }
090:
091: public int getRowCount() {
092: return data.size();
093: }
094:
095: public long[][] getHistoryAt(int index) {
096: return data.get(index);
097: }
098:
099: public long getThreadCountAt(int index) {
100: return threadCounts.get(index);
101: }
102:
103: public StatisticsHistoryModel getTestStepHistory(int testStepIndex) {
104: if (!testStepStatisticHistories.containsKey(testStepIndex)) {
105: testStepStatisticHistories.put(testStepIndex,
106: new TestStepStatisticsHistory(testStepIndex));
107: }
108:
109: return testStepStatisticHistories.get(testStepIndex);
110: }
111:
112: public StatisticsHistoryModel getStatisticsValueHistory(
113: Statistic statistic) {
114: if (!statisticsValueHistories.containsKey(statistic)) {
115: statisticsValueHistories.put(statistic,
116: new StatisticsValueHistory(statistic));
117: }
118:
119: return statisticsValueHistories.get(statistic);
120: }
121:
122: public void reset() {
123: data.clear();
124: threadCounts.clear();
125:
126: for (StatisticsValueHistory history : statisticsValueHistories
127: .values()) {
128: history.fireTableDataChanged();
129: history.fireTableStructureChanged();
130: }
131:
132: for (TestStepStatisticsHistory history : testStepStatisticHistories
133: .values()) {
134: history.fireTableDataChanged();
135: history.fireTableStructureChanged();
136: }
137: }
138:
139: private synchronized void updateHistory() {
140: if (statistics.getStatistic(LoadTestStatistics.TOTAL,
141: Statistic.COUNT) == 0) {
142: reset();
143: } else {
144: int columnCount = statistics.getColumnCount();
145: int rowCount = statistics.getRowCount();
146:
147: long[][] values = new long[rowCount][columnCount - 2];
148:
149: for (int c = 0; c < rowCount; c++) {
150: for (int i = 2; i < columnCount; i++) {
151: try {
152: values[c][i - 2] = Long.parseLong(statistics
153: .getValueAt(c, i).toString());
154: } catch (NumberFormatException ex) {
155: values[c][i - 2] = (long) Float
156: .parseFloat(statistics.getValueAt(c, i)
157: .toString());
158: }
159: }
160: }
161:
162: data.add(values);
163: threadCounts.add(statistics.getLoadTest().getThreadCount());
164:
165: // notify!
166: int sz = data.size() - 1;
167: for (StatisticsValueHistory history : statisticsValueHistories
168: .values()) {
169: history.fireTableRowsInserted(sz, sz);
170: }
171:
172: for (TestStepStatisticsHistory history : testStepStatisticHistories
173: .values()) {
174: history.fireTableRowsInserted(sz, sz);
175: }
176: }
177: }
178:
179: public abstract class StatisticsHistoryModel extends
180: AbstractTableModel {
181: public abstract void release();
182: }
183:
184: private class TestStepStatisticsHistory extends
185: StatisticsHistoryModel {
186: private final int testStepIndex;
187:
188: public TestStepStatisticsHistory(int testStepIndex) {
189: this .testStepIndex = testStepIndex == -1 ? statistics
190: .getRowCount() - 1 : testStepIndex;
191: }
192:
193: public int getTestStepIndex() {
194: return testStepIndex;
195: }
196:
197: public int getRowCount() {
198: return data.size();
199: }
200:
201: public int getColumnCount() {
202: return statistics.getColumnCount() - 1;
203: }
204:
205: public Object getValueAt(int rowIndex, int columnIndex) {
206: if (columnIndex == 0)
207: return threadCounts.get(rowIndex);
208:
209: // tolerance..
210: if (rowIndex < data.size())
211: return data.get(rowIndex)[testStepIndex][columnIndex - 1];
212: else
213: return new Long(0);
214: }
215:
216: public Class<?> getColumnClass(int columnIndex) {
217: return Long.class;
218: }
219:
220: public String getColumnName(int column) {
221: return column == 0 ? "ThreadCount" : Statistic.forIndex(
222: column - 1).getName();
223: }
224:
225: public void release() {
226: testStepStatisticHistories.remove(testStepIndex);
227: }
228: }
229:
230: private class StatisticsValueHistory extends StatisticsHistoryModel {
231: private final Statistic statistic;
232:
233: public StatisticsValueHistory(Statistic statistic) {
234: this .statistic = statistic;
235: }
236:
237: public Statistic getStatistic() {
238: return statistic;
239: }
240:
241: public int getRowCount() {
242: return data.size();
243: }
244:
245: public int getColumnCount() {
246: return statistics.getRowCount() + 1;
247: }
248:
249: public Object getValueAt(int rowIndex, int columnIndex) {
250: if (columnIndex == 0)
251: return threadCounts.get(rowIndex);
252:
253: return data.get(rowIndex)[columnIndex - 1][statistic
254: .getIndex()];
255: }
256:
257: public Class<?> getColumnClass(int columnIndex) {
258: return Long.class;
259: }
260:
261: public String getColumnName(int column) {
262: if (column == 0)
263: return "ThreadCount";
264:
265: if (column == statistics.getRowCount())
266: return "Total";
267:
268: return statistics.getLoadTest().getTestCase()
269: .getTestStepAt(column - 1).getName();
270: }
271:
272: public void release() {
273: statisticsValueHistories.remove(statistic);
274: }
275: }
276:
277: private class InternalTableModelListener implements
278: TableModelListener {
279: public synchronized void tableChanged(TableModelEvent e) {
280: if ((resolution > 0 && statistics.getLoadTest().isRunning())
281: || e.getType() != TableModelEvent.UPDATE
282: || statistics.getLoadTest().getHistoryLimit() == 0)
283: return;
284:
285: updateHistory();
286: }
287: }
288:
289: private final class Updater implements Runnable {
290: public void run() {
291: WsdlLoadTest loadTest = statistics.getLoadTest();
292:
293: while (resolution > 0 && loadTest.isRunning()) {
294: try {
295: if (loadTest.getHistoryLimit() != 0)
296: updateHistory();
297:
298: // chunck wait so we can get canceled..
299: long res = resolution;
300: while (res > 100 && resolution > 0
301: && loadTest.isRunning()) {
302: Thread.sleep(res);
303: res -= 100;
304: }
305:
306: if (resolution > 0 && loadTest.isRunning())
307: Thread.sleep(res);
308: } catch (InterruptedException e) {
309: SoapUI.logError(e);
310: break;
311: }
312: }
313: }
314: }
315: }
|