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.mock;
14  
15  import java.io.IOException;
16  import java.io.PrintWriter;
17  import java.io.StringReader;
18  import java.util.Collections;
19  import java.util.HashMap;
20  import java.util.HashSet;
21  import java.util.LinkedList;
22  import java.util.List;
23  import java.util.Map;
24  import java.util.Set;
25  
26  import javax.servlet.http.HttpServletRequest;
27  import javax.servlet.http.HttpServletResponse;
28  
29  import org.mortbay.jetty.Request;
30  import org.xml.sax.InputSource;
31  
32  import com.eviware.soapui.SoapUI;
33  import com.eviware.soapui.impl.wsdl.WsdlInterface;
34  import com.eviware.soapui.impl.wsdl.WsdlOperation;
35  import com.eviware.soapui.impl.wsdl.support.soap.SoapUtils;
36  import com.eviware.soapui.impl.wsdl.support.soap.SoapVersion;
37  import com.eviware.soapui.impl.wsdl.support.wsdl.CachedWsdlLoader;
38  import com.eviware.soapui.impl.wsdl.support.wsdl.WsdlUtils;
39  import com.eviware.soapui.impl.wsdl.testcase.WsdlTestRunContext;
40  import com.eviware.soapui.model.iface.Interface;
41  import com.eviware.soapui.model.mock.MockResult;
42  import com.eviware.soapui.model.mock.MockRunListener;
43  import com.eviware.soapui.model.mock.MockRunner;
44  import com.eviware.soapui.monitor.MockEngine;
45  import com.eviware.soapui.support.StringUtils;
46  import com.eviware.soapui.support.types.StringToStringMap;
47  import com.eviware.soapui.support.xml.XmlUtils;
48  
49  /***
50   * MockRunner that dispatches Http Requests to their designated
51   * WsdlMockOperation if possible
52   * 
53   * @author ole.matzura
54   */
55  
56  public class WsdlMockRunner implements MockRunner
57  {
58  	private WsdlMockService mockService;
59  	private final List<WsdlMockResult> mockResults = Collections.synchronizedList( new LinkedList<WsdlMockResult>() );
60  	private long maxResults = 100;
61  	private int removed = 0;
62  	private final WsdlMockRunContext mockContext;
63  	private final Map<String, StringToStringMap> wsdlCache = new HashMap<String, StringToStringMap>();
64  	private boolean running;
65  
66  	public WsdlMockRunner( WsdlMockService mockService, WsdlTestRunContext context ) throws Exception
67  	{
68  		this.mockService = mockService;
69  
70  		Set<WsdlInterface> interfaces = new HashSet<WsdlInterface>();
71  
72  		for( int i = 0; i < mockService.getMockOperationCount(); i++ )
73  		{
74  			WsdlOperation operation = mockService.getMockOperationAt( i ).getOperation();
75  			if( operation != null )
76  				interfaces.add( operation.getInterface() );
77  		}
78  
79  		for( WsdlInterface iface : interfaces )
80  			iface.getWsdlContext().loadIfNecessary( false );
81  
82  		mockContext = new WsdlMockRunContext( mockService, context );
83  
84  		mockService.runStartScript( mockContext, this );
85  
86  		SoapUI.getMockEngine().startMockService( this );
87  		running = true;
88  		
89  		MockRunListener[] mockRunListeners = mockService.getMockRunListeners();
90  
91  		for( MockRunListener listener : mockRunListeners )
92  		{
93  			listener.onMockRunnerStart( this );
94  		}
95  
96  		initWsdlCache();
97  	}
98  
99  	private void initWsdlCache()
100 	{
101 		for( Interface iface : mockService.getMockedInterfaces() )
102 		{
103 			try
104 			{
105 				CachedWsdlLoader loader = null;
106 
107 				if( iface.isCached() )
108 				{
109 					loader = ( CachedWsdlLoader ) iface.createWsdlLoader();
110 				}
111 				else
112 				{
113 					loader = new CachedWsdlLoader( iface.getDefinition() );
114 				}
115 
116 				String wsdlPrefix = getInterfacePrefix( iface ).substring( 1 );
117 				StringToStringMap parts = loader.createFilesForExport( wsdlPrefix + "&part=" );
118 
119 				for( String key : parts.keySet() )
120 				{
121 					if( key.endsWith( ".wsdl" ) )
122 					{
123 						InputSource inputSource = new InputSource( new StringReader( parts.get( key ) ) );
124 						String content = WsdlUtils.replacePortEndpoint( iface, inputSource,  getLocalMockServiceEndpoint() );
125 						
126 						if( content != null )
127 							parts.put( key, content );
128 					}
129 				}
130 
131 				wsdlCache.put( iface.getName(), parts );
132 
133 				MockEngine.log.info( "Mounted WSDL for interface [" + iface.getName() + "] at [" + wsdlPrefix + "]" );
134 			}
135 			catch( Exception e )
136 			{
137 				e.printStackTrace();
138 			}
139 		}
140 	}
141 
142 	public String getLocalMockServiceEndpoint()
143 	{
144 		String host = mockService.getHost();
145 		if( StringUtils.isNullOrEmpty( host ))
146 			host = "127.0.0.1";
147 		
148 		return "http://" + host + ":" + mockService.getPort()	+ mockService.getPath();
149 	}
150 
151 	public String getInterfacePrefix( Interface iface )
152 	{
153 		String wsdlPrefix = getOverviewUrl() + "&interface=" + iface.getName();
154 		return wsdlPrefix;
155 	}
156 
157 	public WsdlMockRunContext getMockContext()
158 	{
159 		return mockContext;
160 	}
161 
162 	public synchronized void addMockResult( WsdlMockResult mockResult )
163 	{
164 		mockResults.add( mockResult );
165 		while( mockResults.size() > maxResults )
166 		{
167 			mockResults.remove( 0 );
168 			removed++;
169 		}
170 	}
171 	
172 	public boolean isRunning()
173 	{
174 		return running;
175 	}
176 
177 	public void stop()
178 	{
179 		if( !isRunning() )
180 			return;
181 		
182 		SoapUI.getMockEngine().stopMockService( this );
183 
184 		MockRunListener[] mockRunListeners = mockService.getMockRunListeners();
185 
186 		for( MockRunListener listener : mockRunListeners )
187 		{
188 			listener.onMockRunnerStop( this );
189 		}
190 
191 		try
192 		{
193 			mockService.runStopScript( mockContext, this );
194 			running = false;
195 		}
196 		catch( Exception e )
197 		{
198 			SoapUI.logError( e );
199 		}
200 	}
201 
202 	public WsdlMockService getMockService()
203 	{
204 		return mockService;
205 	}
206 
207 	public long getMaxResults()
208 	{
209 		return maxResults;
210 	}
211 
212 	public synchronized void setMaxResults( long l )
213 	{
214 		this.maxResults = l;
215 
216 		while( mockResults.size() > l )
217 		{
218 			mockResults.remove( 0 );
219 			removed++;
220 		}
221 	}
222 
223 	@SuppressWarnings( "unchecked" )
224 	public WsdlMockResult dispatchMockRequest( HttpServletRequest request, HttpServletResponse response )
225 				throws DispatchException
226 	{
227 		WsdlMockResult result = null;
228 		MockRunListener[] mockRunListeners = mockService.getMockRunListeners();
229 
230 		try
231 		{
232 			for( MockRunListener listener : mockRunListeners )
233 			{
234 				listener.onMockRequest( this, request, response );
235 			}
236 
237 			long timestamp = System.currentTimeMillis();
238 			WsdlMockRequest mockRequest = new WsdlMockRequest( request, response, mockContext );
239 
240 			SoapVersion soapVersion = mockRequest.getSoapVersion();
241 			if( soapVersion == null )
242 				throw new DispatchException( "Unrecognized SOAP Version" );
243 
244 			String soapAction = mockRequest.getSoapAction();
245 
246 			WsdlOperation operation = SoapUtils.findOperationForRequest( soapVersion, soapAction, mockRequest
247 						.getRequestXmlObject(), mockService.getProject().getInterfaceList(), mockService.isRequireSoapVersion() );
248 
249 			if( operation != null )
250 			{
251 				WsdlMockOperation mockOperation = mockService.getMockOperation( operation );
252 				if( mockOperation != null )
253 				{
254 					long startTime = System.nanoTime();
255 					result = mockOperation.dispatchRequest( mockRequest, response );
256 					( ( Request ) request ).setHandled( true );
257 					result.setTimeTaken( ( System.nanoTime() - startTime ) / 1000000 );
258 					result.setTimestamp( timestamp );
259 					addMockResult( result );
260 					return result;
261 				}
262 				else
263 				{
264 					throw new DispatchException( "Failed to find matching operation for request" );
265 				}
266 			}
267 
268 			throw new DispatchException( "Missing operation for soapAction [" + soapAction + "] and body element ["
269 						+ XmlUtils.getQName( mockRequest.getContentElement().getDomNode() ) + "] with SOAP Version ["
270 						+ mockRequest.getSoapVersion() + "]" );
271 		}
272 		catch( Exception e )
273 		{
274 			if( e instanceof DispatchException )
275 				throw ( DispatchException ) e;
276 
277 			throw new DispatchException( e );
278 		}
279 		finally
280 		{
281 			if( result != null )
282 			{
283 				for( MockRunListener listener : mockRunListeners )
284 				{
285 					listener.onMockResult( result );
286 				}
287 			}
288 		}
289 	}
290 
291 	public MockResult getMockResultAt( int index )
292 	{
293 		return index <= removed ? null : mockResults.get( index - removed );
294 	}
295 
296 	public int getMockResultCount()
297 	{
298 		return mockResults.size() + removed;
299 	}
300 
301 	public synchronized void clearResults()
302 	{
303 		mockResults.clear();
304 	}
305 
306 	public void release()
307 	{
308 		clearResults();
309 		mockService = null;
310 		mockContext.clear();
311 	}
312 
313 	public void dispatchWsdlRequest( HttpServletRequest request, HttpServletResponse response ) throws DispatchException
314 	{
315 		try
316 		{
317 			String ifaceName = request.getParameter( "interface" );
318 			WsdlInterface iface = mockService.getProject().getInterfaceByName( ifaceName );
319 			if( iface == null )
320 			{
321 				printInterfaceList( response );
322 				return;
323 			}
324 
325 			StringToStringMap parts = wsdlCache.get( iface.getName() );
326 			String content = parts.get( request.getParameter( "part" ) );
327 
328 			if( content == null )
329 			{
330 				printPartList( iface, parts, response );
331 				return;
332 			}
333 
334 			if( content != null )
335 			{
336 				response.setStatus( HttpServletResponse.SC_OK );
337 				response.setContentType( "text/xml" );
338 				response.setCharacterEncoding( "UTF-8" );
339 				response.getWriter().print( content );
340 			}
341 		}
342 		catch( Exception e )
343 		{
344 			e.printStackTrace();
345 		}
346 		finally
347 		{
348 			try
349 			{
350 				response.flushBuffer();
351 			}
352 			catch( IOException e )
353 			{
354 				e.printStackTrace();
355 			}
356 		}
357 	}
358 
359 	private void printPartList( WsdlInterface iface, StringToStringMap parts, HttpServletResponse response )
360 				throws IOException
361 	{
362 		response.setStatus( HttpServletResponse.SC_OK );
363 		response.setContentType( "text/html" );
364 
365 		PrintWriter out = response.getWriter();
366 		out.print( "<html><body><p>Parts in interface [" + iface.getName() + "]</p><ul>" );
367 
368 		for( String key : parts.keySet() )
369 		{
370 			out.print( "<li><a href=\"" );
371 			out.print( getInterfacePrefix( iface ) + "&part=" + key );
372 			out.print( "\">" + key + "</a></li>" );
373 		}
374 
375 		out.print( "</ul></p></body></html>" );
376 	}
377 
378 	private void printInterfaceList( HttpServletResponse response ) throws IOException
379 	{
380 		response.setStatus( HttpServletResponse.SC_OK );
381 		response.setContentType( "text/html" );
382 
383 		PrintWriter out = response.getWriter();
384 		out.print( "<html><body><p>Mocked Interfaces in project [" + mockService.getProject().getName() + "]</p><ul>" );
385 
386 		for( Interface iface : mockService.getProject().getInterfaceList() )
387 		{
388 			out.print( "<li><a href=\"" );
389 			out.print( getInterfacePrefix( iface ) );
390 			out.print( "\">" + iface.getName() + "</a></li>" );
391 		}
392 
393 		out.print( "</ul></p></body></html>" );
394 	}
395 
396 	public String getOverviewUrl()
397 	{
398 		return mockService.getPath() + "?WSDL";
399 	}
400 }