View Javadoc

1   /*
2    *  soapUI, copyright (C) 2004-2010 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.support;
14  
15  import java.util.Timer;
16  import java.util.TimerTask;
17  import java.util.concurrent.ExecutorService;
18  import java.util.concurrent.Executors;
19  import java.util.concurrent.Future;
20  
21  import org.apache.log4j.Logger;
22  
23  import com.eviware.soapui.SoapUI;
24  import com.eviware.soapui.model.testsuite.TestRunContext;
25  import com.eviware.soapui.model.testsuite.TestRunnable;
26  import com.eviware.soapui.model.testsuite.TestRunner;
27  import com.eviware.soapui.support.UISupport;
28  import com.eviware.soapui.support.types.StringToObjectMap;
29  
30  /***
31   * WSDL TestCase Runner - runs all steps in a testcase and collects performance
32   * data
33   * 
34   * @author Ole.Matzura
35   */
36  
37  public abstract class AbstractTestRunner<T extends TestRunnable, T2 extends TestRunContext> implements Runnable,
38  		TestRunner
39  {
40  	private final T testRunnable;
41  	private Status status;
42  	private Throwable error;
43  	private T2 runContext;
44  	private long startTime;
45  	private String reason;
46  	private volatile Future<?> future;
47  	private int id;
48  	private final static ExecutorService threadPool = Executors.newCachedThreadPool();
49  
50  	private final static Logger log = Logger.getLogger( AbstractTestRunner.class );
51  
52  	private static int idCounter = 0;
53  
54  	private Timer timeoutTimer;
55  	private TimeoutTimerTask timeoutTimerTask;
56  	private Thread thread;
57  	private long timeTaken;
58  
59  	public AbstractTestRunner( T modelItem, StringToObjectMap properties )
60  	{
61  		this.testRunnable = modelItem;
62  		status = Status.INITIALIZED;
63  		id = ++idCounter;
64  
65  		runContext = createContext( properties );
66  	}
67  
68  	public abstract T2 createContext( StringToObjectMap properties );
69  
70  	public T2 getRunContext()
71  	{
72  		return runContext;
73  	}
74  
75  	public void start( boolean async )
76  	{
77  		status = Status.RUNNING;
78  		if( async )
79  			future = threadPool.submit( this );
80  		else
81  			run();
82  	}
83  
84  	public void cancel( String reason )
85  	{
86  		if( status == Status.CANCELED || status == Status.FINISHED || status == Status.FAILED || runContext == null )
87  			return;
88  		onCancel( reason );
89  		status = Status.CANCELED;
90  		this.reason = reason;
91  	}
92  
93  	protected void onCancel( String reason2 )
94  	{
95  	}
96  
97  	public void fail( String reason )
98  	{
99  		if( status == Status.CANCELED || status == Status.FAILED || runContext == null )
100 			return;
101 		onFail( reason );
102 		status = Status.FAILED;
103 		this.reason = reason;
104 	}
105 
106 	protected void onFail( String reason )
107 	{
108 	}
109 
110 	public Status getStatus()
111 	{
112 		return status;
113 	}
114 
115 	public int getId()
116 	{
117 		return id;
118 	}
119 
120 	public Thread getThread()
121 	{
122 		return thread;
123 	}
124 
125 	public void run()
126 	{
127 		if( future != null )
128 		{
129 			thread = Thread.currentThread();
130 			thread.setName( "TestRunner Thread for " + testRunnable.getName() );
131 		}
132 
133 		try
134 		{
135 			status = Status.RUNNING;
136 			setStartTime();
137 
138 			internalRun( runContext );
139 		}
140 		catch( Throwable t )
141 		{
142 			log.error( "Exception during Test Execution", t );
143 
144 			if( t instanceof OutOfMemoryError && UISupport.confirm( "Exit now without saving?", "Out of Memory Error" ) )
145 			{
146 				System.exit( 0 );
147 			}
148 
149 			status = Status.FAILED;
150 			error = t;
151 			reason = t.toString();
152 		}
153 		finally
154 		{
155 			setTimeTaken();
156 			if( timeoutTimer != null )
157 			{
158 				timeoutTimer.cancel();
159 			}
160 
161 			if( status == Status.RUNNING )
162 			{
163 				status = Status.FINISHED;
164 			}
165 
166 			internalFinally( runContext );
167 		}
168 	}
169 
170 	protected void setStartTime()
171 	{
172 		startTime = System.currentTimeMillis();
173 	}
174 
175 	public boolean isRunning()
176 	{
177 		return getStatus() == Status.RUNNING;
178 	}
179 
180 	public boolean isCanceled()
181 	{
182 		return getStatus() == Status.CANCELED;
183 	}
184 
185 	public boolean isFailed()
186 	{
187 		return getStatus() == Status.FAILED;
188 	}
189 
190 	protected void setStatus( Status status )
191 	{
192 		this.status = status;
193 	}
194 
195 	protected void setError( Throwable error )
196 	{
197 		this.error = error;
198 	}
199 
200 	protected abstract void internalRun( T2 runContext2 ) throws Exception;
201 
202 	protected abstract void internalFinally( T2 runContext2 );
203 
204 	protected void startTimeoutTimer( long timeout )
205 	{
206 		timeoutTimer = new Timer();
207 		timeoutTimerTask = new TimeoutTimerTask();
208 		timeoutTimer.schedule( timeoutTimerTask, timeout );
209 	}
210 
211 	public T getTestRunnable()
212 	{
213 		return testRunnable;
214 	}
215 
216 	public synchronized Status waitUntilFinished()
217 	{
218 		if( future != null )
219 		{
220 			if( !future.isDone() )
221 			{
222 				try
223 				{
224 					future.get();
225 				}
226 				catch( Exception e )
227 				{
228 					SoapUI.logError( e );
229 				}
230 			}
231 		}
232 		else
233 			throw new RuntimeException( "cannot wait on null future" );
234 
235 		return getStatus();
236 	}
237 
238 	protected void setTimeTaken()
239 	{
240 		timeTaken = System.currentTimeMillis() - startTime;
241 	}
242 	
243 	public long getTimeTaken()
244 	{
245 		return timeTaken;
246 	}
247 
248 	public long getStartTime()
249 	{
250 		return startTime;
251 	}
252 
253 	public Throwable getError()
254 	{
255 		return error;
256 	}
257 
258 	public String getReason()
259 	{
260 		return reason == null ? error == null ? null : error.toString() : reason;
261 	}
262 
263 	private final class TimeoutTimerTask extends TimerTask
264 	{
265 		@Override
266 		public void run()
267 		{
268 			fail( "TestCase timed out" );
269 		}
270 	}
271 
272 	
273 }