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