/*
* SoapUI, Copyright (C) 2004-2016 SmartBear Software
*
* Licensed under the EUPL, Version 1.1 or - as soon as they will be approved by the European Commission - subsequent
* versions of the EUPL (the "Licence");
* You may not use this work except in compliance with the Licence.
* You may obtain a copy of the Licence at:
*
* http://ec.europa.eu/idabc/eupl
*
* Unless required by applicable law or agreed to in writing, software distributed under the Licence is
* distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the Licence for the specific language governing permissions and limitations
* under the Licence.
*/
package com.eviware.soapui.impl.wsdl.loadtest.data;
import com.eviware.soapui.SoapUI;
import com.eviware.soapui.impl.wsdl.loadtest.WsdlLoadTest;
import com.eviware.soapui.impl.wsdl.loadtest.data.LoadTestStatistics.Statistic;
import com.eviware.soapui.model.support.LoadTestRunListenerAdapter;
import com.eviware.soapui.model.testsuite.LoadTestRunContext;
import com.eviware.soapui.model.testsuite.LoadTestRunner;
import org.apache.log4j.Logger;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.AbstractTableModel;
import java.util.ArrayList;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Collector of statistics to be exposed as TableModels
*
* @author Ole.Matzura
*/
public class StatisticsHistory {
private final LoadTestStatistics statistics;
private List<long[][]> data = new ArrayList<long[][]>();
private List<Long> threadCounts = new ArrayList<Long>();
private Map<Integer, TestStepStatisticsHistory> testStepStatisticHistories = new HashMap<Integer, TestStepStatisticsHistory>();
private EnumMap<Statistic, StatisticsValueHistory> statisticsValueHistories = new EnumMap<Statistic, StatisticsValueHistory>(
Statistic.class);
@SuppressWarnings("unused")
private final static Logger logger = Logger.getLogger(StatisticsHistory.class);
private long resolution = 0;
private InternalTableModelListener internalTableModelListener = new InternalTableModelListener();
private Updater updater = new Updater();
public StatisticsHistory(LoadTestStatistics statistics) {
this.statistics = statistics;
statistics.addTableModelListener(internalTableModelListener);
statistics.getLoadTest().addLoadTestRunListener(new LoadTestRunListenerAdapter() {
public void beforeLoadTest(LoadTestRunner loadTestRunner, LoadTestRunContext context) {
if (resolution > 0) {
new Thread(updater, StatisticsHistory.this.statistics.getLoadTest().getName()
+ " StatisticsHistory Updater").start();
}
}
});
}
public Map<Integer, TestStepStatisticsHistory> getTestStepStatisticHistories() {
return testStepStatisticHistories;
}
public long getResolution() {
return resolution;
}
public void setResolution(long resolution) {
long old = this.resolution;
this.resolution = resolution;
if (resolution > 0 && old == 0 && statistics.getLoadTest().getHistoryLimit() != 0) {
new Thread(updater, statistics.getLoadTest().getName() + " StatisticsHistory Updater").start();
}
}
public int getRowCount() {
return data.size();
}
public long[][] getHistoryAt(int index) {
return data.get(index);
}
public long getThreadCountAt(int index) {
return threadCounts.get(index);
}
public StatisticsHistoryModel getTestStepHistory(int testStepIndex) {
if (!testStepStatisticHistories.containsKey(testStepIndex)) {
testStepStatisticHistories.put(testStepIndex, new TestStepStatisticsHistory(testStepIndex));
}
return testStepStatisticHistories.get(testStepIndex);
}
public StatisticsHistoryModel getStatisticsValueHistory(Statistic statistic) {
if (!statisticsValueHistories.containsKey(statistic)) {
statisticsValueHistories.put(statistic, new StatisticsValueHistory(statistic));
}
return statisticsValueHistories.get(statistic);
}
public void reset() {
data.clear();
threadCounts.clear();
for (StatisticsValueHistory history : statisticsValueHistories.values()) {
history.fireTableDataChanged();
history.fireTableStructureChanged();
}
for (TestStepStatisticsHistory history : testStepStatisticHistories.values()) {
history.fireTableDataChanged();
history.fireTableStructureChanged();
}
}
private synchronized void updateHistory() {
if (statistics.getStatistic(LoadTestStatistics.TOTAL, Statistic.COUNT) == 0) {
reset();
} else {
int columnCount = statistics.getColumnCount();
int rowCount = statistics.getRowCount();
long[][] values = new long[rowCount][columnCount - 2];
for (int c = 0; c < rowCount; c++) {
for (int i = 2; i < columnCount; i++) {
try {
values[c][i - 2] = Long.parseLong(statistics.getValueAt(c, i).toString());
} catch (NumberFormatException ex) {
values[c][i - 2] = (long) Float.parseFloat(statistics.getValueAt(c, i).toString());
}
}
}
data.add(values);
threadCounts.add(statistics.getLoadTest().getThreadCount());
// notify!
int sz = data.size() - 1;
for (StatisticsValueHistory history : statisticsValueHistories.values()) {
history.fireTableRowsInserted(sz, sz);
}
for (TestStepStatisticsHistory history : testStepStatisticHistories.values()) {
history.fireTableRowsInserted(sz, sz);
}
}
}
public abstract class StatisticsHistoryModel extends AbstractTableModel {
public abstract void release();
}
public class TestStepStatisticsHistory extends StatisticsHistoryModel {
private final int testStepIndex;
public TestStepStatisticsHistory(int testStepIndex) {
this.testStepIndex = testStepIndex == -1 ? statistics.getRowCount() - 1 : testStepIndex;
}
public int getTestStepIndex() {
return testStepIndex;
}
public int getRowCount() {
return data.size();
}
public int getColumnCount() {
return statistics.getColumnCount() - 1;
}
public Object getValueAt(int rowIndex, int columnIndex) {
if (columnIndex == 0) {
return threadCounts.get(rowIndex);
}
// tolerance..
if (rowIndex < data.size()) {
return data.get(rowIndex)[testStepIndex][columnIndex - 1];
} else {
return new Long(0);
}
}
public Class<?> getColumnClass(int columnIndex) {
return Long.class;
}
public String getColumnName(int column) {
return column == 0 ? "ThreadCount" : Statistic.forIndex(column - 1).getName();
}
public void release() {
testStepStatisticHistories.remove(testStepIndex);
}
}
private class StatisticsValueHistory extends StatisticsHistoryModel {
private final Statistic statistic;
public StatisticsValueHistory(Statistic statistic) {
this.statistic = statistic;
}
@SuppressWarnings("unused")
public Statistic getStatistic() {
return statistic;
}
public int getRowCount() {
return data.size();
}
public int getColumnCount() {
return statistics.getRowCount() + 1;
}
public Object getValueAt(int rowIndex, int columnIndex) {
if (columnIndex == 0) {
return threadCounts.get(rowIndex);
}
return data.get(rowIndex)[columnIndex - 1][statistic.getIndex()];
}
public Class<?> getColumnClass(int columnIndex) {
return Long.class;
}
public String getColumnName(int column) {
if (column == 0) {
return "ThreadCount";
}
if (column == statistics.getRowCount()) {
return "Total";
}
return statistics.getLoadTest().getTestCase().getTestStepAt(column - 1).getName();
}
public void release() {
statisticsValueHistories.remove(statistic);
}
}
private class InternalTableModelListener implements TableModelListener {
public synchronized void tableChanged(TableModelEvent e) {
if ((resolution > 0 && statistics.getLoadTest().isRunning()) || e.getType() != TableModelEvent.UPDATE
|| statistics.getLoadTest().getHistoryLimit() == 0) {
return;
}
updateHistory();
}
}
private final class Updater implements Runnable {
public void run() {
WsdlLoadTest loadTest = statistics.getLoadTest();
while (resolution > 0 && loadTest.isRunning()) {
try {
if (loadTest.getHistoryLimit() != 0) {
updateHistory();
}
// chunck wait so we can get canceled..
long res = resolution;
while (res > 100 && resolution > 0 && loadTest.isRunning()) {
Thread.sleep(res);
res -= 100;
}
if (resolution > 0 && loadTest.isRunning()) {
Thread.sleep(res);
}
} catch (InterruptedException e) {
SoapUI.logError(e);
break;
}
}
}
}
}