View Javadoc

1   /*
2    *  soapUI, copyright (C) 2004-2007 eviware.com 
3    *
4    *  soapUI is free software; you can redistribute it and/or modify it under the 
5    *  terms of version 2.1 of the GNU Lesser General Public License as published by 
6    *  the Free Software Foundation.
7    *
8    *  soapUI is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without 
9    *  even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
10   *  See the GNU Lesser General Public License for more details at gnu.org.
11   */
12  
13  package com.eviware.soapui.impl.wsdl.loadtest.data;
14  
15  import java.util.ArrayList;
16  import java.util.EnumMap;
17  import java.util.HashMap;
18  import java.util.List;
19  import java.util.Map;
20  
21  import javax.swing.event.TableModelEvent;
22  import javax.swing.event.TableModelListener;
23  import javax.swing.table.AbstractTableModel;
24  
25  import com.eviware.soapui.impl.wsdl.loadtest.data.LoadTestStatistics.Statistic;
26  import com.eviware.soapui.model.support.LoadTestRunListenerAdapter;
27  import com.eviware.soapui.model.testsuite.LoadTestRunContext;
28  import com.eviware.soapui.model.testsuite.LoadTestRunner;
29  
30  /***
31   * Collector of statistics to be exposed as TableModels
32   * 
33   * @author Ole.Matzura
34   */
35  
36  public class StatisticsHistory 
37  {
38  	private final LoadTestStatistics statistics;
39  	private List<long[][]> data = new ArrayList<long[][]>();
40  	private List<Long> threadCounts = new ArrayList<Long>();
41  	private Map<Integer,TestStepStatisticsHistory> testStepStatisticHistories = 
42  		new HashMap<Integer,TestStepStatisticsHistory>();
43  	private EnumMap<Statistic,StatisticsValueHistory> statisticsValueHistories = 
44  		new EnumMap<Statistic,StatisticsValueHistory>( Statistic.class );
45  
46  //	private final static Logger logger = Logger.getLogger( StatisticsHistory.class );
47  	private long resolution = 0;
48  	private InternalTableModelListener internalTableModelListener = new InternalTableModelListener();
49  	private Updater updater = new Updater();
50  	
51  	public StatisticsHistory( LoadTestStatistics statistics )
52  	{
53  		this.statistics = statistics;
54  		
55  		statistics.addTableModelListener( internalTableModelListener );
56  		statistics.getLoadTest().addLoadTestRunListener( new LoadTestRunListenerAdapter() {
57  
58  			public void beforeLoadTest( LoadTestRunner loadTestRunner, LoadTestRunContext context )
59  			{
60  				if( resolution > 0 )
61  					new Thread( updater ).start();
62  			}
63  		} );
64  	}
65  	
66  	public long getResolution()
67  	{
68  		return resolution;
69  	}
70  
71  	public void setResolution( long resolution )
72  	{
73  		long old = this.resolution;
74  		this.resolution = resolution;
75  		
76  		if( resolution > 0 && old == 0 )
77  		{
78  			new Thread( updater ).start();
79  		}
80  	}
81  
82  	public int getRowCount()
83  	{
84  		return data.size();
85  	}
86  
87  	public long[][] getHistoryAt( int index )
88  	{
89  		return data.get( index );
90  	}
91  	
92  	public long getThreadCountAt( int index )
93  	{
94  		return threadCounts.get( index );
95  	}
96  
97  	public StatisticsHistoryModel getTestStepHistory( int testStepIndex )
98  	{
99  		if( !testStepStatisticHistories.containsKey( testStepIndex ))
100 		{
101 			testStepStatisticHistories.put( testStepIndex, new TestStepStatisticsHistory( testStepIndex ));
102 		}
103 		
104 		return testStepStatisticHistories.get( testStepIndex );
105 	}
106 	
107 	public StatisticsHistoryModel getStatisticsValueHistory( Statistic statistic  )
108 	{
109 		if( !statisticsValueHistories.containsKey( statistic ))
110 		{
111 			statisticsValueHistories.put( statistic, new StatisticsValueHistory( statistic ) );
112 		}
113 		
114 		return statisticsValueHistories.get( statistic );
115 	}
116 	
117 	public void reset()
118 	{
119 		data.clear(); 
120 		threadCounts.clear();
121 		
122 		for( StatisticsValueHistory history : statisticsValueHistories.values() )
123 		{
124 			history.fireTableDataChanged();
125 			history.fireTableStructureChanged();
126 		}
127 		
128 		for( TestStepStatisticsHistory history : testStepStatisticHistories.values() )
129 		{
130 			history.fireTableDataChanged();
131 			history.fireTableStructureChanged();
132 		}
133 	}
134 	
135 	private synchronized void updateHistory()
136 	{
137 		if( statistics.getStatistic( LoadTestStatistics.TOTAL, Statistic.COUNT ) == 0 )
138 		{
139 			reset();
140 		}
141 		else
142 		{
143 			int columnCount = statistics.getColumnCount();
144 			int rowCount = statistics.getRowCount();
145 			
146 			long[][] values = new long[rowCount][columnCount-2];
147 			
148 			for( int c = 0; c < rowCount; c++ )
149 			{
150 				for( int i = 2; i< columnCount; i++ )
151 				{
152 					try
153 					{
154 						values[c][i - 2] = Long.parseLong(statistics.getValueAt(c, i).toString());
155 					}
156 					catch (NumberFormatException ex)
157 					{
158 						values[c][i - 2] = (long) Float.parseFloat(statistics.getValueAt(c, i).toString());
159 					}					
160 				}
161 			}
162 			
163 			data.add( values );
164 			threadCounts.add( statistics.getLoadTest().getThreadCount() );
165 			
166 			//	 notify!
167 			int sz = data.size()-1;
168 			for( StatisticsValueHistory history : statisticsValueHistories.values() )
169 			{
170 				history.fireTableRowsInserted( sz, sz );
171 			}
172 			
173 			for( TestStepStatisticsHistory history : testStepStatisticHistories.values() )
174 			{
175 				history.fireTableRowsInserted( sz, sz );
176 			}
177 		}
178 	}
179 
180 	public abstract class StatisticsHistoryModel extends AbstractTableModel
181 	{
182 		public abstract void release();
183 	}
184 
185 	private class TestStepStatisticsHistory extends StatisticsHistoryModel
186 	{
187 		private final int testStepIndex;
188 
189 		public TestStepStatisticsHistory(int testStepIndex)
190 		{
191 			this.testStepIndex = testStepIndex == -1 ? statistics.getRowCount()-1 : testStepIndex;
192 		}
193 
194 		public int getTestStepIndex()
195 		{
196 			return testStepIndex;
197 		}
198 
199 		public int getRowCount()
200 		{
201 			return data.size();
202 		}
203 
204 		public int getColumnCount()
205 		{
206 			return statistics.getColumnCount()-1;
207 		}
208 
209 		public Object getValueAt(int rowIndex, int columnIndex)
210 		{
211 			if( columnIndex == 0 ) return  threadCounts.get( rowIndex );
212 			
213 			// tolerance..
214 			if( rowIndex < data.size() )
215 				return data.get( rowIndex )[testStepIndex][columnIndex-1];
216 			else return 
217 			   new Long( 0 );
218 		}
219 
220 		public Class<?> getColumnClass(int columnIndex)
221 		{
222 			return Long.class;
223 		}
224 
225 		public String getColumnName(int column)
226 		{
227 			return column == 0 ? "ThreadCount" : 
228 				Statistic.forIndex( column-1 ).getName();
229 		}
230 
231 		public void release()
232 		{
233 			testStepStatisticHistories.remove( testStepIndex );
234 		}
235 	}
236 	
237 	private class StatisticsValueHistory extends StatisticsHistoryModel
238 	{
239 		private final Statistic statistic;
240 
241 		public StatisticsValueHistory(Statistic statistic)
242 		{
243 			this.statistic = statistic;
244 		}
245 
246 		public Statistic getStatistic()
247 		{
248 			return statistic;
249 		}
250 
251 		public int getRowCount()
252 		{
253 			return data.size();
254 		}
255 
256 		public int getColumnCount()
257 		{
258 			return statistics.getRowCount()+1;
259 		}
260 
261 		public Object getValueAt(int rowIndex, int columnIndex)
262 		{
263 			if( columnIndex == 0 )
264 				return threadCounts.get( rowIndex );
265 			
266 			return data.get( rowIndex )[columnIndex-1][statistic.getIndex()];
267 		}
268 
269 		public Class<?> getColumnClass(int columnIndex)
270 		{
271 			return Long.class;
272 		}
273 
274 		public String getColumnName(int column)
275 		{
276 			if( column == 0 )
277 				return "ThreadCount";
278 			
279 			if( column == statistics.getRowCount() )
280 				return "Total";
281 			
282 			return statistics.getLoadTest().getTestCase().getTestStepAt( column-1 ).getName();
283 		}
284 
285 		public void release()
286 		{
287 			statisticsValueHistories.remove( statistic );
288 		}
289 	}
290 	
291 	private class InternalTableModelListener implements TableModelListener
292 	{
293 		public synchronized void tableChanged(TableModelEvent e)
294 		{
295 			if( (resolution > 0 && statistics.getLoadTest().isRunning()) || 
296 						e.getType() != TableModelEvent.UPDATE ) return;
297 			updateHistory();
298 		}
299 	}
300 	
301 	private final class Updater implements Runnable
302 	{
303 		public void run()
304 		{
305 			while( resolution > 0 && statistics.getLoadTest().isRunning() )
306 			{
307 				try
308 				{
309 					updateHistory();
310 					Thread.sleep( resolution );
311 				}
312 				catch( InterruptedException e )
313 				{
314 					e.printStackTrace();
315 					break;
316 				}
317 			}
318 		}
319 	}
320 }