View Javadoc

1   /*
2    *  soapUI, copyright (C) 2004-2009 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  
58  	public AbstractTestRunner( T modelItem, StringToObjectMap properties )
59  	{
60  		this.testRunnable = modelItem;
61  		status = Status.INITIALIZED;
62  		id = ++idCounter;
63  
64  		runContext = createContext( properties );
65  	}
66  
67  	public abstract T2 createContext( StringToObjectMap properties );
68  
69  	public T2 getRunContext()
70  	{
71  		return runContext;
72  	}
73  
74  	public void start( boolean async )
75  	{
76  		status = Status.RUNNING;
77  		if( async )
78  			future = threadPool.submit( this );
79  		else
80  			run();
81  	}
82  
83  	public void cancel( String reason )
84  	{
85  		if( status == Status.CANCELED || status == Status.FINISHED || status == Status.FAILED || runContext == null )
86  			return;
87  		onCancel( reason );
88  		status = Status.CANCELED;
89  		this.reason = reason;
90  	}
91  
92  	protected void onCancel( String reason2 )
93  	{
94  	}
95  
96  	public void fail( String reason )
97  	{
98  		if( status == Status.CANCELED || status == Status.FAILED || runContext == null )
99  			return;
100 		onFail( reason );
101 		status = Status.FAILED;
102 		this.reason = reason;
103 	}
104 
105 	protected void onFail( String reason )
106 	{
107 	}
108 
109 	public Status getStatus()
110 	{
111 		return status;
112 	}
113 
114 	public int getId()
115 	{
116 		return id;
117 	}
118 
119 	public Thread getThread()
120 	{
121 		return thread;
122 	}
123 
124 	public void run()
125 	{
126 		if( future != null )
127 		{
128 			thread = Thread.currentThread();
129 			thread.setName( "TestRunner Thread for " + testRunnable.getName() );
130 		}
131 
132 		try
133 		{
134 			status = Status.RUNNING;
135 			startTime = System.currentTimeMillis();
136 
137 			internalRun( runContext );
138 		}
139 		catch( Throwable t )
140 		{
141 			log.error( "Exception during Test Execution", t );
142 
143 			if( t instanceof OutOfMemoryError && UISupport.confirm( "Exit now without saving?", "Out of Memory Error" ) )
144 			{
145 				System.exit( 0 );
146 			}
147 
148 			status = Status.FAILED;
149 			error = t;
150 			reason = t.toString();
151 		}
152 		finally
153 		{
154 			if( timeoutTimer != null )
155 			{
156 				timeoutTimer.cancel();
157 			}
158 
159 			if( status == Status.RUNNING )
160 			{
161 				status = Status.FINISHED;
162 			}
163 
164 			internalFinally( runContext );
165 		}
166 	}
167 
168 	public boolean isRunning()
169 	{
170 		return getStatus() == Status.RUNNING;
171 	}
172 
173 	public boolean isCanceled()
174 	{
175 		return getStatus() == Status.CANCELED;
176 	}
177 
178 	public boolean isFailed()
179 	{
180 		return getStatus() == Status.FAILED;
181 	}
182 
183 	protected void setStatus( Status status )
184 	{
185 		this.status = status;
186 	}
187 
188 	protected void setError( Throwable error )
189 	{
190 		this.error = error;
191 	}
192 
193 	protected abstract void internalRun( T2 runContext2 ) throws Exception;
194 
195 	protected abstract void internalFinally( T2 runContext2 );
196 
197 	protected void startTimeoutTimer( long timeout )
198 	{
199 		timeoutTimer = new Timer();
200 		timeoutTimerTask = new TimeoutTimerTask();
201 		timeoutTimer.schedule( timeoutTimerTask, timeout );
202 	}
203 
204 	public T getTestRunnable()
205 	{
206 		return testRunnable;
207 	}
208 
209 	public synchronized Status waitUntilFinished()
210 	{
211 		if( future != null )
212 		{
213 			if( !future.isDone() )
214 			{
215 				try
216 				{
217 					future.get();
218 				}
219 				catch( Exception e )
220 				{
221 					SoapUI.logError( e );
222 				}
223 			}
224 		}
225 		else
226 			throw new RuntimeException( "cannot wait on null future" );
227 
228 		return getStatus();
229 	}
230 
231 	public long getTimeTaken()
232 	{
233 		return System.currentTimeMillis() - startTime;
234 	}
235 
236 	public long getStartTime()
237 	{
238 		return startTime;
239 	}
240 
241 	public Throwable getError()
242 	{
243 		return error;
244 	}
245 
246 	public String getReason()
247 	{
248 		return reason == null ? error == null ? null : error.toString() : reason;
249 	}
250 
251 	private final class TimeoutTimerTask extends TimerTask
252 	{
253 		@Override
254 		public void run()
255 		{
256 			fail( "TestCase timed out" );
257 		}
258 	}
259 
260 	
261 }