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