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