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 WsdlOperation operation = null;
247
248 if( SoapUtils.isSoapFault( mockRequest.getRequestContent(), soapVersion ) )
249 {
250
251 WsdlMockOperation faultMockOperation = mockService.getFaultMockOperation();
252 if( faultMockOperation != null )
253 operation = faultMockOperation.getOperation();
254 }
255 else
256 {
257 try
258 {
259 operation = SoapUtils.findOperationForRequest( soapVersion, soapAction, mockRequest
260 .getRequestXmlObject(), mockService.getMockedOperations(),
261 mockService.isRequireSoapVersion(), mockService.isRequireSoapAction() );
262 }
263 catch( Exception e )
264 {
265 if( mockService.isDispatchResponseMessages() )
266 {
267 try
268 {
269 operation = SoapUtils.findOperationForResponse( soapVersion, soapAction, mockRequest
270 .getRequestXmlObject(), mockService.getMockedOperations(),
271 mockService.isRequireSoapVersion(), mockService.isRequireSoapAction() );
272
273 if( operation != null )
274 {
275 mockRequest.setResponseMessage( true );
276 }
277 }
278 catch( Exception e2 )
279 {
280 throw e;
281 }
282 }
283 else
284 {
285 throw e;
286 }
287 }
288 }
289
290 if( operation != null )
291 {
292 WsdlMockOperation mockOperation = mockService.getMockOperation( operation );
293 if( mockOperation != null )
294 {
295 long startTime = System.nanoTime();
296 try
297 {
298 result = mockOperation.dispatchRequest( mockRequest );
299 }
300 catch( DispatchException e )
301 {
302 result = new WsdlMockResult( mockRequest );
303
304 String fault = SoapMessageBuilder.buildFault( "Server", e.getMessage(), mockRequest.getSoapVersion() );
305 result.setResponseContent( fault );
306 result.setMockOperation( mockOperation );
307
308 mockRequest.getHttpResponse().getWriter().write( fault );
309 }
310
311 if( mockRequest.getHttpRequest() instanceof org.mortbay.jetty.Request )
312 ( (org.mortbay.jetty.Request) mockRequest.getHttpRequest() ).setHandled( true );
313
314 result.setTimeTaken( ( System.nanoTime() - startTime ) / 1000000 );
315 result.setTimestamp( timestamp );
316 addMockResult( result );
317 return result;
318 }
319 else
320 {
321 throw new DispatchException( "Failed to find matching operation for request" );
322 }
323 }
324
325 throw new DispatchException( "Missing operation for soapAction [" + soapAction + "] and body element ["
326 + XmlUtils.getQName( mockRequest.getContentElement().getDomNode() ) + "] with SOAP Version ["
327 + mockRequest.getSoapVersion() + "]" );
328 }
329 catch( Exception e )
330 {
331 if( e instanceof DispatchException )
332 throw (DispatchException) e;
333
334 throw new DispatchException( e );
335 }
336 finally
337 {
338 if( result != null )
339 {
340 for( MockRunListener listener : mockRunListeners )
341 {
342 listener.onMockResult( result );
343 }
344 }
345 }
346 }
347
348 public MockResult getMockResultAt( int index )
349 {
350 return index <= removed ? null : mockResults.get( index - removed );
351 }
352
353 public int getMockResultCount()
354 {
355 return mockResults.size() + removed;
356 }
357
358 public synchronized void clearResults()
359 {
360 mockResults.clear();
361 }
362
363 public void release()
364 {
365 clearResults();
366 mockService = null;
367 mockContext.clear();
368 }
369
370 @Override
371 public MockResult dispatchRequest( HttpServletRequest request, HttpServletResponse response ) throws DispatchException
372 {
373 try
374 {
375 WsdlMockRequest mockRequest = new WsdlMockRequest( request, response, mockContext );
376 Object result = mockService.runOnRequestScript( mockContext, this, mockRequest );
377 if( !( result instanceof MockResult ) )
378 {
379 String method = request.getMethod();
380
381 if( method.equals( "POST" ) )
382 result = dispatchPostRequest( mockRequest );
383 else
384 result = super.dispatchRequest( request, response );
385 }
386
387 mockService.runAfterRequestScript( mockContext, this, (MockResult) result );
388 return (MockResult) result;
389 }
390 catch( Exception e )
391 {
392 throw new DispatchException( e );
393 }
394 }
395
396 public MockResult dispatchGetRequest( HttpServletRequest request, HttpServletResponse response ) throws DispatchException
397 {
398 try
399 {
400 if( request.getQueryString() != null && request.getQueryString().startsWith( "WSDL" ) )
401 {
402 dispatchWsdlRequest( request, response );
403 }
404 else
405 {
406 String docroot = getMockService().getDocroot();
407 if( StringUtils.hasContent( docroot ) )
408 {
409 try
410 {
411 File file = new File( docroot + request.getPathInfo().replace( '/', File.separatorChar ) );
412 FileInputStream in = new FileInputStream( file );
413 response.setStatus( HttpServletResponse.SC_OK );
414 long length = file.length();
415 response.setContentLength( (int) length );
416 response.setContentType( ContentTypeHandler.getContentTypeFromFilename( file.getName() ) );
417 Tools.readAndWrite( in, length, response.getOutputStream() );
418 }
419 catch( Exception e )
420 {
421 throw new DispatchException( e );
422 }
423 }
424 }
425
426 return null;
427 }
428 catch( Exception e )
429 {
430 throw new DispatchException( e );
431 }
432 }
433
434 protected void dispatchWsdlRequest( HttpServletRequest request, HttpServletResponse response ) throws IOException
435 {
436 if( request.getQueryString().equalsIgnoreCase( "WSDL" ) )
437 {
438 printWsdl( response );
439 return;
440 }
441
442 String ifaceName = request.getParameter( "interface" );
443 WsdlInterface iface = (WsdlInterface) mockService.getProject().getInterfaceByName( ifaceName );
444 if( iface == null )
445 {
446 printInterfaceList( response );
447 return;
448 }
449
450 StringToStringMap parts = wsdlCache.get( iface.getName() );
451 String part = request.getParameter( "part" );
452 String content = StringUtils.isNullOrEmpty( part ) ? null : parts.get( part );
453
454 if( content == null )
455 {
456 printPartList( iface, parts, response );
457 return;
458 }
459
460 if( content != null )
461 {
462 printOkXmlResult( response, content );
463 }
464 }
465
466 private void printOkXmlResult( HttpServletResponse response, String content ) throws IOException
467 {
468 response.setStatus( HttpServletResponse.SC_OK );
469 response.setContentType( "text/xml" );
470 response.setCharacterEncoding( "UTF-8" );
471 response.getWriter().print( content );
472 }
473
474 private void printWsdl( HttpServletResponse response ) throws IOException
475 {
476 WsdlInterface[] mockedInterfaces = mockService.getMockedInterfaces();
477 if( mockedInterfaces.length == 1 )
478 {
479 StringToStringMap parts = wsdlCache.get( mockedInterfaces[0].getName() );
480 printOkXmlResult( response, parts.get( parts.get( "#root#" ) ) );
481 }
482 else
483 {
484 try
485 {
486 WSDLFactory wsdlFactory = WSDLFactory.newInstance();
487 Definition def = wsdlFactory.newDefinition();
488 for( WsdlInterface iface : mockedInterfaces )
489 {
490 StringToStringMap parts = wsdlCache.get( iface.getName() );
491 Import wsdlImport = def.createImport();
492 wsdlImport.setLocationURI( getInterfacePrefix( iface ) + "&part=" + parts.get( "#root#" ) );
493 wsdlImport.setNamespaceURI( iface.getWsdlContext().getDefinition().getTargetNamespace() );
494
495 def.addImport( wsdlImport );
496 }
497
498 response.setStatus( HttpServletResponse.SC_OK );
499 response.setContentType( "text/xml" );
500 response.setCharacterEncoding( "UTF-8" );
501
502 WSDLWriter writer = wsdlFactory.newWSDLWriter();
503 writer.writeWSDL( def, response.getWriter() );
504 }
505 catch( Exception e )
506 {
507 SoapUI.logError( e );
508 throw new IOException( "Failed to create combined WSDL" );
509 }
510 }
511 }
512
513 private void printPartList( WsdlInterface iface, StringToStringMap parts, HttpServletResponse response )
514 throws IOException
515 {
516 response.setStatus( HttpServletResponse.SC_OK );
517 response.setContentType( "text/html" );
518
519 PrintWriter out = response.getWriter();
520 out.print( "<html><body><p>Parts in interface [" + iface.getName() + "]</p><ul>" );
521
522 for( String key : parts.keySet() )
523 {
524 if( key.equals( "#root#" ) )
525 continue;
526
527 out.print( "<li><a href=\"" );
528 out.print( getInterfacePrefix( iface ) + "&part=" + key );
529 out.print( "\">" + key + "</a></li>" );
530 }
531
532 out.print( "</ul></p></body></html>" );
533 }
534
535 private void printInterfaceList( HttpServletResponse response ) throws IOException
536 {
537 response.setStatus( HttpServletResponse.SC_OK );
538 response.setContentType( "text/html" );
539
540 PrintWriter out = response.getWriter();
541 out.print( "<html><body><p>Mocked Interfaces in project [" + mockService.getProject().getName() + "]</p><ul>" );
542
543 for( Interface iface : mockService.getProject().getInterfaceList() )
544 {
545 out.print( "<li><a href=\"" );
546 out.print( getInterfacePrefix( iface ) );
547 out.print( "\">" + iface.getName() + "</a></li>" );
548 }
549
550 out.print( "</ul></p></body></html>" );
551 }
552
553 public String getOverviewUrl()
554 {
555 return mockService.getPath() + "?WSDL";
556 }
557
558 public void setLogEnabled( boolean logEnabled )
559 {
560 this.logEnabled = logEnabled;
561 }
562 }