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();
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(), 
248 						mockService.isRequireSoapVersion(), mockService.isRequireSoapAction() );
249 
250 			if( operation != null )
251 			{
252 				WsdlMockOperation mockOperation = mockService.getMockOperation( operation );
253 				if( mockOperation != null )
254 				{
255 					long startTime = System.nanoTime();
256 					result = mockOperation.dispatchRequest( mockRequest, response );
257 					( ( Request ) request ).setHandled( true );
258 					result.setTimeTaken( ( System.nanoTime() - startTime ) / 1000000 );
259 					result.setTimestamp( timestamp );
260 					addMockResult( result );
261 					return result;
262 				}
263 				else
264 				{
265 					throw new DispatchException( "Failed to find matching operation for request" );
266 				}
267 			}
268 
269 			throw new DispatchException( "Missing operation for soapAction [" + soapAction + "] and body element ["
270 						+ XmlUtils.getQName( mockRequest.getContentElement().getDomNode() ) + "] with SOAP Version ["
271 						+ mockRequest.getSoapVersion() + "]" );
272 		}
273 		catch( Exception e )
274 		{
275 			if( e instanceof DispatchException )
276 				throw ( DispatchException ) e;
277 
278 			throw new DispatchException( e );
279 		}
280 		finally
281 		{
282 			if( result != null )
283 			{
284 				for( MockRunListener listener : mockRunListeners )
285 				{
286 					listener.onMockResult( result );
287 				}
288 			}
289 		}
290 	}
291 
292 	public MockResult getMockResultAt( int index )
293 	{
294 		return index <= removed ? null : mockResults.get( index - removed );
295 	}
296 
297 	public int getMockResultCount()
298 	{
299 		return mockResults.size() + removed;
300 	}
301 
302 	public synchronized void clearResults()
303 	{
304 		mockResults.clear();
305 	}
306 
307 	public void release()
308 	{
309 		clearResults();
310 		mockService = null;
311 		mockContext.clear();
312 	}
313 
314 	public void dispatchWsdlRequest( HttpServletRequest request, HttpServletResponse response ) throws DispatchException
315 	{
316 		try
317 		{
318 			String ifaceName = request.getParameter( "interface" );
319 			WsdlInterface iface = mockService.getProject().getInterfaceByName( ifaceName );
320 			if( iface == null )
321 			{
322 				printInterfaceList( response );
323 				return;
324 			}
325 
326 			StringToStringMap parts = wsdlCache.get( iface.getName() );
327 			String content = parts.get( request.getParameter( "part" ) );
328 
329 			if( content == null )
330 			{
331 				printPartList( iface, parts, response );
332 				return;
333 			}
334 
335 			if( content != null )
336 			{
337 				response.setStatus( HttpServletResponse.SC_OK );
338 				response.setContentType( "text/xml" );
339 				response.setCharacterEncoding( "UTF-8" );
340 				response.getWriter().print( content );
341 			}
342 		}
343 		catch( Exception e )
344 		{
345 			e.printStackTrace();
346 		}
347 		finally
348 		{
349 			try
350 			{
351 				response.flushBuffer();
352 			}
353 			catch( IOException e )
354 			{
355 				e.printStackTrace();
356 			}
357 		}
358 	}
359 
360 	private void printPartList( WsdlInterface iface, StringToStringMap parts, HttpServletResponse response )
361 				throws IOException
362 	{
363 		response.setStatus( HttpServletResponse.SC_OK );
364 		response.setContentType( "text/html" );
365 
366 		PrintWriter out = response.getWriter();
367 		out.print( "<html><body><p>Parts in interface [" + iface.getName() + "]</p><ul>" );
368 
369 		for( String key : parts.keySet() )
370 		{
371 			out.print( "<li><a href=\"" );
372 			out.print( getInterfacePrefix( iface ) + "&part=" + key );
373 			out.print( "\">" + key + "</a></li>" );
374 		}
375 
376 		out.print( "</ul></p></body></html>" );
377 	}
378 
379 	private void printInterfaceList( HttpServletResponse response ) throws IOException
380 	{
381 		response.setStatus( HttpServletResponse.SC_OK );
382 		response.setContentType( "text/html" );
383 
384 		PrintWriter out = response.getWriter();
385 		out.print( "<html><body><p>Mocked Interfaces in project [" + mockService.getProject().getName() + "]</p><ul>" );
386 
387 		for( Interface iface : mockService.getProject().getInterfaceList() )
388 		{
389 			out.print( "<li><a href=\"" );
390 			out.print( getInterfacePrefix( iface ) );
391 			out.print( "\">" + iface.getName() + "</a></li>" );
392 		}
393 
394 		out.print( "</ul></p></body></html>" );
395 	}
396 
397 	public String getOverviewUrl()
398 	{
399 		return mockService.getPath() + "?WSDL";
400 	}
401 }