1
2
3
4
5
6
7
8
9
10
11
12
13 package com.eviware.soapui.impl.wsdl.mock;
14
15 import com.eviware.soapui.SoapUI;
16 import com.eviware.soapui.impl.WsdlInterfaceFactory;
17 import com.eviware.soapui.impl.support.definition.export.WsdlDefinitionExporter;
18 import com.eviware.soapui.impl.wsdl.WsdlInterface;
19 import com.eviware.soapui.impl.wsdl.WsdlOperation;
20 import com.eviware.soapui.impl.wsdl.support.soap.SoapMessageBuilder;
21 import com.eviware.soapui.impl.wsdl.support.soap.SoapUtils;
22 import com.eviware.soapui.impl.wsdl.support.soap.SoapVersion;
23 import com.eviware.soapui.impl.wsdl.support.wsdl.WsdlUtils;
24 import com.eviware.soapui.impl.wsdl.testcase.WsdlTestRunContext;
25 import com.eviware.soapui.model.iface.Interface;
26 import com.eviware.soapui.model.mock.MockResult;
27 import com.eviware.soapui.model.mock.MockRunListener;
28 import com.eviware.soapui.model.support.AbstractMockRunner;
29 import com.eviware.soapui.monitor.MockEngine;
30 import com.eviware.soapui.support.StringUtils;
31 import com.eviware.soapui.support.Tools;
32 import com.eviware.soapui.support.editor.inspectors.attachments.ContentTypeHandler;
33 import com.eviware.soapui.support.types.StringToStringMap;
34 import com.eviware.soapui.support.xml.XmlUtils;
35 import org.xml.sax.InputSource;
36
37 import javax.servlet.http.HttpServletRequest;
38 import javax.servlet.http.HttpServletResponse;
39 import javax.wsdl.Definition;
40 import javax.wsdl.Import;
41 import javax.wsdl.factory.WSDLFactory;
42 import javax.wsdl.xml.WSDLWriter;
43 import java.io.*;
44 import java.util.*;
45
46 /***
47 * MockRunner that dispatches Http Requests to their designated
48 * WsdlMockOperation if possible
49 *
50 * @author ole.matzura
51 */
52
53 public class WsdlMockRunner extends AbstractMockRunner
54 {
55 private WsdlMockService mockService;
56 private final List<WsdlMockResult> mockResults = Collections.synchronizedList( new LinkedList<WsdlMockResult>() );
57 private long maxResults = 100;
58 private int removed = 0;
59 private final WsdlMockRunContext mockContext;
60 private final Map<String, StringToStringMap> wsdlCache = new HashMap<String, StringToStringMap>();
61 private boolean running;
62 private boolean logEnabled = true;
63
64 public WsdlMockRunner( WsdlMockService mockService, WsdlTestRunContext context ) throws Exception
65 {
66 this.mockService = mockService;
67
68 Set<WsdlInterface> interfaces = new HashSet<WsdlInterface>();
69
70 for( int i = 0; i < mockService.getMockOperationCount(); i++ )
71 {
72 WsdlOperation operation = mockService.getMockOperationAt( i ).getOperation();
73 if( operation != null )
74 interfaces.add( operation.getInterface() );
75 }
76
77 for( WsdlInterface iface : interfaces )
78 iface.getWsdlContext().loadIfNecessary();
79
80 mockContext = new WsdlMockRunContext( mockService, context );
81
82 mockService.runStartScript( mockContext, this );
83
84 SoapUI.getMockEngine().startMockService( this );
85 running = true;
86
87 MockRunListener[] mockRunListeners = mockService.getMockRunListeners();
88
89 for( MockRunListener listener : mockRunListeners )
90 {
91 listener.onMockRunnerStart( this );
92 }
93
94 initWsdlCache();
95 }
96
97 private void initWsdlCache()
98 {
99 for( Interface iface : mockService.getMockedInterfaces() )
100 {
101 if( !iface.getInterfaceType().equals( WsdlInterfaceFactory.WSDL_TYPE ) )
102 continue;
103
104 try
105 {
106 WsdlDefinitionExporter exporter = new WsdlDefinitionExporter( (WsdlInterface) iface );
107
108 String wsdlPrefix = getInterfacePrefix( iface ).substring( 1 );
109 StringToStringMap parts = exporter.createFilesForExport( wsdlPrefix + "&part=" );
110
111 for( String key : parts.keySet() )
112 {
113 if( key.toLowerCase().endsWith( ".wsdl" ) )
114 {
115 InputSource inputSource = new InputSource( new StringReader( parts.get( key ) ) );
116 String content = WsdlUtils.replacePortEndpoint( (WsdlInterface) iface, inputSource, getLocalMockServiceEndpoint() );
117
118 if( content != null )
119 parts.put( key, content );
120 }
121 }
122
123 wsdlCache.put( iface.getName(), parts );
124
125 MockEngine.log.info( "Mounted WSDL for interface [" + iface.getName() + "] at [" + getOverviewUrl() + "]" );
126 }
127 catch( Exception e )
128 {
129 SoapUI.logError( e );
130 }
131 }
132 }
133
134 public String getLocalMockServiceEndpoint()
135 {
136 String host = mockService.getHost();
137 if( StringUtils.isNullOrEmpty( host ) )
138 host = "127.0.0.1";
139
140 return "http://" + host + ":" + mockService.getPort() + mockService.getPath();
141 }
142
143 public String getInterfacePrefix( Interface iface )
144 {
145 String wsdlPrefix = getOverviewUrl() + "&interface=" + iface.getName();
146 return wsdlPrefix;
147 }
148
149 public WsdlMockRunContext getMockContext()
150 {
151 return mockContext;
152 }
153
154 public synchronized void addMockResult( WsdlMockResult mockResult )
155 {
156 if( maxResults > 0 && logEnabled )
157 mockResults.add( mockResult );
158
159 while( mockResults.size() > maxResults )
160 {
161 mockResults.remove( 0 );
162 removed++;
163 }
164 }
165
166 public boolean isRunning()
167 {
168 return running;
169 }
170
171 public void stop()
172 {
173 if( !isRunning() )
174 return;
175
176 SoapUI.getMockEngine().stopMockService( this );
177
178 MockRunListener[] mockRunListeners = mockService.getMockRunListeners();
179
180 for( MockRunListener listener : mockRunListeners )
181 {
182 listener.onMockRunnerStop( this );
183 }
184
185 try
186 {
187 mockService.runStopScript( mockContext, this );
188 running = false;
189 }
190 catch( Exception e )
191 {
192 SoapUI.logError( e );
193 }
194 }
195
196 public WsdlMockService getMockService()
197 {
198 return mockService;
199 }
200
201 public long getMaxResults()
202 {
203 return maxResults;
204 }
205
206 public synchronized void setMaxResults( long l )
207 {
208 this.maxResults = l;
209
210 while( mockResults.size() > l )
211 {
212 mockResults.remove( 0 );
213 removed++;
214 }
215 }
216
217 @Override
218 public MockResult dispatchHeadRequest( HttpServletRequest request, HttpServletResponse response )
219 throws DispatchException
220 {
221 response.setStatus( HttpServletResponse.SC_OK );
222 return null;
223 }
224
225 @SuppressWarnings( "unchecked" )
226 public WsdlMockResult dispatchPostRequest( WsdlMockRequest mockRequest )
227 throws DispatchException
228 {
229 WsdlMockResult result = null;
230 MockRunListener[] mockRunListeners = mockService.getMockRunListeners();
231
232 try
233 {
234 for( MockRunListener listener : mockRunListeners )
235 {
236 listener.onMockRequest( this, mockRequest.getHttpRequest(), mockRequest.getHttpResponse() );
237 }
238
239 long timestamp = System.currentTimeMillis();
240
241 SoapVersion soapVersion = mockRequest.getSoapVersion();
242 if( soapVersion == null )
243 throw new DispatchException( "Unrecognized SOAP Version" );
244
245 String soapAction = mockRequest.getSoapAction();
246
247 WsdlOperation operation = SoapUtils.findOperationForRequest( soapVersion, soapAction, mockRequest
248 .getRequestXmlObject(), mockService.getMockedOperations(),
249 mockService.isRequireSoapVersion(), mockService.isRequireSoapAction() );
250
251 if( operation != null )
252 {
253 WsdlMockOperation mockOperation = mockService.getMockOperation( operation );
254 if( mockOperation != null )
255 {
256 long startTime = System.nanoTime();
257 try
258 {
259 result = mockOperation.dispatchRequest( mockRequest );
260 }
261 catch( DispatchException e )
262 {
263 result = new WsdlMockResult( mockRequest );
264
265 String fault = SoapMessageBuilder.buildFault( "Server", e.getMessage(), mockRequest.getSoapVersion() );
266 result.setResponseContent( fault );
267 result.setMockOperation( mockOperation );
268
269 mockRequest.getHttpResponse().getWriter().write( fault );
270 }
271
272 if( mockRequest.getHttpRequest() instanceof org.mortbay.jetty.Request )
273 ( (org.mortbay.jetty.Request) mockRequest.getHttpRequest() ).setHandled( true );
274
275 result.setTimeTaken( ( System.nanoTime() - startTime ) / 1000000 );
276 result.setTimestamp( timestamp );
277 addMockResult( result );
278 return result;
279 }
280 else
281 {
282 throw new DispatchException( "Failed to find matching operation for request" );
283 }
284 }
285
286 throw new DispatchException( "Missing operation for soapAction [" + soapAction + "] and body element ["
287 + XmlUtils.getQName( mockRequest.getContentElement().getDomNode() ) + "] with SOAP Version ["
288 + mockRequest.getSoapVersion() + "]" );
289 }
290 catch( Exception e )
291 {
292 if( e instanceof DispatchException )
293 throw (DispatchException) e;
294
295 throw new DispatchException( e );
296 }
297 finally
298 {
299 if( result != null )
300 {
301 for( MockRunListener listener : mockRunListeners )
302 {
303 listener.onMockResult( result );
304 }
305 }
306 }
307 }
308
309 public MockResult getMockResultAt( int index )
310 {
311 return index <= removed ? null : mockResults.get( index - removed );
312 }
313
314 public int getMockResultCount()
315 {
316 return mockResults.size() + removed;
317 }
318
319 public synchronized void clearResults()
320 {
321 mockResults.clear();
322 }
323
324 public void release()
325 {
326 clearResults();
327 mockService = null;
328 mockContext.clear();
329 }
330
331 @Override
332 public MockResult dispatchRequest( HttpServletRequest request, HttpServletResponse response ) throws DispatchException
333 {
334 try
335 {
336 WsdlMockRequest mockRequest = new WsdlMockRequest( request, response, mockContext );
337 Object result = mockService.runOnRequestScript( mockContext, this, mockRequest );
338 if( !(result instanceof MockResult) )
339 {
340 String method = request.getMethod();
341
342 if( method.equals( "POST" ) )
343 result = dispatchPostRequest( mockRequest );
344 else
345 result = super.dispatchRequest( request, response );
346 }
347
348 mockService.runAfterRequestScript( mockContext, this, (MockResult) result );
349 return (MockResult) result;
350 }
351 catch( Exception e )
352 {
353 throw new DispatchException( e );
354 }
355 }
356
357 public MockResult dispatchGetRequest( HttpServletRequest request, HttpServletResponse response ) throws DispatchException
358 {
359 try
360 {
361 if( request.getQueryString() != null && request.getQueryString().startsWith( "WSDL" ) )
362 {
363 dispatchWsdlRequest( request, response );
364 }
365 else
366 {
367 String docroot = getMockService().getDocroot();
368 if( StringUtils.hasContent( docroot ) )
369 {
370 try
371 {
372 File file = new File( docroot + request.getPathInfo().replace( '/', File.separatorChar ) );
373 FileInputStream in = new FileInputStream( file );
374 response.setStatus( HttpServletResponse.SC_OK );
375 long length = file.length();
376 response.setContentLength( (int) length );
377 response.setContentType( ContentTypeHandler.getContentTypeFromFilename( file.getName() ) );
378 Tools.readAndWrite( in, length, response.getOutputStream() );
379 }
380 catch( Exception e )
381 {
382 throw new DispatchException( e );
383 }
384 }
385 }
386
387 return null;
388 }
389 catch( Exception e )
390 {
391 throw new DispatchException( e );
392 }
393 finally
394 {
395 try
396 {
397 response.flushBuffer();
398 }
399 catch( IOException e )
400 {
401 throw new DispatchException( e );
402 }
403 }
404 }
405
406 protected void dispatchWsdlRequest( HttpServletRequest request, HttpServletResponse response ) throws IOException
407 {
408 if( request.getQueryString().equalsIgnoreCase( "WSDL" ) )
409 {
410 printWsdl( response );
411 return;
412 }
413
414 String ifaceName = request.getParameter( "interface" );
415 WsdlInterface iface = (WsdlInterface) mockService.getProject().getInterfaceByName( ifaceName );
416 if( iface == null )
417 {
418 printInterfaceList( response );
419 return;
420 }
421
422 StringToStringMap parts = wsdlCache.get( iface.getName() );
423 String part = request.getParameter( "part" );
424 String content = StringUtils.isNullOrEmpty( part ) ? null : parts.get( part );
425
426 if( content == null )
427 {
428 printPartList( iface, parts, response );
429 return;
430 }
431
432 if( content != null )
433 {
434 printOkXmlResult( response, content );
435 }
436 }
437
438 private void printOkXmlResult( HttpServletResponse response, String content ) throws IOException
439 {
440 response.setStatus( HttpServletResponse.SC_OK );
441 response.setContentType( "text/xml" );
442 response.setCharacterEncoding( "UTF-8" );
443 response.getWriter().print( content );
444 }
445
446 private void printWsdl( HttpServletResponse response ) throws IOException
447 {
448 WsdlInterface[] mockedInterfaces = mockService.getMockedInterfaces();
449 if( mockedInterfaces.length == 1 )
450 {
451 StringToStringMap parts = wsdlCache.get( mockedInterfaces[0].getName() );
452 printOkXmlResult( response, parts.get( parts.get( "#root#" ) ) );
453 }
454 else
455 {
456 try
457 {
458 WSDLFactory wsdlFactory = WSDLFactory.newInstance();
459 Definition def = wsdlFactory.newDefinition();
460 for( WsdlInterface iface : mockedInterfaces )
461 {
462 StringToStringMap parts = wsdlCache.get( iface.getName() );
463 Import wsdlImport = def.createImport();
464 wsdlImport.setLocationURI( getInterfacePrefix( iface ) + "&part=" + parts.get( "#root#" ) );
465 wsdlImport.setNamespaceURI( iface.getWsdlContext().getDefinition().getTargetNamespace() );
466
467 def.addImport( wsdlImport );
468 }
469
470 response.setStatus( HttpServletResponse.SC_OK );
471 response.setContentType( "text/xml" );
472 response.setCharacterEncoding( "UTF-8" );
473
474 WSDLWriter writer = wsdlFactory.newWSDLWriter();
475 writer.writeWSDL( def, response.getWriter() );
476 }
477 catch( Exception e )
478 {
479 SoapUI.logError( e );
480 throw new IOException( "Failed to create combined WSDL" );
481 }
482 }
483 }
484
485 private void printPartList( WsdlInterface iface, StringToStringMap parts, HttpServletResponse response )
486 throws IOException
487 {
488 response.setStatus( HttpServletResponse.SC_OK );
489 response.setContentType( "text/html" );
490
491 PrintWriter out = response.getWriter();
492 out.print( "<html><body><p>Parts in interface [" + iface.getName() + "]</p><ul>" );
493
494 for( String key : parts.keySet() )
495 {
496 if( key.equals( "#root#" ) )
497 continue;
498
499 out.print( "<li><a href=\"" );
500 out.print( getInterfacePrefix( iface ) + "&part=" + key );
501 out.print( "\">" + key + "</a></li>" );
502 }
503
504 out.print( "</ul></p></body></html>" );
505 }
506
507 private void printInterfaceList( HttpServletResponse response ) throws IOException
508 {
509 response.setStatus( HttpServletResponse.SC_OK );
510 response.setContentType( "text/html" );
511
512 PrintWriter out = response.getWriter();
513 out.print( "<html><body><p>Mocked Interfaces in project [" + mockService.getProject().getName() + "]</p><ul>" );
514
515 for( Interface iface : mockService.getProject().getInterfaceList() )
516 {
517 out.print( "<li><a href=\"" );
518 out.print( getInterfacePrefix( iface ) );
519 out.print( "\">" + iface.getName() + "</a></li>" );
520 }
521
522 out.print( "</ul></p></body></html>" );
523 }
524
525 public String getOverviewUrl()
526 {
527 return mockService.getPath() + "?WSDL";
528 }
529
530 public void setLogEnabled( boolean logEnabled )
531 {
532 this.logEnabled = logEnabled;
533 }
534 }