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.panels.teststeps;
14  
15  import java.sql.CallableStatement;
16  import java.sql.Connection;
17  import java.sql.DriverManager;
18  import java.sql.PreparedStatement;
19  import java.sql.ResultSet;
20  import java.sql.SQLException;
21  import java.sql.SQLFeatureNotSupportedException;
22  import java.util.List;
23  import java.util.concurrent.Future;
24  
25  import com.eviware.soapui.SoapUI;
26  import com.eviware.soapui.impl.wsdl.panels.teststeps.support.NamedParameterStatement;
27  import com.eviware.soapui.impl.wsdl.teststeps.JdbcRequestTestStep;
28  import com.eviware.soapui.model.iface.Request;
29  import com.eviware.soapui.model.iface.Submit;
30  import com.eviware.soapui.model.iface.SubmitContext;
31  import com.eviware.soapui.model.iface.SubmitListener;
32  import com.eviware.soapui.model.propertyexpansion.PropertyExpander;
33  import com.eviware.soapui.model.testsuite.TestProperty;
34  import com.eviware.soapui.support.SoapUIException;
35  import com.eviware.soapui.support.StringUtils;
36  import com.eviware.soapui.support.UISupport;
37  
38  public class JdbcSubmit implements Submit, Runnable
39  {
40  	public static final String JDBC_ERROR = "JDBC_ERROR";
41  	public static final String JDBC_TIMEOUT = "JDBC_TIMEOUT";
42  	private volatile Future<?> future;
43  	private SubmitContext context;
44  	private Status status;
45  	private SubmitListener[] listeners;
46  	private Exception error;
47  	private long timestamp;
48  	protected ResultSet resultSet;
49  	protected PreparedStatement statement;
50  	private Connection connection;
51  	private long timeTaken;
52  	private final JdbcRequest request;
53  	private JdbcResponse response;
54  
55  	public JdbcSubmit( JdbcRequest request, SubmitContext submitContext, boolean async )
56  	{
57  		this.request = request;
58  		this.context = submitContext;
59  
60  		List<SubmitListener> regListeners = SoapUI.getListenerRegistry().getListeners( SubmitListener.class );
61  
62  		SubmitListener[] submitListeners = request.getSubmitListeners();
63  		this.listeners = new SubmitListener[submitListeners.length + regListeners.size()];
64  		for( int c = 0; c < submitListeners.length; c++ )
65  			this.listeners[c] = submitListeners[c];
66  
67  		for( int c = 0; c < regListeners.size(); c++ )
68  			this.listeners[submitListeners.length + c] = regListeners.get( c );
69  
70  		error = null;
71  		status = Status.INITIALIZED;
72  
73  		if( async )
74  			future = SoapUI.getThreadPool().submit( this );
75  		else
76  			run();
77  	}
78  
79  	public void cancel()
80  	{
81  		if( status == Status.CANCELED )
82  			return;
83  
84  		JdbcRequest.logger.info( "Canceling request.." );
85  		if( status == Status.RUNNING )
86  		{
87  			cancelQuery();
88  		}
89  
90  		status = Status.CANCELED;
91  
92  		for( int i = 0; i < listeners.length; i++ )
93  		{
94  			try
95  			{
96  				listeners[i].afterSubmit( this, context );
97  			}
98  			catch( Throwable e )
99  			{
100 				SoapUI.logError( e );
101 			}
102 		}
103 	}
104 
105 	public Exception getError()
106 	{
107 		return error;
108 	}
109 
110 	public Request getRequest()
111 	{
112 		return request;
113 	}
114 
115 	public JdbcResponse getResponse()
116 	{
117 		return response;
118 	}
119 
120 	public Status getStatus()
121 	{
122 		return status;
123 	}
124 
125 	public Status waitUntilFinished()
126 	{
127 		if( future != null )
128 		{
129 			if( !future.isDone() )
130 			{
131 				try
132 				{
133 					future.get();
134 				}
135 				catch( Exception e )
136 				{
137 					SoapUI.logError( e );
138 				}
139 			}
140 		}
141 		else
142 			throw new RuntimeException( "cannot wait on null future" );
143 
144 		return getStatus();
145 	}
146 
147 	public void run()
148 	{
149 		try
150 		{
151 			for( int i = 0; i < listeners.length; i++ )
152 			{
153 				if( !listeners[i].beforeSubmit( this, context ) )
154 				{
155 					status = Status.CANCELED;
156 					System.err.println( "listener cancelled submit.." );
157 					return;
158 				}
159 			}
160 
161 			status = Status.RUNNING;
162 			runQuery();
163 
164 			if( status != Status.CANCELED )
165 			{
166 				status = Status.FINISHED;
167 			}
168 		}
169 		catch( Exception e )
170 		{
171 			SoapUI.logError( e );
172 			error = e;
173 		}
174 		finally
175 		{
176 			if( status != Status.CANCELED )
177 			{
178 				for( int i = 0; i < listeners.length; i++ )
179 				{
180 					try
181 					{
182 						listeners[i].afterSubmit( this, context );
183 					}
184 					catch( Throwable e )
185 					{
186 						SoapUI.logError( e );
187 					}
188 				}
189 			}
190 		}
191 	}
192 
193 	protected void runQuery() throws Exception
194 	{
195 		try
196 		{
197 			prepare();
198 			load();
199 		}
200 		catch( SQLException e )
201 		{
202 			throw e;
203 		}
204 		createResponse();
205 	}
206 
207 	public void cancelQuery()
208 	{
209 		try
210 		{
211 			if( statement != null )
212 				statement.cancel();
213 		}
214 		catch( SQLFeatureNotSupportedException e )
215 		{
216 			UISupport.showErrorMessage( e );
217 		}
218 		catch( SQLException ex )
219 		{
220 			UISupport.showErrorMessage( ex );
221 		}
222 	}
223 
224 	protected void getDatabaseConnection() throws Exception, SQLException
225 	{
226 		String drvr = "";
227 		String connStr = "";
228 		String pass = "";
229 
230 		JdbcRequestTestStep testStep = request.getTestStep();
231 
232 		if( !StringUtils.isNullOrEmpty( testStep.getDriver() )
233 				&& !StringUtils.isNullOrEmpty( testStep.getConnectionString() ) )
234 		{
235 			drvr = PropertyExpander.expandProperties( context, testStep.getDriver() ).trim();
236 			connStr = PropertyExpander.expandProperties( context, testStep.getConnectionString() ).trim();
237 			pass = PropertyExpander.expandProperties( context, testStep.getPassword() ).trim();
238 		}
239 		else
240 		{
241 			UISupport.showErrorMessage( "Please supply connection settings for all DataSources" );
242 			throw new SoapUIException( "Please supply connection settings" );
243 		}
244 		if( connStr.contains( JdbcRequestTestStep.PASS_TEMPLATE ) )
245 		{
246 			connStr = connStr.replaceFirst( JdbcRequestTestStep.PASS_TEMPLATE, pass );
247 		}
248 		try
249 		{
250 			DriverManager.getDriver( connStr );
251 		}
252 		catch( SQLException e )
253 		{
254 			try
255 			{
256 				Class.forName( drvr ).newInstance();
257 			}
258 			catch( Exception e1 )
259 			{
260 				throw new Exception( "Failed to init connection for drvr [" + drvr + "], connectionString ["
261 						+ testStep.getConnectionString() + "]" );
262 			}
263 		}
264 
265 		resultSet = null;
266 		connection = DriverManager.getConnection( connStr );
267 		// IMPORTANT: setting as readOnly raises an exception in calling stored
268 		// procedures!
269 		// connection.setReadOnly( true );
270 	}
271 
272 	protected void load() throws SQLException
273 	{
274 		try
275 		{
276 			JdbcRequestTestStep testStep = request.getTestStep();
277 
278 			if( testStep.isStoredProcedure() )
279 			{
280 				timestamp = System.currentTimeMillis();
281 				statement.execute();
282 			}
283 			else
284 			{
285 				timestamp = System.currentTimeMillis();
286 				statement.execute();
287 			}
288 			timeTaken = System.currentTimeMillis() - timestamp;
289 			if( !StringUtils.isNullOrEmpty( request.getTimeout() ) && timeTaken > Long.parseLong( request.getTimeout() ) )
290 			{
291 				context.setProperty( JDBC_TIMEOUT, PropertyExpander.expandProperties( context, request.getTimeout() ) );
292 			}
293 		}
294 		catch( SQLException e )
295 		{
296 			context.setProperty( JDBC_ERROR, e );
297 			throw e;
298 		}
299 		finally
300 		{
301 			timeTaken = System.currentTimeMillis() - timestamp;
302 		}
303 	}
304 
305 	protected void prepare() throws Exception
306 	{
307 		JdbcRequestTestStep testStep = request.getTestStep();
308 		getDatabaseConnection();
309 		String sql;
310 		List<TestProperty> props = testStep.getPropertyList();
311 		if( testStep.isStoredProcedure() )
312 		{
313 			sql = PropertyExpander.expandProperties( context, testStep.getQuery() );
314 
315 			if( !sql.startsWith( "{call " ) && !sql.endsWith( "}" ) )
316 				sql = "{call " + sql + "}";
317 
318 		}
319 		else
320 		{
321 			sql = PropertyExpander.expandProperties( context, testStep.getQuery() );
322 		}
323 		NamedParameterStatement p = new NamedParameterStatement( connection, sql );
324 		for( TestProperty testProperty : props )
325 		{
326 			String value = PropertyExpander.expandProperties( context, testProperty.getValue() );
327 			if( !testProperty.getName().equals( "ResponseAsXML" ) )
328 			{
329 				p.setString( testProperty.getName(), value );
330 			}
331 		}
332 		statement = p.getStatement();
333 
334 		try
335 		{
336 			if( !StringUtils.isNullOrEmpty( testStep.getQueryTimeout() ) )
337 			{
338 				String queryTimeout = PropertyExpander.expandProperties( testStep, testStep.getQueryTimeout() );
339 				statement.setQueryTimeout( Integer.parseInt( queryTimeout ) );
340 			}
341 		}
342 		catch( NumberFormatException e )
343 		{
344 			UISupport.showErrorMessage( "Problem setting timeout: " + e.getMessage() );
345 		}
346 
347 		try
348 		{
349 			if( !StringUtils.isNullOrEmpty( testStep.getMaxRows() ) )
350 			{
351 				String maxRows = PropertyExpander.expandProperties( testStep, testStep.getMaxRows() );
352 				statement.setMaxRows( Integer.parseInt( maxRows ) );
353 			}
354 		}
355 		catch( NumberFormatException e )
356 		{
357 			UISupport.showErrorMessage( "Problem setting maxRows: " + e.getMessage() );
358 		}
359 		try
360 		{
361 			if( !StringUtils.isNullOrEmpty( testStep.getFetchSize() ) )
362 			{
363 				String fetchSize = PropertyExpander.expandProperties( testStep, testStep.getFetchSize() );
364 				statement.setFetchSize( Integer.parseInt( fetchSize ) );
365 			}
366 		}
367 		catch( NumberFormatException e )
368 		{
369 			UISupport.showErrorMessage( "Problem setting fetchSize: " + e.getMessage() );
370 		}
371 	}
372 
373 	protected String createResponse()
374 	{
375 		try
376 		{
377 			response = new JdbcResponse( request, statement );
378 			response.setTimestamp( timestamp );
379 			response.setTimeTaken( timeTaken );
380 		}
381 		catch( Exception e )
382 		{
383 			SoapUI.logError( e );
384 		}
385 		finally
386 		{
387 			try
388 			{
389 				if( connection != null )
390 					connection.close();
391 				if( statement != null )
392 					statement.close();
393 				if( resultSet != null )
394 					resultSet.close();
395 			}
396 			catch( Exception e )
397 			{
398 			}
399 		}
400 		return null;
401 	}
402 }