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 org.apache.log4j.Logger;
26  
27  import com.eviware.soapui.SoapUI;
28  import com.eviware.soapui.impl.wsdl.loadtest.WsdlLoadTest;
29  import com.eviware.soapui.impl.wsdl.loadtest.data.LoadTestStatistics.Statistic;
30  import com.eviware.soapui.model.support.LoadTestRunListenerAdapter;
31  import com.eviware.soapui.model.testsuite.LoadTestRunContext;
32  import com.eviware.soapui.model.testsuite.LoadTestRunner;
33  
34  /***
35   * Collector of statistics to be exposed as TableModels
36   * 
37   * @author Ole.Matzura
38   */
39  
40  public class StatisticsHistory 
41  {
42  	private final LoadTestStatistics statistics;
43  	private List<long[][]> data = new ArrayList<long[][]>();
44  	private List<Long> threadCounts = new ArrayList<Long>();
45  	private Map<Integer,TestStepStatisticsHistory> testStepStatisticHistories = 
46  		new HashMap<Integer,TestStepStatisticsHistory>();
47  	private EnumMap<Statistic,StatisticsValueHistory> statisticsValueHistories = 
48  		new EnumMap<Statistic,StatisticsValueHistory>( Statistic.class );
49  
50  	@SuppressWarnings("unused")
51  	private final static Logger logger = Logger.getLogger( StatisticsHistory.class );
52  	private long resolution = 0;
53  	private InternalTableModelListener internalTableModelListener = new InternalTableModelListener();
54  	private Updater updater = new Updater();
55  	
56  	public StatisticsHistory( LoadTestStatistics statistics )
57  	{
58  		this.statistics = statistics;
59  		
60  		statistics.addTableModelListener( internalTableModelListener );
61  		statistics.getLoadTest().addLoadTestRunListener( new LoadTestRunListenerAdapter() {
62  
63  			public void beforeLoadTest( LoadTestRunner loadTestRunner, LoadTestRunContext context )
64  			{
65  				if( resolution > 0 )
66  					new Thread( updater, StatisticsHistory.this.statistics.getLoadTest().getName() + " StatisticsHistory Updater" ).start();
67  			}
68  		} );
69  	}
70  	
71  	public long getResolution()
72  	{
73  		return resolution;
74  	}
75  
76  	public void setResolution( long resolution )
77  	{
78  		long old = this.resolution;
79  		this.resolution = resolution;
80  		
81  		if( resolution > 0 && old == 0 && statistics.getLoadTest().getHistoryLimit() != 0 )
82  		{
83  			new Thread( updater, statistics.getLoadTest().getName() + " StatisticsHistory Updater" ).start();
84  		}
85  	}
86  
87  	public int getRowCount()
88  	{
89  		return data.size();
90  	}
91  
92  	public long[][] getHistoryAt( int index )
93  	{
94  		return data.get( index );
95  	}
96  	
97  	public long getThreadCountAt( int index )
98  	{
99  		return threadCounts.get( index );
100 	}
101 
102 	public StatisticsHistoryModel getTestStepHistory( int testStepIndex )
103 	{
104 		if( !testStepStatisticHistories.containsKey( testStepIndex ))
105 		{
106 			testStepStatisticHistories.put( testStepIndex, new TestStepStatisticsHistory( testStepIndex ));
107 		}
108 		
109 		return testStepStatisticHistories.get( testStepIndex );
110 	}
111 	
112 	public StatisticsHistoryModel getStatisticsValueHistory( Statistic statistic  )
113 	{
114 		if( !statisticsValueHistories.containsKey( statistic ))
115 		{
116 			statisticsValueHistories.put( statistic, new StatisticsValueHistory( statistic ) );
117 		}
118 		
119 		return statisticsValueHistories.get( statistic );
120 	}
121 	
122 	public void reset()
123 	{
124 		data.clear(); 
125 		threadCounts.clear();
126 		
127 		for( StatisticsValueHistory history : statisticsValueHistories.values() )
128 		{
129 			history.fireTableDataChanged();
130 			history.fireTableStructureChanged();
131 		}
132 		
133 		for( TestStepStatisticsHistory history : testStepStatisticHistories.values() )
134 		{
135 			history.fireTableDataChanged();
136 			history.fireTableStructureChanged();
137 		}
138 	}
139 	
140 	private synchronized void updateHistory()
141 	{
142 		if( statistics.getStatistic( LoadTestStatistics.TOTAL, Statistic.COUNT ) == 0 )
143 		{
144 			reset();
145 		}
146 		else
147 		{
148 			int columnCount = statistics.getColumnCount();
149 			int rowCount = statistics.getRowCount();
150 			
151 			long[][] values = new long[rowCount][columnCount-2];
152 			
153 			for( int c = 0; c < rowCount; c++ )
154 			{
155 				for( int i = 2; i< columnCount; i++ )
156 				{
157 					try
158 					{
159 						values[c][i - 2] = Long.parseLong(statistics.getValueAt(c, i).toString());
160 					}
161 					catch (NumberFormatException ex)
162 					{
163 						values[c][i - 2] = (long) Float.parseFloat(statistics.getValueAt(c, i).toString());
164 					}					
165 				}
166 			}
167 			
168 			data.add( values );
169 			threadCounts.add( statistics.getLoadTest().getThreadCount() );
170 			
171 			//	 notify!
172 			int sz = data.size()-1;
173 			for( StatisticsValueHistory history : statisticsValueHistories.values() )
174 			{
175 				history.fireTableRowsInserted( sz, sz );
176 			}
177 			
178 			for( TestStepStatisticsHistory history : testStepStatisticHistories.values() )
179 			{
180 				history.fireTableRowsInserted( sz, sz );
181 			}
182 		}
183 	}
184 
185 	public abstract class StatisticsHistoryModel extends AbstractTableModel
186 	{
187 		public abstract void release();
188 	}
189 
190 	private class TestStepStatisticsHistory extends StatisticsHistoryModel
191 	{
192 		private final int testStepIndex;
193 
194 		public TestStepStatisticsHistory(int testStepIndex)
195 		{
196 			this.testStepIndex = testStepIndex == -1 ? statistics.getRowCount()-1 : testStepIndex;
197 		}
198 
199 		public int getTestStepIndex()
200 		{
201 			return testStepIndex;
202 		}
203 
204 		public int getRowCount()
205 		{
206 			return data.size();
207 		}
208 
209 		public int getColumnCount()
210 		{
211 			return statistics.getColumnCount()-1;
212 		}
213 
214 		public Object getValueAt(int rowIndex, int columnIndex)
215 		{
216 			if( columnIndex == 0 ) return  threadCounts.get( rowIndex );
217 			
218 			// tolerance..
219 			if( rowIndex < data.size() )
220 				return data.get( rowIndex )[testStepIndex][columnIndex-1];
221 			else return 
222 			   new Long( 0 );
223 		}
224 
225 		public Class<?> getColumnClass(int columnIndex)
226 		{
227 			return Long.class;
228 		}
229 
230 		public String getColumnName(int column)
231 		{
232 			return column == 0 ? "ThreadCount" : 
233 				Statistic.forIndex( column-1 ).getName();
234 		}
235 
236 		public void release()
237 		{
238 			testStepStatisticHistories.remove( testStepIndex );
239 		}
240 	}
241 	
242 	private class StatisticsValueHistory extends StatisticsHistoryModel
243 	{
244 		private final Statistic statistic;
245 
246 		public StatisticsValueHistory(Statistic statistic)
247 		{
248 			this.statistic = statistic;
249 		}
250 
251 		public Statistic getStatistic()
252 		{
253 			return statistic;
254 		}
255 
256 		public int getRowCount()
257 		{
258 			return data.size();
259 		}
260 
261 		public int getColumnCount()
262 		{
263 			return statistics.getRowCount()+1;
264 		}
265 
266 		public Object getValueAt(int rowIndex, int columnIndex)
267 		{
268 			if( columnIndex == 0 )
269 				return threadCounts.get( rowIndex );
270 			
271 			return data.get( rowIndex )[columnIndex-1][statistic.getIndex()];
272 		}
273 
274 		public Class<?> getColumnClass(int columnIndex)
275 		{
276 			return Long.class;
277 		}
278 
279 		public String getColumnName(int column)
280 		{
281 			if( column == 0 )
282 				return "ThreadCount";
283 			
284 			if( column == statistics.getRowCount() )
285 				return "Total";
286 			
287 			return statistics.getLoadTest().getTestCase().getTestStepAt( column-1 ).getName();
288 		}
289 
290 		public void release()
291 		{
292 			statisticsValueHistories.remove( statistic );
293 		}
294 	}
295 	
296 	private class InternalTableModelListener implements TableModelListener
297 	{
298 		public synchronized void tableChanged(TableModelEvent e)
299 		{
300 			if( (resolution > 0 && statistics.getLoadTest().isRunning()) || 
301 						e.getType() != TableModelEvent.UPDATE ||
302 						statistics.getLoadTest().getHistoryLimit() == 0 ) return;
303 			
304 			updateHistory();
305 		}
306 	}
307 	
308 	private final class Updater implements Runnable
309 	{
310 		public void run()
311 		{
312 			WsdlLoadTest loadTest = statistics.getLoadTest();
313 			
314 			while( resolution > 0 && loadTest.isRunning() )
315 			{
316 				try
317 				{
318 					if( loadTest.getHistoryLimit() != 0 )
319 						updateHistory();
320 					
321 					// chunck wait so we can get canceled..
322 					long res = resolution;
323 					while( res > 100 && resolution > 0 && loadTest.isRunning() )
324 					{
325 						Thread.sleep( res );
326 						res -= 100;
327 					}
328 					
329 					if( resolution > 0 && loadTest.isRunning() )
330 						Thread.sleep( res );
331 				}
332 				catch( InterruptedException e )
333 				{
334 					SoapUI.logError( e );
335 					break;
336 				}
337 			}
338 		}
339 	}
340 }