/*
* soapUI, copyright (C) 2004-2011 eviware.com
*
* soapUI is free software; you can redistribute it and/or modify it under the
* terms of version 2.1 of the GNU Lesser General Public License as published by
* the Free Software Foundation.
*
* soapUI is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
* even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details at gnu.org.
*/
package com.eviware.soapui.impl.wsdl.loadtest.data;
import java.util.ArrayList;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.AbstractTableModel;
import org.apache.log4j.Logger;
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;
/**
* 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;
}
}
}
}
}