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